1#!/usr/bin/perl
2# vim: set ai shiftwidth=4 tabstop=4 expandtab:
3
4#   dget - Download Debian source and binary packages
5#   Copyright (C) 2005-2013 Christoph Berg <myon@debian.org>
6#   Modifications Copyright (C) 2005-06 Julian Gilbey <jdg@debian.org>
7#
8#   This program is free software; you can redistribute it and/or modify
9#   it under the terms of the GNU General Public License as published by
10#   the Free Software Foundation; either version 2 of the License, or
11#   (at your option) any later version.
12#
13#   This program is distributed in the hope that it will be useful,
14#   but WITHOUT ANY WARRANTY; without even the implied warranty of
15#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16#   GNU General Public License for more details.
17#
18#   You should have received a copy of the GNU General Public License
19#   along with this program; if not, write to the Free Software
20#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
21
22# 2005-10-04 cb: initial release
23# 2005-12-11 cb: -x option, update documentation
24# 2005-12-31 cb: -b, -q options, use getopt
25# 2006-01-10 cb: support new binnmu version scheme
26# 2006-11-12 cb: also look in other places in the local filesystem (e.g. pbuilder result dir)
27# Later modifications: see debian/changelog
28
29use strict;
30use warnings;
31use Cwd qw(abs_path);
32use IO::Dir;
33use IO::File;
34use Digest::MD5;
35use Devscripts::Compression;
36use Dpkg::Control;
37use Getopt::Long qw(:config bundling permute no_getopt_compat);
38use File::Basename;
39
40# global variables
41
42my $progname = basename($0, '.pl');    # the '.pl' is for when we're debugging
43my $found_dsc;
44my $wget;
45my $opt;
46my $backup_dir = "backup";
47my @dget_path  = ("/var/cache/apt/archives");
48my $modified_conf_msg;
49
50my $compression_re = compression_get_file_extension_regex();
51
52# use curl if installed, wget otherwise
53if (system("command -v curl >/dev/null 2>&1") == 0) {
54    $wget = "curl";
55} elsif (system("command -v wget >/dev/null 2>&1") == 0) {
56    $wget = "wget";
57} else {
58    die
59"$progname: can't find either curl or wget; you need at least one of these\ninstalled to run me!\n";
60}
61
62# functions
63
64sub usage {
65    print <<"EOT";
66Usage: $progname [options] URL ...
67       $progname [options] [--all] package[=version] ...
68
69Downloads Debian packages (source and binary) from the specified URLs (first form),
70or using the mirror configured in /etc/apt/sources.list(.d) (second form).
71It is capable of downloading several packages at once.
72
73   -a, --all       Package is a source package; download all binary packages
74   -b, --backup    Move files that would be overwritten to ./backup
75   -q, --quiet     Suppress wget/curl output
76   -d, --download-only
77                   Do not extract downloaded source
78   -x, --extract   Unpack downloaded source (default)
79   -u, --allow-unauthenticated
80                   Do not attempt to verify source package signature
81   --build         Build package with dpkg-buildpackage after download
82   --path DIR      Check these directories in addition to the apt archive;
83                   if DIR='' then clear current list (may be used multiple
84                   times)
85   --insecure      Do not check SSL certificates when downloading
86   --no-cache      Disable server-side HTTP cache
87   --no-conf       Don\'t read devscripts config files;
88                   must be the first option given
89   -h, --help      This message
90   -V, --version   Version information
91
92Default settings modified by devscripts configuration files:
93$modified_conf_msg
94EOT
95}
96
97sub version {
98    print <<"EOF";
99This is $progname, from the Debian devscripts package, version ###VERSION###
100This code is copyright 2005-08 by Christoph Berg <myon\@debian.org>.
101Modifications copyright 2005-06 by Julian Gilbey <jdg\@debian.org>.
102All rights reserved.
103This program comes with ABSOLUTELY NO WARRANTY.
104You are free to redistribute this code under the terms of the
105GNU General Public License, version 2 or later.
106EOF
107}
108
109sub wget {
110    my ($file, $url) = @_;
111
112    # schemes not supported by all backends
113    if ($url =~ m!^(file|copy):(.+)!) {
114        my $path = abs_path($2);
115        unless ($path) {
116            warn "$progname: unable to resolve full path for $2: $!\n";
117            return 1;
118        }
119        if ($1 eq "copy" or not link($path, $file)) {
120            system 'cp', '-aL', $path, $file;
121            return $? >> 8;
122        }
123        return;
124    }
125
126    my @cmd = ($wget);
127    # curl does not follow document moved headers, and does not exit
128    # with a non-zero error code by default if a document is not found
129    push @cmd, "-f", "-L" if $wget eq "curl";
130    push @cmd, ($wget eq "wget" ? "-nv" : ("-s", "-S")) if $opt->{'quiet'};
131    push @cmd, ($wget eq "wget" ? "--no-check-certificate" : "--insecure")
132      if $opt->{'insecure'};
133    push @cmd,
134      ($wget eq "wget" ? "--no-cache" : ("--header", "Pragma: no-cache"))
135      if $opt->{'no-cache'};
136    push @cmd, ($wget eq "wget" ? "-O" : "-o");
137    system @cmd, $file, $url;
138    return $? >> 8;
139}
140
141sub backup_or_unlink {
142    my $file = shift;
143    return unless -e $file;
144    if ($opt->{'backup'}) {
145        unless (-d $backup_dir) {
146            mkdir $backup_dir or die "mkdir $backup_dir: $!";
147        }
148        rename $file, "$backup_dir/$file"
149          or die "rename $file $backup_dir/$file: $!";
150    } else {
151        unlink $file or die "unlink $file: $!";
152    }
153}
154
155# some files both are in .dsc and .changes, download only once
156my %seen;
157
158sub get_file {
159    my ($dir, $file, $md5sum) = @_;
160    return 1 if $seen{$file};
161
162    if ($md5sum eq "unlink") {
163        backup_or_unlink($file);
164    }
165
166    # check the existing file's md5sum
167    if (-e $file) {
168        my $md5        = Digest::MD5->new;
169        my $fh5        = new IO::File($file) or die "$file: $!";
170        my $md5sum_new = Digest::MD5->new->addfile($fh5)->hexdigest();
171        close $fh5;
172        if (not $md5sum or ($md5sum_new eq $md5sum)) {
173            print "$progname: using existing $file\n" unless $opt->{'quiet'};
174        } else {
175            print "$progname: removing $file (md5sum does not match)\n"
176              unless $opt->{'quiet'};
177            backup_or_unlink($file);
178        }
179    }
180
181    # look for the file in other local directories
182    unless (-e $file) {
183        foreach my $path (@dget_path) {
184            next unless -e "$path/$file";
185
186            my $fh5        = new IO::File("$path/$file") or next;
187            my $md5        = Digest::MD5->new;
188            my $md5sum_new = Digest::MD5->new->addfile($fh5)->hexdigest();
189            close $fh5;
190
191            if ($md5sum_new eq $md5sum) {
192                if (link "$path/$file", $file) {
193                    print "$progname: using $path/$file (hardlink)\n"
194                      unless $opt->{'quiet'};
195                } else {
196                    print "$progname: using $path/$file (copy)\n"
197                      unless $opt->{'quiet'};
198                    system 'cp', '-aL', "$path/$file", $file;
199                }
200                last;
201            }
202        }
203    }
204
205    # finally get it from the web
206    unless (-e $file) {
207        print "$progname: retrieving $dir/$file\n" unless $opt->{'quiet'};
208        if (wget($file, "$dir/$file")) {
209            warn "$progname: $wget $file $dir/$file failed\n";
210            unlink $file;
211        }
212    }
213
214    # try apt-get if it is still not there
215    my $ext = $compression_re;
216    if (not -e $file
217        and $file =~ m!^([a-z0-9][a-z0-9.+-]+)_[^/]+\.(?:diff|tar)\.$ext$!) {
218        my @cmd = ('apt-get', 'source', '--print-uris', $1);
219        my $cmd = join ' ', @cmd;
220        open(my $apt, '-|', @cmd) or die "$cmd: $!";
221        while (<$apt>) {
222            if (/'(\S+)'\s+\S+\s+\d+\s+([\da-f]+)/i and $2 eq $md5sum) {
223                if (wget($file, $1)) {
224                    warn "$progname: $wget $file $1 failed\n";
225                    unlink $file;
226                }
227            }
228        }
229        close $apt;
230    }
231
232    # still not there, return
233    unless (-e $file) {
234        return 0;
235    }
236
237    $seen{$file} = 1;
238
239    if ($file =~ /\.(?:changes|dsc)$/) {
240        parse_file($dir, $file);
241    }
242    if ($file =~ /\.dsc$/) {
243        $found_dsc = $file;
244    }
245
246    return 1;
247}
248
249sub parse_file {
250    my ($dir, $file) = @_;
251
252    my $fh = new IO::File($file);
253    open $fh, $file or die "$file: $!";
254    while (<$fh>) {
255        if (/^ ([0-9a-f]{32}) (?:\S+ )*(\S+)$/) {
256            my ($_sum, $_file) = ($1, $2);
257            $_file !~ m,[/\x00],
258              or die "File name contains invalid characters: $_file";
259            get_file($dir, $_file, $_sum) or return;
260        }
261    }
262    close $fh;
263}
264
265sub quote_version {
266    my $version = shift;
267    $version = quotemeta($version);
268    $version =~ s/^([^:]+:)/(?:$1)?/;    # Epochs are not part of the filename
269    $version
270      =~ s/-([^.-]+)$/-$1(?:\\+b\\d+|\.0\.\\d+)?/; # BinNMU: -x -> -x.0.1 -x+by
271    $version =~ s/-([^.-]+\.[^.-]+)$/-$1(?:\\+b\\d+|\.\\d+)?/
272      ;                                            # -x.y -> -x.y.1 -x.y+bz
273    return $version;
274}
275
276# we reinvent "apt-get -d install" here, without requiring root
277# (and we do not download dependencies)
278sub apt_get {
279    my ($package, $version) = @_;
280
281    my ($archpackage, $arch) = $package;
282    ($package, $arch) = split(/:/, $package, 2);
283
284    my $qpackage = quotemeta($package);
285    my $qversion = quote_version($version) if $version;
286    my @hosts;
287
288    my $apt = IO::File->new("LC_ALL=C apt-cache policy $archpackage |")
289      or die "$!";
290  OUTER: while (<$apt>) {
291        if (not $version and /^  Candidate: (.+)/) {
292            $version  = $1;
293            $qversion = quote_version($version);
294        }
295        if ($qversion and /^ [ *]{3} ($qversion) \d/) {
296            while (<$apt>) {
297                last OUTER unless /^  *(?:\d+) (\S+)/;
298                (my $host = $1) =~ s@/$@@;
299                next if $host eq '/var/lib/dpkg/status';
300                push @hosts, $host;
301            }
302        }
303    }
304    close $apt;
305    unless ($version) {
306        die "$progname: $archpackage has no installation candidate\n";
307    }
308    unless (@hosts) {
309        die
310"$progname: no hostnames in apt-cache policy $archpackage for version $version found\n";
311    }
312
313    $apt = IO::File->new("LC_ALL=C apt-cache show $archpackage=$version |")
314      or die "$!";
315    my ($v, $p, $filename, $md5sum);
316    while (<$apt>) {
317        if (/^Package: $qpackage$/) {
318            $p = $package;
319        }
320        if (/^Version: $qversion$/) {
321            $v = $version;
322        }
323        if (/^Filename: (.*)/) {
324            $filename = $1;
325        }
326        if (/^MD5sum: (.*)/) {
327            $md5sum = $1;
328        }
329        if (/^Description:/) {    # we assume this is the last field
330            if ($p and $v and $filename) {
331                last;
332            }
333            undef $p;
334            undef $v;
335            undef $filename;
336            undef $md5sum;
337        }
338    }
339    close $apt;
340
341    unless ($filename) {
342        die "$progname: no filename for $archpackage ($version) found\n";
343    }
344
345    # find deb lines matching the hosts in the policy output
346    my %repositories;
347# the regexp within the map below can be removed and replaced with only the quotemeta statement once bug #154868 is fixed
348    my $host_re = '(?:' . (
349        join '|',
350        map {
351            my $host = quotemeta;
352            $host =~ s@^(\w+\\:\\/\\/[^:/]+)\\/@$1(?::[0-9]+)?\\/@;
353            $host;
354        } @hosts
355    ) . ')';
356
357    my @sources;
358    if (-f "/etc/apt/sources.list") {
359        push @sources, "/etc/apt/sources.list";
360    }
361    my %dir;
362    tie %dir, "IO::Dir", "/etc/apt/sources.list.d";
363    foreach (keys %dir) {
364        next unless /\.list$/;
365        push @sources, "/etc/apt/sources.list.d/$_";
366    }
367
368    foreach my $source (@sources) {
369        $apt = IO::File->new($source) or die "$source: $!";
370        while (<$apt>) {
371            if (/^\s*deb\s*(?:\[[^]]*\]\s*)?($host_re\b)/) {
372                $repositories{$1} = 1;
373            }
374        }
375        close $apt;
376    }
377    unless (%repositories) {
378        die "no repository found in /etc/apt/sources.list or sources.list.d";
379    }
380
381    # try each repository in turn
382    foreach my $repository (keys %repositories) {
383        my ($dir, $file) = ($repository, $filename);
384        if ($filename =~ /(.*)\/([^\/]*)$/) {
385            ($dir, $file) = ("$repository/$1", $2);
386        }
387
388        get_file($dir, $file, $md5sum) and return;
389    }
390    exit 1;
391}
392
393# main program
394
395# Now start by reading configuration files and then command line
396# The next stuff is boilerplate
397
398my ($dget_path, $dget_unpack, $dget_verify);
399
400if (@ARGV and $ARGV[0] =~ /^--no-?conf$/) {
401    $modified_conf_msg = "  (no configuration files read)";
402    shift;
403} else {
404    my @config_files = ('/etc/devscripts.conf', '~/.devscripts');
405    my %config_vars  = (
406        'DGET_PATH'   => '',
407        'DGET_UNPACK' => 'yes',
408        'DGET_VERIFY' => 'yes',
409    );
410    my %config_default = %config_vars;
411
412    my $shell_cmd;
413    # Set defaults
414    foreach my $var (keys %config_vars) {
415        $shell_cmd .= "$var='$config_vars{$var}';\n";
416    }
417    $shell_cmd .= 'for file in ' . join(" ", @config_files) . "; do\n";
418    $shell_cmd .= '[ -f $file ] && . $file; done;' . "\n";
419    # Read back values
420    foreach my $var (keys %config_vars) { $shell_cmd .= "echo \$$var;\n" }
421    my $shell_out = `/bin/bash -c '$shell_cmd'`;
422    @config_vars{ keys %config_vars } = split /\n/, $shell_out, -1;
423
424    foreach my $var (sort keys %config_vars) {
425        if ($config_vars{$var} ne $config_default{$var}) {
426            $modified_conf_msg .= "  $var=$config_vars{$var}\n";
427        }
428    }
429    $modified_conf_msg ||= "  (none)\n";
430    chomp $modified_conf_msg;
431
432    $dget_path   = $config_vars{'DGET_PATH'};
433    $dget_unpack = $config_vars{'DGET_UNPACK'} =~ /^y/i;
434    $dget_verify = $config_vars{'DGET_VERIFY'} =~ /^y/i;
435}
436
437# handle options
438Getopt::Long::Configure('bundling');
439GetOptions(
440    "a|all"                   => \$opt->{'all'},
441    "b|backup"                => \$opt->{'backup'},
442    "q|quiet"                 => \$opt->{'quiet'},
443    "build"                   => \$opt->{'build'},
444    "d|download-only"         => sub { $dget_unpack = 0 },
445    "x|extract"               => sub { $dget_unpack = 1 },
446    "u|allow-unauthenticated" => sub { $dget_verify = 0 },
447    "insecure"                => \$opt->{'insecure'},
448    "no-cache"                => \$opt->{'no-cache'},
449    "noconf|no-conf"          => \$opt->{'no-conf'},
450    "path=s"                  => sub {
451        if ($_[1] eq '') { $dget_path = ''; }
452        else             { $dget_path .= ":$_[1]"; }
453    },
454    "h|help"    => \$opt->{'help'},
455    "V|version" => \$opt->{'version'},
456  )
457  or die
458  "$progname: unrecognised option. Run $progname --help for more details.\n";
459
460if ($opt->{'help'})    { usage();   exit 0; }
461if ($opt->{'version'}) { version(); exit 0; }
462if ($opt->{'no-conf'}) {
463    die
464"$progname: --no-conf is only acceptable as the first command-line option!\n";
465}
466
467if ($dget_path) {
468    foreach my $p (split /:/, $dget_path) {
469        push @dget_path, $p if -d $p;
470    }
471}
472
473if (!@ARGV) {
474    die
475"Usage: $progname [options] URL|package[=version]\nRun $progname --help for more details.\n";
476}
477
478# handle arguments
479for my $arg (@ARGV) {
480    $found_dsc = "";
481
482    # case 1: URL
483    if ($arg
484        =~ /^((?:copy|file|ftp|gopher|http|rsh|rsync|scp|sftp|ssh|www).*)\/([^\/]+\.\w+)$/
485    ) {
486        get_file($1, $2, "unlink") or exit 1;
487        if ($found_dsc) {
488            if ($dget_verify) {    # We are duplicating work here a bit as
489                    # dpkg-source -x will also verify signatures. Still, we
490                    # also want to barf with -d, and on unsigned packages.
491                system 'dscverify', $found_dsc;
492                exit $? >> 8 if $? >> 8 != 0;
493            }
494            my @cmd = qw(dpkg-source -x);
495            push @cmd, '--no-check' unless $dget_verify;
496            if ($opt->{'build'}) {
497                my @output = `LC_ALL=C @cmd $found_dsc`;
498                my $rc     = $?;
499                print @output unless $opt->{'quiet'};
500                exit $rc >> 8 if $rc >> 8 != 0;
501                foreach (@output) {
502                    if (/^dpkg-source: (?:info: )?extracting .* in (.*)/) {
503                        chdir $1;
504                        exec 'dpkg-buildpackage', '-b', '-uc';
505                        die "Unable to run dpkg-buildpackage: $!";
506                    }
507                }
508            } elsif ($dget_unpack) {
509                system @cmd, $found_dsc;
510                exit $? >> 8 if $? >> 8 != 0;
511            }
512        }
513
514        # case 2a: --all srcpackage[=version]
515    } elsif ($opt->{'all'}
516        and $arg =~ /^([a-z0-9.+-:]{2,})(?:=([a-zA-Z0-9.:~+-]+))?$/) {
517        my ($source, $version, $arch) = ($1, $2);
518        ($source, $arch) = split(/:/, $source, 2);
519        my $cmd = "apt-cache showsrc $source";
520        # unfortunately =version doesn't work here, and even if it did, was the
521        # user referring to the source version or the binary version?  The code
522        # assumes binary version.
523        #$cmd .= "=$version" if ($version);
524        open my $showsrc, '-|', $cmd;
525        my $c = Dpkg::Control->new(type => CTRL_INDEX_SRC);
526        while ($c->parse($showsrc, $cmd)) {
527            if ($arch) {
528                my @packages = grep { $_ } split /\n/, $c->{'Package-List'};
529                # Find all packages whose architecture is either 'all', 'any',
530                # or the given architecture.  The Package-List lines are
531                # $pkg $debtype $section $priority arch=$archlist
532                foreach my $package (@packages) {
533                    $package =~ s/^\s*//;
534                    my ($binary, $debtype, $section, $priority, $archs)
535                      = split(/\s+/, $package, 5);
536                    if ($archs =~ m/all/) {
537                        eval { apt_get($binary, $version) } or print "$@";
538                    } elsif ($archs =~ m/any|[=,]$arch/) {
539                        eval { apt_get("$binary:$arch", $version) }
540                          or print "$@";
541                    }
542                }
543            } else {
544                my @packages = split /, /, $c->{Binary};
545                foreach my $package (@packages) {
546                    eval { apt_get($package, $version) } or print "$@";
547                }
548            }
549            last;
550        }
551        close $showsrc;
552
553        # case 2b: package[=version]
554    } elsif ($arg =~ /^([a-z0-9.+-:]{2,})(?:=([a-zA-Z0-9.:~+-]+))?$/) {
555        apt_get($1, $2);
556
557    } else {
558        usage();
559    }
560}
561
562=head1 NAME
563
564dget - Download Debian source and binary packages
565
566=head1 SYNOPSIS
567
568=over
569
570=item B<dget> [I<options>] I<URL> ...
571
572=item B<dget> [I<options>] [B<--all>] I<package>[B<=>I<version>] ...
573
574=back
575
576=head1 DESCRIPTION
577
578B<dget> downloads Debian packages.  In the first form, B<dget> fetches
579the requested URLs.  If this is a .dsc or .changes file, then B<dget>
580acts as a source-package aware form of B<wget>: it also fetches any
581files referenced in the .dsc/.changes file.  The downloaded source is
582then checked with B<dscverify> and, if successful, unpacked by
583B<dpkg-source>.
584
585In the second form, B<dget> downloads a I<binary> package (i.e., a
586I<.deb> file) from the Debian mirror configured in
587/etc/apt/sources.list(.d).  Unlike B<apt-get install -d>, it does not
588require root privileges, writes to the current directory, and does not
589download dependencies.  If a version number is specified, this version
590of the package is requested.  With B<--all>, the list of all binaries for the
591source package I<package> is extracted from the output of
592C<apt-cache showsrc package>.
593
594In both cases dget is capable of getting several packages and/or URLs
595at once.
596
597(Note that I<.udeb> packages used by debian-installer are located in separate
598packages files from I<.deb> packages. In order to use I<.udebs> with B<dget>,
599you will need to have configured B<apt> to use a packages file for
600I<component>/I<debian-installer>).
601
602Before downloading files listed in .dsc and .changes files, and before
603downloading binary packages, B<dget> checks to see whether any of
604these files already exist.  If they do, then their md5sums are
605compared to avoid downloading them again unnecessarily.  B<dget> also
606looks for matching files in I</var/cache/apt/archives> and directories
607given by the B<--path> option or specified in the configuration files
608(see below).  Finally, if downloading (.orig).tar.gz or .diff.gz files
609fails, dget consults B<apt-get source --print-uris>.  Download backends
610used are B<curl> and B<wget>, looked for in that order.
611
612B<dget> was written to make it easier to retrieve source packages from
613the web for sponsor uploads.  For checking the package with
614B<debdiff>, the last binary version is available via B<dget>
615I<package>, the last source version via B<apt-get source> I<package>.
616
617=head1 OPTIONS
618
619=over 4
620
621=item B<-a>, B<--all>
622
623Interpret I<package> as a source package name, and download all binaries as
624found in the output of "apt-cache showsrc I<package>".  If I<package> is
625arch-qualified, then only binary packages which are "Arch: all", "Arch: any",
626or "Arch: $arch" will be downloaded.
627
628=item B<-b>, B<--backup>
629
630Move files that would be overwritten to I<./backup>.
631
632=item B<-q>, B<--quiet>
633
634Suppress B<wget>/B<curl> non-error output.
635
636=item B<-d>, B<--download-only>
637
638Do not run B<dpkg-source -x> on the downloaded source package.  This can
639only be used with the first method of calling B<dget>.
640
641=item B<-x>, B<--extract>
642
643Run B<dpkg-source -x> on the downloaded source package to unpack it.
644This option is the default and can only be used with the first method of
645calling B<dget>.
646
647=item B<-u>, B<--allow-unauthenticated>
648
649Do not attempt to verify the integrity of downloaded source packages
650using B<dscverify>.
651
652=item B<--build>
653
654Run B<dpkg-buildpackage -b -uc> on the downloaded source package.
655
656=item B<--path> I<DIR>[B<:>I<DIR> ...]
657
658In addition to I</var/cache/apt/archives>, B<dget> uses the
659colon-separated list given as argument to B<--path> to find files with
660a matching md5sum.  For example: "--path
661/srv/pbuilder/result:/home/cb/UploadQueue".  If DIR is empty (i.e.,
662"--path ''" is specified), then any previously listed directories
663or directories specified in the configuration files will be ignored.
664This option may be specified multiple times, and all of the
665directories listed will be searched; hence, the above example could
666have been written as: "--path /srv/pbuilder/result --path
667/home/cb/UploadQueue".
668
669=item B<--insecure>
670
671Allow SSL connections to untrusted hosts.
672
673=item B<--no-cache>
674
675Bypass server-side HTTP caches by sending a B<Pragma: no-cache> header.
676
677=item B<-h>, B<--help>
678
679Show a help message.
680
681=item B<-V>, B<--version>
682
683Show version information.
684
685=back
686
687=head1 CONFIGURATION VARIABLES
688
689The two configuration files F</etc/devscripts.conf> and
690F<~/.devscripts> are sourced by a shell in that order to set
691configuration variables.  Command line options can be used to override
692configuration file settings.  Environment variable settings are
693ignored for this purpose.  The currently recognised variable is:
694
695=over 4
696
697=item B<DGET_PATH>
698
699This can be set to a colon-separated list of directories in which to
700search for files in addition to the default
701I</var/cache/apt/archives>.  It has the same effect as the B<--path>
702command line option.  It is not set by default.
703
704=item B<DGET_UNPACK>
705
706Set to 'no' to disable extracting downloaded source packages.  Default
707is 'yes'.
708
709=item B<DGET_VERIFY>
710
711Set to 'no' to disable checking signatures of downloaded source
712packages.  Default is 'yes'.
713
714=back
715
716=head1 EXAMPLES
717
718Download all I<.deb> files for the previous version of a package and run B<debdiff>
719on them:
720
721  dget --all mypackage=1.2-1
722  debdiff --from *_1.2-1_*.deb --to *_1.2-2_*.deb
723
724=head1 BUGS AND COMPATIBILITY
725
726B<dget> I<package> should be implemented in B<apt-get install -d>.
727
728Before devscripts version 2.10.17, the default was not to extract the
729downloaded source. Set DGET_UNPACK=no to revert to the old behaviour.
730
731=head1 AUTHOR
732
733This program is Copyright (C) 2005-2013 by Christoph Berg <myon@debian.org>.
734Modifications are Copyright (C) 2005-06 by Julian Gilbey <jdg@debian.org>.
735
736This program is licensed under the terms of the GPL, either version 2
737of the License, or (at your option) any later version.
738
739=head1 SEE ALSO
740
741B<apt-get>(1), B<curl>(1), B<debcheckout>(1), B<debdiff>(1), B<dpkg-source>(1),
742B<wget>(1)
743