line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#! perl |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package App::Module::Setup; |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
### Please use this module via the command line module-setup tool. |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.07'; |
8
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
68006
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
36
|
|
10
|
1
|
|
|
1
|
|
7
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
20
|
|
11
|
1
|
|
|
1
|
|
5
|
use File::Find; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
55
|
|
12
|
1
|
|
|
1
|
|
6
|
use File::Basename qw( dirname ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
68
|
|
13
|
1
|
|
|
1
|
|
7
|
use File::Path qw( mkpath ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1075
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub main { |
16
|
0
|
|
|
0
|
1
|
|
my $options = shift; |
17
|
|
|
|
|
|
|
# Just in case we're called as a method. |
18
|
0
|
0
|
|
|
|
|
eval { $options->{module} || 1 } or $options = shift; |
|
0
|
0
|
|
|
|
|
|
19
|
|
|
|
|
|
|
|
20
|
0
|
|
|
|
|
|
my $tpldir = "templates/". $options->{template}; |
21
|
0
|
|
|
|
|
|
my $mod = $options->{module}; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# Replacement variables |
24
|
|
|
|
|
|
|
my $vars = |
25
|
|
|
|
|
|
|
{ "module.name" => $mod, # Foo::Bar |
26
|
|
|
|
|
|
|
"module.version" => "0.01", |
27
|
|
|
|
|
|
|
"module.license" => $options->{license} || "perl_5", |
28
|
|
|
|
|
|
|
"current.year" => $options->{year} || 1900 + (localtime)[5], |
29
|
|
|
|
|
|
|
"author.name" => $options->{author} || (getpwuid($<))[6], |
30
|
|
|
|
|
|
|
"author.email" => $options->{email}, |
31
|
|
|
|
|
|
|
"author.cpanid" => $options->{cpanid}, |
32
|
0
|
|
0
|
|
|
|
"perl.minversion" => $options->{minperl} || '5.008000', |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
33
|
|
|
|
|
|
|
}; |
34
|
|
|
|
|
|
|
|
35
|
0
|
|
|
|
|
|
my $dir; |
36
|
0
|
0
|
|
|
|
|
if ( $options->{'install-templates'} ) { |
37
|
0
|
|
|
|
|
|
$dir = $tpldir; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
else { |
40
|
0
|
|
|
|
|
|
( $dir = $mod ) =~ s/::/-/g; |
41
|
0
|
|
|
|
|
|
$vars->{"module.distname"} = $dir; # Foo-Bar |
42
|
0
|
|
|
|
|
|
$vars->{"module.distnamelc"} = lc($dir); |
43
|
0
|
|
|
|
|
|
( my $t = $mod ) =~ s/::/\//g; |
44
|
0
|
|
|
|
|
|
$vars->{"module.filename"} = $t . ".pm"; # Foo/Bar.pm |
45
|
|
|
|
|
|
|
$vars->{"author.cpanid"} ||= $1 |
46
|
|
|
|
|
|
|
if $options->{email} |
47
|
0
|
0
|
0
|
|
|
|
&& $options->{email} =~ /^(.*)\@cpan.org$/i; |
|
|
|
0
|
|
|
|
|
48
|
|
|
|
|
|
|
$vars->{"author.cpanid"} = uc( $vars->{"author.cpanid"} ) |
49
|
0
|
0
|
|
|
|
|
if $vars->{"author.cpanid"}; |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
0
|
0
|
|
|
|
|
if ( -d $dir ) { |
53
|
0
|
|
|
|
|
|
die( "Directory $dir exists. Aborted!\n" ); |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# Get template names and data. |
57
|
0
|
|
|
|
|
|
my ( $files, $dirs, $data ); |
58
|
0
|
|
|
|
|
|
for my $cfg ( "./", @{ $options->{_configs} } ) { |
|
0
|
|
|
|
|
|
|
59
|
0
|
0
|
|
|
|
|
if ( -d "$cfg$tpldir" ) { |
60
|
0
|
|
|
|
|
|
( $files, $dirs, $data ) = |
61
|
|
|
|
|
|
|
load_templates_from_directory( "$cfg$tpldir" ); |
62
|
0
|
0
|
|
|
|
|
last if $files; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# Nope. Use built-in defaults. |
67
|
0
|
0
|
|
|
|
|
unless ( $files ) { |
68
|
0
|
0
|
|
|
|
|
unless ( $options->{template} eq "default" ) { |
69
|
|
|
|
|
|
|
warn( "No templates found for ", $options->{template}, |
70
|
0
|
|
|
|
|
|
", using default templates\n" ); |
71
|
|
|
|
|
|
|
} |
72
|
0
|
|
|
|
|
|
require App::Module::Setup::Templates::Default; |
73
|
0
|
|
|
|
|
|
( $files, $dirs, $data ) = |
74
|
|
|
|
|
|
|
App::Module::Setup::Templates::Default->load; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
0
|
0
|
|
|
|
|
if ( $options->{'install-templates'} ) { |
78
|
0
|
|
|
|
|
|
warn( "Writing built-in templates to $dir\n" ); |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
else { |
81
|
|
|
|
|
|
|
# Change the magic _Module.pm name to |
82
|
|
|
|
|
|
|
# the module file name. |
83
|
0
|
|
|
|
|
|
for my $file ( @$files ) { |
84
|
0
|
0
|
|
|
|
|
if ( $file =~ /^(.*)_Module.pm$/ ) { |
85
|
0
|
|
|
|
|
|
my $t = $1 . $vars->{"module.filename"}; |
86
|
0
|
|
|
|
|
|
push( @$dirs, dirname($t) ); |
87
|
0
|
|
|
|
|
|
$data->{$t} = delete $data->{$file}; |
88
|
0
|
|
|
|
|
|
$file = $t; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
0
|
|
|
|
|
|
my $massage; |
94
|
0
|
0
|
|
|
|
|
if ( $options->{'install-templates'} ) { |
95
|
0
|
|
|
0
|
|
|
$massage = sub { $_[0] }; |
|
0
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
else { |
98
|
0
|
|
|
|
|
|
require App::Module::Setup::Templates; |
99
|
0
|
|
|
|
|
|
$massage = App::Module::Setup::Templates->can("templater"); |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# Create the neccessary directories. |
103
|
0
|
|
|
|
|
|
mkpath($dir, $options->{trace}, 0777 ); |
104
|
0
|
0
|
|
|
|
|
chdir($dir) or die( "Error creating directory $dir\n" ); |
105
|
0
|
|
|
|
|
|
mkpath( $dirs, $options->{trace}, 0777 ); |
106
|
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
|
for my $target ( @$files ) { |
108
|
0
|
|
|
|
|
|
$vars->{" file"} = $target; |
109
|
0
|
0
|
|
|
|
|
open( my $fd, '>', $target ) |
110
|
|
|
|
|
|
|
or die( "Error opening ", "$dir/$target: $!\n" ); |
111
|
0
|
|
|
|
|
|
print { $fd } $massage->( $data->{$target}, $vars ); |
|
0
|
|
|
|
|
|
|
112
|
0
|
0
|
|
|
|
|
close($fd) |
113
|
|
|
|
|
|
|
or die( "Error writing $target: $!\n" ); |
114
|
|
|
|
|
|
|
warn( "Wrote: $dir/$target\n" ) |
115
|
0
|
0
|
|
|
|
|
if $options->{verbose}; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
# Postprocessing, e.g., set up git repo. |
119
|
0
|
|
|
|
|
|
foreach my $cmd ( @{ $options->{postcmd} } ) { |
|
0
|
|
|
|
|
|
|
120
|
0
|
|
|
|
|
|
system( $cmd ); |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# If we have a git repo, add all boilerplate files. |
124
|
0
|
0
|
|
|
|
|
if ( -d ".git" ) { |
125
|
0
|
|
|
|
|
|
system( "git", "add", @$files ); |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
0
|
|
|
|
|
|
chdir(".."); # see t/90-ivp.t |
129
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
|
return 1; # assume everything went ok |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub load_templates_from_directory { |
134
|
0
|
|
|
0
|
0
|
|
my ( $dir ) = shift; |
135
|
0
|
|
|
|
|
|
my $dl = length($dir); |
136
|
0
|
0
|
|
|
|
|
$dl++ unless $dir =~ m;/$;; |
137
|
0
|
|
|
|
|
|
my ( $files, $dirs, $data ); |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
find( { wanted => sub { |
140
|
0
|
0
|
|
0
|
|
|
return if length($_) < $dl; # skip top |
141
|
0
|
|
|
|
|
|
my $f = substr( $_, $dl ); # file relative to top |
142
|
0
|
0
|
|
|
|
|
if ( -d $_ ) { |
143
|
0
|
|
|
|
|
|
push( @$dirs, $f ); |
144
|
0
|
|
|
|
|
|
return; |
145
|
|
|
|
|
|
|
} |
146
|
0
|
0
|
|
|
|
|
return unless -f $_; |
147
|
0
|
0
|
|
|
|
|
return if /~$/; |
148
|
|
|
|
|
|
|
|
149
|
0
|
|
|
|
|
|
push( @$files, $f ); |
150
|
0
|
0
|
|
|
|
|
open( my $fd, '<', $_ ) |
151
|
|
|
|
|
|
|
or die( "Error reading template $_: $!\n" ); |
152
|
0
|
|
|
|
|
|
local $/; |
153
|
0
|
|
|
|
|
|
$data->{$f} = <$fd>; |
154
|
0
|
|
|
|
|
|
close($fd); |
155
|
|
|
|
|
|
|
}, |
156
|
0
|
|
|
|
|
|
no_chdir => 1, |
157
|
|
|
|
|
|
|
}, $dir ); |
158
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
return ( $files, $dirs, $data ); |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=head1 NAME |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
App::Module::Setup - a simple setup for a new module |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=head1 SYNOPSIS |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
Nothing in here is meant for public consumption. Use F |
171
|
|
|
|
|
|
|
from the command line. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
module-setup --author="A.U. Thor" --email=a.u.thor@example.com Foo::Bar |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=head1 DESCRIPTION |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
This is the core module for App::Module::Setup. If you're not looking |
179
|
|
|
|
|
|
|
to extend or alter the behavior of this module, you probably want to |
180
|
|
|
|
|
|
|
look at L instead. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
App::Module::Setup is used to create a skeletal CPAN distribution, |
183
|
|
|
|
|
|
|
including basic builder scripts, tests, documentation, and module |
184
|
|
|
|
|
|
|
code. This is done through just one method, C. |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=head1 METHODS |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=head2 App::Module::Setup->main( $options ) |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
C is the only method you should need to use from outside this |
192
|
|
|
|
|
|
|
module; all the other methods are called internally by this one. |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
This method creates the distribution and populates it with the all the |
195
|
|
|
|
|
|
|
requires files. |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
It takes a reference to a hash of params, as follows: |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
module # module to create in distro |
200
|
|
|
|
|
|
|
version # initial version |
201
|
|
|
|
|
|
|
author # author's full name (taken from C if not provided) |
202
|
|
|
|
|
|
|
email # author's email address |
203
|
|
|
|
|
|
|
verbose # bool: print progress messages; defaults to 0 |
204
|
|
|
|
|
|
|
template # template set to use |
205
|
|
|
|
|
|
|
postcmd # array ref of commands to execute after creating |
206
|
|
|
|
|
|
|
install-templates # bool: just install the selected templates |
207
|
|
|
|
|
|
|
minperl # minimal perl version, e.g. 5.010000 |
208
|
|
|
|
|
|
|
license # e.g. perl_5 |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=cut |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head1 AUTHOR |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
Johan Vromans, C<< >> |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=head1 BUGS |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through |
221
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll |
222
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=head1 SUPPORT |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
perldoc App::Module::Setup |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
You can also look for information at: |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=over 4 |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
L |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=item * Search CPAN |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
L |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=back |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
David Golden, for giving me the final incentive to write this module. |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
Sawyer X, for writing Module::Starter where I borrowed many ideas from. |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
Copyright 2013 Johan Vromans, all rights reserved. |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
258
|
|
|
|
|
|
|
under the same terms as Perl itself. |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=cut |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
1; # End of App::Module::Setup |