fixed minor bugs
[deployable.git] / deployable
blob31fef262bf69ae994c751cbc2fa9c2cb1f0029e1
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|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|-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 directory /path/to/etc for inclusion and extraction
378 # directly as /etc
379 shell$ deployable -o dep.pl --rootdir /path/to/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 | -R <dirname> >>
625 Include C<dirname> as a directory that will be extracted under root
626 directory. The actual production procedure is: grab a tarball of
627 C<dirname>. During deployment, hop into C</> and extract the tarball.
629 This is useful if you have a directory (or a group of directories) that
630 you want to deploy directly under the root.
632 =item B<< --tar | -t <program-path> >>
634 Set the system C<tar> program to use.
636 =item B<< --tempdir-mode | -m >>
638 set default permissions for temporary directory of deployable script
640 =item B<< --workdir | --deploy-directory | -w <path> >>
642 Set the working directory for the deploy.
644 =back
646 =head1 ROOT OR ROOTDIR?
648 There are two options that allow you to specify things to be deployed
649 in C</>, so what should you use? Thing is... whatever you want!
651 If you have a bunch of directories that have to appear under root, probably
652 your best bet is to put them all inside a directory called C<myroot> and
653 use option C<--root>:
655 shell$ mkdir -p myroot/{etc,opt,var,lib,usr,whatever}
656 # Now put stuff in the directories created above...
657 shell$ deployable --root myroot ...
659 On the other hand, if you just want to put stuff starting from one or
660 two directories that have to show up in C</>, you can avoid creating
661 the extra C<myroot> directory and use C<--rootdir> instead:
663 shell$ mkdir -p etc/whatever
664 # Now put stuff in etc/whatever...
665 shell$ deployable --rootdir etc ...
667 They are indeed somehow equivalent, the first avoiding you much typing
668 when you have many directories to be deployed starting from root (just
669 put them into the same subdirectory), the second allowing you to avoid
670 putting an extra directory layer.
672 There is indeed an additional catch that makes them quite different. When
673 you use C<root>, the whole content of the directory specified will be
674 used as a base, so you will end up with a listing like this:
676 opt/
677 opt/local/
678 opt/local/application/
679 opt/local/application/myfile.txt
680 opt/local/application/otherfile.txt
682 i.e. all intermediate directories will be saved. On the other hand, when
683 you specify a directory with C<--rootdir>, you're not limited to provide
684 a "single-step" directory, so for example:
686 shell$ deployable --rootdir opt/local/application
688 will result in the following list of files/directories to be stored:
690 opt/local/application/
691 opt/local/application/myfile.txt
692 opt/local/application/otherfile.txt
694 i.e. the upper level directories will not be included. What is better for
695 you is for you to judge.
697 =head1 THE DEPLOY SCRIPT
699 The net result of calling this script is to produce another script,
700 that we call the I<deploy script>. This script is made of two parts: the
701 code, which is fixed, and the configurations/files, which is what is
702 actually produced. The latter part is put after the C<__END__> marker,
703 as usual.
705 Stuff in the configuration part is always hexified in order to prevent
706 strange tricks or errors. Comments will help you devise what's inside the
707 configurations themselves.
709 The I<deploy script> has options itself, even if they are quite minimal.
710 In particular, it supports the same options C<--workdir|-w> and
711 C<--cleanup> described above, allowing the final user to override the
712 configured values. By default, the I<workdir> is set to C</tmp>
713 and the script will clean up after itself.
715 The following options are supported in the I<deploy script>:
717 =over
719 =item B<--usage | --man | --help>
721 print a minimal help and exit
723 =item B<--version>
725 print script version and exit
727 =item B<--bundle | --all-exec | -X>
729 treat all executables in the main deployment directory as scripts
730 to be executed
732 =item B<--cleanup | --no-cleanup>
734 perform / don't perform temporary directory cleanup after work done
736 =item B<< --deploy | --no-deploy >>
738 deploy scripts are executed by default (same as specifying '--deploy')
739 but you can prevent it.
741 =item B<--dryrun | --dry-run>
743 print final options and exit
745 =item B<< --filelist | --list | -l >>
747 print a list of files that are shipped in the deploy script
749 =item B<< --heretar | --here-tar | -H >>
751 print out the tar file that contains all the files that would be
752 extracted in the temporary directory, useful to redirect to file or
753 pipe to the tar program
755 =item B<< --inspect <dirname> >>
757 just extract all the stuff into <dirname> for inspection. Implies
758 C<--no-deploy>, C<--no-tempdir>, ignores C<--bundle> (as a consequence of
759 C<--no-deploy>), disables C<--cleanup> and sets the working directory
760 to C<dirname>
762 =item B<< --no-tar >>
764 don't use system C<tar>
766 =item B<< --rootar | --root-tar | -R >>
768 print out the tar file that contains all the files that would be
769 extracted in the root directory, useful to redirect to file or
770 pipe to the tar program
772 =item B<--show | --show-options | -s>
774 print configured options and exit
776 =item B<< --tar | -t <program-path> >>
778 set the system C<tar> program to use.
780 =item B<< --tarfile | -F <filename> >>
782 add the specified C<filename> (assumed to be an uncompressed
783 TAR file) to the lot for root extraction. This can come handy
784 when you already have all the files backed up in a TAR archive
785 and you're not willing to expand them (e.g. because your
786 filesystem is case-insensitive...).
788 =item B<< --tempdir | --no-tempdir >>
790 by default a temporary directory is created (same as specifying
791 C<--tempdir>), but you can execute directly in the workdir (see below)
792 without creating it.
794 =item B<< --tempdir-mode | -m >>
796 temporary directories (see C<--tempdir>) created by File::Temp have
797 permission 600 that prevents group/others from even looking at the
798 contents. You might want to invoke some of the internal scripts
799 from another user (e.g. via C<su>), so you can pass a mode to be
800 set on the temporary directory.
802 Works only if C<--tempdir> is active.
804 =item B<--workdir | --work-directory | --deploy-directory | -w>
806 working base directory (a temporary subdirectory will be created
807 there anyway)
809 =back
811 Note the difference between C<--show> and C<--dryrun>: the former will
812 give you the options that are "embedded" in the I<deploy script> without
813 taking into account other options given on the command line, while the
814 latter will give you the final options that would be used if the script
815 were called without C<--dryrun>.
817 =head2 Deploy Script Example Usage
819 In the following, we'll assume that the I<deploy script> is called
820 C<deploy.pl>.
822 To execute the script with the already configured options, you just have
823 to call it:
825 shell$ ./deploy.pl
827 If you just want to see which configurations are in the I<deploy script>:
829 shell$ ./deploy.pl --show
831 To see which files are included, you have two options. One is asking the
832 script:
834 shell$ ./deploy.pl --filelist
836 the other is piping to tar:
838 shell$ ./deploy.pl --tar | tar tvf -
840 Extract contents of the script in a temp directory and simply inspect
841 what's inside:
843 # extract stuff into subdirectory 'inspect' for... inspection
844 shell$ ./deploy.pl --no-tempdir --no-deploy --workdir inspect
846 =head2 Deploy Script Requirements
848 You'll need a working Perl with version at least 5.6.2.
850 If you specify L</--include-archive-tar>, the module L<Archive::Tar> will
851 be included as well. This should ease your life and avoid you to have
852 B<tar> on the target machine. On the other hand, if you already know
853 that B<tar> will be available, you can avoid including C<Archive::Tar>
854 and have the generated script use it (it could be rather slower anyway).
856 =head1 DIAGNOSTICS
858 Each error message should be enough explicit to be understood without the
859 need for furter explainations. Which is another way to say that I'm way
860 too lazy to list all possible ways that this script has to fail.
863 =head1 CONFIGURATION AND ENVIRONMENT
865 deployable requires no configuration files or environment variables.
867 Please note that deployable B<needs> to find its master B<remote> file
868 to produce the final script. This must be put in the same directory where
869 deployable is put. You should be able to B<symlink> deployable where you
870 think it's better, anyway - it will go search for the original file
871 and look for B<remote> inside the same directory. This does not apply to
872 hard links, of course.
875 =head1 DEPENDENCIES
877 All core modules, apart the following:
879 =over
881 =item B<< Archive::Tar >>
883 =item B<< File::Find::Rule >>
885 =back
887 =head1 BUGS AND LIMITATIONS
889 No bugs have been reported.
891 Please report any bugs or feature requests to the AUTHOR below.
893 Be sure to read L<CONFIGURATION AND ENVIRONMENT> for a slight limitation
894 about the availability of the B<remote> script.
896 =head1 AUTHOR
898 Flavio Poletti C<flavio [AT] polettix.it>
901 =head1 LICENSE AND COPYRIGHT
903 Copyright (c) 2008, Flavio Poletti C<flavio [AT] polettix.it>. All rights reserved.
905 This script is free software; you can redistribute it and/or
906 modify it under the same terms as Perl itself. See L<perlartistic>
907 and L<perlgpl>.
909 =head1 DISCLAIMER OF WARRANTY
911 BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
912 FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
913 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
914 PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
915 EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
916 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
917 ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
918 YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
919 NECESSARY SERVICING, REPAIR, OR CORRECTION.
921 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
922 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
923 REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
924 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
925 OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
926 THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
927 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
928 FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
929 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
930 SUCH DAMAGES.
932 =cut
934 package main; # ensure DATA is main::DATA
935 __DATA__