Added options to isolate stdout or stderr only. Added documentation.
[deployable.git] / deployable
blob58125cf6328578eb274a3b3bba31b43c572af028
1 #!/usr/bin/env perl
2 use strict;
3 use warnings;
4 use Carp;
5 use version; our $VERSION = qv('0.0.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 open my $fh, '<', $config{tarfile}
85 or croak "open('$config{tarfile}'): $OS_ERROR";
86 print {$out_fh} <$fh>;
87 close $fh;
88 close $out_fh;
89 exit 0;
92 # Where all the data will be kept
93 my $tar = Archive::Tar->new();
95 { # Add a configuration file
96 my %general_configuration;
97 for my $name (qw( workdir cleanup bundle deploy )) {
98 $general_configuration{$name} = $config{$name}
99 if exists $config{$name};
101 $tar->add_data('deployable/config.pl', Dumper \%general_configuration);
104 # Process files and directories. All these will be reported in the
105 # extraction directory, i.e. basename() will be applied to them. For
106 # directories, they will be re-created
107 for my $file (@ARGV) {
108 croak "'$file' not readable" unless -r $file;
109 if (-d $file) {
110 print {*STDERR} "processing directory '$file'\n";
111 save_directory($tar, '.', '.', 'here');
112 } ## end if (-d $file)
113 else {
114 print {*STDERR} "processing file '$file'\n";
115 save_file($tar, $file, 'here');
116 } ## end else [ if (-d $file)
117 } ## end for my $file (@ARGV)
119 # heredir-s are directories that are extracted directly into the ex dir
120 for my $heredir (@{$config{heredir}}) {
121 croak "'$heredir' not readable" unless -r $heredir;
122 print {*STDERR} "processing here-directory '$heredir'\n";
123 save_directory($tar, $heredir, '.', 'here');
124 } ## end for my $heredir (@{$config...
126 # rootdir-s are directories that will go under root
127 for my $rootdir (@{$config{rootdir}}) {
128 croak "'$rootdir' not readable" unless -r $rootdir;
129 print {*STDERR} "processing root-directory '$rootdir'\n";
130 save_directory($tar, '.', $rootdir, 'root');
133 # root-s are directories whose contents go under root
134 for my $root (@{$config{root}}) {
135 croak "'$root' not readable" unless -r $root;
136 print {*STDERR} "processing root-directory '$root'\n";
137 save_directory($tar, $root, '.', 'root');
140 # Save tar file, it will close the filehandle as well
141 $tar->write($out_fh);
143 # Set as executable
144 if ($config{output} ne '-') {
145 chmod oct(755), $config{output}
146 or carp "chmod(0755, '$config{output}'): $OS_ERROR";
150 my $cwd;
151 sub save_directory {
152 my ($tar, $localstart, $localdir, $remotestart) = @_;
154 $cwd ||= cwd();
155 chdir $localstart;
157 save_file($tar, $_, $remotestart) for File::Find::Rule->file()->in($localdir);
159 chdir $cwd;
161 return;
162 } ## end sub save_directory
165 sub save_file {
166 my ($tar, $filename, $remotestart) = @_;
168 my ($ftar) = $tar->add_files($filename);
169 $ftar->rename("$remotestart/$filename");
171 return;
172 } ## end sub save_file
174 sub get_remote_script {
175 open my $fh, '<', $config{remote}
176 or croak "open('$config{remote}'): $OS_ERROR";
177 my @lines;
178 while (<$fh>) {
179 last if /\A __END__ \s*\z/mxs;
180 push @lines, $_;
182 close $fh;
183 return join '', @lines, "__END__\n";
184 } ## end sub get_remote_script
186 __END__
188 =head1 NAME
190 deployable - create a deploy script for some files/scripts
192 =head1 VERSION
194 See version at beginning of script, variable $VERSION, or call
196 shell$ deployable --version
198 =head1 USAGE
200 deployable [--usage] [--help] [--man] [--version]
202 deployable [--bundle|--all-exec|-X] [--cleanup|-c]
203 [--deploy|--exec|d <program>] [--heredir|-H <dirname>]
204 [--include-archive-tar|-T] [--output|-o <filename>]
205 [--root|-r <dirname>] [--rootdir|-R <dirname>]
206 [--tarfile|--tar|-t <filename>]
207 [--workdir|-w <path>] [ files or directories... ]
209 =head1 EXAMPLES
211 # pack some files and a deploy script together.
212 shell$ deployable script.sh file.txt some/directory -d script.sh
214 # Use a directory's contents as elements for the target root
215 shell$ ls -1 /path/to/target/root
220 # The above will be deployed as /etc, /opt, /usr and /var
221 shell$ deployable -o dep.pl --root /path/to/target/root
223 # Include directory /path/to/etc for inclusion and extraction
224 # directly as /etc
225 shell$ deployable -o dep.pl --rootdir /path/to/etc
227 =head1 DESCRIPTION
229 This is a meta-script to create deploy scripts. The latter ones are
230 suitable to be distributed in order to deploy something.
232 You basically have to provide two things: files to install and programs
233 to be executed. Files can be put directly into the deployed script, or
234 can be included in gzipped tar archives.
236 When called, this script creates a deploy script for you. This script
237 includes all the specified files, and when executed it will extract
238 those files and execute the given programs. In this way, you can ship
239 both files and logic needed to correctly install those files, but this
240 is of course of of scope.
242 All files and archives will be extracted under a configured path
243 (see L<--workdir> below), which we'll call I<workdir> from now on. Under
244 the I<workdir> a temporary directory will be created, and the files
245 will be put in the temporary directory. You can specify if you want to
246 clean up this temporary directory or keep it, at your choice. (You're able
247 to both set a default for this cleanup when invoking deployable, or when
248 invoking the deploy script itself). The temporary directory will be
249 called I<tmpdir> in the following.
251 There are several ways to embed files to be shipped:
253 =over
255 =item *
257 pass the name of an already-prepared tar file via L</--tarfile>. This is
258 by far the most flexible of the options, but it requires more work on
259 your side. If you pass this option, all other input files/directories will
260 be ignored;
262 =item *
264 specify the file name directly on the command line. A file given in this
265 way will always be extracted into the I<tmpdir>, whatever its initial path
266 was;
268 =item *
270 specify the name of a directory on the command line. In this case,
271 C<tar> will be used to archive the directory, with the usual option to
272 turn absolute paths into relative ones; this means that directories will
273 be re-created under I<tmpdir> when extraction is performed;
275 =item *
277 give the name of a directory to be used as a "here directory", using
278 the C<--heredir|-H> option. This is much the same as giving the directory
279 name (see above), but in this case C<tar> will be told to change into the
280 directory first, and archive '.'. This means that the contents of the
281 "here-directory" will be extracted directly into I<tmpdir>.
283 =back
285 =head2 Extended Example
287 Suppose you have a few server which have the same configuration, apart
288 from some specific stuff (e.g. the hostname, the IP addresses, etc.).
289 You'd like to perform changes to all with the minimum work possible...
290 so you know you should script something.
292 For example, suppose you want to update a few files in /etc, setting these
293 files equal for all hosts. You would typically do the following:
295 # In your computer
296 shell$ mkdir -p /tmp/newfiles/etc
297 shell$ cd /tmp/newfiles/etc
298 # Craft the new files
299 shell$ cd ..
300 shell$ tar cvzf newetc.tar.gz etc
302 # Now, for each server:
303 shell$ scp newetc.tar.gz $server:/tmp
304 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
307 So far, so good. But what if you need to kick in a little more logic?
308 For example, if you update some configuration files, you'll most likey
309 want to restart some services. So you could do the following:
311 shell$ mkdir -p /tmp/newfiles/tmp
312 shell$ cd /tmp/newfiles/tmp
313 # craft a shell script to be executed remotely and set the exec bit
314 # Suppose it's called deploy.sh
315 shell$ cd ..
316 shell$ tar cvzf newetc.tar.gz etc tmp
318 # Now, for each server:
319 shell$ scp newetc.tar.gz $server:/tmp
320 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
321 shell$ ssh $server /tmp/deploy.sh
323 And what if you want to install files depending on the particular machine?
324 Or you have a bundle of stuff to deploy and a bunch of scripts to execute?
325 You can use deployable. In this case, you can do the following:
327 shell$ mkdir -p /tmp/newfiles/etc
328 shell$ cd /tmp/newfiles/etc
329 # Craft the new files
330 shell$ cd ..
331 # craft a shell script to be executed remotely and set the exec bit
332 # Suppose it's called deploy.sh
333 shell$ deployable -o deploy.pl etc deploy.sh --exec deploy.sh
335 # Now, for each server
336 shell$ scp deploy.pl $server:/tmp
337 shell$ ssh $server /tmp/deploy.pl
339 And you're done. This can be particularly useful if you have another
340 layer of deployment, e.g. if you have to run a script to decide which
341 of a group of archives should be deployed. For example, you could craft
342 a different new "etc" for each server (which is particularly true if
343 network configurations are in the package), and produce a simple script
344 to choose which file to use based on the MAC address of the machine. In
345 this case you could have:
347 =over
349 =item newetc.*.tar.gz
351 a bunch of tar files with the configurations for each different server
353 =item newetc.list
355 a list file with the association between the MAC addresses and the
356 real tar file to deploy from the bunch in the previous bullet
358 =item deploy-the-right-stuff.sh
360 a script to get the real MAC address of the machine, select the right
361 tar file and do the deployment.
363 =back
365 So, you can do the following:
367 shell$ deployable -o deploy.pl newetc.*.tar.gz newetc.list \
368 deploy-the-right-stuff.sh --exec deploy-the-right-stuff.sh
370 # Now, for each server:
371 shell$ scp deploy.pl $server:/tmp
372 shell$ ssh $server /tmp/deploy.pl
374 So, once you have the deploy script on the target machine all you need
375 to do is to execute it. This can come handy when you cannot access the
376 machines from the network, but you have to go there physically: you
377 can prepare all in advance, and just call the deploy script.
380 =head1 OPTIONS
382 Meta-options:
384 =over
386 =item B<--help>
388 print a somewhat more verbose help, showing usage, this description of
389 the options and some examples from the synopsis.
391 =item B<--man>
393 print out the full documentation for the script.
395 =item B<--usage>
397 print a concise usage line and exit.
399 =item B<--version>
401 print the version of the script.
403 =back
405 Real-world options:
407 =over
409 =item B<< --bundle | --all-exec | -X >>
411 Set bundle flag in the produced script. If the bundle flag is set, the
412 I<deploy script> will treat all executables in the main deployment
413 directory as scripts to be executed.
415 By default the flag is not set.
417 =item B<< --cleanup | -c >>
419 Set cleanup flag in the produced script. If the cleanup flag is set, the
420 I<deploy script> will clean up after having performed all operations.
422 You can set this flag to C<0> by using C<--no-cleanup>.
424 =item B<< --deploy | --exec | -d <filename> >>
426 Set the name of a program to execute after extraction. You can provide
427 multiple program names, they will be executed in the same order.
429 =item B<< --heredir | -H <path> >>
431 Set the name of a "here directory" (see L<DESCRIPTION>). You can use this
432 option multiple times to provide multiple directories.
434 =item B<< --include-archive-tar | -T >>
436 Embed L<Archive::Tar> (with its dependencies L<Archive::Tar::Constant> and
437 L<Archive::Tar::File>) inside the final script. Use this when you know (or
438 aren't sure) that L<Archive::Tar> will not be available in the target
439 machine.
441 =item B<< --output | -o <filename> >>
443 Set the output file name. By default the I<deploy script> will be given
444 out on the standard output; if you provide a filename (different from
445 C<->, of course!) the script will be saved there and the permissions will
446 be set to 0755.
448 =item B<< --root | -r <dirname> >>
450 Include C<dirname> contents for deployment under root directory. The
451 actual production procedure is: hop into C<dirname> and grab a tarball
452 of C<.>. During deployment, hop into C</> and extract the tarball.
454 This is useful if you're already building up the absolute deployment
455 layout under a given directory: just treat that directory as if it were
456 the root of the target system.
458 =item B<< --rootdir | -R <dirname >>
460 Include C<dirname> as a directory that will be extracted under root
461 directory. The actual production procedure is: grab a tarball of
462 C<dirname>. During deployment, hop into C</> and extract the tarball.
464 This is useful if you have a directory (or a group of directories) that
465 you want to deploy directly under the root.
467 =item B<< --tarfile | --tar | -t <filename> >>
469 Use the given file as the only contents for the deployed script. The
470 filename should point to a valid tar file, which will be the only
471 one stored into the resulting script (i.e. all other files/directories
472 will be ignored). This requires more work on your side, but gives you
473 full flexibility.
475 Note that the generated script will interpret the generated tar file
476 as follows:
478 =over
480 =item B<< deployable/config.pl >> (file)
482 will be C<eval>ed, expecting to receive a reference to an anonymous
483 hash with the configurations;
485 =item B<< here >> (directory)
487 will be normally deployed into the working directory in the target
488 system;
490 =item B<< root >> (directory)
492 will be normally deployed under C</> in the target system.
494 =back
496 =item B<< --workdir | --deploy-directory | -w <path> >>
498 Set the working directory for the deploy.
500 =back
502 =head1 THE DEPLOY SCRIPT
504 The net result of calling this script is to produce another script,
505 that we call the I<deploy script>. This script is made of two parts: the
506 code, which is fixed, and the configurations/files, which is what is
507 actually produced. The latter part is put after the C<__END__> marker,
508 as usual.
510 Stuff in the configuration part is always hexified in order to prevent
511 strange tricks or errors. Comments will help you devise what's inside the
512 configurations themselves.
514 The I<deploy script> has options itself, even if they are quite minimal.
515 In particular, it supports the same options C<--workdir|-w> and
516 C<--cleanup> described above, allowing the final user to override the
517 configured values. By default, the I<workdir> is set to C</tmp/our-deploy>
518 and the script will clean up after itself.
520 The following options are supported in the I<deploy script>:
522 =over
524 =item B<--usage | --man | --help>
526 print a minimal help and exit
528 =item B<--version>
530 print script version and exit
532 =item B<--bundle | --all-exec | -X>
534 treat all executables in the main deployment directory as scripts
535 to be executed
537 =item B<--cleanup | --no-cleanup>
539 perform / don't perform temporary directory cleanup after work done
541 =item B<< --deploy | --no-deploy >>
543 deploy scripts are executed by default (same as specifying '--deploy')
544 but you can prevent it.
546 =item B<--dryrun | --dry-run>
548 print final options and exit
550 =item B<< --filelist | --list | -l >>
552 print a list of files that are shipped in the deploy script
554 =item B<< --inspect <dirname> >>
556 just extract all the stuff into <dirname> for inspection. Implies
557 C<--no-deploy>, C<--no-tempdir>, ignores C<--bundle> (as a consequence of
558 C<--no-deploy>), disables C<--cleanup> and sets the working directory
559 to C<dirname>
561 =item B<--show | --show-options | -s>
563 print configured options and exit
565 =item B<< --tar | -t >>
567 print out the tar file that contains all the shipped files, useful
568 to redirect to file or pipe to the B<tar> program
570 =item B<< --tempdir | --no-tempdir >>
572 by default a temporary directory is created (same as specifying
573 C<--tempdir>), but you can execute directly in the workdir (see below)
574 without creating it.
576 =item B<--workdir | --work-directory | --deploy-directory | -w>
578 working base directory (a temporary subdirectory will be created
579 there anyway)
581 =back
583 Note the difference between C<--show> and C<--dryrun>: the former will
584 give you the options that are "embedded" in the I<deploy script> without
585 taking into account other options given on the command line, while the
586 latter will give you the final options that would be used if the script
587 were called without C<--dryrun>.
589 =head2 Deploy Script Example Usage
591 In the following, we'll assume that the I<deploy script> is called
592 C<deploy.pl>.
594 To execute the script with the already configured options, you just have
595 to call it:
597 shell$ ./deploy.pl
599 If you just want to see which configurations are in the I<deploy script>:
601 shell$ ./deploy.pl --show
603 To see which files are included, you have two options. One is asking the
604 script:
606 shell$ ./deploy.pl --filelist
608 the other is piping to tar:
610 shell$ ./deploy.pl --tar | tar tvf -
612 Extract contents of the script in a temp directory and simply inspect
613 what's inside:
615 # extract stuff into subdirectory 'inspect' for... inspection
616 shell$ ./deploy.pl --no-tempdir --no-deploy --workdir inspect
618 =head2 Deploy Script Requirements
620 You'll need a working Perl with version at least 5.6.2.
622 If you specify L</--include-archive-tar>, the module L<Archive::Tar> will
623 be included as well. This should ease your life and avoid you to have
624 B<tar> on the target machine. On the other hand, if you already know
625 that B<tar> will be available, you can avoid including C<Archive::Tar>
626 and have the generated script use it (it could be rather slower anyway).
628 =head1 DIAGNOSTICS
630 Each error message should be enough explicit to be understood without the
631 need for furter explainations. Which is another way to say that I'm way
632 too lazy to list all possible ways that this script has to fail.
635 =head1 CONFIGURATION AND ENVIRONMENT
637 deployable requires no configuration files or environment variables.
639 Please note that deployable B<needs> to find its master B<remote> file
640 to produce the final script. This must be put in the same directory where
641 deployable is put. You should be able to B<symlink> deployable where you
642 think it's better, anyway - it will go search for the original file
643 and look for B<remote> inside the same directory. This does not apply to
644 hard links, of course.
647 =head1 DEPENDENCIES
649 All core modules, apart the following:
651 =over
653 =item B<< Archive::Tar >>
655 =item B<< File::Find::Rule >>
657 =back
659 =head1 BUGS AND LIMITATIONS
661 No bugs have been reported.
663 Please report any bugs or feature requests to the AUTHOR below.
665 Be sure to read L<CONFIGURATION AND ENVIRONMENT> for a slight limitation
666 about the availability of the B<remote> script.
668 =head1 AUTHOR
670 Flavio Poletti C<flavio [AT] polettix.it>
673 =head1 LICENSE AND COPYRIGHT
675 Copyright (c) 2008, Flavio Poletti C<flavio [AT] polettix.it>. All rights reserved.
677 This script is free software; you can redistribute it and/or
678 modify it under the same terms as Perl itself. See L<perlartistic>
679 and L<perlgpl>.
681 Questo script è software libero: potete ridistribuirlo e/o
682 modificarlo negli stessi termini di Perl stesso. Vedete anche
683 L<perlartistic> e L<perlgpl>.
686 =head1 DISCLAIMER OF WARRANTY
688 BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
689 FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
690 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
691 PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
692 EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
693 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
694 ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
695 YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
696 NECESSARY SERVICING, REPAIR, OR CORRECTION.
698 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
699 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
700 REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
701 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
702 OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
703 THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
704 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
705 FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
706 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
707 SUCH DAMAGES.
709 =head1 NEGAZIONE DELLA GARANZIA
711 Poiché questo software viene dato con una licenza gratuita, non
712 c'è alcuna garanzia associata ad esso, ai fini e per quanto permesso
713 dalle leggi applicabili. A meno di quanto possa essere specificato
714 altrove, il proprietario e detentore del copyright fornisce questo
715 software "così com'è" senza garanzia di alcun tipo, sia essa espressa
716 o implicita, includendo fra l'altro (senza però limitarsi a questo)
717 eventuali garanzie implicite di commerciabilità e adeguatezza per
718 uno scopo particolare. L'intero rischio riguardo alla qualità ed
719 alle prestazioni di questo software rimane a voi. Se il software
720 dovesse dimostrarsi difettoso, vi assumete tutte le responsabilità
721 ed i costi per tutti i necessari servizi, riparazioni o correzioni.
723 In nessun caso, a meno che ciò non sia richiesto dalle leggi vigenti
724 o sia regolato da un accordo scritto, alcuno dei detentori del diritto
725 di copyright, o qualunque altra parte che possa modificare, o redistribuire
726 questo software così come consentito dalla licenza di cui sopra, potrà
727 essere considerato responsabile nei vostri confronti per danni, ivi
728 inclusi danni generali, speciali, incidentali o conseguenziali, derivanti
729 dall'utilizzo o dall'incapacità di utilizzo di questo software. Ciò
730 include, a puro titolo di esempio e senza limitarsi ad essi, la perdita
731 di dati, l'alterazione involontaria o indesiderata di dati, le perdite
732 sostenute da voi o da terze parti o un fallimento del software ad
733 operare con un qualsivoglia altro software. Tale negazione di garanzia
734 rimane in essere anche se i dententori del copyright, o qualsiasi altra
735 parte, è stata avvisata della possibilità di tali danneggiamenti.
737 Se decidete di utilizzare questo software, lo fate a vostro rischio
738 e pericolo. Se pensate che i termini di questa negazione di garanzia
739 non si confacciano alle vostre esigenze, o al vostro modo di
740 considerare un software, o ancora al modo in cui avete sempre trattato
741 software di terze parti, non usatelo. Se lo usate, accettate espressamente
742 questa negazione di garanzia e la piena responsabilità per qualsiasi
743 tipo di danno, di qualsiasi natura, possa derivarne.
745 =cut