moved handling all with sub-tars to speed up extraction
[deployable.git] / deployable
blob55630257cc2644e5af3c5d2a827e5cf3bfe88a58
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 POSIX qw( strftime );
13 use Cwd qw( cwd realpath );
14 use Archive::Tar;
15 use File::Find::Rule;
16 use Data::Dumper;
18 my %config = (
19 output => '-',
20 remote => catfile(dirname(realpath(__FILE__)), 'remote'),
21 tarfile => [],
22 heredir => [],
23 rootdir => [],
24 root => [],
25 deploy => [],
27 GetOptions(
28 \%config,
29 qw(
30 usage! help! man! version!
32 bundle|all-exec|X!
33 cleanup|c!
34 deploy|exec|d=s@
35 heredir|H=s@
36 include-archive-tar|T!
37 output|o=s
38 root|r=s@
39 rootdir|R=s@
40 tarfile|tar=s
41 workdir|work-directory|deploy-directory|w=s
44 pod2usage(message => "$0 $VERSION", -verbose => 99, -sections => '')
45 if $config{version};
46 pod2usage(-verbose => 99, -sections => 'USAGE') if $config{usage};
47 pod2usage(-verbose => 99, -sections => 'USAGE|EXAMPLES|OPTIONS')
48 if $config{help};
49 pod2usage(-verbose => 2) if $config{man};
51 pod2usage(
52 message => 'working directory must be an absolute path',
53 -verbose => 99,
54 -sections => ''
56 if exists $config{workdir} && !file_name_is_absolute($config{workdir});
58 if ($config{'include-archive-tar'}) {
59 $config{remote} = catfile(dirname(realpath(__FILE__)), 'remote-at');
60 if (! -e $config{remote}) { # "make" it
61 print {*STDERR} "### Making remote-at...\n";
62 my $startdir = cwd();
63 chdir dirname realpath __FILE__;
64 system {'make'} qw( make remote-at );
65 chdir $startdir;
69 # Establish output channel
70 my $out_fh = \*STDOUT;
71 if ($config{output} ne '-') {
72 open my $fh, '>', $config{output} ## no critic
73 or croak "open('$config{output}'): $OS_ERROR";
74 $out_fh = $fh;
76 binmode $out_fh;
78 # Emit script code to be executed remotely. It is guaranteed to end
79 # with __END__, so that all what comes next is data
80 print {$out_fh} get_remote_script();
82 # If a tarfile was given, simply put it and exit
83 if (@{$config{tarfile}}) {
84 croak "UNSUPPORTED";
85 open my $fh, '<', $config{tarfile}
86 or croak "open('$config{tarfile}'): $OS_ERROR";
87 print {$out_fh} <$fh>;
88 close $fh;
89 close $out_fh;
90 exit 0;
93 # Where all the data will be kept
94 my $tar = get_tar(\%config, @ARGV);
96 # Save tar file, it will close the filehandle as well
97 $tar->write($out_fh);
99 # Set as executable
100 if ($config{output} ne '-') {
101 chmod oct(755), $config{output}
102 or carp "chmod(0755, '$config{output}'): $OS_ERROR";
105 sub get_tar {
106 my ($config, @ARGV) = @_;
108 my $tar = Archive::Tar->new();
110 # Add a configuration file to the main tar
111 my %general_configuration;
112 for my $name (qw( workdir cleanup bundle deploy )) {
113 $general_configuration{$name} = $config->{$name}
114 if exists $config->{$name};
116 $tar->add_data('config.pl', Dumper \%general_configuration); # FIXME
118 my $here_tar = get_here_tar(@ARGV);
119 $tar->add_data('here.tar', data_from($here_tar));
121 my $root_tar = get_root_tar(@{$config}{qw( rootdir root )});
122 $tar->add_data('root.tar', data_from($root_tar));
124 return $tar;
127 sub data_from {
128 my ($tar) = @_;
129 my $buffer = '';
130 open my $fh, '>', \$buffer or die "open() on internal variable: $OS_ERROR";
131 binmode $fh;
132 $tar->write($fh); # closes $fh
133 return $buffer;
136 # Process files and directories. All these will be reported in the
137 # extraction directory, i.e. basename() will be applied to them. For
138 # directories, they will be re-created
139 sub get_here_tar {
140 my @ARGV = @_;
141 my $tar = Archive::Tar->new();
143 for my $file (@ARGV) {
144 croak "'$file' not readable" unless -r $file;
145 if (-d $file) {
146 print {*STDERR} "processing directory '$file'\n";
147 save_directory($tar, '.', '.');
148 } ## end if (-d $file)
149 else {
150 print {*STDERR} "processing file '$file'\n";
151 $tar->add_files($file);
152 } ## end else [ if (-d $file)
153 } ## end for my $file (@ARGV)
155 # heredir-s are directories that are extracted directly into the ex dir
156 for my $heredir (@{$config{heredir}}) {
157 croak "'$heredir' not readable" unless -r $heredir;
158 print {*STDERR} "processing here-directory '$heredir'\n";
159 save_directory($tar, $heredir, '.');
160 } ## end for my $heredir (@{$config...
162 return $tar;
165 sub get_root_tar {
166 my ($rootdirs, $roots) = @_;
167 my $tar = Archive::Tar->new();
169 # rootdir-s are directories that will go under root
170 for my $rootdir (@$rootdirs) {
171 croak "'$rootdir' not readable" unless -r $rootdir;
172 print {*STDERR} "processing root-directory '$rootdir'\n";
173 save_directory($tar, '.', $rootdir);
176 # root-s are directories whose contents go under root
177 for my $root (@$roots) {
178 croak "'$root' not readable" unless -r $root;
179 print {*STDERR} "processing root-directory '$root'\n";
180 save_directory($tar, $root, '.');
183 return $tar;
187 my $cwd;
188 sub save_directory {
189 my ($tar, $localstart, $localdir) = @_;
191 $cwd ||= cwd();
192 chdir $localstart;
194 $tar->add_files($_)
195 for File::Find::Rule->file()->in($localdir);
197 chdir $cwd;
199 return;
200 } ## end sub save_directory
203 sub get_remote_script {
204 open my $fh, '<', $config{remote}
205 or croak "open('$config{remote}'): $OS_ERROR";
206 my @lines;
207 while (<$fh>) {
208 last if /\A __END__ \s*\z/mxs;
209 push @lines, $_;
211 close $fh;
212 return join '', @lines, "__END__\n";
213 } ## end sub get_remote_script
215 __END__
217 =head1 NAME
219 deployable - create a deploy script for some files/scripts
221 =head1 VERSION
223 See version at beginning of script, variable $VERSION, or call
225 shell$ deployable --version
227 =head1 USAGE
229 deployable [--usage] [--help] [--man] [--version]
231 deployable [--bundle|--all-exec|-X] [--cleanup|-c]
232 [--deploy|--exec|d <program>] [--heredir|-H <dirname>]
233 [--include-archive-tar|-T] [--output|-o <filename>]
234 [--root|-r <dirname>] [--rootdir|-R <dirname>]
235 [--tarfile|--tar|-t <filename>]
236 [--workdir|-w <path>] [ files or directories... ]
238 =head1 EXAMPLES
240 # pack some files and a deploy script together.
241 shell$ deployable script.sh file.txt some/directory -d script.sh
243 # Use a directory's contents as elements for the target root
244 shell$ ls -1 /path/to/target/root
249 # The above will be deployed as /etc, /opt, /usr and /var
250 shell$ deployable -o dep.pl --root /path/to/target/root
252 # Include directory /path/to/etc for inclusion and extraction
253 # directly as /etc
254 shell$ deployable -o dep.pl --rootdir /path/to/etc
256 =head1 DESCRIPTION
258 This is a meta-script to create deploy scripts. The latter ones are
259 suitable to be distributed in order to deploy something.
261 You basically have to provide two things: files to install and programs
262 to be executed. Files can be put directly into the deployed script, or
263 can be included in gzipped tar archives.
265 When called, this script creates a deploy script for you. This script
266 includes all the specified files, and when executed it will extract
267 those files and execute the given programs. In this way, you can ship
268 both files and logic needed to correctly install those files, but this
269 is of course of of scope.
271 All files and archives will be extracted under a configured path
272 (see L<--workdir> below), which we'll call I<workdir> from now on. Under
273 the I<workdir> a temporary directory will be created, and the files
274 will be put in the temporary directory. You can specify if you want to
275 clean up this temporary directory or keep it, at your choice. (You're able
276 to both set a default for this cleanup when invoking deployable, or when
277 invoking the deploy script itself). The temporary directory will be
278 called I<tmpdir> in the following.
280 There are several ways to embed files to be shipped:
282 =over
284 =item *
286 pass the name of an already-prepared tar file via L</--tarfile>. This is
287 by far the most flexible of the options, but it requires more work on
288 your side. If you pass this option, all other input files/directories will
289 be ignored;
291 =item *
293 specify the file name directly on the command line. A file given in this
294 way will always be extracted into the I<tmpdir>, whatever its initial path
295 was;
297 =item *
299 specify the name of a directory on the command line. In this case,
300 C<tar> will be used to archive the directory, with the usual option to
301 turn absolute paths into relative ones; this means that directories will
302 be re-created under I<tmpdir> when extraction is performed;
304 =item *
306 give the name of a directory to be used as a "here directory", using
307 the C<--heredir|-H> option. This is much the same as giving the directory
308 name (see above), but in this case C<tar> will be told to change into the
309 directory first, and archive '.'. This means that the contents of the
310 "here-directory" will be extracted directly into I<tmpdir>.
312 =back
314 =head2 Extended Example
316 Suppose you have a few server which have the same configuration, apart
317 from some specific stuff (e.g. the hostname, the IP addresses, etc.).
318 You'd like to perform changes to all with the minimum work possible...
319 so you know you should script something.
321 For example, suppose you want to update a few files in /etc, setting these
322 files equal for all hosts. You would typically do the following:
324 # In your computer
325 shell$ mkdir -p /tmp/newfiles/etc
326 shell$ cd /tmp/newfiles/etc
327 # Craft the new files
328 shell$ cd ..
329 shell$ tar cvzf newetc.tar.gz etc
331 # Now, for each server:
332 shell$ scp newetc.tar.gz $server:/tmp
333 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
336 So far, so good. But what if you need to kick in a little more logic?
337 For example, if you update some configuration files, you'll most likey
338 want to restart some services. So you could do the following:
340 shell$ mkdir -p /tmp/newfiles/tmp
341 shell$ cd /tmp/newfiles/tmp
342 # craft a shell script to be executed remotely and set the exec bit
343 # Suppose it's called deploy.sh
344 shell$ cd ..
345 shell$ tar cvzf newetc.tar.gz etc tmp
347 # Now, for each server:
348 shell$ scp newetc.tar.gz $server:/tmp
349 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
350 shell$ ssh $server /tmp/deploy.sh
352 And what if you want to install files depending on the particular machine?
353 Or you have a bundle of stuff to deploy and a bunch of scripts to execute?
354 You can use deployable. In this case, you can do the following:
356 shell$ mkdir -p /tmp/newfiles/etc
357 shell$ cd /tmp/newfiles/etc
358 # Craft the new files
359 shell$ cd ..
360 # craft a shell script to be executed remotely and set the exec bit
361 # Suppose it's called deploy.sh
362 shell$ deployable -o deploy.pl etc deploy.sh --exec deploy.sh
364 # Now, for each server
365 shell$ scp deploy.pl $server:/tmp
366 shell$ ssh $server /tmp/deploy.pl
368 And you're done. This can be particularly useful if you have another
369 layer of deployment, e.g. if you have to run a script to decide which
370 of a group of archives should be deployed. For example, you could craft
371 a different new "etc" for each server (which is particularly true if
372 network configurations are in the package), and produce a simple script
373 to choose which file to use based on the MAC address of the machine. In
374 this case you could have:
376 =over
378 =item newetc.*.tar.gz
380 a bunch of tar files with the configurations for each different server
382 =item newetc.list
384 a list file with the association between the MAC addresses and the
385 real tar file to deploy from the bunch in the previous bullet
387 =item deploy-the-right-stuff.sh
389 a script to get the real MAC address of the machine, select the right
390 tar file and do the deployment.
392 =back
394 So, you can do the following:
396 shell$ deployable -o deploy.pl newetc.*.tar.gz newetc.list \
397 deploy-the-right-stuff.sh --exec deploy-the-right-stuff.sh
399 # Now, for each server:
400 shell$ scp deploy.pl $server:/tmp
401 shell$ ssh $server /tmp/deploy.pl
403 So, once you have the deploy script on the target machine all you need
404 to do is to execute it. This can come handy when you cannot access the
405 machines from the network, but you have to go there physically: you
406 can prepare all in advance, and just call the deploy script.
409 =head1 OPTIONS
411 Meta-options:
413 =over
415 =item B<--help>
417 print a somewhat more verbose help, showing usage, this description of
418 the options and some examples from the synopsis.
420 =item B<--man>
422 print out the full documentation for the script.
424 =item B<--usage>
426 print a concise usage line and exit.
428 =item B<--version>
430 print the version of the script.
432 =back
434 Real-world options:
436 =over
438 =item B<< --bundle | --all-exec | -X >>
440 Set bundle flag in the produced script. If the bundle flag is set, the
441 I<deploy script> will treat all executables in the main deployment
442 directory as scripts to be executed.
444 By default the flag is not set.
446 =item B<< --cleanup | -c >>
448 Set cleanup flag in the produced script. If the cleanup flag is set, the
449 I<deploy script> will clean up after having performed all operations.
451 You can set this flag to C<0> by using C<--no-cleanup>.
453 =item B<< --deploy | --exec | -d <filename> >>
455 Set the name of a program to execute after extraction. You can provide
456 multiple program names, they will be executed in the same order.
458 =item B<< --heredir | -H <path> >>
460 Set the name of a "here directory" (see L<DESCRIPTION>). You can use this
461 option multiple times to provide multiple directories.
463 =item B<< --include-archive-tar | -T >>
465 Embed L<Archive::Tar> (with its dependencies L<Archive::Tar::Constant> and
466 L<Archive::Tar::File>) inside the final script. Use this when you know (or
467 aren't sure) that L<Archive::Tar> will not be available in the target
468 machine.
470 =item B<< --output | -o <filename> >>
472 Set the output file name. By default the I<deploy script> will be given
473 out on the standard output; if you provide a filename (different from
474 C<->, of course!) the script will be saved there and the permissions will
475 be set to 0755.
477 =item B<< --root | -r <dirname> >>
479 Include C<dirname> contents for deployment under root directory. The
480 actual production procedure is: hop into C<dirname> and grab a tarball
481 of C<.>. During deployment, hop into C</> and extract the tarball.
483 This is useful if you're already building up the absolute deployment
484 layout under a given directory: just treat that directory as if it were
485 the root of the target system.
487 =item B<< --rootdir | -R <dirname >>
489 Include C<dirname> as a directory that will be extracted under root
490 directory. The actual production procedure is: grab a tarball of
491 C<dirname>. During deployment, hop into C</> and extract the tarball.
493 This is useful if you have a directory (or a group of directories) that
494 you want to deploy directly under the root.
496 =item B<< --tarfile | --tar | -t <filename> >>
498 Use the given file as the only contents for the deployed script. The
499 filename should point to a valid tar file, which will be the only
500 one stored into the resulting script (i.e. all other files/directories
501 will be ignored). This requires more work on your side, but gives you
502 full flexibility.
504 Note that the generated script will interpret the generated tar file
505 as follows:
507 =over
509 =item B<< config.pl >> (file)
511 will be C<eval>ed, expecting to receive a reference to an anonymous
512 hash with the configurations;
514 =item B<< here.tar >> (tar file)
516 will be normally extracted into the working/temporary directory in the
517 target system;
519 =item B<< root.tar >> (tar file)
521 will be normally extracted under C</> in the target system.
523 =back
525 =item B<< --workdir | --deploy-directory | -w <path> >>
527 Set the working directory for the deploy.
529 =back
531 =head1 THE DEPLOY SCRIPT
533 The net result of calling this script is to produce another script,
534 that we call the I<deploy script>. This script is made of two parts: the
535 code, which is fixed, and the configurations/files, which is what is
536 actually produced. The latter part is put after the C<__END__> marker,
537 as usual.
539 Stuff in the configuration part is always hexified in order to prevent
540 strange tricks or errors. Comments will help you devise what's inside the
541 configurations themselves.
543 The I<deploy script> has options itself, even if they are quite minimal.
544 In particular, it supports the same options C<--workdir|-w> and
545 C<--cleanup> described above, allowing the final user to override the
546 configured values. By default, the I<workdir> is set to C</tmp/our-deploy>
547 and the script will clean up after itself.
549 The following options are supported in the I<deploy script>:
551 =over
553 =item B<--usage | --man | --help>
555 print a minimal help and exit
557 =item B<--version>
559 print script version and exit
561 =item B<--bundle | --all-exec | -X>
563 treat all executables in the main deployment directory as scripts
564 to be executed
566 =item B<--cleanup | --no-cleanup>
568 perform / don't perform temporary directory cleanup after work done
570 =item B<< --deploy | --no-deploy >>
572 deploy scripts are executed by default (same as specifying '--deploy')
573 but you can prevent it.
575 =item B<--dryrun | --dry-run>
577 print final options and exit
579 =item B<< --filelist | --list | -l >>
581 print a list of files that are shipped in the deploy script
583 =item B<< --heretar | --here-tar | -H >>
585 print out the tar file that contains all the files that would be
586 extracted in the temporary directory, useful to redirect to file or
587 pipe to the tar program
589 =item B<< --inspect <dirname> >>
591 just extract all the stuff into <dirname> for inspection. Implies
592 C<--no-deploy>, C<--no-tempdir>, ignores C<--bundle> (as a consequence of
593 C<--no-deploy>), disables C<--cleanup> and sets the working directory
594 to C<dirname>
596 =item B<< --rootar | --root-tar | -R >>
598 print out the tar file that contains all the files that would be
599 extracted in the root directory, useful to redirect to file or
600 pipe to the tar program
602 =item B<--show | --show-options | -s>
604 print configured options and exit
606 =item B<< --tar | -t >>
608 print out the tar file that contains all the shipped files, useful
609 to redirect to file or pipe to the B<tar> program
611 =item B<< --tempdir | --no-tempdir >>
613 by default a temporary directory is created (same as specifying
614 C<--tempdir>), but you can execute directly in the workdir (see below)
615 without creating it.
617 =item B<--workdir | --work-directory | --deploy-directory | -w>
619 working base directory (a temporary subdirectory will be created
620 there anyway)
622 =back
624 Note the difference between C<--show> and C<--dryrun>: the former will
625 give you the options that are "embedded" in the I<deploy script> without
626 taking into account other options given on the command line, while the
627 latter will give you the final options that would be used if the script
628 were called without C<--dryrun>.
630 =head2 Deploy Script Example Usage
632 In the following, we'll assume that the I<deploy script> is called
633 C<deploy.pl>.
635 To execute the script with the already configured options, you just have
636 to call it:
638 shell$ ./deploy.pl
640 If you just want to see which configurations are in the I<deploy script>:
642 shell$ ./deploy.pl --show
644 To see which files are included, you have two options. One is asking the
645 script:
647 shell$ ./deploy.pl --filelist
649 the other is piping to tar:
651 shell$ ./deploy.pl --tar | tar tvf -
653 Extract contents of the script in a temp directory and simply inspect
654 what's inside:
656 # extract stuff into subdirectory 'inspect' for... inspection
657 shell$ ./deploy.pl --no-tempdir --no-deploy --workdir inspect
659 =head2 Deploy Script Requirements
661 You'll need a working Perl with version at least 5.6.2.
663 If you specify L</--include-archive-tar>, the module L<Archive::Tar> will
664 be included as well. This should ease your life and avoid you to have
665 B<tar> on the target machine. On the other hand, if you already know
666 that B<tar> will be available, you can avoid including C<Archive::Tar>
667 and have the generated script use it (it could be rather slower anyway).
669 =head1 DIAGNOSTICS
671 Each error message should be enough explicit to be understood without the
672 need for furter explainations. Which is another way to say that I'm way
673 too lazy to list all possible ways that this script has to fail.
676 =head1 CONFIGURATION AND ENVIRONMENT
678 deployable requires no configuration files or environment variables.
680 Please note that deployable B<needs> to find its master B<remote> file
681 to produce the final script. This must be put in the same directory where
682 deployable is put. You should be able to B<symlink> deployable where you
683 think it's better, anyway - it will go search for the original file
684 and look for B<remote> inside the same directory. This does not apply to
685 hard links, of course.
688 =head1 DEPENDENCIES
690 All core modules, apart the following:
692 =over
694 =item B<< Archive::Tar >>
696 =item B<< File::Find::Rule >>
698 =back
700 =head1 BUGS AND LIMITATIONS
702 No bugs have been reported.
704 Please report any bugs or feature requests to the AUTHOR below.
706 Be sure to read L<CONFIGURATION AND ENVIRONMENT> for a slight limitation
707 about the availability of the B<remote> script.
709 =head1 AUTHOR
711 Flavio Poletti C<flavio [AT] polettix.it>
714 =head1 LICENSE AND COPYRIGHT
716 Copyright (c) 2008, Flavio Poletti C<flavio [AT] polettix.it>. All rights reserved.
718 This script is free software; you can redistribute it and/or
719 modify it under the same terms as Perl itself. See L<perlartistic>
720 and L<perlgpl>.
722 Questo script è software libero: potete ridistribuirlo e/o
723 modificarlo negli stessi termini di Perl stesso. Vedete anche
724 L<perlartistic> e L<perlgpl>.
727 =head1 DISCLAIMER OF WARRANTY
729 BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
730 FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
731 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
732 PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
733 EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
734 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
735 ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
736 YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
737 NECESSARY SERVICING, REPAIR, OR CORRECTION.
739 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
740 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
741 REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
742 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
743 OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
744 THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
745 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
746 FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
747 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
748 SUCH DAMAGES.
750 =head1 NEGAZIONE DELLA GARANZIA
752 Poiché questo software viene dato con una licenza gratuita, non
753 c'è alcuna garanzia associata ad esso, ai fini e per quanto permesso
754 dalle leggi applicabili. A meno di quanto possa essere specificato
755 altrove, il proprietario e detentore del copyright fornisce questo
756 software "così com'è" senza garanzia di alcun tipo, sia essa espressa
757 o implicita, includendo fra l'altro (senza però limitarsi a questo)
758 eventuali garanzie implicite di commerciabilità e adeguatezza per
759 uno scopo particolare. L'intero rischio riguardo alla qualità ed
760 alle prestazioni di questo software rimane a voi. Se il software
761 dovesse dimostrarsi difettoso, vi assumete tutte le responsabilità
762 ed i costi per tutti i necessari servizi, riparazioni o correzioni.
764 In nessun caso, a meno che ciò non sia richiesto dalle leggi vigenti
765 o sia regolato da un accordo scritto, alcuno dei detentori del diritto
766 di copyright, o qualunque altra parte che possa modificare, o redistribuire
767 questo software così come consentito dalla licenza di cui sopra, potrà
768 essere considerato responsabile nei vostri confronti per danni, ivi
769 inclusi danni generali, speciali, incidentali o conseguenziali, derivanti
770 dall'utilizzo o dall'incapacità di utilizzo di questo software. Ciò
771 include, a puro titolo di esempio e senza limitarsi ad essi, la perdita
772 di dati, l'alterazione involontaria o indesiderata di dati, le perdite
773 sostenute da voi o da terze parti o un fallimento del software ad
774 operare con un qualsivoglia altro software. Tale negazione di garanzia
775 rimane in essere anche se i dententori del copyright, o qualsiasi altra
776 parte, è stata avvisata della possibilità di tali danneggiamenti.
778 Se decidete di utilizzare questo software, lo fate a vostro rischio
779 e pericolo. Se pensate che i termini di questa negazione di garanzia
780 non si confacciano alle vostre esigenze, o al vostro modo di
781 considerare un software, o ancora al modo in cui avete sempre trattato
782 software di terze parti, non usatelo. Se lo usate, accettate espressamente
783 questa negazione di garanzia e la piena responsabilità per qualsiasi
784 tipo di danno, di qualsiasi natura, possa derivarne.
786 =cut