finalized passthrough feature w/ tests
[deployable.git] / deployable
blob2d30609a645f0c9d08ea70d1a4ef87d15ad18ddc
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 File::Find::Rule;
17 use Data::Dumper;
18 use Encode;
20 my %config = (
21 output => '-',
22 remote => catfile(dirname(realpath(__FILE__)), 'remote'),
23 tarfile => [],
24 heredir => [],
25 rootdir => [],
26 root => [],
27 deploy => [],
28 passthrough => 0,
30 GetOptions(
31 \%config,
32 qw(
33 usage! help! man! version!
35 bundle|all-exec|X!
36 bzip2|bz2|j!
37 cleanup|c!
38 deploy|exec|d=s@
39 gzip|gz|z!
40 heredir|H=s@
41 include-archive-tar|T!
42 no-tar!
43 output|o=s
44 passthrough!
45 root|r=s@
46 rootdir|R=s@
47 tar|t=s
48 workdir|work-directory|deploy-directory|w=s
51 pod2usage(message => "$0 $VERSION", -verbose => 99, -sections => '')
52 if $config{version};
53 pod2usage(-verbose => 99, -sections => 'USAGE') if $config{usage};
54 pod2usage(-verbose => 99, -sections => 'USAGE|EXAMPLES|OPTIONS')
55 if $config{help};
56 pod2usage(-verbose => 2) if $config{man};
58 pod2usage(
59 message => 'working directory must be an absolute path',
60 -verbose => 99,
61 -sections => ''
62 ) if exists $config{workdir} && !file_name_is_absolute($config{workdir});
64 if ($config{'include-archive-tar'}) {
65 $config{remote} = catfile(dirname(realpath(__FILE__)), 'remote-at');
66 if (!-e $config{remote}) { # "make" it
67 print {*STDERR} "### Making remote-at...\n";
68 my $startdir = cwd();
69 chdir dirname realpath __FILE__;
70 system {'make'} qw( make remote-at );
71 chdir $startdir;
72 } ## end if (!-e $config{remote...
73 } ## end if ($config{'include-archive-tar'...
75 # Establish output channel
76 my $out_fh = \*STDOUT;
77 if ($config{output} ne '-') {
78 open my $fh, '>', $config{output} ## no critic
79 or croak "open('$config{output}'): $OS_ERROR";
80 $out_fh = $fh;
82 binmode $out_fh;
84 # Emit script code to be executed remotely. It is guaranteed to end
85 # with __END__, so that all what comes next is data
86 print {$out_fh} get_remote_script();
88 # If a tarfile was given, simply put it and exit
89 if (@{$config{tarfile}}) {
90 croak "UNSUPPORTED";
91 open my $fh, '<', $config{tarfile}
92 or croak "open('$config{tarfile}'): $OS_ERROR";
93 print {$out_fh} <$fh>;
94 close $fh;
95 close $out_fh;
96 exit 0;
97 } ## end if (@{$config{tarfile}...
99 # Where all the data will be kept
100 print_configuration($out_fh, \%config);
102 print_here_stuff($out_fh, \%config, @ARGV);
103 print_root_stuff($out_fh, \%config);
105 close $out_fh;
107 # Set as executable
108 if ($config{output} ne '-') {
109 chmod oct(755), $config{output}
110 or carp "chmod(0755, '$config{output}'): $OS_ERROR";
113 sub header {
114 my %params = @_;
115 my $namesize = length $params{name};
116 return "$namesize $params{size}\n$params{name}";
119 sub print_configuration { # FIXME
120 my ($fh, $config) = @_;
121 my %general_configuration;
122 for my $name (qw( workdir cleanup bundle deploy gzip bzip2 passthrough )) {
123 $general_configuration{$name} = $config->{$name}
124 if exists $config->{$name};
126 my $configuration = Dumper \%general_configuration;
127 print {$fh} header(name => 'config.pl', size => length($configuration)),
128 "\n", $configuration, "\n\n";
129 } ## end sub freeze_configuration
131 # Process files and directories. All these will be reported in the
132 # extraction directory, i.e. basename() will be applied to them. For
133 # directories, they will be re-created
134 sub print_here_stuff {
135 my $fh = shift;
136 my $config = shift;
137 my @ARGV = @_;
139 my $ai = Deployable::Tar->new($config);
140 $ai->add(
141 '.' => \@ARGV,
142 map { $_ => [ '.' ] } @{$config->{heredir}}
145 print {$fh} header(name => 'here', size => $ai->size()), "\n";
146 $ai->copy_to($fh);
147 print {$fh} "\n\n";
149 return;
150 } ## end sub get_here_tar
152 sub print_root_stuff {
153 my ($fh, $config) = @_;
155 my $ai = Deployable::Tar->new($config);
156 $ai->add(
157 '.' => $config->{rootdir},
158 map { $_ => [ '.' ] } @{$config->{root}}
161 print {$fh} header(name => 'root', size => $ai->size()), "\n";
162 $ai->copy_to($fh);
163 print {$fh} "\n\n";
165 return;
166 } ## end sub get_root_tar
168 sub get_remote_script {
169 open my $fh, '<', $config{remote}
170 or croak "open('$config{remote}'): $OS_ERROR";
171 my @lines;
172 while (<$fh>) {
173 last if /\A __END__ \s*\z/mxs;
174 push @lines, $_;
176 close $fh;
177 return join '', @lines, "__END__\n";
178 } ## end sub get_remote_script
180 package Deployable::Tar;
182 sub new {
183 my $package = shift;
184 my $self = { ref $_[0] ? %{$_[0]} : @_ };
185 $package = 'Deployable::Tar::Internal';
186 if (! $self->{'no-tar'}) {
187 if ((exists $self->{tar}) || (open my $fh, '-|', 'tar', '--help')) {
188 $package = 'Deployable::Tar::External';
189 $self->{tar} ||= 'tar';
192 bless $self, $package;
193 $self->initialise();
194 return $self;
198 package Deployable::Tar::External;
199 use File::Temp qw( :seekable );
200 use English qw( -no_match_vars );
201 use Cwd ();
202 use Carp;
203 our @ISA = qw( Deployable::Tar );
205 sub initialise {
206 my $self = shift;
207 $self->{_temp} = File::Temp->new();
208 $self->{_filename} = Cwd::abs_path($self->{_temp}->filename());
209 return $self;
212 sub add {
213 my $self = shift;
214 my $tar = $self->{tar};
215 delete $self->{_compressed};
216 while (@_) {
217 my ($directory, $stuff) = splice @_, 0, 2;
218 my @stuff = @$stuff;
219 while (@stuff) {
220 my @chunk = splice @stuff, 0, 50;
221 system {$tar} $tar, 'rvf', $self->{_filename},
222 '-C', $directory, '--', @chunk;
225 return $self;
228 sub _compress {
229 my $self = shift;
230 return if exists $self->{_compressed};
232 $self->{_temp}->sysseek(0, SEEK_SET);
233 if ($self->{bzip2}) {
234 require IO::Compress::Bzip2;
235 $self->{_compressed} = File::Temp->new();
237 # double-quotes needed to force usage of filename
238 # instead of filehandle
239 IO::Compress::Bzip2::bzip2($self->{_temp}, "$self->{_compressed}");
241 elsif ($self->{gzip}) {
242 require IO::Compress::Gzip;
243 $self->{_compressed} = File::Temp->new();
245 # double-quotes needed to force usage of filename
246 # instead of filehandle
247 IO::Compress::Gzip::gzip($self->{_temp}, "$self->{_compressed}");
249 else {
250 $self->{_compressed} = $self->{_temp};
253 return $self;
256 sub size {
257 my ($self) = @_;
258 $self->_compress();
259 return (stat $self->{_compressed})[7];
262 sub copy_to {
263 my ($self, $out_fh) = @_;
264 $self->_compress();
265 my $in_fh = $self->{_compressed};
266 $in_fh->sysseek(0, SEEK_SET);
267 while ('true') {
268 my $nread = $in_fh->sysread(my $buffer, 4096);
269 croak "sysread(): $OS_ERROR" unless defined $nread;
270 last unless $nread;
271 print {$out_fh} $buffer;
273 return $self;
277 package Deployable::Tar::Internal;
278 use Archive::Tar ();
279 use Cwd ();
280 use File::Find::Rule ();
281 our @ISA = qw( Deployable::Tar );
283 sub initialise {
284 my $self = shift;
285 $self->{_tar} = Archive::Tar->new();
286 return $self;
289 sub add {
290 my $self = shift;
291 delete $self->{_string};
292 my $tar = $self->{_tar};
293 my $cwd = Cwd::getcwd();
294 while (@_) {
295 my ($directory, $stuff) = splice @_, 0, 2;
296 chdir $directory;
297 for my $item (@$stuff) {
298 $tar->add_files($_) for File::Find::Rule->in($item);
300 chdir $cwd;
302 return $self;
305 sub size {
306 my ($self) = @_;
307 $self->{_string} = $self->{_tar}->write() unless exists $self->{_string};
308 return length $self->{_string};
311 sub copy_to {
312 my ($self, $out_fh) = @_;
313 $self->{_string} = $self->{_tar}->write() unless exists $self->{_string};
314 print {$out_fh} $self->{_string};
317 __END__
319 =head1 NAME
321 deployable - create a deploy script for some files/scripts
323 =head1 VERSION
325 See version at beginning of script, variable $VERSION, or call
327 shell$ deployable --version
329 =head1 USAGE
331 deployable [--usage] [--help] [--man] [--version]
333 deployable [--bundle|--all-exec|-X] [--bzip2|--bz2|-j] [--cleanup|-c]
334 [--deploy|--exec|d <program>] [--gzip|-gz|-z]
335 [--heredir|-H <dirname>] [--include-archive-tar|-T]
336 [--output|-o <filename>] [--root|-r <dirname>]
337 [--rootdir|-R <dirname>] [--tarfile|--tar|-t <filename>]
338 [--workdir|-w <path>] [ files or directories... ]
340 =head1 EXAMPLES
342 # pack some files and a deploy script together.
343 shell$ deployable script.sh file.txt some/directory -d script.sh
345 # Use a directory's contents as elements for the target root
346 shell$ ls -1 /path/to/target/root
351 # The above will be deployed as /etc, /opt, /usr and /var
352 shell$ deployable -o dep.pl --root /path/to/target/root
354 # Include directory /path/to/etc for inclusion and extraction
355 # directly as /etc
356 shell$ deployable -o dep.pl --rootdir /path/to/etc
358 =head1 DESCRIPTION
360 This is a meta-script to create deploy scripts. The latter ones are
361 suitable to be distributed in order to deploy something.
363 You basically have to provide two things: files to install and programs
364 to be executed. Files can be put directly into the deployed script, or
365 can be included in gzipped tar archives.
367 When called, this script creates a deploy script for you. This script
368 includes all the specified files, and when executed it will extract
369 those files and execute the given programs. In this way, you can ship
370 both files and logic needed to correctly install those files, but this
371 is of course of of scope.
373 All files and archives will be extracted under a configured path
374 (see L<--workdir> below), which we'll call I<workdir> from now on. Under
375 the I<workdir> a temporary directory will be created, and the files
376 will be put in the temporary directory. You can specify if you want to
377 clean up this temporary directory or keep it, at your choice. (You're able
378 to both set a default for this cleanup when invoking deployable, or when
379 invoking the deploy script itself). The temporary directory will be
380 called I<tmpdir> in the following.
382 There are several ways to embed files to be shipped:
384 =over
386 =item *
388 pass the name of an already-prepared tar file via L</--tarfile>. This is
389 by far the most flexible of the options, but it requires more work on
390 your side. If you pass this option, all other input files/directories will
391 be ignored;
393 =item *
395 specify the file name directly on the command line. A file given in this
396 way will always be extracted into the I<tmpdir>, whatever its initial path
397 was;
399 =item *
401 specify the name of a directory on the command line. In this case,
402 C<tar> will be used to archive the directory, with the usual option to
403 turn absolute paths into relative ones; this means that directories will
404 be re-created under I<tmpdir> when extraction is performed;
406 =item *
408 give the name of a directory to be used as a "here directory", using
409 the C<--heredir|-H> option. This is much the same as giving the directory
410 name (see above), but in this case C<tar> will be told to change into the
411 directory first, and archive '.'. This means that the contents of the
412 "here-directory" will be extracted directly into I<tmpdir>.
414 =back
416 =head2 Extended Example
418 Suppose you have a few server which have the same configuration, apart
419 from some specific stuff (e.g. the hostname, the IP addresses, etc.).
420 You'd like to perform changes to all with the minimum work possible...
421 so you know you should script something.
423 For example, suppose you want to update a few files in /etc, setting these
424 files equal for all hosts. You would typically do the following:
426 # In your computer
427 shell$ mkdir -p /tmp/newfiles/etc
428 shell$ cd /tmp/newfiles/etc
429 # Craft the new files
430 shell$ cd ..
431 shell$ tar cvzf newetc.tar.gz etc
433 # Now, for each server:
434 shell$ scp newetc.tar.gz $server:/tmp
435 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
438 So far, so good. But what if you need to kick in a little more logic?
439 For example, if you update some configuration files, you'll most likey
440 want to restart some services. So you could do the following:
442 shell$ mkdir -p /tmp/newfiles/tmp
443 shell$ cd /tmp/newfiles/tmp
444 # craft a shell script to be executed remotely and set the exec bit
445 # Suppose it's called deploy.sh
446 shell$ cd ..
447 shell$ tar cvzf newetc.tar.gz etc tmp
449 # Now, for each server:
450 shell$ scp newetc.tar.gz $server:/tmp
451 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
452 shell$ ssh $server /tmp/deploy.sh
454 And what if you want to install files depending on the particular machine?
455 Or you have a bundle of stuff to deploy and a bunch of scripts to execute?
456 You can use deployable. In this case, you can do the following:
458 shell$ mkdir -p /tmp/newfiles/etc
459 shell$ cd /tmp/newfiles/etc
460 # Craft the new files
461 shell$ cd ..
462 # craft a shell script to be executed remotely and set the exec bit
463 # Suppose it's called deploy.sh
464 shell$ deployable -o deploy.pl etc deploy.sh --exec deploy.sh
466 # Now, for each server
467 shell$ scp deploy.pl $server:/tmp
468 shell$ ssh $server /tmp/deploy.pl
470 And you're done. This can be particularly useful if you have another
471 layer of deployment, e.g. if you have to run a script to decide which
472 of a group of archives should be deployed. For example, you could craft
473 a different new "etc" for each server (which is particularly true if
474 network configurations are in the package), and produce a simple script
475 to choose which file to use based on the MAC address of the machine. In
476 this case you could have:
478 =over
480 =item newetc.*.tar.gz
482 a bunch of tar files with the configurations for each different server
484 =item newetc.list
486 a list file with the association between the MAC addresses and the
487 real tar file to deploy from the bunch in the previous bullet
489 =item deploy-the-right-stuff.sh
491 a script to get the real MAC address of the machine, select the right
492 tar file and do the deployment.
494 =back
496 So, you can do the following:
498 shell$ deployable -o deploy.pl newetc.*.tar.gz newetc.list \
499 deploy-the-right-stuff.sh --exec deploy-the-right-stuff.sh
501 # Now, for each server:
502 shell$ scp deploy.pl $server:/tmp
503 shell$ ssh $server /tmp/deploy.pl
505 So, once you have the deploy script on the target machine all you need
506 to do is to execute it. This can come handy when you cannot access the
507 machines from the network, but you have to go there physically: you
508 can prepare all in advance, and just call the deploy script.
511 =head1 OPTIONS
513 Meta-options:
515 =over
517 =item B<--help>
519 print a somewhat more verbose help, showing usage, this description of
520 the options and some examples from the synopsis.
522 =item B<--man>
524 print out the full documentation for the script.
526 =item B<--usage>
528 print a concise usage line and exit.
530 =item B<--version>
532 print the version of the script.
534 =back
536 Real-world options:
538 =over
540 =item B<< --bundle | --all-exec | -X >>
542 Set bundle flag in the produced script. If the bundle flag is set, the
543 I<deploy script> will treat all executables in the main deployment
544 directory as scripts to be executed.
546 By default the flag is not set.
548 =item B<< --bzip2 | --bz2 | -j >>
550 Compress tar archives with bzip2.
552 =item B<< --cleanup | -c >>
554 Set cleanup flag in the produced script. If the cleanup flag is set, the
555 I<deploy script> will clean up after having performed all operations.
557 You can set this flag to C<0> by using C<--no-cleanup>.
559 =item B<< --deploy | --exec | -d <filename> >>
561 Set the name of a program to execute after extraction. You can provide
562 multiple program names, they will be executed in the same order.
564 =item B<< --gzip | --gz | -z >>
566 Compress tar archives with gzip.
568 =item B<< --heredir | -H <path> >>
570 Set the name of a "here directory" (see L<DESCRIPTION>). You can use this
571 option multiple times to provide multiple directories.
573 =item B<< --include-archive-tar | -T >>
575 Embed L<Archive::Tar> (with its dependencies L<Archive::Tar::Constant> and
576 L<Archive::Tar::File>) inside the final script. Use this when you know (or
577 aren't sure) that L<Archive::Tar> will not be available in the target
578 machine.
580 =item B<< --no-tar >>
582 Don't use system C<tar>.
584 =item B<< --output | -o <filename> >>
586 Set the output file name. By default the I<deploy script> will be given
587 out on the standard output; if you provide a filename (different from
588 C<->, of course!) the script will be saved there and the permissions will
589 be set to 0755.
591 =item B<< --root | -r <dirname> >>
593 Include C<dirname> contents for deployment under root directory. The
594 actual production procedure is: hop into C<dirname> and grab a tarball
595 of C<.>. During deployment, hop into C</> and extract the tarball.
597 This is useful if you're already building up the absolute deployment
598 layout under a given directory: just treat that directory as if it were
599 the root of the target system.
601 =item B<< --rootdir | -R <dirname >>
603 Include C<dirname> as a directory that will be extracted under root
604 directory. The actual production procedure is: grab a tarball of
605 C<dirname>. During deployment, hop into C</> and extract the tarball.
607 This is useful if you have a directory (or a group of directories) that
608 you want to deploy directly under the root.
610 =item B<< --tar | -t <program-path> >>
612 Set the system C<tar> program to use.
614 =item B<< --workdir | --deploy-directory | -w <path> >>
616 Set the working directory for the deploy.
618 =back
620 =head1 THE DEPLOY SCRIPT
622 The net result of calling this script is to produce another script,
623 that we call the I<deploy script>. This script is made of two parts: the
624 code, which is fixed, and the configurations/files, which is what is
625 actually produced. The latter part is put after the C<__END__> marker,
626 as usual.
628 Stuff in the configuration part is always hexified in order to prevent
629 strange tricks or errors. Comments will help you devise what's inside the
630 configurations themselves.
632 The I<deploy script> has options itself, even if they are quite minimal.
633 In particular, it supports the same options C<--workdir|-w> and
634 C<--cleanup> described above, allowing the final user to override the
635 configured values. By default, the I<workdir> is set to C</tmp/our-deploy>
636 and the script will clean up after itself.
638 The following options are supported in the I<deploy script>:
640 =over
642 =item B<--usage | --man | --help>
644 print a minimal help and exit
646 =item B<--version>
648 print script version and exit
650 =item B<--bundle | --all-exec | -X>
652 treat all executables in the main deployment directory as scripts
653 to be executed
655 =item B<--cleanup | --no-cleanup>
657 perform / don't perform temporary directory cleanup after work done
659 =item B<< --deploy | --no-deploy >>
661 deploy scripts are executed by default (same as specifying '--deploy')
662 but you can prevent it.
664 =item B<--dryrun | --dry-run>
666 print final options and exit
668 =item B<< --filelist | --list | -l >>
670 print a list of files that are shipped in the deploy script
672 =item B<< --heretar | --here-tar | -H >>
674 print out the tar file that contains all the files that would be
675 extracted in the temporary directory, useful to redirect to file or
676 pipe to the tar program
678 =item B<< --inspect <dirname> >>
680 just extract all the stuff into <dirname> for inspection. Implies
681 C<--no-deploy>, C<--no-tempdir>, ignores C<--bundle> (as a consequence of
682 C<--no-deploy>), disables C<--cleanup> and sets the working directory
683 to C<dirname>
685 =item B<< --no-tar >>
687 don't use system C<tar>
689 =item B<< --rootar | --root-tar | -R >>
691 print out the tar file that contains all the files that would be
692 extracted in the root directory, useful to redirect to file or
693 pipe to the tar program
695 =item B<--show | --show-options | -s>
697 print configured options and exit
699 =item B<< --tar | -t <program-path> >>
701 set the system C<tar> program to use.
703 =item B<< --tempdir | --no-tempdir >>
705 by default a temporary directory is created (same as specifying
706 C<--tempdir>), but you can execute directly in the workdir (see below)
707 without creating it.
709 =item B<--workdir | --work-directory | --deploy-directory | -w>
711 working base directory (a temporary subdirectory will be created
712 there anyway)
714 =back
716 Note the difference between C<--show> and C<--dryrun>: the former will
717 give you the options that are "embedded" in the I<deploy script> without
718 taking into account other options given on the command line, while the
719 latter will give you the final options that would be used if the script
720 were called without C<--dryrun>.
722 =head2 Deploy Script Example Usage
724 In the following, we'll assume that the I<deploy script> is called
725 C<deploy.pl>.
727 To execute the script with the already configured options, you just have
728 to call it:
730 shell$ ./deploy.pl
732 If you just want to see which configurations are in the I<deploy script>:
734 shell$ ./deploy.pl --show
736 To see which files are included, you have two options. One is asking the
737 script:
739 shell$ ./deploy.pl --filelist
741 the other is piping to tar:
743 shell$ ./deploy.pl --tar | tar tvf -
745 Extract contents of the script in a temp directory and simply inspect
746 what's inside:
748 # extract stuff into subdirectory 'inspect' for... inspection
749 shell$ ./deploy.pl --no-tempdir --no-deploy --workdir inspect
751 =head2 Deploy Script Requirements
753 You'll need a working Perl with version at least 5.6.2.
755 If you specify L</--include-archive-tar>, the module L<Archive::Tar> will
756 be included as well. This should ease your life and avoid you to have
757 B<tar> on the target machine. On the other hand, if you already know
758 that B<tar> will be available, you can avoid including C<Archive::Tar>
759 and have the generated script use it (it could be rather slower anyway).
761 =head1 DIAGNOSTICS
763 Each error message should be enough explicit to be understood without the
764 need for furter explainations. Which is another way to say that I'm way
765 too lazy to list all possible ways that this script has to fail.
768 =head1 CONFIGURATION AND ENVIRONMENT
770 deployable requires no configuration files or environment variables.
772 Please note that deployable B<needs> to find its master B<remote> file
773 to produce the final script. This must be put in the same directory where
774 deployable is put. You should be able to B<symlink> deployable where you
775 think it's better, anyway - it will go search for the original file
776 and look for B<remote> inside the same directory. This does not apply to
777 hard links, of course.
780 =head1 DEPENDENCIES
782 All core modules, apart the following:
784 =over
786 =item B<< Archive::Tar >>
788 =item B<< File::Find::Rule >>
790 =back
792 =head1 BUGS AND LIMITATIONS
794 No bugs have been reported.
796 Please report any bugs or feature requests to the AUTHOR below.
798 Be sure to read L<CONFIGURATION AND ENVIRONMENT> for a slight limitation
799 about the availability of the B<remote> script.
801 =head1 AUTHOR
803 Flavio Poletti C<flavio [AT] polettix.it>
806 =head1 LICENSE AND COPYRIGHT
808 Copyright (c) 2008, Flavio Poletti C<flavio [AT] polettix.it>. All rights reserved.
810 This script is free software; you can redistribute it and/or
811 modify it under the same terms as Perl itself. See L<perlartistic>
812 and L<perlgpl>.
814 Questo script è software libero: potete ridistribuirlo e/o
815 modificarlo negli stessi termini di Perl stesso. Vedete anche
816 L<perlartistic> e L<perlgpl>.
819 =head1 DISCLAIMER OF WARRANTY
821 BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
822 FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
823 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
824 PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
825 EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
826 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
827 ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
828 YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
829 NECESSARY SERVICING, REPAIR, OR CORRECTION.
831 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
832 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
833 REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
834 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
835 OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
836 THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
837 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
838 FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
839 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
840 SUCH DAMAGES.
842 =head1 NEGAZIONE DELLA GARANZIA
844 Poiché questo software viene dato con una licenza gratuita, non
845 c'è alcuna garanzia associata ad esso, ai fini e per quanto permesso
846 dalle leggi applicabili. A meno di quanto possa essere specificato
847 altrove, il proprietario e detentore del copyright fornisce questo
848 software "così com'è" senza garanzia di alcun tipo, sia essa espressa
849 o implicita, includendo fra l'altro (senza però limitarsi a questo)
850 eventuali garanzie implicite di commerciabilità e adeguatezza per
851 uno scopo particolare. L'intero rischio riguardo alla qualità ed
852 alle prestazioni di questo software rimane a voi. Se il software
853 dovesse dimostrarsi difettoso, vi assumete tutte le responsabilità
854 ed i costi per tutti i necessari servizi, riparazioni o correzioni.
856 In nessun caso, a meno che ciò non sia richiesto dalle leggi vigenti
857 o sia regolato da un accordo scritto, alcuno dei detentori del diritto
858 di copyright, o qualunque altra parte che possa modificare, o redistribuire
859 questo software così come consentito dalla licenza di cui sopra, potrà
860 essere considerato responsabile nei vostri confronti per danni, ivi
861 inclusi danni generali, speciali, incidentali o conseguenziali, derivanti
862 dall'utilizzo o dall'incapacità di utilizzo di questo software. Ciò
863 include, a puro titolo di esempio e senza limitarsi ad essi, la perdita
864 di dati, l'alterazione involontaria o indesiderata di dati, le perdite
865 sostenute da voi o da terze parti o un fallimento del software ad
866 operare con un qualsivoglia altro software. Tale negazione di garanzia
867 rimane in essere anche se i dententori del copyright, o qualsiasi altra
868 parte, è stata avvisata della possibilità di tali danneggiamenti.
870 Se decidete di utilizzare questo software, lo fate a vostro rischio
871 e pericolo. Se pensate che i termini di questa negazione di garanzia
872 non si confacciano alle vostre esigenze, o al vostro modo di
873 considerare un software, o ancora al modo in cui avete sempre trattato
874 software di terze parti, non usatelo. Se lo usate, accettate espressamente
875 questa negazione di garanzia e la piena responsabilità per qualsiasi
876 tipo di danno, di qualsiasi natura, possa derivarne.
878 =cut