chiark / gitweb /
New cleaning arrangements (wip).
[dgit.git] / dgit
diff --git a/dgit b/dgit
index 22596134bb94027477209cd9baba3ac53ea1330c..37b235b33e4a4741b16c328304915bf1d95f41f3 100755 (executable)
--- a/dgit
+++ b/dgit
@@ -24,6 +24,7 @@ use Data::Dumper;
 use LWP::UserAgent;
 use Dpkg::Control::Hash;
 use File::Path;
+use File::Basename;
 use Dpkg::Version;
 use POSIX;
 
@@ -36,6 +37,7 @@ our $dryrun = 0;
 our $changesfile;
 our $new_package = 0;
 our $existing_package = 'dpkg';
+our $clean = 'dpkg-source';
 
 our %format_ok = map { $_=>1 } ("1.0","3.0 (native)","3.0 (quilt)");
 
@@ -45,14 +47,19 @@ our (@dput) = qw(dput);
 our (@debsign) = qw(debsign);
 our (@sbuild) = qw(sbuild -A);
 our (@dpkgbuildpackage) = qw(dpkg-buildpackage -i\.git/ -I.git);
+our (@dpkgsource) = qw(dpkg-source -i\.git/ -I.git);
+our (@dpkggenchanges) = qw(dpkg-genchanges);
 our (@mergechanges) = qw(mergechanges -f);
-
+our (@changesopts) = ('');
 
 our %opts_opt_map = ('dget' => \@dget,
                     'dput' => \@dput,
                     'debsign' => \@debsign,
                      'sbuild' => \@sbuild,
+                     'dpkg-source' => \@dpkgsource,
                      'dpkg-buildpackage' => \@dpkgbuildpackage,
+                     'dpkg-genchanges' => \@dpkggenchanges,
+                     'ch' => \@changesopts,
                      'mergechanges' => \@mergechanges);
 
 our $keyid;
@@ -78,6 +85,8 @@ sub debiantag ($) {
 
 sub dscfn ($) { return "${package}_$_[0].dsc"; }
 
+sub changesopts () { return @changesopts[1..$#changesopts]; }
+
 our $us = 'dgit';
 
 sub fail { die "$us: @_\n"; }
@@ -104,6 +113,7 @@ sub url_get {
     my $what = $_[$#_];
     print "downloading $what...\n";
     my $r = $ua->get(@_) or die $!;
+    return undef if $r->code == 404;
     $r->is_success or fail "failed to fetch $what: ".$r->status_line;
     return $r->decoded_content();
 }
@@ -372,26 +382,27 @@ sub canonicalise_suite_sshdakls ($$) {
 
 sub madison_parse ($) {
     my ($rmad) = @_;
-    if (!length $rmad) {
-       return ();
-    }
-    $rmad =~ m{^ \s*( [^ \t|]+ )\s* \|
-                 \s*( [^ \t|]+ )\s* \|
-                 \s*( [^ \t|/]+ )(?:/([^ \t|/]+))? \s* \|
-                 \s*( [^ \t|]+ )\s* }x or die "$rmad $?";
-    $1 eq $package or die "$rmad $package ?";
-    my $vsn = $2;
-    my $newsuite = $3;
-    my $component;
-    if (defined $4) {
-       $component = $4;
-    } else {
-       $component = access_cfg('archive-query-default-component');
+    my @out;
+    foreach my $l (split /\n/, $rmad) {
+       $l =~ m{^ \s*( [^ \t|]+ )\s* \|
+                  \s*( [^ \t|]+ )\s* \|
+                  \s*( [^ \t|/]+ )(?:/([^ \t|/]+))? \s* \|
+                  \s*( [^ \t|]+ )\s* }x or die "$rmad $?";
+       $1 eq $package or die "$rmad $package ?";
+       my $vsn = $2;
+       my $newsuite = $3;
+       my $component;
+       if (defined $4) {
+           $component = $4;
+       } else {
+           $component = access_cfg('archive-query-default-component');
+       }
+       $5 eq 'source' or die "$rmad ?";
+       my $prefix = substr($package, 0, $package =~ m/^l/ ? 4 : 1);
+       my $subpath = "/pool/$component/$prefix/$package/${package}_$vsn.dsc";
+       push @out, [$vsn,$subpath,$newsuite];
     }
-    $5 eq 'source' or die "$rmad ?";
-    my $prefix = substr($package, 0, $package =~ m/^l/ ? 4 : 1);
-    my $subpath = "/pool/$component/$prefix/$package/${package}_$vsn.dsc";
-    return ($vsn,$subpath,$newsuite);
+    return sort { -version_compare_string($a->[0],$b->[0]); } @out;
 }
 
 sub canonicalise_suite_madison ($$) {
@@ -400,7 +411,7 @@ sub canonicalise_suite_madison ($$) {
        "unable to canonicalise suite using package $package".
        " which does not appear to exist in suite $isuite;".
        " --existing-package may help";
-    return $r[2];
+    return $r[0][2];
 }
 
 sub canonicalise_suite () {
@@ -412,17 +423,24 @@ sub canonicalise_suite () {
 }
 
 sub get_archive_dsc () {
-    my ($vsn,$subpath) = archive_query('archive_query');
     canonicalise_suite();
-    if (!defined $vsn) { $dsc=undef; return undef; }
-    $dscurl = access_cfg('mirror').$subpath;
-    $dscdata = url_get($dscurl);
-    my $dscfh = new IO::File \$dscdata, '<' or die $!;
-    print DEBUG Dumper($dscdata) if $debug>1;
-    $dsc = parsecontrolfh($dscfh,$dscurl, allow_pgp=>1);
-    print DEBUG Dumper($dsc) if $debug>1;
-    my $fmt = getfield $dsc, 'Format';
-    fail "unsupported source format $fmt, sorry" unless $format_ok{$fmt};
+    my @vsns = archive_query('archive_query');
+    foreach my $vinfo (@vsns) {
+       my ($vsn,$subpath) = @$vinfo;
+       $dscurl = access_cfg('mirror').$subpath;
+       $dscdata = url_get($dscurl);
+       next unless defined $dscdata;
+       $dscurl = access_cfg('mirror').$subpath;
+       $dscdata = url_get($dscurl);
+       my $dscfh = new IO::File \$dscdata, '<' or die $!;
+       print DEBUG Dumper($dscdata) if $debug>1;
+       $dsc = parsecontrolfh($dscfh,$dscurl, allow_pgp=>1);
+       print DEBUG Dumper($dsc) if $debug>1;
+       my $fmt = getfield $dsc, 'Format';
+       fail "unsupported source format $fmt, sorry" unless $format_ok{$fmt};
+       return $dsc;
+    }
+    return undef;
 }
 
 sub check_for_git () {
@@ -447,9 +465,7 @@ sub create_remote_git_repo () {
        runcmd_ordryrun
            (access_cfg('ssh'),access_gituserhost(),
             "set -e; cd ".access_cfg('git-path').";".
-            " mkdir -p $package.git;".
-            " cd $package.git;".
-            " if ! test -d objects; then git init --bare; fi");
+            " cp -a _template $package.git");
     } else {
        badcfg "unknown git-create \`$how'";
     }
@@ -652,11 +668,12 @@ sub fetch_from_archive () {
     if (defined $dsc_hash) {
        fail "missing git history even though dsc has hash -".
            " could not find commit $dsc_hash".
-           " (should be in ".access_giturl()."#".rref().")"
+           " (should be in ".access_giturl()."#".rrref().")"
            unless $upload_hash;
        $hash = $dsc_hash;
        ensure_we_have_orig();
-       if (is_fast_fwd($dsc_hash,$upload_hash)) {
+       if ($dsc_hash eq $upload_hash) {
+       } elsif (is_fast_fwd($dsc_hash,$upload_hash)) {
            print STDERR <<END or die $!;
 
 Git commit in archive is behind the last version allegedly pushed/uploaded.
@@ -665,6 +682,9 @@ Last allegedly pushed/uploaded: $upload_hash
 $later_warning_msg
 END
            $hash = $upload_hash;
+       } else {
+           fail "archive's .dsc refers to ".$dsc_hash.
+               " but this is an ancestor of ".$upload_hash;
        }
     } else {
        $hash = generate_commit_from_dsc();
@@ -927,6 +947,9 @@ sub cmd_push {
     } else {
        badusage "incorrect arguments to dgit push";
     }
+    if (check_for_git()) {
+       git_fetch_us();
+    }
     if (fetch_from_archive()) {
        is_fast_fwd(lrref(), 'HEAD') or die;
     } else {
@@ -940,6 +963,7 @@ sub cmd_push {
 sub cmd_build {
     # we pass further options and args to git-buildpackage
     badusage "-p is not allowed with dgit build" if defined $package;
+    badusage "dgit build implies --clean=dpkg-source" if defined $package;
     my $clogp = parsechangelog();
     $isuite = getfield $clogp, 'Distribution';
     $package = getfield $clogp, 'Source';
@@ -950,21 +974,54 @@ sub cmd_build {
        canonicalise_suite();
        push @cmd, "--git-debian-branch=".lbranch();
     }
+    push @cmd, changesopts();
     runcmd_ordryrun @cmd, @ARGV;
     printdone "build successful\n";
 }
 
-sub cmd_sbuild {
+our $version;
+our $sourcechanges;
+our $dscfn;
+
+sub build_source {
     check_not_dirty();
-    badusage "-p is not allowed with dgit sbuild" if defined $package;
+    badusage "-p is not allowed with this action" if defined $package;
     my $clogp = parsechangelog();
     $package = getfield $clogp, 'Source';
     my $isuite = getfield $clogp, 'Distribution';
-    my $version = getfield $clogp, 'Version';
-    runcmd_ordryrun (@dpkgbuildpackage, qw(-us -uc -S));
+    $version = getfield $clogp, 'Version';
+    $sourcechanges = "${package}_${version}_source.changes";
+    $dscfn = dscfn($version);
+    if ($cleanmode eq 'dpkg-source') {
+       runcmd_ordryrun (@dpkgbuildpackage, qw(-us -uc -S)), changesopts();
+    } else {
+       if ($cleanmode eq 'git') {
+           runcmd_ordryrun @git, qw(clean -xdf);
+       } elsif ($cleanmode eq 'none') {
+       } else {
+           die "$cleanmode ?";
+       }
+       my $pwd = cmdoutput qw(env - pwd);
+       my $leafdir = basename $pwd;
+       chdir ".." or die $!;
+       runcmd_ordryrun @dpkgsource, qw(-b --), $leafdir;
+       chdir $pwd or die $!;
+       runcmd_ordryrun qw(sh -ec),
+           'exec >$1; shift; exec "$@"','x',
+           $sourcechanges,
+           @dpkggenchanges, qw(-S), changesopts();
+    }
+}
+
+sub cmd_build_source {
+    badusage "build-source takes no additional arguments" if @ARGV;
+    build_source();
+    printdone "source built, results in $dscfn and $sourcechanges";
+}
+
+sub cmd_sbuild {
+    build_source();
     chdir ".." or die $!;
-    my $sourcechanges = "${package}_${version}_source.changes";
-    my $dscfn = dscfn($version);
     my $pat = "${package}_${version}_*.changes";
     if (!$dryrun) {
        stat $dscfn or fail "$dscfn (in parent directory): $!";
@@ -1004,14 +1061,21 @@ sub parseopts () {
                helponly();
            } elsif (m/^--new$/) {
                $new_package=1;
-           } elsif (m/^--(\w+)=(.*)/s && ($om = $opts_opt_map{$1})) {
+           } elsif (m/^--(\w+)=(.*)/s &&
+                    ($om = $opts_opt_map{$1}) &&
+                    length $om->[0]) {
                $om->[0] = $2;
-           } elsif (m/^--(\w+):(.*)/s && ($om = $opts_opt_map{$1})) {
+           } elsif (m/^--(\w+):(.*)/s &&
+                    ($om = $opts_opt_map{$1})) {
                push @$om, $2;
            } elsif (m/^--existing-package=(.*)/s) {
                $existing_package = $1;
            } elsif (m/^--distro=(.*)/s) {
                $idistro = $1;
+           } elsif (m/^--clean=(dpkg-source|git|none)$/s) {
+               $cleanmode = $1;
+           } elsif (m/^--clean=(.*)$/s) {
+               badusage "unknown cleaning mode \`$1'";
            } else {
                badusage "unknown long option \`$_'";
            }
@@ -1026,6 +1090,9 @@ sub parseopts () {
                    $debug++;
                } elsif (s/^-N/-/) {
                    $new_package=1;
+               } elsif (m/^-[vm]/) {
+                   push @changesopts, $_;
+                   $_ = '';
                } elsif (s/^-c(.*=.*)//s) {
                    push @git, '-c', $1;
                } elsif (s/^-d(.*)//s) {