added repo file for ignoring files
[deployable.git] / deployable
blob863c11394899374c6ebcbe5fa6ce4073871a3593
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
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 open my $fh, '<', $config{remote}
168 or croak "open('$config{remote}'): $OS_ERROR";
169 my @lines;
170 while (<$fh>) {
171 last if /\A __END__ \s*\z/mxs;
172 push @lines, $_;
174 close $fh;
175 return join '', @lines, "__END__\n";
176 } ## end sub get_remote_script
178 package Deployable::Tar;
180 sub new {
181 my $package = shift;
182 my $self = {ref $_[0] ? %{$_[0]} : @_};
183 $package = 'Deployable::Tar::Internal';
184 if (!$self->{'no-tar'}) {
185 if ((exists $self->{tar}) || (open my $fh, '-|', 'tar', '--help')) {
186 $package = 'Deployable::Tar::External';
187 $self->{tar} ||= 'tar';
189 } ## end if (!$self->{'no-tar'})
190 bless $self, $package;
191 $self->initialise();
192 return $self;
193 } ## end sub new
195 package Deployable::Tar::External;
196 use File::Temp qw( :seekable );
197 use English qw( -no_match_vars );
198 use Cwd ();
199 use Carp;
200 our @ISA = qw( Deployable::Tar );
202 sub initialise {
203 my $self = shift;
204 $self->{_temp} = File::Temp->new();
205 $self->{_filename} = Cwd::abs_path($self->{_temp}->filename());
206 return $self;
207 } ## end sub initialise
209 sub add {
210 my $self = shift;
211 my $tar = $self->{tar};
212 delete $self->{_compressed};
213 while (@_) {
214 my ($directory, $stuff) = splice @_, 0, 2;
215 my @stuff = @$stuff;
216 if (defined $directory) {
217 while (@stuff) {
218 my @chunk = splice @stuff, 0, 50;
219 system {$tar} $tar, 'rvf', $self->{_filename},
220 '-C', $directory, '--', @chunk;
222 } ## end if (defined $directory)
223 else { # it's another TAR file, concatenate
224 while (@stuff) {
225 my @chunk = splice @stuff, 0, 50;
226 system {$tar} $tar, 'Avf', $self->{_filename}, '--', @chunk;
228 } ## end else [ if (defined $directory)]
229 } ## end while (@_)
230 return $self;
231 } ## end sub add
233 sub _compress {
234 my $self = shift;
235 return if exists $self->{_compressed};
237 $self->{_temp}->sysseek(0, SEEK_SET);
238 if ($self->{bzip2}) {
239 require IO::Compress::Bzip2;
240 $self->{_compressed} = File::Temp->new();
242 # double-quotes needed to force usage of filename
243 # instead of filehandle
244 IO::Compress::Bzip2::bzip2($self->{_temp}, "$self->{_compressed}");
245 } ## end if ($self->{bzip2})
246 elsif ($self->{gzip}) {
247 require IO::Compress::Gzip;
248 $self->{_compressed} = File::Temp->new();
250 # double-quotes needed to force usage of filename
251 # instead of filehandle
252 IO::Compress::Gzip::gzip($self->{_temp}, "$self->{_compressed}");
253 } ## end elsif ($self->{gzip})
254 else {
255 $self->{_compressed} = $self->{_temp};
258 return $self;
259 } ## end sub _compress
261 sub size {
262 my ($self) = @_;
263 $self->_compress();
264 return (stat $self->{_compressed})[7];
267 sub copy_to {
268 my ($self, $out_fh) = @_;
269 $self->_compress();
270 my $in_fh = $self->{_compressed};
271 $in_fh->sysseek(0, SEEK_SET);
272 while ('true') {
273 my $nread = $in_fh->sysread(my $buffer, 4096);
274 croak "sysread(): $OS_ERROR" unless defined $nread;
275 last unless $nread;
276 print {$out_fh} $buffer;
277 } ## end while ('true')
278 return $self;
279 } ## end sub copy_to
281 package Deployable::Tar::Internal;
282 use Archive::Tar ();
283 use Cwd ();
284 use File::Find::Rule ();
285 use Carp qw< croak >;
286 our @ISA = qw( Deployable::Tar );
288 sub initialise {
289 my $self = shift;
290 $self->{_tar} = Archive::Tar->new();
291 return $self;
294 sub add {
295 my $self = shift;
296 delete $self->{_string};
297 my $tar = $self->{_tar};
298 my $cwd = Cwd::getcwd();
299 while (@_) {
300 my ($directory, $stuff) = splice @_, 0, 2;
301 if (defined $directory) {
302 chdir $directory;
303 for my $item (@$stuff) {
304 $tar->add_files($_) for File::Find::Rule->in($item);
306 chdir $cwd;
307 } ## end if (defined $directory)
308 else { # It's another TAR file to be concatenated
309 for my $item (@$stuff) {
310 my $iterator = Archive::Tar->iter($item);
311 while (my $f = $iterator->()) {
312 $tar->add_files($f);
316 } ## end while (@_)
317 return $self;
318 } ## end sub add
320 sub size {
321 my ($self) = @_;
322 $self->{_string} = $self->{_tar}->write()
323 unless exists $self->{_string};
324 return length $self->{_string};
325 } ## end sub size
327 sub copy_to {
328 my ($self, $out_fh) = @_;
329 $self->{_string} = $self->{_tar}->write()
330 unless exists $self->{_string};
331 print {$out_fh} $self->{_string};
332 } ## end sub copy_to
334 __END__
336 =head1 NAME
338 deployable - create a deploy script for some files/scripts
340 =head1 VERSION
342 See version at beginning of script, variable $VERSION, or call
344 shell$ deployable --version
346 =head1 USAGE
348 deployable [--usage] [--help] [--man] [--version]
350 deployable [--bundle|--all-exec|-X] [--bzip2|--bz2|-j] [--cleanup|-c]
351 [--deploy|--exec|d <program>] [--gzip|-gz|-z]
352 [--heredir|-H <dirname>] [--include-archive-tar|-T]
353 [--no-tar] [--output|-o <filename>] [--root|-r <dirname>]
354 [--rootdir|-R <dirname>] [--tar|-t <program-path>]
355 [--tarfile|-F <filename>] [--tempdir-mode|-m <mode>]
356 [--workdir|-w <path>] [ files or directories... ]
358 =head1 EXAMPLES
360 # pack some files and a deploy script together.
361 shell$ deployable script.sh file.txt some/directory -d script.sh
363 # Use a directory's contents as elements for the target root
364 shell$ ls -1 /path/to/target/root
369 # The above will be deployed as /etc, /opt, /usr and /var
370 shell$ deployable -o dep.pl --root /path/to/target/root
372 # Include directory /path/to/etc for inclusion and extraction
373 # directly as /etc
374 shell$ deployable -o dep.pl --rootdir /path/to/etc
376 =head1 DESCRIPTION
378 This is a meta-script to create deploy scripts. The latter ones are
379 suitable to be distributed in order to deploy something.
381 You basically have to provide two things: files to install and programs
382 to be executed. Files can be put directly into the deployed script, or
383 can be included in gzipped tar archives.
385 When called, this script creates a deploy script for you. This script
386 includes all the specified files, and when executed it will extract
387 those files and execute the given programs. In this way, you can ship
388 both files and logic needed to correctly install those files, but this
389 is of course of of scope.
391 All files and archives will be extracted under a configured path
392 (see L<--workdir> below), which we'll call I<workdir> from now on. Under
393 the I<workdir> a temporary directory will be created, and the files
394 will be put in the temporary directory. You can specify if you want to
395 clean up this temporary directory or keep it, at your choice. (You're able
396 to both set a default for this cleanup when invoking deployable, or when
397 invoking the deploy script itself). The temporary directory will be
398 called I<tmpdir> in the following.
400 There are several ways to embed files to be shipped:
402 =over
404 =item *
406 pass the name of an already-prepared tar file via L</--tarfile>. The
407 contents of this file will be assumed to be referred to the root
408 directory;
410 =item *
412 specify the file name directly on the command line. A file given in this
413 way will always be extracted into the I<tmpdir>, whatever its initial path
414 was;
416 =item *
418 specify the name of a directory on the command line. In this case,
419 C<tar> will be used to archive the directory, with the usual option to
420 turn absolute paths into relative ones; this means that directories will
421 be re-created under I<tmpdir> when extraction is performed;
423 =item *
425 give the name of a directory to be used as a "here directory", using
426 the C<--heredir|-H> option. This is much the same as giving the directory
427 name (see above), but in this case C<tar> will be told to change into the
428 directory first, and archive '.'. This means that the contents of the
429 "here-directory" will be extracted directly into I<tmpdir>.
431 =back
433 =head2 Extended Example
435 Suppose you have a few server which have the same configuration, apart
436 from some specific stuff (e.g. the hostname, the IP addresses, etc.).
437 You'd like to perform changes to all with the minimum work possible...
438 so you know you should script something.
440 For example, suppose you want to update a few files in /etc, setting these
441 files equal for all hosts. You would typically do the following:
443 # In your computer
444 shell$ mkdir -p /tmp/newfiles/etc
445 shell$ cd /tmp/newfiles/etc
446 # Craft the new files
447 shell$ cd ..
448 shell$ tar cvzf newetc.tar.gz etc
450 # Now, for each server:
451 shell$ scp newetc.tar.gz $server:/tmp
452 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
455 So far, so good. But what if you need to kick in a little more logic?
456 For example, if you update some configuration files, you'll most likey
457 want to restart some services. So you could do the following:
459 shell$ mkdir -p /tmp/newfiles/tmp
460 shell$ cd /tmp/newfiles/tmp
461 # craft a shell script to be executed remotely and set the exec bit
462 # Suppose it's called deploy.sh
463 shell$ cd ..
464 shell$ tar cvzf newetc.tar.gz etc tmp
466 # Now, for each server:
467 shell$ scp newetc.tar.gz $server:/tmp
468 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
469 shell$ ssh $server /tmp/deploy.sh
471 And what if you want to install files depending on the particular machine?
472 Or you have a bundle of stuff to deploy and a bunch of scripts to execute?
473 You can use deployable. In this case, you can do the following:
475 shell$ mkdir -p /tmp/newfiles/etc
476 shell$ cd /tmp/newfiles/etc
477 # Craft the new files
478 shell$ cd ..
479 # craft a shell script to be executed remotely and set the exec bit
480 # Suppose it's called deploy.sh
481 shell$ deployable -o deploy.pl -R etc deploy.sh -d deploy.sh
483 # Now, for each server
484 shell$ scp deploy.pl $server:/tmp
485 shell$ ssh $server /tmp/deploy.pl
487 And you're done. This can be particularly useful if you have another
488 layer of deployment, e.g. if you have to run a script to decide which
489 of a group of archives should be deployed. For example, you could craft
490 a different new "etc" for each server (which is particularly true if
491 network configurations are in the package), and produce a simple script
492 to choose which file to use based on the MAC address of the machine. In
493 this case you could have:
495 =over
497 =item newetc.*.tar.gz
499 a bunch of tar files with the configurations for each different server
501 =item newetc.list
503 a list file with the association between the MAC addresses and the
504 real tar file to deploy from the bunch in the previous bullet
506 =item deploy-the-right-stuff.sh
508 a script to get the real MAC address of the machine, select the right
509 tar file and do the deployment.
511 =back
513 So, you can do the following:
515 shell$ deployable -o deploy.pl newetc.*.tar.gz newetc.list \
516 deploy-the-right-stuff.sh --exec deploy-the-right-stuff.sh
518 # Now, for each server:
519 shell$ scp deploy.pl $server:/tmp
520 shell$ ssh $server /tmp/deploy.pl
522 So, once you have the deploy script on the target machine all you need
523 to do is to execute it. This can come handy when you cannot access the
524 machines from the network, but you have to go there physically: you
525 can prepare all in advance, and just call the deploy script.
528 =head1 OPTIONS
530 Meta-options:
532 =over
534 =item B<--help>
536 print a somewhat more verbose help, showing usage, this description of
537 the options and some examples from the synopsis.
539 =item B<--man>
541 print out the full documentation for the script.
543 =item B<--usage>
545 print a concise usage line and exit.
547 =item B<--version>
549 print the version of the script.
551 =back
553 Real-world options:
555 =over
557 =item B<< --bundle | --all-exec | -X >>
559 Set bundle flag in the produced script. If the bundle flag is set, the
560 I<deploy script> will treat all executables in the main deployment
561 directory as scripts to be executed.
563 By default the flag is not set.
565 =item B<< --bzip2 | --bz2 | -j >>
567 Compress tar archives with bzip2.
569 =item B<< --cleanup | -c >>
571 Set cleanup flag in the produced script. If the cleanup flag is set, the
572 I<deploy script> will clean up after having performed all operations.
574 You can set this flag to C<0> by using C<--no-cleanup>.
576 =item B<< --deploy | --exec | -d <filename> >>
578 Set the name of a program to execute after extraction. You can provide
579 multiple program names, they will be executed in the same order.
581 =item B<< --gzip | --gz | -z >>
583 Compress tar archives with gzip.
585 =item B<< --heredir | -H <path> >>
587 Set the name of a "here directory" (see L<DESCRIPTION>). You can use this
588 option multiple times to provide multiple directories.
590 =item B<< --include-archive-tar | -T >>
592 Embed L<Archive::Tar> (with its dependencies L<Archive::Tar::Constant> and
593 L<Archive::Tar::File>) inside the final script. Use this when you know (or
594 aren't sure) that L<Archive::Tar> will not be available in the target
595 machine.
597 =item B<< --no-tar >>
599 Don't use system C<tar>.
601 =item B<< --output | -o <filename> >>
603 Set the output file name. By default the I<deploy script> will be given
604 out on the standard output; if you provide a filename (different from
605 C<->, of course!) the script will be saved there and the permissions will
606 be set to 0755.
608 =item B<< --root | -r <dirname> >>
610 Include C<dirname> contents for deployment under root directory. The
611 actual production procedure is: hop into C<dirname> and grab a tarball
612 of C<.>. During deployment, hop into C</> and extract the tarball.
614 This is useful if you're already building up the absolute deployment
615 layout under a given directory: just treat that directory as if it were
616 the root of the target system.
618 =item B<< --rootdir | -R <dirname> >>
620 Include C<dirname> as a directory that will be extracted under root
621 directory. The actual production procedure is: grab a tarball of
622 C<dirname>. During deployment, hop into C</> and extract the tarball.
624 This is useful if you have a directory (or a group of directories) that
625 you want to deploy directly under the root.
627 =item B<< --tar | -t <program-path> >>
629 Set the system C<tar> program to use.
631 =item B<< --tempdir-mode | -m >>
633 set default permissions for temporary directory of deployable script
635 =item B<< --workdir | --deploy-directory | -w <path> >>
637 Set the working directory for the deploy.
639 =back
641 =head1 ROOT OR ROOTDIR?
643 There are two options that allow you to specify things to be deployed
644 in C</>, so what should you use? Thing is... whatever you want!
646 If you have a bunch of directories that have to appear under root, probably
647 your best bet is to put them all inside a directory called C<myroot> and
648 use option C<--root>:
650 shell$ mkdir -p myroot/{etc,opt,var,lib,usr,whatever}
651 # Now put stuff in the directories created above...
652 shell$ deployable --root myroot ...
654 On the other hand, if you just want to put stuff starting from one or
655 two directories that have to show up in C</>, you can avoid creating
656 the extra C<myroot> directory and use C<--rootdir> instead:
658 shell$ mkdir -p etc/whatever
659 # Now put stuff in etc/whatever...
660 shell$ deployable --rootdir etc ...
662 They are indeed somehow equivalent, the first avoiding you much typing
663 when you have many directories to be deployed starting from root (just
664 put them into the same subdirectory), the second allowing you to avoid
665 putting an extra directory layer.
667 There is indeed an additional catch that makes them quite different. When
668 you use C<root>, the whole content of the directory specified will be
669 used as a base, so you will end up with a listing like this:
671 opt/
672 opt/local/
673 opt/local/application/
674 opt/local/application/myfile.txt
675 opt/local/application/otherfile.txt
677 i.e. all intermediate directories will be saved. On the other hand, when
678 you specify a directory with C<--rootdir>, you're not limited to provide
679 a "single-step" directory, so for example:
681 shell$ deployable --rootdir opt/local/application
683 will result in the following list of files/directories to be stored:
685 opt/local/application/
686 opt/local/application/myfile.txt
687 opt/local/application/otherfile.txt
689 i.e. the upper level directories will not be included. What is better for
690 you is for you to judge.
692 =head1 THE DEPLOY SCRIPT
694 The net result of calling this script is to produce another script,
695 that we call the I<deploy script>. This script is made of two parts: the
696 code, which is fixed, and the configurations/files, which is what is
697 actually produced. The latter part is put after the C<__END__> marker,
698 as usual.
700 Stuff in the configuration part is always hexified in order to prevent
701 strange tricks or errors. Comments will help you devise what's inside the
702 configurations themselves.
704 The I<deploy script> has options itself, even if they are quite minimal.
705 In particular, it supports the same options C<--workdir|-w> and
706 C<--cleanup> described above, allowing the final user to override the
707 configured values. By default, the I<workdir> is set to C</tmp>
708 and the script will clean up after itself.
710 The following options are supported in the I<deploy script>:
712 =over
714 =item B<--usage | --man | --help>
716 print a minimal help and exit
718 =item B<--version>
720 print script version and exit
722 =item B<--bundle | --all-exec | -X>
724 treat all executables in the main deployment directory as scripts
725 to be executed
727 =item B<--cleanup | --no-cleanup>
729 perform / don't perform temporary directory cleanup after work done
731 =item B<< --deploy | --no-deploy >>
733 deploy scripts are executed by default (same as specifying '--deploy')
734 but you can prevent it.
736 =item B<--dryrun | --dry-run>
738 print final options and exit
740 =item B<< --filelist | --list | -l >>
742 print a list of files that are shipped in the deploy script
744 =item B<< --heretar | --here-tar | -H >>
746 print out the tar file that contains all the files that would be
747 extracted in the temporary directory, useful to redirect to file or
748 pipe to the tar program
750 =item B<< --inspect <dirname> >>
752 just extract all the stuff into <dirname> for inspection. Implies
753 C<--no-deploy>, C<--no-tempdir>, ignores C<--bundle> (as a consequence of
754 C<--no-deploy>), disables C<--cleanup> and sets the working directory
755 to C<dirname>
757 =item B<< --no-tar >>
759 don't use system C<tar>
761 =item B<< --rootar | --root-tar | -R >>
763 print out the tar file that contains all the files that would be
764 extracted in the root directory, useful to redirect to file or
765 pipe to the tar program
767 =item B<--show | --show-options | -s>
769 print configured options and exit
771 =item B<< --tar | -t <program-path> >>
773 set the system C<tar> program to use.
775 =item B<< --tarfile | -F <filename> >>
777 add the specified C<filename> (assumed to be an uncompressed
778 TAR file) to the lot for root extraction. This can come handy
779 when you already have all the files backed up in a TAR archive
780 and you're not willing to expand them (e.g. because your
781 filesystem is case-insensitive...).
783 =item B<< --tempdir | --no-tempdir >>
785 by default a temporary directory is created (same as specifying
786 C<--tempdir>), but you can execute directly in the workdir (see below)
787 without creating it.
789 =item B<< --tempdir-mode | -m >>
791 temporary directories (see C<--tempdir>) created by File::Temp have
792 permission 600 that prevents group/others from even looking at the
793 contents. You might want to invoke some of the internal scripts
794 from another user (e.g. via C<su>), so you can pass a mode to be
795 set on the temporary directory.
797 Works only if C<--tempdir> is active.
799 =item B<--workdir | --work-directory | --deploy-directory | -w>
801 working base directory (a temporary subdirectory will be created
802 there anyway)
804 =back
806 Note the difference between C<--show> and C<--dryrun>: the former will
807 give you the options that are "embedded" in the I<deploy script> without
808 taking into account other options given on the command line, while the
809 latter will give you the final options that would be used if the script
810 were called without C<--dryrun>.
812 =head2 Deploy Script Example Usage
814 In the following, we'll assume that the I<deploy script> is called
815 C<deploy.pl>.
817 To execute the script with the already configured options, you just have
818 to call it:
820 shell$ ./deploy.pl
822 If you just want to see which configurations are in the I<deploy script>:
824 shell$ ./deploy.pl --show
826 To see which files are included, you have two options. One is asking the
827 script:
829 shell$ ./deploy.pl --filelist
831 the other is piping to tar:
833 shell$ ./deploy.pl --tar | tar tvf -
835 Extract contents of the script in a temp directory and simply inspect
836 what's inside:
838 # extract stuff into subdirectory 'inspect' for... inspection
839 shell$ ./deploy.pl --no-tempdir --no-deploy --workdir inspect
841 =head2 Deploy Script Requirements
843 You'll need a working Perl with version at least 5.6.2.
845 If you specify L</--include-archive-tar>, the module L<Archive::Tar> will
846 be included as well. This should ease your life and avoid you to have
847 B<tar> on the target machine. On the other hand, if you already know
848 that B<tar> will be available, you can avoid including C<Archive::Tar>
849 and have the generated script use it (it could be rather slower anyway).
851 =head1 DIAGNOSTICS
853 Each error message should be enough explicit to be understood without the
854 need for furter explainations. Which is another way to say that I'm way
855 too lazy to list all possible ways that this script has to fail.
858 =head1 CONFIGURATION AND ENVIRONMENT
860 deployable requires no configuration files or environment variables.
862 Please note that deployable B<needs> to find its master B<remote> file
863 to produce the final script. This must be put in the same directory where
864 deployable is put. You should be able to B<symlink> deployable where you
865 think it's better, anyway - it will go search for the original file
866 and look for B<remote> inside the same directory. This does not apply to
867 hard links, of course.
870 =head1 DEPENDENCIES
872 All core modules, apart the following:
874 =over
876 =item B<< Archive::Tar >>
878 =item B<< File::Find::Rule >>
880 =back
882 =head1 BUGS AND LIMITATIONS
884 No bugs have been reported.
886 Please report any bugs or feature requests to the AUTHOR below.
888 Be sure to read L<CONFIGURATION AND ENVIRONMENT> for a slight limitation
889 about the availability of the B<remote> script.
891 =head1 AUTHOR
893 Flavio Poletti C<flavio [AT] polettix.it>
896 =head1 LICENSE AND COPYRIGHT
898 Copyright (c) 2008, Flavio Poletti C<flavio [AT] polettix.it>. All rights reserved.
900 This script is free software; you can redistribute it and/or
901 modify it under the same terms as Perl itself. See L<perlartistic>
902 and L<perlgpl>.
904 Questo script è software libero: potete ridistribuirlo e/o
905 modificarlo negli stessi termini di Perl stesso. Vedete anche
906 L<perlartistic> e 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 =head1 NEGAZIONE DELLA GARANZIA
934 Poiché questo software viene dato con una licenza gratuita, non
935 c'è alcuna garanzia associata ad esso, ai fini e per quanto permesso
936 dalle leggi applicabili. A meno di quanto possa essere specificato
937 altrove, il proprietario e detentore del copyright fornisce questo
938 software "così com'è" senza garanzia di alcun tipo, sia essa espressa
939 o implicita, includendo fra l'altro (senza però limitarsi a questo)
940 eventuali garanzie implicite di commerciabilità e adeguatezza per
941 uno scopo particolare. L'intero rischio riguardo alla qualità ed
942 alle prestazioni di questo software rimane a voi. Se il software
943 dovesse dimostrarsi difettoso, vi assumete tutte le responsabilità
944 ed i costi per tutti i necessari servizi, riparazioni o correzioni.
946 In nessun caso, a meno che ciò non sia richiesto dalle leggi vigenti
947 o sia regolato da un accordo scritto, alcuno dei detentori del diritto
948 di copyright, o qualunque altra parte che possa modificare, o redistribuire
949 questo software così come consentito dalla licenza di cui sopra, potrà
950 essere considerato responsabile nei vostri confronti per danni, ivi
951 inclusi danni generali, speciali, incidentali o conseguenziali, derivanti
952 dall'utilizzo o dall'incapacità di utilizzo di questo software. Ciò
953 include, a puro titolo di esempio e senza limitarsi ad essi, la perdita
954 di dati, l'alterazione involontaria o indesiderata di dati, le perdite
955 sostenute da voi o da terze parti o un fallimento del software ad
956 operare con un qualsivoglia altro software. Tale negazione di garanzia
957 rimane in essere anche se i dententori del copyright, o qualsiasi altra
958 parte, è stata avvisata della possibilità di tali danneggiamenti.
960 Se decidete di utilizzare questo software, lo fate a vostro rischio
961 e pericolo. Se pensate che i termini di questa negazione di garanzia
962 non si confacciano alle vostre esigenze, o al vostro modo di
963 considerare un software, o ancora al modo in cui avete sempre trattato
964 software di terze parti, non usatelo. Se lo usate, accettate espressamente
965 questa negazione di garanzia e la piena responsabilità per qualsiasi
966 tipo di danno, di qualsiasi natura, possa derivarne.
968 =cut