Updated documentation with more examples and new options.
[deployable.git] / deployable
blob42ab428ca95b77a21000be799a0ecca96a7a555c
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( realpath );
15 # Other recommended modules (uncomment to use):
16 # use IO::Prompt;
17 # use Readonly;
18 # use Data::Dumper;
20 # Integrated logging facility
21 # use Log::Log4perl qw( :easy );
22 # Log::Log4perl->easy_init($INFO);
24 my %config = (
25 output => '-',
26 remote => catfile(dirname(realpath(__FILE__)), 'remote'),
27 tarfile => [],
28 heredir => [],
29 rootdir => [],
30 root => [],
31 deploy => [],
33 GetOptions(
34 \%config, 'usage',
35 'help', 'man',
36 'version', 'output|o=s',
37 'deploy|exec|d=s@', 'workdir|work-directory|deploy-directory|w=s',
38 'cleanup|c!', 'tarfile|T=s@',
39 'heredir|H=s@', 'bundle|all-exec|X!',
40 'rootdir|R=s@', 'root|r=s@',
42 pod2usage(message => "$0 $VERSION", -verbose => 99, -sections => '')
43 if $config{version};
44 pod2usage(-verbose => 99, -sections => 'USAGE') if $config{usage};
45 pod2usage(-verbose => 99, -sections => 'USAGE|EXAMPLES|OPTIONS')
46 if $config{help};
47 pod2usage(-verbose => 2) if $config{man};
49 pod2usage(
50 message => 'working directory must be an absolute path',
51 -verbose => 99,
52 -sections => ''
54 if exists $config{workdir} && !file_name_is_absolute($config{workdir});
56 my $out_fh = \*STDOUT;
57 if ($config{output} ne '-') {
58 open my $fh, '>', $config{output} ## no critic
59 or croak "open('$config{output}'): $OS_ERROR";
60 $out_fh = $fh;
63 # Emit script code to be executed remotely. It is guaranteed to end
64 # with __END__, so that all what comes next is data
65 print {$out_fh} get_remote_script();
67 # Emit these configurations, if present
68 print {$out_fh} '#' x 72, "\n# General configurations\n\n";
69 for my $name (qw( workdir cleanup bundle )) {
70 print {$out_fh} confline($name, $config{$name}), "\n\n"
71 if exists $config{$name};
74 # Emit list of deploy scripts
75 print {$out_fh} confline('deploy@', $_), "\n\n"
76 for @{$config{deploy}};
78 # Time for tarfiles now
79 print {$out_fh} '#' x 72, "\n# List of files\n[files]\n\n";
81 # Process files and directories. All these will be reported in the
82 # extraction directory, i.e. basename() will be applied to them. For
83 # directories, they will be re-created
84 for my $file (@ARGV) {
85 croak "'$file' not readable" unless -r $file;
86 if (-d $file) {
87 print {*STDERR} "processing directory '$file'\n";
88 print {$out_fh} as_comment("directory $file, extracted into:"), "\n";
89 print {$out_fh} confline('directory', '.'), "\n";
90 save_directory('.', $file, $out_fh);
91 } ## end if (-d $file)
92 else {
93 print {*STDERR} "processing file '$file'\n";
94 my $mode = sprintf '0%lo', (stat $file)[2] & oct(7777);
95 print {$out_fh} as_comment('file saves both mode and filename'),
96 "\n";
97 print {$out_fh} confline('file', $mode . ' ' . basename($file)),
98 "\n";
99 save_file($file, $out_fh);
100 } ## end else [ if (-d $file)
101 } ## end for my $file (@ARGV)
103 # Tarfiles are files that will be extracted in the target directory
104 for my $tarfile (@{$config{tarfile}}) {
105 croak "'$tarfile' not readable" unless -r $tarfile;
106 print {*STDERR} "processing tarfile '$tarfile'\n";
107 print {$out_fh} as_comment('tarfile will also be extracted into .'),
108 "\n";
109 print {$out_fh} confline(tarfile => $tarfile), "\n";
110 save_file($tarfile, $out_fh);
111 } ## end for my $tarfile (@{$config...
113 # Heredirs are directories that are extracted directly into the ex dir
114 for my $heredir (@{$config{heredir}}) {
115 croak "'$heredir' not readable" unless -r $heredir;
116 print {*STDERR} "processing here-directory '$heredir'\n";
117 print {$out_fh}
118 as_comment("here-directory = $heredir, extracted into:"), "\n";
119 print {$out_fh} confline('directory', '.'), "\n";
120 save_directory($heredir, '.', $out_fh);
121 } ## end for my $heredir (@{$config...
123 for my $rootdir (@{$config{rootdir}}) {
124 croak "'$rootdir' not readable" unless -r $rootdir;
125 print {*STDERR} "processing root-directory '$rootdir'\n";
126 print {$out_fh}
127 as_comment("root-directory = $rootdir, extracted into:"), "\n";
128 print {$out_fh} confline('directory', '/'), "\n";
129 save_directory('.', $rootdir, $out_fh);
132 for my $root (@{$config{root}}) {
133 croak "'$root' not readable" unless -r $root;
134 print {*STDERR} "processing root-directory '$root'\n";
135 print {$out_fh}
136 as_comment("root-directory = $root, extracted into:"), "\n";
137 print {$out_fh} confline('directory', '/'), "\n";
138 save_directory($root, '.', $out_fh);
141 close $out_fh;
142 if ($config{output} ne '-') {
143 chmod oct(755), $config{output}
144 or carp "chmod(0755, '$config{output}'): $OS_ERROR";
147 sub save_directory {
148 my ($changedir, $filename, $out_fh) = @_;
150 ## no critic
151 open my $fh, '-|', '/bin/tar', 'czf', '-', '-b', '1', '-C', $changedir,
152 $filename,
153 or croak "open() for /bin/tar: $OS_ERROR";
155 return hexified_copy($fh, $out_fh);
156 } ## end sub save_directory
158 sub save_file {
159 my ($filename, $out_fh) = @_;
161 ## no critic
162 open my $fh, '<', $filename
163 or croak "open('$filename'): $OS_ERROR";
164 return hexified_copy($fh, $out_fh);
165 } ## end sub save_file
167 sub hexified_copy {
168 my ($in_fh, $out_fh) = @_;
169 binmode $in_fh;
170 while (read $in_fh, my $data, 32) {
171 print {$out_fh} unpack('H*', $data), "\n";
173 print {$out_fh} "\n";
174 return;
175 } ## end sub hexified_copy
177 sub as_comment { ## no critic
178 return join "\n", map { '# ' . $_ } map { split /\n/mxs } @_;
181 sub confline {
182 my ($name, $data) = @_;
183 my $comment = "$name = $data";
184 my $line = join ' = ', $name, unpack 'H*', $data;
185 return join "\n", as_comment("$name = $data"), $line;
186 } ## end sub confline
188 sub get_remote_script {
189 open my $fh, '<', $config{remote}
190 or croak "open('$config{remote}'): $OS_ERROR";
191 my @lines;
192 while (<$fh>) {
193 last if /\A __END__ \s*\z/mxs;
194 push @lines, $_;
196 close $fh;
197 return join '', @lines, "__END__\n";
198 } ## end sub get_remote_script
200 __END__
202 =head1 NAME
204 deployable - create a deploy script for some files/scripts
207 =head1 VERSION
209 See version at beginning of script, variable $VERSION, or call
211 shell$ deployable --version
213 =head1 USAGE
215 deployable [--usage] [--help] [--man] [--version]
217 deployable [--bundle|--all-exec|-X] [--cleanup|-c]
218 [--deploy|--exec|d <program>] [--heredir|-H <dirname>]
219 [--output|-o <filename>] [--root|-r <dirname>]
220 [--rootdir|-R <dirname>] [--tarfile|-T <filename>]
221 [--workdir|-w <path>] [ files or directories... ]
224 =head1 EXAMPLES
226 shell$ deployable
228 # Create script.pl embedding distro.tar.gz. When executed, this
229 # tar file will be extracted, and script.sh will be executed.
230 shell$ deployable -o script.pl --exec script.sh -T distro.tar.gz
232 # Use a directory's contents as elements for the target root
233 shell$ ls -1 /path/to/target/root
238 # The above will be deployed as /etc, /opt, /usr and /var
239 shell$ deployable -o dep.pl --root /path/to/target/root
241 # Include directory /path/to/etc for inclusion and extraction
242 # directly as /etc
243 shell$ deployable -o dep.pl --rootdir /path/to/etc
245 =head1 DESCRIPTION
247 This is a meta-script to create deploy scripts. The latter ones are
248 suitable to be distributed in order to deploy something.
250 You basically have to provide two things: files to install and programs
251 to be executed. Files can be put directly into the deployed script, or
252 can be included in gzipped tar archives.
254 When called, this script creates a deploy script for you. This script
255 includes all the specified files, and when executed it will extract
256 those files and execute the given programs. In this way, you can ship
257 both files and logic needed to correctly install those files, but this
258 is of course of of scope.
260 All files and archives will be extracted under a configured path
261 (see L<--workdir> below), which we'll call I<workdir> from now on. Under
262 the I<workdir> a temporary directory will be created, and the files
263 will be put in the temporary directory. You can specify if you want to
264 clean up this temporary directory or keep it, at your choice. (You're able
265 to both set a default for this cleanup when invoking deployable, or when
266 invoking the deploy script itself). The temporary directory will be
267 called I<tmpdir> in the following.
269 There are several ways to embed files to be shipped:
271 =over
273 =item *
275 specify the file name directly on the command line. A file given in this
276 way will always be extracted into the I<tmpdir>, whatever its initial path
277 was.
279 =item *
281 specify the name of a directory on the command line. In this case,
282 C<tar> will be used to archive the directory, with the usual option to
283 turn absolute paths into relative ones; this means that directories will
284 be re-created under I<tmpdir> when extraction is performed.
286 =item *
288 give the name of an already available gzipped C<tar> archive, using the
289 C<--tarfile|-T> option. This lets you have the maximum flexibility.
291 =item *
293 give the name of a directory to be used as a "here directory", using
294 the C<--heredir|-H> option. This is much the same as giving the directory
295 name (see above), but in this case C<tar> will be told to change into the
296 directory first, and archive '.'. This means that the contents of the
297 "here-directory" will be extracted directly into I<tmpdir>.
299 =back
301 =head2 Extended Example
303 Suppose you have a few server which have the same configuration, apart
304 from some specific stuff (e.g. the hostname, the IP addresses, etc.).
305 You'd like to perform changes to all with the minimum work possible...
306 so you know you should script something.
308 For example, suppose you want to update a few files in /etc, setting these
309 files equal for all hosts. You would typically do the following:
311 # In your computer
312 shell$ mkdir -p /tmp/newfiles/etc
313 shell$ cd /tmp/newfiles/etc
314 # Craft the new files
315 shell$ cd ..
316 shell$ tar cvzf newetc.tar.gz etc
318 # Now, for each server:
319 shell$ scp newetc.tar.gz $server:/tmp
320 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
323 So far, so good. But what if you need to kick in a little more logic?
324 For example, if you update some configuration files, you'll most likey
325 want to restart some services. So you could do the following:
327 shell$ mkdir -p /tmp/newfiles/tmp
328 shell$ cd /tmp/newfiles/tmp
329 # craft a shell script to be executed remotely and set the exec bit
330 # Suppose it's called deploy.sh
331 shell$ cd ..
332 shell$ tar cvzf newetc.tar.gz etc tmp
334 # Now, for each server:
335 shell$ scp newetc.tar.gz $server:/tmp
336 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
337 shell$ ssh $server /tmp/deploy.sh
339 And what if you want to install files depending on the particular machine?
340 Or you have a bundle of stuff to deploy and a bunch of scripts to execute?
341 You can use deployable. In this case, you can do the following:
343 shell$ mkdir -p /tmp/newfiles/etc
344 shell$ cd /tmp/newfiles/etc
345 # Craft the new files
346 shell$ cd ..
347 # craft a shell script to be executed remotely and set the exec bit
348 # Suppose it's called deploy.sh
349 shell$ deployable -o deploy.pl etc deploy.sh --exec deploy.sh
351 # Now, for each server
352 shell$ scp deploy.pl $server:/tmp
353 shell$ ssh $server /tmp/deploy.pl
355 And you're done. This can be particularly useful if you have another
356 layer of deployment, e.g. if you have to run a script to decide which
357 of a group of archives should be deployed. For example, you could craft
358 a different new "etc" for each server (which is particularly true if
359 network configurations are in the package), and produce a simple script
360 to choose which file to use based on the MAC address of the machine. In
361 this case you could have:
363 =over
365 =item newetc.*.tar.gz
367 a bunch of tar files with the configurations for each different server
369 =item newetc.list
371 a list file with the association between the MAC addresses and the
372 real tar file to deploy from the bunch in the previous bullet
374 =item deploy-the-right-stuff.sh
376 a script to get the real MAC address of the machine, select the right
377 tar file and do the deployment.
379 =back
381 So, you can do the following:
383 shell$ deployable -o deploy.pl newetc.*.tar.gz newetc.list \
384 deploy-the-right-stuff.sh --exec deploy-the-right-stuff.sh
386 # Now, for each server:
387 shell$ scp deploy.pl $server:/tmp
388 shell$ ssh $server /tmp/deploy.pl
390 So, once you have the deploy script on the target machine all you need
391 to do is to execute it. This can come handy when you cannot access the
392 machines from the network, but you have to go there physically: you
393 can prepare all in advance, and just call the deploy script.
396 =head1 OPTIONS
398 Meta-options:
400 =over
402 =item B<--help>
404 print a somewhat more verbose help, showing usage, this description of
405 the options and some examples from the synopsis.
407 =item B<--man>
409 print out the full documentation for the script.
411 =item B<--usage>
413 print a concise usage line and exit.
415 =item B<--version>
417 print the version of the script.
419 =back
421 Real-world options:
423 =over
425 =item B<< --bundle | --all-exec | -X >>
427 Set bundle flag in the produced script. If the bundle flag is set, the
428 I<deploy script> will treat all executables in the main deployment
429 directory as scripts to be executed.
431 By default the flag is not set.
433 =item B<< --cleanup | -c >>
435 Set cleanup flag in the produced script. If the cleanup flag is set, the
436 I<deploy script> will clean up after having performed all operations.
438 You can set this flag to C<0> by using C<--no-cleanup>.
440 =item B<< --deploy | --exec | -d <filename> >>
442 Set the name of a program to execute after extraction. You can provide
443 multiple program names, they will be executed in the same order.
445 =item B<< --heredir | -H <path> >>
447 Set the name of a "here directory" (see L<DESCRIPTION>). You can use this
448 option multiple times to provide multiple directories.
450 =item B<< --output | -o <filename> >>
452 Set the output file name. By default the I<deploy script> will be given
453 out on the standard output; if you provide a filename (different from
454 C<->, of course!) the script will be saved there and the permissions will
455 be set to 0755.
457 =item B<< --root | -r <dirname> >>
459 Include C<dirname> contents for deployment under root directory. The
460 actual production procedure is: hop into C<dirname> and grab a tarball
461 of C<.>. During deployment, hop into C</> and extract the tarball.
463 This is useful if you're already building up the absolute deployment
464 layout under a given directory: just treat that directory as if it were
465 the root of the target system.
467 =item B<< --rootdir | -R <dirname >>
469 Include C<dirname> as a directory that will be extracted under root
470 directory. The actual production procedure is: grab a tarball of
471 C<dirname>. During deployment, hop into C</> and extract the tarball.
473 This is useful if you have a directory (or a group of directories) that
474 you want to deploy directly under the root.
476 =item B<< --tarfile | -T <filename >>
478 Set the name of a B<tar> file, see L<DESCRIPTION>. You can use this option
479 multiple times to provide multiple B<tar> archives.
481 =item B<< --workdir | --deploy-directory | -w <path> >>
483 Set the working directory for the deploy.
485 =back
487 =head1 THE DEPLOY SCRIPT
489 The net result of calling this script is to produce another script,
490 that we call the I<deploy script>. This script is made of two parts: the
491 code, which is fixed, and the configurations/files, which is what is
492 actually produced. The latter part is put after the C<__END__> marker,
493 as usual.
495 Stuff in the configuration part is always hexified in order to prevent
496 strange tricks or errors. Comments will help you devise what's inside the
497 configurations themselves.
499 The I<deploy script> has options itself, even if they are quite minimal.
500 In particular, it supports the same options C<--workdir|-w> and
501 C<--cleanup> described above, allowing the final user to override the
502 configured values. By default, the I<workdir> is set to C</tmp/our-deploy>
503 and the script will clean up after itself.
505 The following options are supported in the I<deploy script>:
507 =over
509 =item B<--usage | --man | --help>
511 print a minimal help and exit
513 =item B<--version>
515 print script version and exit
517 =item B<--bundle | --all-exec | -X>
519 treat all executables in the main deployment directory as scripts
520 to be executed
522 =item B<--cleanup | --no-cleanup>
524 perform / don't perform temporary directory cleanup after work done
526 =item B<--dryrun | --dry-run>
528 print final options and exit
530 =item B<< --inspect <dirname> >>
532 just extract all the stuff into <dirname> for inspection. Implies
533 C<--no-deploy>, C<--no-tempdir>, ignores C<--bundle> (as a consequence of
534 C<--no-deploy>), disables C<--cleanup> and sets the working directory
535 to C<dirname>
537 =item B<--no-deploy>
539 prevent execution of deploy scripts (they are executed by default)
541 =item B<--no-workdir>
543 execute directly in workdir (see below), without creating the
544 temporary directory
546 =item B<--show | --show-options | -s>
548 print configured options and exit
550 =item B<--workdir | -w>
552 working base directory (a temporary subdirectory will be created
553 there anyway)
555 =back
557 Note the difference between C<--show> and C<--dryrun>: the former will
558 give you the options that are "embedded" in the I<deploy script> without
559 taking into account other options given on the command line, while the
560 latter will give you the final options that would be used if the script
561 were called without C<--dryrun>.
563 =head2 Deploy Script Example Usage
565 In the following, we'll assume that the I<deploy script> is called
566 C<deploy.pl>.
568 To execute the script with the already configured options, you just have
569 to call it:
571 shell$ ./deploy.pl
573 If you just want to see which configurations are in the I<deploy script>:
575 shell$ ./deploy.pl --show
577 Extract contents of the script in a temp directory and simply inspect
578 what's inside:
580 # extract stuff into subdirectory 'inspect' for... inspection
581 shell$ ./deploy.pl --no-tempdir --no-deploy --workdir inspect
583 =head2 Deploy Script Requirements
585 Care has been taken to make the requirements of the deploy script as low
586 as possible. The result is that you'll need a working Perl with version
587 at least 5.6.2, and GNU B<tar> with support for options C<--touch> and
588 C<--no-same-owner>. Good luck.
591 =head1 DIAGNOSTICS
593 Each error message should be enough explicit to be understood without the
594 need for furter explainations. Which is another way to say that I'm way
595 too lazy to list all possible ways that this script has to fail.
598 =head1 CONFIGURATION AND ENVIRONMENT
600 deployable requires no configuration files or environment variables.
602 Please note that deployable B<needs> to find its master B<remote> file
603 to produce the final script. This must be put in the same directory where
604 deployable is put. You should be able to B<symlink> deployable where you
605 think it's better, anyway - it will go search for the original file
606 and look for B<remote> inside the same directory. This does not apply to
607 hard links, of course.
610 =head1 DEPENDENCIES
612 All core modules, apart from L<version> which is nearly-core.
615 =head1 BUGS AND LIMITATIONS
617 No bugs have been reported.
619 Please report any bugs or feature requests to the AUTHOR below.
622 =head1 AUTHOR
624 Flavio Poletti C<flavio [AT] polettix.it>
627 =head1 LICENSE AND COPYRIGHT
629 Copyright (c) 2008, Flavio Poletti C<flavio [AT] polettix.it>. All rights reserved.
631 This script is free software; you can redistribute it and/or
632 modify it under the same terms as Perl itself. See L<perlartistic>
633 and L<perlgpl>.
635 Questo script è software libero: potete ridistribuirlo e/o
636 modificarlo negli stessi termini di Perl stesso. Vedete anche
637 L<perlartistic> e L<perlgpl>.
640 =head1 DISCLAIMER OF WARRANTY
642 BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
643 FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
644 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
645 PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
646 EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
647 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
648 ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
649 YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
650 NECESSARY SERVICING, REPAIR, OR CORRECTION.
652 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
653 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
654 REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
655 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
656 OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
657 THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
658 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
659 FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
660 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
661 SUCH DAMAGES.
663 =head1 NEGAZIONE DELLA GARANZIA
665 Poiché questo software viene dato con una licenza gratuita, non
666 c'è alcuna garanzia associata ad esso, ai fini e per quanto permesso
667 dalle leggi applicabili. A meno di quanto possa essere specificato
668 altrove, il proprietario e detentore del copyright fornisce questo
669 software "così com'è" senza garanzia di alcun tipo, sia essa espressa
670 o implicita, includendo fra l'altro (senza però limitarsi a questo)
671 eventuali garanzie implicite di commerciabilità e adeguatezza per
672 uno scopo particolare. L'intero rischio riguardo alla qualità ed
673 alle prestazioni di questo software rimane a voi. Se il software
674 dovesse dimostrarsi difettoso, vi assumete tutte le responsabilità
675 ed i costi per tutti i necessari servizi, riparazioni o correzioni.
677 In nessun caso, a meno che ciò non sia richiesto dalle leggi vigenti
678 o sia regolato da un accordo scritto, alcuno dei detentori del diritto
679 di copyright, o qualunque altra parte che possa modificare, o redistribuire
680 questo software così come consentito dalla licenza di cui sopra, potrà
681 essere considerato responsabile nei vostri confronti per danni, ivi
682 inclusi danni generali, speciali, incidentali o conseguenziali, derivanti
683 dall'utilizzo o dall'incapacità di utilizzo di questo software. Ciò
684 include, a puro titolo di esempio e senza limitarsi ad essi, la perdita
685 di dati, l'alterazione involontaria o indesiderata di dati, le perdite
686 sostenute da voi o da terze parti o un fallimento del software ad
687 operare con un qualsivoglia altro software. Tale negazione di garanzia
688 rimane in essere anche se i dententori del copyright, o qualsiasi altra
689 parte, è stata avvisata della possibilità di tali danneggiamenti.
691 Se decidete di utilizzare questo software, lo fate a vostro rischio
692 e pericolo. Se pensate che i termini di questa negazione di garanzia
693 non si confacciano alle vostre esigenze, o al vostro modo di
694 considerare un software, o ancora al modo in cui avete sempre trattato
695 software di terze parti, non usatelo. Se lo usate, accettate espressamente
696 questa negazione di garanzia e la piena responsabilità per qualsiasi
697 tipo di danno, di qualsiasi natura, possa derivarne.
699 =cut