saving starting pwd() in OLD_PWD
[deployable.git] / deployable
blob39d586be6209fc0dc363a72ba7fa6f554828e22b
1 #!/usr/bin/env perl
2 use strict;
3 use warnings;
4 use Carp;
5 use version; our $VERSION = qv('0.1.1');
6 use Fatal qw( close );
7 use Pod::Usage qw( pod2usage );
8 use Getopt::Long qw( :config gnu_getopt );
9 use English qw( -no_match_vars );
10 use File::Basename qw( basename dirname );
11 use File::Spec::Functions qw( file_name_is_absolute catfile );
12 use File::Temp qw( tempfile );
13 use POSIX qw( strftime );
14 use Cwd qw( cwd realpath );
15 use Archive::Tar;
16 use Data::Dumper;
17 use Encode;
19 use File::Find::Rule;
21 my %config = (
22 output => '-',
23 remote => catfile(dirname(realpath(__FILE__)), 'remote'),
24 tarfile => [],
25 heredir => [],
26 rootdir => [],
27 root => [],
28 tarfile => [],
29 deploy => [],
30 passthrough => 0,
32 GetOptions(
33 \%config,
34 qw(
35 usage! help! man! version!
37 bundle|all-exec|X!
38 bzip2|bz2|j!
39 cleanup|c!
40 deploy|exec|d=s@
41 gzip|gz|z!
42 heredir|H=s@
43 include-archive-tar|T!
44 no-tar!
45 output|o=s
46 passthrough|P!
47 root|r=s@
48 rootdir|in-root|R=s@
49 tar|t=s
50 tarfile|F=s@
51 tempdir-mode|m=s
52 workdir|work-directory|deploy-directory|w=s
54 ) or pod2usage(message => "invalid command line", -verbose => 99, -sections => ' ');
55 pod2usage(message => "$0 $VERSION", -verbose => 99, -sections => ' ')
56 if $config{version};
57 pod2usage(-verbose => 99, -sections => 'USAGE') if $config{usage};
58 pod2usage(-verbose => 99, -sections => 'USAGE|EXAMPLES|OPTIONS')
59 if $config{help};
60 pod2usage(-verbose => 2) if $config{man};
62 pod2usage(
63 message => 'working directory must be an absolute path',
64 -verbose => 99,
65 -sections => ''
66 ) if exists $config{workdir} && !file_name_is_absolute($config{workdir});
68 if ($config{'include-archive-tar'}) {
69 $config{remote} = catfile(dirname(realpath(__FILE__)), 'remote-at');
70 if (!-e $config{remote}) { # "make" it
71 print {*STDERR} "### Making remote-at...\n";
72 my $startdir = cwd();
73 chdir dirname realpath __FILE__;
74 system {'make'} qw( make remote-at );
75 chdir $startdir;
76 } ## end if (!-e $config{remote...})
77 } ## end if ($config{'include-archive-tar'...})
79 # Establish output channel
80 my $out_fh = \*STDOUT;
81 if ($config{output} ne '-') {
82 open my $fh, '>', $config{output} ## no critic
83 or croak "open('$config{output}'): $OS_ERROR";
84 $out_fh = $fh;
86 binmode $out_fh;
88 # Emit script code to be executed remotely. It is guaranteed to end
89 # with __END__, so that all what comes next is data
90 print {$out_fh} get_remote_script();
92 # Where all the data will be kept
93 print_configuration($out_fh, \%config);
95 print_here_stuff($out_fh, \%config, @ARGV);
96 print_root_stuff($out_fh, \%config);
98 close $out_fh;
100 # Set as executable
101 if ($config{output} ne '-') {
102 chmod oct(755), $config{output}
103 or carp "chmod(0755, '$config{output}'): $OS_ERROR";
106 sub header {
107 my %params = @_;
108 my $namesize = length $params{name};
109 return "$namesize $params{size}\n$params{name}";
112 sub print_configuration { # FIXME
113 my ($fh, $config) = @_;
114 my %general_configuration;
115 for my $name (
116 qw( workdir cleanup bundle deploy
117 gzip bzip2 passthrough tempdir-mode )
120 $general_configuration{$name} = $config->{$name}
121 if exists $config->{$name};
122 } ## end for my $name (qw( workdir cleanup bundle deploy...))
123 my $configuration = Dumper \%general_configuration;
124 print {$fh} header(name => 'config.pl', size => length($configuration)),
125 "\n", $configuration, "\n\n";
126 } ## end sub print_configuration
128 # Process files and directories. All these will be reported in the
129 # extraction directory, i.e. basename() will be applied to them. For
130 # directories, they will be re-created
131 sub print_here_stuff {
132 my $fh = shift;
133 my $config = shift;
134 my @ARGV = @_;
136 my $ai = Deployable::Tar->new($config);
137 $ai->add(
138 '.' => \@ARGV,
139 map { $_ => ['.'] } @{$config->{heredir}}
142 print {$fh} header(name => 'here', size => $ai->size()), "\n";
143 $ai->copy_to($fh);
144 print {$fh} "\n\n";
146 return;
147 } ## end sub print_here_stuff
149 sub print_root_stuff {
150 my ($fh, $config) = @_;
152 my $ai = Deployable::Tar->new($config);
153 $ai->add(
154 '.' => $config->{rootdir},
155 (undef, $config->{tarfile}),
156 map { $_ => ['.'] } @{$config->{root}}
159 print {$fh} header(name => 'root', size => $ai->size()), "\n";
160 $ai->copy_to($fh);
161 print {$fh} "\n\n";
163 return;
164 } ## end sub print_root_stuff
166 sub get_remote_script {
167 my $fh;
168 if (-e $config{remote}) {
169 open $fh, '<', $config{remote}
170 or croak "open('$config{remote}'): $OS_ERROR";
172 else {
173 no warnings 'once';
174 $fh = \*DATA;
176 my @lines;
177 while (<$fh>) {
178 last if /\A __END__ \s*\z/mxs;
179 push @lines, $_;
181 close $fh;
182 return join '', @lines, "__END__\n";
183 } ## end sub get_remote_script
185 package Deployable::Tar;
187 sub new {
188 my $package = shift;
189 my $self = {ref $_[0] ? %{$_[0]} : @_};
190 $package = 'Deployable::Tar::Internal';
191 if (!$self->{'no-tar'}) {
192 if ((exists $self->{tar}) || (open my $fh, '-|', 'tar', '--help')) {
193 $package = 'Deployable::Tar::External';
194 $self->{tar} ||= 'tar';
196 } ## end if (!$self->{'no-tar'})
197 bless $self, $package;
198 $self->initialise();
199 return $self;
200 } ## end sub new
202 package Deployable::Tar::External;
203 use File::Temp qw( :seekable );
204 use English qw( -no_match_vars );
205 use Cwd ();
206 use Carp;
207 our @ISA = qw( Deployable::Tar );
209 sub initialise {
210 my $self = shift;
211 $self->{_temp} = File::Temp->new();
212 $self->{_filename} = Cwd::abs_path($self->{_temp}->filename());
213 return $self;
214 } ## end sub initialise
216 sub add {
217 my $self = shift;
218 my $tar = $self->{tar};
219 delete $self->{_compressed};
220 while (@_) {
221 my ($directory, $stuff) = splice @_, 0, 2;
222 my @stuff = @$stuff;
223 if (defined $directory) {
224 while (@stuff) {
225 my @chunk = splice @stuff, 0, 50;
226 system {$tar} $tar, 'rvf', $self->{_filename},
227 '-C', $directory, '--', @chunk;
229 } ## end if (defined $directory)
230 else { # it's another TAR file, concatenate
231 while (@stuff) {
232 my @chunk = splice @stuff, 0, 50;
233 system {$tar} $tar, 'Avf', $self->{_filename}, '--', @chunk;
235 } ## end else [ if (defined $directory)]
236 } ## end while (@_)
237 return $self;
238 } ## end sub add
240 sub _compress {
241 my $self = shift;
242 return if exists $self->{_compressed};
244 $self->{_temp}->sysseek(0, SEEK_SET);
245 if ($self->{bzip2}) {
246 require IO::Compress::Bzip2;
247 $self->{_compressed} = File::Temp->new();
249 # double-quotes needed to force usage of filename
250 # instead of filehandle
251 IO::Compress::Bzip2::bzip2($self->{_temp}, "$self->{_compressed}");
252 } ## end if ($self->{bzip2})
253 elsif ($self->{gzip}) {
254 require IO::Compress::Gzip;
255 $self->{_compressed} = File::Temp->new();
257 # double-quotes needed to force usage of filename
258 # instead of filehandle
259 IO::Compress::Gzip::gzip($self->{_temp}, "$self->{_compressed}");
260 } ## end elsif ($self->{gzip})
261 else {
262 $self->{_compressed} = $self->{_temp};
265 return $self;
266 } ## end sub _compress
268 sub size {
269 my ($self) = @_;
270 $self->_compress();
271 return (stat $self->{_compressed})[7];
274 sub copy_to {
275 my ($self, $out_fh) = @_;
276 $self->_compress();
277 my $in_fh = $self->{_compressed};
278 $in_fh->sysseek(0, SEEK_SET);
279 while ('true') {
280 my $nread = $in_fh->sysread(my $buffer, 4096);
281 croak "sysread(): $OS_ERROR" unless defined $nread;
282 last unless $nread;
283 print {$out_fh} $buffer;
284 } ## end while ('true')
285 return $self;
286 } ## end sub copy_to
288 package Deployable::Tar::Internal;
289 use Archive::Tar ();
290 use Cwd ();
291 use File::Find::Rule ();
292 use Carp qw< croak >;
293 our @ISA = qw( Deployable::Tar );
295 sub initialise {
296 my $self = shift;
297 $self->{_tar} = Archive::Tar->new();
298 return $self;
301 sub add {
302 my $self = shift;
303 delete $self->{_string};
304 my $tar = $self->{_tar};
305 my $cwd = Cwd::getcwd();
306 while (@_) {
307 my ($directory, $stuff) = splice @_, 0, 2;
308 if (defined $directory) {
309 chdir $directory;
310 for my $item (@$stuff) {
311 $tar->add_files($_) for File::Find::Rule->in($item);
313 chdir $cwd;
314 } ## end if (defined $directory)
315 else { # It's another TAR file to be concatenated
316 for my $item (@$stuff) {
317 my $iterator = Archive::Tar->iter($item);
318 while (my $f = $iterator->()) {
319 $tar->add_files($f);
323 } ## end while (@_)
324 return $self;
325 } ## end sub add
327 sub size {
328 my ($self) = @_;
329 $self->{_string} = $self->{_tar}->write()
330 unless exists $self->{_string};
331 return length $self->{_string};
332 } ## end sub size
334 sub copy_to {
335 my ($self, $out_fh) = @_;
336 $self->{_string} = $self->{_tar}->write()
337 unless exists $self->{_string};
338 print {$out_fh} $self->{_string};
339 } ## end sub copy_to
341 =head1 NAME
343 deployable - create a deploy script for some files/scripts
345 =head1 VERSION
347 See version at beginning of script, variable $VERSION, or call
349 shell$ deployable --version
351 =head1 USAGE
353 deployable [--usage] [--help] [--man] [--version]
355 deployable [--bundle|--all-exec|-X] [--bzip2|--bz2|-j] [--cleanup|-c]
356 [--deploy|--exec|d <program>] [--gzip|-gz|-z]
357 [--heredir|-H <dirname>] [--include-archive-tar|-T]
358 [--no-tar] [--output|-o <filename>] [--root|-r <dirname>]
359 [--rootdir|--in-root|-R <dirname>] [--tar|-t <program-path>]
360 [--tarfile|-F <filename>] [--tempdir-mode|-m <mode>]
361 [--workdir|-w <path>] [ files or directories... ]
363 =head1 EXAMPLES
365 # pack some files and a deploy script together.
366 shell$ deployable script.sh file.txt some/directory -d script.sh
368 # Use a directory's contents as elements for the target root
369 shell$ ls -1 /path/to/target/root
374 # The above will be deployed as /etc, /opt, /usr and /var
375 shell$ deployable -o dep.pl --root /path/to/target/root
377 # Include sub-directory etc/ for inclusion and extraction
378 # directly as /etc/
379 shell$ deployable -o dep.pl --in-root etc/
381 =head1 DESCRIPTION
383 This is a meta-script to create deploy scripts. The latter ones are
384 suitable to be distributed in order to deploy something.
386 You basically have to provide two things: files to install and programs
387 to be executed. Files can be put directly into the deployed script, or
388 can be included in gzipped tar archives.
390 When called, this script creates a deploy script for you. This script
391 includes all the specified files, and when executed it will extract
392 those files and execute the given programs. In this way, you can ship
393 both files and logic needed to correctly install those files, but this
394 is of course of of scope.
396 All files and archives will be extracted under a configured path
397 (see L<--workdir> below), which we'll call I<workdir> from now on. Under
398 the I<workdir> a temporary directory will be created, and the files
399 will be put in the temporary directory. You can specify if you want to
400 clean up this temporary directory or keep it, at your choice. (You're able
401 to both set a default for this cleanup when invoking deployable, or when
402 invoking the deploy script itself). The temporary directory will be
403 called I<tmpdir> in the following.
405 There are several ways to embed files to be shipped:
407 =over
409 =item *
411 pass the name of an already-prepared tar file via L</--tarfile>. The
412 contents of this file will be assumed to be referred to the root
413 directory;
415 =item *
417 specify the file name directly on the command line. A file given in this
418 way will always be extracted into the I<tmpdir>, whatever its initial path
419 was;
421 =item *
423 specify the name of a directory on the command line. In this case,
424 C<tar> will be used to archive the directory, with the usual option to
425 turn absolute paths into relative ones; this means that directories will
426 be re-created under I<tmpdir> when extraction is performed;
428 =item *
430 give the name of a directory to be used as a "here directory", using
431 the C<--heredir|-H> option. This is much the same as giving the directory
432 name (see above), but in this case C<tar> will be told to change into the
433 directory first, and archive '.'. This means that the contents of the
434 "here-directory" will be extracted directly into I<tmpdir>.
436 =back
438 =head2 Extended Example
440 Suppose you have a few server which have the same configuration, apart
441 from some specific stuff (e.g. the hostname, the IP addresses, etc.).
442 You'd like to perform changes to all with the minimum work possible...
443 so you know you should script something.
445 For example, suppose you want to update a few files in /etc, setting these
446 files equal for all hosts. You would typically do the following:
448 # In your computer
449 shell$ mkdir -p /tmp/newfiles/etc
450 shell$ cd /tmp/newfiles/etc
451 # Craft the new files
452 shell$ cd ..
453 shell$ tar cvzf newetc.tar.gz etc
455 # Now, for each server:
456 shell$ scp newetc.tar.gz $server:/tmp
457 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
460 So far, so good. But what if you need to kick in a little more logic?
461 For example, if you update some configuration files, you'll most likey
462 want to restart some services. So you could do the following:
464 shell$ mkdir -p /tmp/newfiles/tmp
465 shell$ cd /tmp/newfiles/tmp
466 # craft a shell script to be executed remotely and set the exec bit
467 # Suppose it's called deploy.sh
468 shell$ cd ..
469 shell$ tar cvzf newetc.tar.gz etc tmp
471 # Now, for each server:
472 shell$ scp newetc.tar.gz $server:/tmp
473 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
474 shell$ ssh $server /tmp/deploy.sh
476 And what if you want to install files depending on the particular machine?
477 Or you have a bundle of stuff to deploy and a bunch of scripts to execute?
478 You can use deployable. In this case, you can do the following:
480 shell$ mkdir -p /tmp/newfiles/etc
481 shell$ cd /tmp/newfiles/etc
482 # Craft the new files
483 shell$ cd ..
484 # craft a shell script to be executed remotely and set the exec bit
485 # Suppose it's called deploy.sh
486 shell$ deployable -o deploy.pl -R etc deploy.sh -d deploy.sh
488 # Now, for each server
489 shell$ scp deploy.pl $server:/tmp
490 shell$ ssh $server /tmp/deploy.pl
492 And you're done. This can be particularly useful if you have another
493 layer of deployment, e.g. if you have to run a script to decide which
494 of a group of archives should be deployed. For example, you could craft
495 a different new "etc" for each server (which is particularly true if
496 network configurations are in the package), and produce a simple script
497 to choose which file to use based on the MAC address of the machine. In
498 this case you could have:
500 =over
502 =item newetc.*.tar.gz
504 a bunch of tar files with the configurations for each different server
506 =item newetc.list
508 a list file with the association between the MAC addresses and the
509 real tar file to deploy from the bunch in the previous bullet
511 =item deploy-the-right-stuff.sh
513 a script to get the real MAC address of the machine, select the right
514 tar file and do the deployment.
516 =back
518 So, you can do the following:
520 shell$ deployable -o deploy.pl newetc.*.tar.gz newetc.list \
521 deploy-the-right-stuff.sh --exec deploy-the-right-stuff.sh
523 # Now, for each server:
524 shell$ scp deploy.pl $server:/tmp
525 shell$ ssh $server /tmp/deploy.pl
527 So, once you have the deploy script on the target machine all you need
528 to do is to execute it. This can come handy when you cannot access the
529 machines from the network, but you have to go there physically: you
530 can prepare all in advance, and just call the deploy script.
533 =head1 OPTIONS
535 Meta-options:
537 =over
539 =item B<--help>
541 print a somewhat more verbose help, showing usage, this description of
542 the options and some examples from the synopsis.
544 =item B<--man>
546 print out the full documentation for the script.
548 =item B<--usage>
550 print a concise usage line and exit.
552 =item B<--version>
554 print the version of the script.
556 =back
558 Real-world options:
560 =over
562 =item B<< --bundle | --all-exec | -X >>
564 Set bundle flag in the produced script. If the bundle flag is set, the
565 I<deploy script> will treat all executables in the main deployment
566 directory as scripts to be executed.
568 By default the flag is not set.
570 =item B<< --bzip2 | --bz2 | -j >>
572 Compress tar archives with bzip2.
574 =item B<< --cleanup | -c >>
576 Set cleanup flag in the produced script. If the cleanup flag is set, the
577 I<deploy script> will clean up after having performed all operations.
579 You can set this flag to C<0> by using C<--no-cleanup>.
581 =item B<< --deploy | --exec | -d <filename> >>
583 Set the name of a program to execute after extraction. You can provide
584 multiple program names, they will be executed in the same order.
586 =item B<< --gzip | --gz | -z >>
588 Compress tar archives with gzip.
590 =item B<< --heredir | -H <path> >>
592 Set the name of a "here directory" (see L<DESCRIPTION>). You can use this
593 option multiple times to provide multiple directories.
595 =item B<< --include-archive-tar | -T >>
597 Embed L<Archive::Tar> (with its dependencies L<Archive::Tar::Constant> and
598 L<Archive::Tar::File>) inside the final script. Use this when you know (or
599 aren't sure) that L<Archive::Tar> will not be available in the target
600 machine.
602 =item B<< --no-tar >>
604 Don't use system C<tar>.
606 =item B<< --output | -o <filename> >>
608 Set the output file name. By default the I<deploy script> will be given
609 out on the standard output; if you provide a filename (different from
610 C<->, of course!) the script will be saved there and the permissions will
611 be set to 0755.
613 =item B<< --root | -r <dirname> >>
615 Include C<dirname> contents for deployment under root directory. The
616 actual production procedure is: hop into C<dirname> and grab a tarball
617 of C<.>. During deployment, hop into C</> and extract the tarball.
619 This is useful if you're already building up the absolute deployment
620 layout under a given directory: just treat that directory as if it were
621 the root of the target system.
623 =item B<< --rootdir | --in-root | -R <filename> >>
625 Include C<filename> as an item that will be extracted under root
626 directory. The actual production procedure is: grab a tarball of
627 C<filename>. During deployment, hop into C</> and extract the tarball.
629 This is useful e.g. if you have a directory (or a group of directories)
630 that you want to deploy directly under the root.
632 Note that the C<--rootdir> alias is kept for backwards compatibility
633 but is not 100% correct - you can specify both a dirname (like it was
634 previously stated) or a single file with this option. This is why it's
635 more readably to use C<--in-root> instead.
637 =item B<< --tar | -t <program-path> >>
639 Set the system C<tar> program to use.
641 =item B<< --tempdir-mode | -m >>
643 set default permissions for temporary directory of deployable script
645 =item B<< --workdir | --deploy-directory | -w <path> >>
647 Set the working directory for the deploy.
649 =back
651 =head1 ROOT OR ROOTDIR?
653 There are two options that allow you to specify things to be deployed
654 in C</>, so what should you use? Thing is... whatever you want!
656 If you have a bunch of directories that have to appear under root, probably
657 your best bet is to put them all inside a directory called C<myroot> and
658 use option C<--root>:
660 shell$ mkdir -p myroot/{etc,opt,var,lib,usr,whatever}
661 # Now put stuff in the directories created above...
662 shell$ deployable --root myroot ...
664 On the other hand, if you just want to put stuff starting from one or
665 two directories that have to show up in C</>, you can avoid creating
666 the extra C<myroot> directory and use C<--in-root> instead:
668 shell$ mkdir -p etc/whatever
669 # Now put stuff in etc/whatever...
670 shell$ deployable --in-root etc ...
672 They are indeed somehow equivalent, the first avoiding you much typing
673 when you have many directories to be deployed starting from root (just
674 put them into the same subdirectory), the second allowing you to avoid
675 putting an extra directory layer.
677 There is indeed an additional catch that makes them quite different. When
678 you use C<root>, the whole content of the directory specified will be
679 used as a base, so you will end up with a listing like this:
681 opt/
682 opt/local/
683 opt/local/application/
684 opt/local/application/myfile.txt
685 opt/local/application/otherfile.txt
687 i.e. all intermediate directories will be saved. On the other hand, when
688 you specify a directory with C<--in-root>, you're not limited to provide
689 a "single-step" directory, so for example:
691 shell$ deployable --in-root opt/local/application
693 will result in the following list of files/directories to be stored:
695 opt/local/application/
696 opt/local/application/myfile.txt
697 opt/local/application/otherfile.txt
699 i.e. the upper level directories will not be included. What is better for
700 you is for you to judge.
702 =head1 THE DEPLOY SCRIPT
704 The net result of calling this script is to produce another script,
705 that we call the I<deploy script>. This script is made of two parts: the
706 code, which is fixed, and the configurations/files, which is what is
707 actually produced. The latter part is put after the C<__END__> marker,
708 as usual.
710 Stuff in the configuration part is always hexified in order to prevent
711 strange tricks or errors. Comments will help you devise what's inside the
712 configurations themselves.
714 The I<deploy script> has options itself, even if they are quite minimal.
715 In particular, it supports the same options C<--workdir|-w> and
716 C<--cleanup> described above, allowing the final user to override the
717 configured values. By default, the I<workdir> is set to C</tmp>
718 and the script will clean up after itself.
720 The following options are supported in the I<deploy script>:
722 =over
724 =item B<--usage | --man | --help>
726 print a minimal help and exit
728 =item B<--version>
730 print script version and exit
732 =item B<--bundle | --all-exec | -X>
734 treat all executables in the main deployment directory as scripts
735 to be executed
737 =item B<--cleanup | --no-cleanup>
739 perform / don't perform temporary directory cleanup after work done
741 =item B<< --deploy | --no-deploy >>
743 deploy scripts are executed by default (same as specifying '--deploy')
744 but you can prevent it.
746 =item B<--dryrun | --dry-run>
748 print final options and exit
750 =item B<< --filelist | --list | -l >>
752 print a list of files that are shipped in the deploy script
754 =item B<< --heretar | --here-tar | -H >>
756 print out the tar file that contains all the files that would be
757 extracted in the temporary directory, useful to redirect to file or
758 pipe to the tar program
760 =item B<< --inspect <dirname> >>
762 just extract all the stuff into <dirname> for inspection. Implies
763 C<--no-deploy>, C<--no-tempdir>, ignores C<--bundle> (as a consequence of
764 C<--no-deploy>), disables C<--cleanup> and sets the working directory
765 to C<dirname>
767 =item B<< --no-tar >>
769 don't use system C<tar>
771 =item B<< --rootar | --root-tar | -R >>
773 print out the tar file that contains all the files that would be
774 extracted in the root directory, useful to redirect to file or
775 pipe to the tar program
777 =item B<--show | --show-options | -s>
779 print configured options and exit
781 =item B<< --tar | -t <program-path> >>
783 set the system C<tar> program to use.
785 =item B<< --tarfile | -F <filename> >>
787 add the specified C<filename> (assumed to be an uncompressed
788 TAR file) to the lot for root extraction. This can come handy
789 when you already have all the files backed up in a TAR archive
790 and you're not willing to expand them (e.g. because your
791 filesystem is case-insensitive...).
793 =item B<< --tempdir | --no-tempdir >>
795 by default a temporary directory is created (same as specifying
796 C<--tempdir>), but you can execute directly in the workdir (see below)
797 without creating it.
799 =item B<< --tempdir-mode | -m >>
801 temporary directories (see C<--tempdir>) created by File::Temp have
802 permission 600 that prevents group/others from even looking at the
803 contents. You might want to invoke some of the internal scripts
804 from another user (e.g. via C<su>), so you can pass a mode to be
805 set on the temporary directory.
807 Works only if C<--tempdir> is active.
809 =item B<--workdir | --work-directory | --deploy-directory | -w>
811 working base directory (a temporary subdirectory will be created
812 there anyway)
814 =back
816 Note the difference between C<--show> and C<--dryrun>: the former will
817 give you the options that are "embedded" in the I<deploy script> without
818 taking into account other options given on the command line, while the
819 latter will give you the final options that would be used if the script
820 were called without C<--dryrun>.
822 =head2 Deploy Script Example Usage
824 In the following, we'll assume that the I<deploy script> is called
825 C<deploy.pl>.
827 To execute the script with the already configured options, you just have
828 to call it:
830 shell$ ./deploy.pl
832 If you just want to see which configurations are in the I<deploy script>:
834 shell$ ./deploy.pl --show
836 To see which files are included, you have two options. One is asking the
837 script:
839 shell$ ./deploy.pl --filelist
841 the other is piping to tar:
843 shell$ ./deploy.pl --tar | tar tvf -
845 Extract contents of the script in a temp directory and simply inspect
846 what's inside:
848 # extract stuff into subdirectory 'inspect' for... inspection
849 shell$ ./deploy.pl --no-tempdir --no-deploy --workdir inspect
851 =head2 Deploy Script Requirements
853 You'll need a working Perl with version at least 5.6.2.
855 If you specify L</--include-archive-tar>, the module L<Archive::Tar> will
856 be included as well. This should ease your life and avoid you to have
857 B<tar> on the target machine. On the other hand, if you already know
858 that B<tar> will be available, you can avoid including C<Archive::Tar>
859 and have the generated script use it (it could be rather slower anyway).
861 =head1 DIAGNOSTICS
863 Each error message should be enough explicit to be understood without the
864 need for furter explainations. Which is another way to say that I'm way
865 too lazy to list all possible ways that this script has to fail.
868 =head1 CONFIGURATION AND ENVIRONMENT
870 deployable requires no configuration files or environment variables.
872 Please note that deployable B<needs> to find its master B<remote> file
873 to produce the final script. This must be put in the same directory where
874 deployable is put. You should be able to B<symlink> deployable where you
875 think it's better, anyway - it will go search for the original file
876 and look for B<remote> inside the same directory. This does not apply to
877 hard links, of course.
880 =head1 DEPENDENCIES
882 All core modules, apart the following:
884 =over
886 =item B<< Archive::Tar >>
888 =item B<< File::Find::Rule >>
890 =back
892 =head1 BUGS AND LIMITATIONS
894 No bugs have been reported.
896 Please report any bugs or feature requests to the AUTHOR below.
898 Be sure to read L<CONFIGURATION AND ENVIRONMENT> for a slight limitation
899 about the availability of the B<remote> script.
901 =head1 AUTHOR
903 Flavio Poletti C<flavio [AT] polettix.it>
906 =head1 LICENSE AND COPYRIGHT
908 Copyright (c) 2008, Flavio Poletti C<flavio [AT] polettix.it>. All rights reserved.
910 This script is free software; you can redistribute it and/or
911 modify it under the same terms as Perl itself. See L<perlartistic>
912 and L<perlgpl>.
914 =head1 DISCLAIMER OF WARRANTY
916 BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
917 FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
918 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
919 PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
920 EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
921 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
922 ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
923 YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
924 NECESSARY SERVICING, REPAIR, OR CORRECTION.
926 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
927 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
928 REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
929 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
930 OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
931 THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
932 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
933 FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
934 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
935 SUCH DAMAGES.
937 =cut
939 package main; # ensure DATA is main::DATA
940 __DATA__