Cope with absence of IO::Prompt
[deployable.git] / deployable
blob8bffbbc796f70d03f323e9fbb64b2fc5d259bdc6
1 #!/usr/bin/env perl
2 use strict;
3 use warnings;
4 use Carp;
5 use version; our $VERSION = qv('0.1.2');
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 Data::Dumper;
16 use Encode;
18 use File::Find::Rule;
19 use Archive::Tar;
21 my %config = (
22 output => '-',
23 remote => catfile(dirname(realpath(__FILE__)), 'remote'),
24 heredir => [],
25 herefile => [],
26 rootdir => [],
27 root => [],
28 rootfile => [],
29 tarfile => [],
30 deploy => [],
31 xform => [],
32 passthrough => 0,
34 GetOptions(
35 \%config,
36 qw(
37 usage! help! man! version!
39 bundle|all-exec|X!
40 bzip2|bz2|j!
41 cleanup|c!
42 deploy|exec|d=s@
43 gzip|gz|z!
44 heredir|H=s@
45 include-archive-tar|T!
46 no-tar!
47 output|o=s
48 passthrough|P!
49 root|r=s@
50 rootdir|in-root|R=s@
51 tar|t=s
52 tarfile|F=s@
53 tempdir-mode|m=s
54 xform|x=s@
55 workdir|work-directory|deploy-directory|w=s
57 ) or pod2usage(message => "invalid command line", -verbose => 99, -sections => ' ', -noperldoc => 1);
58 pod2usage(message => "$0 $VERSION", -verbose => 99, -sections => ' ', -noperldoc => 1)
59 if $config{version};
60 pod2usage(-verbose => 99, -sections => 'USAGE', -noperldoc => 1) if $config{usage};
61 pod2usage(-verbose => 99, -sections => 'USAGE|EXAMPLES|OPTIONS', -noperldoc => 1)
62 if $config{help};
63 pod2usage(-verbose => 2, -noperldoc => 1) if $config{man};
65 pod2usage(
66 message => 'working directory must be an absolute path',
67 -verbose => 99,
68 -sections => '',
69 -noperldoc => 1
70 ) if exists $config{workdir} && !file_name_is_absolute($config{workdir});
72 if (@{$config{xform}}) {
73 $config{'no-tar'} = 1; # force internal stuff
74 for my $xform (@{$config{xform}}) {
75 my ($src, $filename) =
76 $xform =~ m{\A((?:[^\\:]|\\.)*) : (.*)}mxs;
77 s{\\(.)}{$1}gmxs for $src, $filename;
78 my $array_name = file_name_is_absolute($filename) ? 'rootfile'
79 : 'herefile';
80 push @{$config{$array_name}}, [$src, $filename];
84 if ($config{'include-archive-tar'}) {
85 $config{remote} = catfile(dirname(realpath(__FILE__)), 'remote-at');
86 if (!-e $config{remote}) { # "make" it
87 print {*STDERR} "### Making remote-at...\n";
88 my $startdir = cwd();
89 chdir dirname realpath __FILE__;
90 system {'make'} qw( make remote-at );
91 chdir $startdir;
92 } ## end if (!-e $config{remote...})
93 } ## end if ($config{'include-archive-tar'...})
95 # Establish output channel
96 my $out_fh = \*STDOUT;
97 if ($config{output} ne '-') {
98 open my $fh, '>', $config{output} ## no critic
99 or croak "open('$config{output}'): $OS_ERROR";
100 $out_fh = $fh;
102 binmode $out_fh;
104 # Emit script code to be executed remotely. It is guaranteed to end
105 # with __END__, so that all what comes next is data
106 print {$out_fh} get_remote_script();
108 # Where all the data will be kept
109 print_configuration($out_fh, \%config);
111 print_here_stuff($out_fh, \%config, @ARGV);
112 print_root_stuff($out_fh, \%config);
114 close $out_fh;
116 # Set as executable
117 if ($config{output} ne '-') {
118 chmod oct(755), $config{output}
119 or carp "chmod(0755, '$config{output}'): $OS_ERROR";
122 sub header {
123 my %params = @_;
124 my $namesize = length $params{name};
125 return "$namesize $params{size}\n$params{name}";
128 sub print_configuration { # FIXME
129 my ($fh, $config) = @_;
130 my %general_configuration;
131 for my $name (
132 qw( workdir cleanup bundle deploy
133 gzip bzip2 passthrough tempdir-mode )
136 $general_configuration{$name} = $config->{$name}
137 if exists $config->{$name};
138 } ## end for my $name (qw( workdir cleanup bundle deploy...))
139 my $configuration = Dumper \%general_configuration;
140 print {$fh} header(name => 'config.pl', size => length($configuration)),
141 "\n", $configuration, "\n\n";
142 } ## end sub print_configuration
144 # Process files and directories. All these will be reported in the
145 # extraction directory, i.e. basename() will be applied to them. For
146 # directories, they will be re-created
147 sub print_here_stuff {
148 my $fh = shift;
149 my $config = shift;
150 my @ARGV = @_;
152 my $ai = Deployable::Tar->new($config);
153 $ai->add(
154 '.' => \@ARGV,
155 '.' => $config->{herefile},
156 map { $_ => ['.'] } @{$config->{heredir}}
159 print {$fh} header(name => 'here', size => $ai->size()), "\n";
160 $ai->copy_to($fh);
161 print {$fh} "\n\n";
163 return;
164 } ## end sub print_here_stuff
166 sub print_root_stuff {
167 my ($fh, $config) = @_;
169 my $ai = Deployable::Tar->new($config);
170 $ai->add(
171 '.' => $config->{rootdir},
172 '.' => $config->{rootfile},
173 (undef, $config->{tarfile}),
174 map { $_ => ['.'] } @{$config->{root}},
177 print {$fh} header(name => 'root', size => $ai->size()), "\n";
178 $ai->copy_to($fh);
179 print {$fh} "\n\n";
181 return;
182 } ## end sub print_root_stuff
184 sub get_remote_script {
185 my $fh;
186 if (-e $config{remote}) {
187 open $fh, '<', $config{remote}
188 or croak "open('$config{remote}'): $OS_ERROR";
190 else {
191 no warnings 'once';
192 $fh = \*DATA;
194 my @lines;
195 while (<$fh>) {
196 last if /\A __END__ \s*\z/mxs;
197 push @lines, $_;
199 close $fh;
200 return join '', @lines, "__END__\n";
201 } ## end sub get_remote_script
203 package Deployable::Tar;
205 sub new {
206 my $package = shift;
207 my $self = {ref $_[0] ? %{$_[0]} : @_};
208 $package = 'Deployable::Tar::Internal';
209 if (!$self->{'no-tar'}) {
210 if ((exists $self->{tar}) || (open my $fh, '-|', 'tar', '--help')) {
211 $package = 'Deployable::Tar::External';
212 $self->{tar} ||= 'tar';
214 } ## end if (!$self->{'no-tar'})
215 bless $self, $package;
216 $self->initialise();
217 return $self;
218 } ## end sub new
220 package Deployable::Tar::External;
221 use File::Temp qw( :seekable );
222 use English qw( -no_match_vars );
223 use Cwd ();
224 use Carp;
225 our @ISA = qw( Deployable::Tar );
227 sub initialise {
228 my $self = shift;
229 $self->{_temp} = File::Temp->new();
230 $self->{_filename} = Cwd::abs_path($self->{_temp}->filename());
231 return $self;
232 } ## end sub initialise
234 sub add {
235 my $self = shift;
236 my $tar = $self->{tar};
237 delete $self->{_compressed};
238 while (@_) {
239 my ($directory, $stuff) = splice @_, 0, 2;
240 my @stuff = @$stuff;
241 if (defined $directory) {
242 while (@stuff) {
243 my @chunk = splice @stuff, 0, 50;
244 system {$tar} $tar, 'rvf', $self->{_filename},
245 '-C', $directory, '--', @chunk;
247 } ## end if (defined $directory)
248 else { # it's another TAR file, concatenate
249 while (@stuff) {
250 my @chunk = splice @stuff, 0, 50;
251 system {$tar} $tar, 'Avf', $self->{_filename}, '--', @chunk;
253 } ## end else [ if (defined $directory)]
254 } ## end while (@_)
255 return $self;
256 } ## end sub add
258 sub _compress {
259 my $self = shift;
260 return if exists $self->{_compressed};
262 $self->{_temp}->sysseek(0, SEEK_SET);
263 if ($self->{bzip2}) {
264 require IO::Compress::Bzip2;
265 $self->{_compressed} = File::Temp->new();
267 # double-quotes needed to force usage of filename
268 # instead of filehandle
269 IO::Compress::Bzip2::bzip2($self->{_temp}, "$self->{_compressed}");
270 } ## end if ($self->{bzip2})
271 elsif ($self->{gzip}) {
272 require IO::Compress::Gzip;
273 $self->{_compressed} = File::Temp->new();
275 # double-quotes needed to force usage of filename
276 # instead of filehandle
277 IO::Compress::Gzip::gzip($self->{_temp}, "$self->{_compressed}");
278 } ## end elsif ($self->{gzip})
279 else {
280 $self->{_compressed} = $self->{_temp};
283 return $self;
284 } ## end sub _compress
286 sub size {
287 my ($self) = @_;
288 $self->_compress();
289 return (stat $self->{_compressed})[7];
292 sub copy_to {
293 my ($self, $out_fh) = @_;
294 $self->_compress();
295 my $in_fh = $self->{_compressed};
296 $in_fh->sysseek(0, SEEK_SET);
297 while ('true') {
298 my $nread = $in_fh->sysread(my $buffer, 4096);
299 croak "sysread(): $OS_ERROR" unless defined $nread;
300 last unless $nread;
301 print {$out_fh} $buffer;
302 } ## end while ('true')
303 return $self;
304 } ## end sub copy_to
306 package Deployable::Tar::Internal;
307 use Archive::Tar ();
308 use Cwd ();
309 use File::Find::Rule ();
310 use Carp qw< croak >;
311 our @ISA = qw( Deployable::Tar );
313 sub initialise {
314 my $self = shift;
315 $self->{_tar} = Archive::Tar->new();
316 return $self;
319 sub add {
320 my $self = shift;
321 delete $self->{_string};
322 my $tar = $self->{_tar};
323 my $cwd = Cwd::getcwd();
324 while (@_) {
325 my ($directory, $stuff) = splice @_, 0, 2;
326 if (defined $directory) {
327 chdir $directory;
328 for my $item (@$stuff) {
329 if (ref $item) {
330 my ($src, $filename) = @$item;
331 my $src_len = length $src;
332 for my $input (File::Find::Rule->in($src)) {
333 my ($atf) = $tar->add_files($input);
334 my $name = $filename . substr $input, $src_len;
335 $atf->rename($name);
338 else {
339 $tar->add_files($_) for File::Find::Rule->in($item);
342 chdir $cwd;
343 } ## end if (defined $directory)
344 else { # It's another TAR file to be concatenated
345 for my $item (@$stuff) {
346 my $iterator = Archive::Tar->iter($item);
347 while (my $f = $iterator->()) {
348 $tar->add_files($f);
352 } ## end while (@_)
353 return $self;
354 } ## end sub add
356 sub size {
357 my ($self) = @_;
358 $self->{_string} = $self->{_tar}->write()
359 unless exists $self->{_string};
360 return length $self->{_string};
361 } ## end sub size
363 sub copy_to {
364 my ($self, $out_fh) = @_;
365 $self->{_string} = $self->{_tar}->write()
366 unless exists $self->{_string};
367 print {$out_fh} $self->{_string};
368 } ## end sub copy_to
370 =head1 NAME
372 deployable - create a deploy script for some files/scripts
374 =head1 VERSION
376 See version at beginning of script, variable $VERSION, or call
378 shell$ deployable --version
380 =head1 USAGE
382 deployable [--usage] [--help] [--man] [--version]
384 deployable [--bundle|--all-exec|-X]
385 [--bzip2|--bz2|-j]
386 [--cleanup|-c]
387 [--deploy|--exec|d <program>]
388 [--gzip|-gz|-z]
389 [--heredir|-H <dirname>]
390 [--include-archive-tar|-T]
391 [--no-tar]
392 [--output|-o <filename>]
393 [--root|-r <dirname>]
394 [--rootdir|--in-root|-R <dirname>]
395 [--tar|-t <program-path>]
396 [--tarfile|-F <filename>]
397 [--tempdir-mode|-m <mode>]
398 [--xform|-x src:filename]
399 [--workdir|-w <path>]
400 [ files or directories... ]
402 =head1 EXAMPLES
404 # pack some files and a deploy script together.
405 shell$ deployable script.sh file.txt some/directory -d script.sh
407 # Use a directory's contents as elements for the target root
408 shell$ ls -1 /path/to/target/root
413 # The above will be deployed as /etc, /opt, /usr and /var
414 shell$ deployable -o dep.pl --root /path/to/target/root
416 # Include sub-directory etc/ for inclusion and extraction
417 # directly as /etc/
418 shell$ deployable -o dep.pl --in-root etc/
420 =head1 DESCRIPTION
422 This is a meta-script to create deploy scripts. The latter ones are
423 suitable to be distributed in order to deploy something.
425 You basically have to provide two things: files to install and programs
426 to be executed. Files can be put directly into the deployed script, or
427 can be included in gzipped tar archives.
429 When called, this script creates a deploy script for you. This script
430 includes all the specified files, and when executed it will extract
431 those files and execute the given programs. In this way, you can ship
432 both files and logic needed to correctly install those files, but this
433 is of course of of scope.
435 All files and archives will be extracted under a configured path
436 (see L<--workdir> below), which we'll call I<workdir> from now on. Under
437 the I<workdir> a temporary directory will be created, and the files
438 will be put in the temporary directory. You can specify if you want to
439 clean up this temporary directory or keep it, at your choice. (You're able
440 to both set a default for this cleanup when invoking deployable, or when
441 invoking the deploy script itself). The temporary directory will be
442 called I<tmpdir> in the following.
444 There are several ways to embed files to be shipped:
446 =over
448 =item *
450 pass the name of an already-prepared tar file via L</--tarfile>. The
451 contents of this file will be assumed to be referred to the root
452 directory;
454 =item *
456 specify the file name directly on the command line. A file given in this
457 way will always be extracted into the I<tmpdir>, whatever its initial path
458 was;
460 =item *
462 specify the name of a directory on the command line. In this case,
463 C<tar> will be used to archive the directory, with the usual option to
464 turn absolute paths into relative ones; this means that directories will
465 be re-created under I<tmpdir> when extraction is performed;
467 =item *
469 give the name of a directory to be used as a "here directory", using
470 the C<--heredir|-H> option. This is much the same as giving the directory
471 name (see above), but in this case C<tar> will be told to change into the
472 directory first, and archive '.'. This means that the contents of the
473 "here-directory" will be extracted directly into I<tmpdir>.
475 =back
477 =head2 Extended Example
479 Suppose you have a few server which have the same configuration, apart
480 from some specific stuff (e.g. the hostname, the IP addresses, etc.).
481 You'd like to perform changes to all with the minimum work possible...
482 so you know you should script something.
484 For example, suppose you want to update a few files in /etc, setting these
485 files equal for all hosts. You would typically do the following:
487 # In your computer
488 shell$ mkdir -p /tmp/newfiles/etc
489 shell$ cd /tmp/newfiles/etc
490 # Craft the new files
491 shell$ cd ..
492 shell$ tar cvzf newetc.tar.gz etc
494 # Now, for each server:
495 shell$ scp newetc.tar.gz $server:/tmp
496 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
499 So far, so good. But what if you need to kick in a little more logic?
500 For example, if you update some configuration files, you'll most likey
501 want to restart some services. So you could do the following:
503 shell$ mkdir -p /tmp/newfiles/tmp
504 shell$ cd /tmp/newfiles/tmp
505 # craft a shell script to be executed remotely and set the exec bit
506 # Suppose it's called deploy.sh
507 shell$ cd ..
508 shell$ tar cvzf newetc.tar.gz etc tmp
510 # Now, for each server:
511 shell$ scp newetc.tar.gz $server:/tmp
512 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
513 shell$ ssh $server /tmp/deploy.sh
515 And what if you want to install files depending on the particular machine?
516 Or you have a bundle of stuff to deploy and a bunch of scripts to execute?
517 You can use deployable. In this case, you can do the following:
519 shell$ mkdir -p /tmp/newfiles/etc
520 shell$ cd /tmp/newfiles/etc
521 # Craft the new files
522 shell$ cd ..
523 # craft a shell script to be executed remotely and set the exec bit
524 # Suppose it's called deploy.sh
525 shell$ deployable -o deploy.pl -R etc deploy.sh -d deploy.sh
527 # Now, for each server
528 shell$ scp deploy.pl $server:/tmp
529 shell$ ssh $server /tmp/deploy.pl
531 And you're done. This can be particularly useful if you have another
532 layer of deployment, e.g. if you have to run a script to decide which
533 of a group of archives should be deployed. For example, you could craft
534 a different new "etc" for each server (which is particularly true if
535 network configurations are in the package), and produce a simple script
536 to choose which file to use based on the MAC address of the machine. In
537 this case you could have:
539 =over
541 =item newetc.*.tar.gz
543 a bunch of tar files with the configurations for each different server
545 =item newetc.list
547 a list file with the association between the MAC addresses and the
548 real tar file to deploy from the bunch in the previous bullet
550 =item deploy-the-right-stuff.sh
552 a script to get the real MAC address of the machine, select the right
553 tar file and do the deployment.
555 =back
557 So, you can do the following:
559 shell$ deployable -o deploy.pl newetc.*.tar.gz newetc.list \
560 deploy-the-right-stuff.sh --exec deploy-the-right-stuff.sh
562 # Now, for each server:
563 shell$ scp deploy.pl $server:/tmp
564 shell$ ssh $server /tmp/deploy.pl
566 So, once you have the deploy script on the target machine all you need
567 to do is to execute it. This can come handy when you cannot access the
568 machines from the network, but you have to go there physically: you
569 can prepare all in advance, and just call the deploy script.
572 =head1 OPTIONS
574 Meta-options:
576 =over
578 =item B<--help>
580 print a somewhat more verbose help, showing usage, this description of
581 the options and some examples from the synopsis.
583 =item B<--man>
585 print out the full documentation for the script.
587 =item B<--usage>
589 print a concise usage line and exit.
591 =item B<--version>
593 print the version of the script.
595 =back
597 Real-world options:
599 =over
601 =item B<< --bundle | --all-exec | -X >>
603 Set bundle flag in the produced script. If the bundle flag is set, the
604 I<deploy script> will treat all executables in the main deployment
605 directory as scripts to be executed.
607 By default the flag is not set.
609 =item B<< --bzip2 | --bz2 | -j >>
611 Compress tar archives with bzip2.
613 =item B<< --cleanup | -c >>
615 Set cleanup flag in the produced script. If the cleanup flag is set, the
616 I<deploy script> will clean up after having performed all operations.
618 You can set this flag to C<0> by using C<--no-cleanup>.
620 =item B<< --deploy | --exec | -d <filename> >>
622 Set the name of a program to execute after extraction. You can provide
623 multiple program names, they will be executed in the same order.
625 =item B<< --gzip | --gz | -z >>
627 Compress tar archives with gzip.
629 =item B<< --heredir | -H <path> >>
631 Set the name of a "here directory" (see L<DESCRIPTION>). You can use this
632 option multiple times to provide multiple directories.
634 =item B<< --include-archive-tar | -T >>
636 Embed L<Archive::Tar> (with its dependencies L<Archive::Tar::Constant> and
637 L<Archive::Tar::File>) inside the final script. Use this when you know (or
638 aren't sure) that L<Archive::Tar> will not be available in the target
639 machine.
641 =item B<< --no-tar >>
643 Don't use system C<tar>.
645 =item B<< --output | -o <filename> >>
647 Set the output file name. By default the I<deploy script> will be given
648 out on the standard output; if you provide a filename (different from
649 C<->, of course!) the script will be saved there and the permissions will
650 be set to 0755.
652 =item B<< --root | -r <dirname> >>
654 Include C<dirname> contents for deployment under root directory. The
655 actual production procedure is: hop into C<dirname> and grab a tarball
656 of C<.>. During deployment, hop into C</> and extract the tarball.
658 This is useful if you're already building up the absolute deployment
659 layout under a given directory: just treat that directory as if it were
660 the root of the target system.
662 =item B<< --rootdir | --in-root | -R <filename> >>
664 Include C<filename> as an item that will be extracted under root
665 directory. The actual production procedure is: grab a tarball of
666 C<filename>. During deployment, hop into C</> and extract the tarball.
668 This is useful e.g. if you have a directory (or a group of directories)
669 that you want to deploy directly under the root.
671 Note that the C<--rootdir> alias is kept for backwards compatibility
672 but is not 100% correct - you can specify both a dirname (like it was
673 previously stated) or a single file with this option. This is why it's
674 more readably to use C<--in-root> instead.
676 =item B<< --tar | -t <program-path> >>
678 Set the system C<tar> program to use.
680 =item B<< --tempdir-mode | -m >>
682 set default permissions for temporary directory of deployable script
684 =item B<< --workdir | --deploy-directory | -w <path> >>
686 Set the working directory for the deploy.
688 =back
690 =head1 ROOT OR ROOTDIR?
692 There are two options that allow you to specify things to be deployed
693 in C</>, so what should you use? Thing is... whatever you want!
695 If you have a bunch of directories that have to appear under root, probably
696 your best bet is to put them all inside a directory called C<myroot> and
697 use option C<--root>:
699 shell$ mkdir -p myroot/{etc,opt,var,lib,usr,whatever}
700 # Now put stuff in the directories created above...
701 shell$ deployable --root myroot ...
703 On the other hand, if you just want to put stuff starting from one or
704 two directories that have to show up in C</>, you can avoid creating
705 the extra C<myroot> directory and use C<--in-root> instead:
707 shell$ mkdir -p etc/whatever
708 # Now put stuff in etc/whatever...
709 shell$ deployable --in-root etc ...
711 They are indeed somehow equivalent, the first avoiding you much typing
712 when you have many directories to be deployed starting from root (just
713 put them into the same subdirectory), the second allowing you to avoid
714 putting an extra directory layer.
716 There is indeed an additional catch that makes them quite different. When
717 you use C<root>, the whole content of the directory specified will be
718 used as a base, so you will end up with a listing like this:
720 opt/
721 opt/local/
722 opt/local/application/
723 opt/local/application/myfile.txt
724 opt/local/application/otherfile.txt
726 i.e. all intermediate directories will be saved. On the other hand, when
727 you specify a directory with C<--in-root>, you're not limited to provide
728 a "single-step" directory, so for example:
730 shell$ deployable --in-root opt/local/application
732 will result in the following list of files/directories to be stored:
734 opt/local/application/
735 opt/local/application/myfile.txt
736 opt/local/application/otherfile.txt
738 i.e. the upper level directories will not be included. What is better for
739 you is for you to judge.
741 =head1 THE DEPLOY SCRIPT
743 The net result of calling this script is to produce another script,
744 that we call the I<deploy script>. This script is made of two parts: the
745 code, which is fixed, and the configurations/files, which is what is
746 actually produced. The latter part is put after the C<__END__> marker,
747 as usual.
749 Stuff in the configuration part is always hexified in order to prevent
750 strange tricks or errors. Comments will help you devise what's inside the
751 configurations themselves.
753 The I<deploy script> has options itself, even if they are quite minimal.
754 In particular, it supports the same options C<--workdir|-w> and
755 C<--cleanup> described above, allowing the final user to override the
756 configured values. By default, the I<workdir> is set to C</tmp>
757 and the script will clean up after itself.
759 The following options are supported in the I<deploy script>:
761 =over
763 =item B<--usage | --man | --help>
765 print a minimal help and exit
767 =item B<--version>
769 print script version and exit
771 =item B<--bundle | --all-exec | -X>
773 treat all executables in the main deployment directory as scripts
774 to be executed
776 =item B<--cleanup | --no-cleanup>
778 perform / don't perform temporary directory cleanup after work done
780 =item B<< --deploy | --no-deploy >>
782 deploy scripts are executed by default (same as specifying '--deploy')
783 but you can prevent it.
785 =item B<--dryrun | --dry-run>
787 print final options and exit
789 =item B<< --filelist | --list | -l >>
791 print a list of files that are shipped in the deploy script
793 =item B<< --heretar | --here-tar | -H >>
795 print out the tar file that contains all the files that would be
796 extracted in the temporary directory, useful to redirect to file or
797 pipe to the tar program
799 =item B<< --inspect <dirname> >>
801 just extract all the stuff into <dirname> for inspection. Implies
802 C<--no-deploy>, C<--no-tempdir>, ignores C<--bundle> (as a consequence of
803 C<--no-deploy>), disables C<--cleanup> and sets the working directory
804 to C<dirname>
806 =item B<< --no-tar >>
808 don't use system C<tar>
810 =item B<< --rootar | --root-tar | -R >>
812 print out the tar file that contains all the files that would be
813 extracted in the root directory, useful to redirect to file or
814 pipe to the tar program
816 =item B<--show | --show-options | -s>
818 print configured options and exit
820 =item B<< --tar | -t <program-path> >>
822 set the system C<tar> program to use.
824 =item B<< --tarfile | -F <filename> >>
826 add the specified C<filename> (assumed to be an uncompressed
827 TAR file) to the lot for root extraction. This can come handy
828 when you already have all the files backed up in a TAR archive
829 and you're not willing to expand them (e.g. because your
830 filesystem is case-insensitive...).
832 =item B<< --tempdir | --no-tempdir >>
834 by default a temporary directory is created (same as specifying
835 C<--tempdir>), but you can execute directly in the workdir (see below)
836 without creating it.
838 =item B<< --tempdir-mode | -m >>
840 temporary directories (see C<--tempdir>) created by File::Temp have
841 permission 600 that prevents group/others from even looking at the
842 contents. You might want to invoke some of the internal scripts
843 from another user (e.g. via C<su>), so you can pass a mode to be
844 set on the temporary directory.
846 Works only if C<--tempdir> is active.
848 =item B<< --xform | -x <src:filename> >>
850 include file or directory C<src> as path C<filename>. The latter can be
851 either an absolute path (included in C<root>) or a relative one
852 (included in the working directory).
854 =item B<--workdir | --work-directory | --deploy-directory | -w>
856 working base directory (a temporary subdirectory will be created
857 there anyway)
859 =back
861 Note the difference between C<--show> and C<--dryrun>: the former will
862 give you the options that are "embedded" in the I<deploy script> without
863 taking into account other options given on the command line, while the
864 latter will give you the final options that would be used if the script
865 were called without C<--dryrun>.
867 =head2 Deploy Script Example Usage
869 In the following, we'll assume that the I<deploy script> is called
870 C<deploy.pl>.
872 To execute the script with the already configured options, you just have
873 to call it:
875 shell$ ./deploy.pl
877 If you just want to see which configurations are in the I<deploy script>:
879 shell$ ./deploy.pl --show
881 To see which files are included, you have two options. One is asking the
882 script:
884 shell$ ./deploy.pl --filelist
886 the other is piping to tar:
888 shell$ ./deploy.pl --tar | tar tvf -
890 Extract contents of the script in a temp directory and simply inspect
891 what's inside:
893 # extract stuff into subdirectory 'inspect' for... inspection
894 shell$ ./deploy.pl --no-tempdir --no-deploy --workdir inspect
896 =head2 Deploy Script Requirements
898 You'll need a working Perl with version at least 5.6.2.
900 If you specify L</--include-archive-tar>, the module L<Archive::Tar> will
901 be included as well. This should ease your life and avoid you to have
902 B<tar> on the target machine. On the other hand, if you already know
903 that B<tar> will be available, you can avoid including C<Archive::Tar>
904 and have the generated script use it (it could be rather slower anyway).
906 =head1 DIAGNOSTICS
908 Each error message should be enough explicit to be understood without the
909 need for furter explainations. Which is another way to say that I'm way
910 too lazy to list all possible ways that this script has to fail.
913 =head1 CONFIGURATION AND ENVIRONMENT
915 deployable requires no configuration files or environment variables.
917 Please note that deployable B<needs> to find its master B<remote> file
918 to produce the final script. This must be put in the same directory where
919 deployable is put. You should be able to B<symlink> deployable where you
920 think it's better, anyway - it will go search for the original file
921 and look for B<remote> inside the same directory. This does not apply to
922 hard links, of course.
925 =head1 DEPENDENCIES
927 All core modules, apart the following:
929 =over
931 =item B<< Archive::Tar >>
933 =item B<< File::Find::Rule >>
935 =back
937 =head1 BUGS AND LIMITATIONS
939 No bugs have been reported.
941 Please report any bugs or feature requests to the AUTHOR below.
943 Be sure to read L<CONFIGURATION AND ENVIRONMENT> for a slight limitation
944 about the availability of the B<remote> script.
946 =head1 AUTHOR
948 Flavio Poletti C<flavio [AT] polettix.it>
951 =head1 LICENSE AND COPYRIGHT
953 Copyright (c) 2008, Flavio Poletti C<flavio [AT] polettix.it>. All rights reserved.
955 This script is free software; you can redistribute it and/or
956 modify it under the same terms as Perl itself. See L<perlartistic>
957 and L<perlgpl>.
959 =head1 DISCLAIMER OF WARRANTY
961 BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
962 FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
963 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
964 PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
965 EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
966 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
967 ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
968 YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
969 NECESSARY SERVICING, REPAIR, OR CORRECTION.
971 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
972 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
973 REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
974 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
975 OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
976 THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
977 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
978 FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
979 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
980 SUCH DAMAGES.
982 =cut
984 package main; # ensure DATA is main::DATA
985 __DATA__