5 use vars
qw( %Content );
9 use ExtUtils::Manifest;
10 use File::Basename qw(basename);
11 use File
::Find
qw(find);
15 my $Quiet = $ENV{SCRIPTDIST_DEBUG
} || 0; # print progress messages
16 print "Quiet is $Quiet\n";
17 my $Name = $FindBin::Script
;
18 my $Home = $ENV{HOME
} || '';
20 print "Home directory is $Home\n" unless $Quiet;
22 my $Rc_directory = File
::Spec
->catfile( $Home, "." . $Name );
23 print "RC directory is $Rc_directory\n" unless $Quiet;
24 my $Config_file = File
::Spec
->catfile( $Home, "." . $Name . "rc" );
26 warn <<"HERE" unless $Home ne '';
27 The environment variable HOME has no value, so I will look in
28 the current directory for $Rc_directory and $Config_file. Set
29 the HOME environment variable to choose another directory.
33 if( $^O
=~ m/MSWin32/ ) { '\\' }
34 elsif( $^O
=~ m/Mac/ ) { ":" }
40 scriptdist - create a distribution for a perl script
44 % scriptdist script.pl
48 The scriptdist program takes a script file and builds, in the current
49 working directory, a Perl script distribution around it. You can add
50 other files to the distribution once it is in place.
52 This script is designed to be a stand-alone program. You do not need
53 any other files to use it. However, you can create a directory named
54 .scriptdist in your home directory, and scriptdist will look for local
55 versions of template files there. Any files in C<~/.scriptdist/t>
56 will show up as is in the script's t directory (until I code the parts
57 to munge those files). The script assumes you have specified your
58 home directory in the environment variable HOME.
60 You can turn on optional progress and debugging messages by setting
61 the environment variable SCRIPTDIST_DEBUG to a true value.
67 =item Check for release information
69 The first time the scriptdist is run, or any time the scriptdist cannot
70 find the file C<.scriptdistrc>, it prompts for CPAN and SourceForge
71 developer information that it can add to the .releaserc file. (NOT
74 =item Create a directory named after the script
76 The distribution directory is named after the script name,
77 with a <.d> attached. The suffix is there only to avoid a
78 name conflict. You can rename it after the script is moved
79 into the directory. If the directory already exists, the
80 script stops. You can either move or delete the directory
83 =item Look for template files
85 The program looks in C<.scriptdistrc> for files to copy into
86 the target script distribution directory. After that, it
87 adds more files unless they already exist (i.e. the script
88 found them in the template directory). The script replaces
89 strings matching C<%%SCRIPTDIST_FOO%%> with the internal
90 value of FOO. The defined values are currently SCRIPT, which
91 substitutes the script name, and VERSION, whose value is
92 currently hard-coded at '0.10'.
94 While looking for files, scriptdist skips directories named
99 A bare bones Changes file
101 =item Create the Makefile.PL
103 =item Create the t directory
105 =item Add compile.t, pod.t, prereq.t
107 =item Create test_manifest
109 =item Copy the script into the directory
111 =item Run make manifest
113 =item prompt for CVS import
115 Prints a friendly message to remind you to add the new directory
116 to your source control system.
120 =head2 Creating the Makefile.PL
122 A few things have to show up in the Makefile.PL---the name of
123 the script and the prerequisites modules are the most important.
124 Luckily, scriptdist can discover these things and fill them in
129 * add support for Module::Build (command line switch)
131 * Create Meta.yml file
133 * Automatically generate PREREQ_PM section (needs Module::Info, Module::CoreList)
135 * Copy modules into lib directory (to create module dist)
137 * Command line switches to turn things on and off
139 =head2 Maybe a good idea, maybe not
141 * Add a cover.t and pod coverage test?
145 * automatically import into CVS?
147 =head1 SOURCE AVAILABILITY
149 This source is part of a SourceForge project which always has the
150 latest sources in CVS, as well as all of the previous releases.
152 http://sourceforge.net/projects/brian-d-foy/
154 If, for some reason, I disappear from the world, one of the other
155 members of the project can shepherd this module appropriately.
159 Thanks to Soren Andersen for putting this script through its paces
160 and suggesting many changes to actually make it work.
164 brian d foy, E<lt>bdfoy@cpan.orgE<gt>
168 Copyright 2004, brian d foy, All rights reserved.
170 You may use this program under the same terms as Perl itself.
174 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
175 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
176 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
179 my $Script = basename
( $Path );
181 print "Processing $Script...\n" unless $Quiet;
188 content
( \
%Defaults );
191 my $Directory = "$Script.d";
192 die <<"HERE" if -d $Directory;
193 Directory $Directory already exists! Either delete it or
194 move it out of the way, then rerun this program.
197 foreach my $dir ( map { $_, File
::Spec
->catfile( $_, "t" ) } $Directory )
199 print "Making directory $dir...\n" unless $Quiet;
200 mkdir $dir, 0755 or die "Could not make [$dir]: $!\n";
203 # Copy local template files
204 print "RC directory is $Rc_directory\n" unless $Quiet;
205 print "cwd is ", getcwd
, "\n";
207 if( -d
$Rc_directory )
209 print "Looking for local templates...\n" unless $Quiet;
210 foreach my $input ( find_files
( $Rc_directory ) )
212 my( $path ) = $input =~ m/\Q$Rc_directory$Dir_sep\E(.*)/g;
214 my @path = File
::Spec
->splitdir( $path );
215 my $file = pop @path;
219 local @ARGV = File
::Spec
->catfile( $Directory, @path );
220 ExtUtils
::Command
::mkpath
unless -d
$ARGV[0];
223 my $output = File
::Spec
->catfile( $Directory, $path );
224 copy
( $input, $output, \
%Defaults );
228 # Add distribution files unless they already exist
229 FILE
: foreach my $filename ( sort keys %Content )
231 my @path = split m
|\Q
$Dir_sep|, $filename;
233 my $file = File
::Spec
->catfile( $Directory, @path );
235 print "Checking for file [$filename]... " unless $Quiet;
236 if( -e
$file ) { print "already exists\n"; next FILE
}
238 print "Adding file [$filename]...\n" unless $Quiet;
239 open my($fh), "> $file" or do {
240 warn "Could not write to [$file]: $!\n";
244 my $contents = $Content{$filename};
249 # Add the script itself
251 print "Adding [$Script]...\n";
252 my $dist_script = File
::Spec
->catfile( $Directory, $Script );
256 print "Copying script...\n";
257 copy
( $Path, $dist_script );
261 print "Using script template...\n";
263 open my( $fh ), "> $dist_script";
264 print $fh ( script_template
( $Script ) );
268 # Create the MANIFEST file
269 print "Creating MANIFEST...\n";
270 chdir $Directory or die "Could not change to $Directory: $!\n";
271 $ExtUtils::Manifest
::Verbose
= 0;
272 ExtUtils
::Manifest
::mkmanifest
;
275 ------------------------------------------------------------------
276 Remember to commit this directory to your source control system.
277 In fact, why not do that right now? Remember, `cvs import` works
278 from within a directory, not above it.
279 ------------------------------------------------------------------
282 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
283 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
284 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
287 my( $query ) = shift;
291 chomp( my $reply = <STDIN
> );
298 my $directory = shift;
304 return if $File::Find
::name
=~ m/\bCVS\b/ ||
305 $File::Find
::name
=~ m/\b\.svn\b/;
306 print "$File::Find::name\n";
307 push( @files, $File::Find
::name
);
316 my( $input, $output, $hash ) = @_;
318 print "Opening input [$input] for output [$output]\n";
320 open my($in_fh), $input or die "Could not open [$input]: $!\n";
321 open my($out_fh), ">" . $output or warn "Could not open [$output]: $!\n";
325 while( readline $in_fh )
327 $count += s/%%SCRIPTDIST_(.*?)%%/$hash->{ lc $1 } || ''/gie;
331 print "Copied [$input] with $count replacements\n" unless $Quiet;
336 my $script_name = shift;
343 $script_name - this script does something
362 $Content{"Changes"} =<<"CHANGES";
364 0.10 - @{ [ scalar localtime ] }
365 + initial distribution created with $Name
368 $Content{"Makefile.PL"} =<<"MAKEFILE_PL";
370 use ExtUtils::MakeMaker;
372 eval "use Test::Manifest";
378 *ExtUtils::MM_Any::test_via_harness = sub
380 my(\$self, \$perl, \$tests) = \@_;
382 return qq|\t\$perl "-MTest::Manifest" | .
383 qq|"-e" "run_t_manifest(\\\$(TEST_VERBOSE), '\\\$(INST_LIB)', | .
384 qq|'\\\$(INST_ARCHLIB)')"\\n|;
388 my \$script_name = "$$hash{script}";
391 'NAME' => \$script_name,
392 'VERSION' => '$$hash{version}',
394 'EXE_FILES' => [ \$script_name ],
400 \$script_name => "\\\$(INST_MAN1DIR)/\$script_name.1",
403 clean => { FILES => "*.bak \$script_name-*" },
409 $Content{"MANIFEST.SKIP"} =<<"MANIFEST_SKIP";
424 $Content{".releaserc"} =<<"RELEASE_RC";
426 cpan_user @{[ $ENV{CPAN_USER} ? $ENV{CPAN_USER} : '' ]}
427 sf_user @{[ $ENV{SF_USER} ? $ENV{SF_USER} : '' ]}
428 sf_group_id @{[ $ENV{SF_GROUP_ID} ? $ENV{SF_GROUP_ID} : '' ]}
429 sf_package_id @{[ $ENV{SF_PACKAGE_ID} ? $ENV{SF_PACKAGE_ID} : '' ]}
432 $Content{".cvsignore"} =<<"CVSIGNORE";
442 $Content{"t/test_manifest"} =<<"TEST_MANIFEST";
448 $Content{"t/pod.t"} = <<"POD_T";
451 eval "use Test::Pod 1.00";
452 plan skip_all => "Test::Pod 1.00 required for testing POD" if \$@;
457 $Content{"t
/prereq
.t
"} = <<"PREREQ_T";
460 eval "use Test::Prereq";
461 plan skip_all
=> "Test::Prereq required to test dependencies" if \
$@
;
465 $Content{"t/compile.t"} = <<"COMPILE_T";
468 use Test::More tests => 1;
470 my \$file = "blib/script/$$hash{script}";
472 print "bail out! Script file is missing!" unless -e \$file;
474 my \$output = `perl -c \$file 2>&1`;
476 print "bail out! Script file is missing!" unless
477 like( \$output, qr/syntax OK\$/, 'script compiles' );