chiark / gitweb /
dgit(1); Mention that -wgf can avoid need for build-deps.
[dgit.git] / dgit
diff --git a/dgit b/dgit
index 19c0657b17eb6741edf3112c8fba0ed9ce9d76b5..079e5dec7c212c0c4ea1be9ecb76f4891af75cfb 100755 (executable)
--- a/dgit
+++ b/dgit
@@ -111,7 +111,7 @@ sub lref () { return "refs/heads/".lbranch(); }
 sub lrref () { return "refs/remotes/$remotename/".server_branch($csuite); }
 sub rrref () { return server_ref($csuite); }
 
-sub lrfetchrefs () { return "refs/dgit-fetch/$isuite"; }
+sub lrfetchrefs () { return "refs/dgit-fetch/$csuite"; }
 
 sub stripepoch ($) {
     my ($vsn) = @_;
@@ -448,6 +448,7 @@ our %defcfg = ('dgit.default.distro' => 'debian',
               'dgit-distro.debian.git-user-force' => 'dgit',
               'dgit-distro.debian.git-proto' => 'git+ssh://',
               'dgit-distro.debian.git-path' => '/dgit/debian/repos',
+              'dgit-distro.debian.git-create' => 'true',
               'dgit-distro.debian.git-check' => 'ssh-cmd',
  'dgit-distro.debian.archive-query-url', 'https://api.ftp-master.debian.org/',
 # 'dgit-distro.debian.archive-query-tls-key',
@@ -1020,7 +1021,7 @@ sub check_for_git () {
            my ($usedistro,) = access_distros();
            $instead_distro= cfg("dgit-distro.$usedistro.diverts.$divert");
            $instead_distro =~ s{^/}{ access_basedistro()."/" }e;
-           printdebug "diverting $divert so using distro $instead_distro\n";
+           progress "diverting to $divert (using config for $instead_distro)";
            return check_for_git();
        }
        failedcmd @cmd unless $r =~ m/^[01]$/;
@@ -1343,12 +1344,33 @@ sub ensure_we_have_orig () {
 }
 
 sub git_fetch_us () {
-    runcmd_ordryrun_local @git, qw(fetch),access_giturl(),fetchspec();
-    if (deliberately_not_fast_forward) {
-       runcmd_ordryrun_local @git, qw(fetch -p), access_giturl(),
-           map { "+refs/$_/*:".lrfetchrefs."/$_/*" }
-           qw(tags heads);
-    }
+    my @specs = (fetchspec());
+    push @specs,
+        map { "+refs/$_/*:".lrfetchrefs."/$_/*" }
+        qw(tags heads);
+    runcmd_ordryrun_local @git, qw(fetch -p -n -q), access_giturl(), @specs;
+
+    my %here;
+    my $tagpat = debiantag('*',access_basedistro);
+
+    git_for_each_ref("refs/tags/".$tagpat, sub {
+       my ($objid,$objtype,$fullrefname,$reftail) = @_;
+       printdebug "currently $fullrefname=$objid\n";
+       $here{$fullrefname} = $objid;
+    });
+    git_for_each_ref(lrfetchrefs."/tags/".$tagpat, sub {
+       my ($objid,$objtype,$fullrefname,$reftail) = @_;
+       my $lref = "refs".substr($fullrefname, length lrfetchrefs);
+       printdebug "offered $lref=$objid\n";
+       if (!defined $here{$lref}) {
+           my @upd = (@git, qw(update-ref), $lref, $objid, '');
+           runcmd_ordryrun_local @upd;
+       } elsif ($here{$lref} eq $objid) {
+       } else {
+           print STDERR \
+               "Not updateting $lref from $here{$lref} to $objid.\n";
+       }
+    });
 }
 
 sub fetch_from_archive () {
@@ -1455,6 +1477,38 @@ END
     return 1;
 }
 
+sub set_local_git_config ($$) {
+    my ($k, $v) = @_;
+    runcmd @git, qw(config), $k, $v;
+}
+
+sub setup_mergechangelogs () {
+    my $driver = 'dpkg-mergechangelogs';
+    my $cb = "merge.$driver";
+    my $attrs = '.git/info/attributes';
+    ensuredir '.git/info';
+
+    open NATTRS, ">", "$attrs.new" or die "$attrs.new $!";
+    if (!open ATTRS, "<", $attrs) {
+       $!==ENOENT or die "$attrs: $!";
+    } else {
+       while (<ATTRS>) {
+           chomp;
+           next if m{^debian/changelog\s};
+           print NATTRS $_, "\n" or die $!;
+       }
+       ATTRS->error and die $!;
+       close ATTRS;
+    }
+    print NATTRS "debian/changelog merge=$driver\n" or die $!;
+    close NATTRS;
+
+    set_local_git_config "$cb.name", 'debian/changelog merge driver';
+    set_local_git_config "$cb.driver", 'dpkg-mergechangelogs -m %O %A %B %A';
+
+    rename "$attrs.new", "$attrs" or die "$attrs: $!";
+}
+
 sub clone ($) {
     my ($dstdir) = @_;
     canonicalise_suite();
@@ -1465,7 +1519,7 @@ sub clone ($) {
     runcmd @git, qw(init -q);
     my $giturl = access_giturl(1);
     if (defined $giturl) {
-       runcmd @git, qw(config), "remote.$remotename.fetch", fetchspec();
+       set_local_git_config "remote.$remotename.fetch", fetchspec();
        open H, "> .git/HEAD" or die $!;
        print H "ref: ".lref()."\n" or die $!;
        close H or die $!;
@@ -1484,6 +1538,7 @@ sub clone ($) {
        $vcsgiturl =~ s/\s+-b\s+\S+//g;
        runcmd @git, qw(remote add vcs-git), $vcsgiturl;
     }
+    setup_mergechangelogs();
     runcmd @git, qw(reset --hard), lrref();
     printdone "ready for work in $dstdir";
 }
@@ -1570,7 +1625,7 @@ sub push_parse_changelog ($) {
 
     $package = getfield $clogp, 'Source';
     my $cversion = getfield $clogp, 'Version';
-    my $tag = debiantag($cversion);
+    my $tag = debiantag($cversion, access_basedistro);
     runcmd @git, qw(check-ref-format), $tag;
 
     my $dscfn = dscfn($cversion);
@@ -1768,7 +1823,6 @@ sub dopush ($) {
     my $tag_obj_hash = cmdoutput @git, qw(hash-object -w -t tag), $tagobjfn;
     runcmd_ordryrun @git, qw(verify-tag), $tag_obj_hash;
     runcmd_ordryrun_local @git, qw(update-ref), "refs/tags/$tag", $tag_obj_hash;
-    runcmd_ordryrun @git, qw(tag -v --), $tag;
 
     if (!check_for_git()) {
        create_remote_git_repo();
@@ -1897,10 +1951,12 @@ sub cmd_push {
     if ($new_package) {
        local ($package) = $existing_package; # this is a hack
        canonicalise_suite();
-    }
-    if (defined $specsuite && $specsuite ne $isuite) {
+    } else {
        canonicalise_suite();
-       $csuite eq $specsuite or
+    }
+    if (defined $specsuite &&
+       $specsuite ne $isuite &&
+       $specsuite ne $csuite) {
            fail "dgit push: changelog specifies $isuite ($csuite)".
                " but command line specifies $specsuite";
     }
@@ -2579,6 +2635,8 @@ sub clean_tree () {
        runcmd_ordryrun_local @dpkgbuildpackage, qw(-T clean);
     } elsif ($cleanmode eq 'git') {
        runcmd_ordryrun_local @git, qw(clean -xdf);
+    } elsif ($cleanmode eq 'git-ff') {
+       runcmd_ordryrun_local @git, qw(clean -xdff);
     } elsif ($cleanmode eq 'none') {
     } else {
        die "$cleanmode ?";
@@ -2628,17 +2686,35 @@ sub changesopts () {
     return @opts;
 }
 
+sub massage_dbp_args ($) {
+    my ($cmd) = @_;
+    return unless $cleanmode =~ m/git|none/;
+    debugcmd '#massaging#', @$cmd if $debuglevel>1;
+    my @newcmd = shift @$cmd;
+    # -nc has the side effect of specifying -b if nothing else specified
+    push @newcmd, '-nc';
+    # and some combinations of -S, -b, et al, are errors, rather than
+    # later simply overriding earlier
+    push @newcmd, '-F' unless grep { m/^-[bBASF]$/ } @$cmd;
+    push @newcmd, @$cmd;
+    @$cmd = @newcmd;
+}
+
 sub cmd_build {
     build_prep();
-    runcmd_ordryrun_local @dpkgbuildpackage, qw(-us -uc), changesopts(), @ARGV;
+    my @dbp = (@dpkgbuildpackage, qw(-us -uc), changesopts(), @ARGV);
+    massage_dbp_args \@dbp;
+    runcmd_ordryrun_local @dbp;
     printdone "build successful\n";
 }
 
 sub cmd_git_build {
     build_prep();
+    my @dbp = @dpkgbuildpackage;
+    massage_dbp_args \@dbp;
     my @cmd =
        (qw(git-buildpackage -us -uc --git-no-sign-tags),
-        "--git-builder=@dpkgbuildpackage");
+        "--git-builder=@dbp");
     unless (grep { m/^--git-debian-branch|^--git-ignore-branch/ } @ARGV) {
        canonicalise_suite();
        push @cmd, "--git-debian-branch=".lbranch();
@@ -2679,7 +2755,7 @@ sub cmd_sbuild {
     changedir "..";
     my $pat = "${package}_".(stripepoch $version)."_*.changes";
     if (act_local()) {
-       stat_exist $dscfn or fail "$dscfn (in parent directory): $!";
+       stat_exists $dscfn or fail "$dscfn (in parent directory): $!";
        stat_exists $sourcechanges
            or fail "$sourcechanges (in parent directory): $!";
        foreach my $cf (glob $pat) {
@@ -2728,6 +2804,11 @@ sub cmd_clone_dgit_repos_server {
     exec @cmd or fail "exec git clone: $!\n";
 }
 
+sub cmd_setup_mergechangelogs {
+    badusage "no arguments allowed to dgit setup-mergechangelogs" if @ARGV;
+    setup_mergechangelogs();
+}
+
 #---------- argument parsing and main program ----------
 
 sub cmd_version {
@@ -2792,7 +2873,7 @@ sub parseopts () {
            } elsif (m/^--build-products-dir=(.*)/s) {
                push @ropts, $_;
                $buildproductsdir = $1;
-           } elsif (m/^--clean=(dpkg-source|git|none)$/s) {
+           } elsif (m/^--clean=(dpkg-source|git|git-ff|none)$/s) {
                push @ropts, $_;
                $cleanmode = $1;
            } elsif (m/^--clean=(.*)$/s) {
@@ -2864,6 +2945,9 @@ sub parseopts () {
                } elsif (s/^-wg$//s) {
                    push @ropts, $&;
                    $cleanmode = 'git';
+               } elsif (s/^-wgf$//s) {
+                   push @ropts, $&;
+                   $cleanmode = 'git-ff';
                } elsif (s/^-wd$//s) {
                    push @ropts, $&;
                    $cleanmode = 'dpkg-source';