X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=dgit.git;a=blobdiff_plain;f=dgit;h=faffba6202a0cc6d0f6616a494aae807355eaa70;hp=ea9652438ff5b4935609d29d21824845519e8c75;hb=9308011c98e2dc4d930efb0991fe92467c23c4ad;hpb=8c95b29b79a159e5153f51affece9cf9314b4d84 diff --git a/dgit b/dgit index ea965243..faffba62 100755 --- a/dgit +++ b/dgit @@ -444,11 +444,15 @@ our %defcfg = ('dgit.default.distro' => 'debian', 'dgit.default.archive-query' => 'madison:', 'dgit.default.sshpsql-dbname' => 'service=projectb', 'dgit-distro.debian.archive-query' => 'ftpmasterapi:', - 'dgit-distro.debian.git-host' => 'dgit-git.debian.net', - '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-check' => 'ssh-cmd', + 'dgit-distro.debian.git-check' => 'url', + 'dgit-distro.debian.git-check-suffix' => '/info/refs', + 'dgit-distro.debian/push.git-url' => '', + 'dgit-distro.debian/push.git-host' => 'push.dgit.debian.org', + 'dgit-distro.debian/push.git-user-force' => 'dgit', + 'dgit-distro.debian/push.git-proto' => 'git+ssh://', + 'dgit-distro.debian/push.git-path' => '/dgit/debian/repos', + 'dgit-distro.debian/push.git-create' => 'true', + 'dgit-distro.debian/push.git-check' => 'ssh-cmd', 'dgit-distro.debian.archive-query-url', 'https://api.ftp-master.debian.org/', # 'dgit-distro.debian.archive-query-tls-key', # '/etc/ssl/certs/%HOST%.pem:/etc/dgit/%HOST%.pem', @@ -459,12 +463,8 @@ our %defcfg = ('dgit.default.distro' => 'debian', # 'dgit-distro.debian.archive-query-tls-curl-args', # '--ca-path=/etc/ssl/ca-debian', # ^ this is a workaround but works (only) on DSA-administered machines - 'dgit-distro.debian.diverts.alioth' => '/alioth', - 'dgit-distro.debian/alioth.git-host' => 'git.debian.org', - 'dgit-distro.debian/alioth.git-user-force' => '', - 'dgit-distro.debian/alioth.git-proto' => 'git+ssh://', - 'dgit-distro.debian/alioth.git-path' => '/git/dgit-repos/repos', - 'dgit-distro.debian/alioth.git-create' => 'ssh-cmd', + 'dgit-distro.debian.git-url' => 'https://git.dgit.debian.org', + 'dgit-distro.debian.git-url-suffix' => '', 'dgit-distro.debian.upload-host' => 'ftp-master', # for dput 'dgit-distro.debian.mirror' => 'http://ftp.debian.org/debian/', 'dgit-distro.debian.backports-quirk' => '(squeeze)-backports*', @@ -484,20 +484,35 @@ our %defcfg = ('dgit.default.distro' => 'debian', 'dgit-distro.test-dummy.upload-host' => 'test-dummy', ); +sub git_get_config ($) { + my ($c) = @_; + + our %git_get_config_memo; + if (exists $git_get_config_memo{$c}) { + return $git_get_config_memo{$c}; + } + + my $v; + my @cmd = (@git, qw(config --), $c); + { + local ($debuglevel) = $debuglevel-2; + $v = cmdoutput_errok @cmd; + }; + if ($?==0) { + } elsif ($?==256) { + $v = undef; + } else { + failedcmd @cmd; + } + $git_get_config_memo{$c} = $v; + return $v; +} + sub cfg { foreach my $c (@_) { return undef if $c =~ /RETURN-UNDEF/; - my @cmd = (@git, qw(config --), $c); - my $v; - { - local ($debuglevel) = $debuglevel-2; - $v = cmdoutput_errok @cmd; - }; - if ($?==0) { - return $v; - } elsif ($?!=256) { - failedcmd @cmd; - } + my $v = git_get_config($c); + return $v if defined $v; my $dv = $defcfg{$c}; return $dv if defined $dv; } @@ -532,6 +547,12 @@ sub access_quirk () { return ('none',undef); } +our $access_pushing = 0; + +sub pushing () { + $access_pushing = 1; +} + sub access_distros () { # Returns list of distros to try, in order # @@ -545,7 +566,12 @@ sub access_distros () { my (undef,$quirkdistro) = access_quirk(); unshift @l, $quirkdistro; unshift @l, $instead_distro; - return grep { defined } @l; + @l = grep { defined } @l; + + if ($access_pushing) { + @l = map { ("$_/push", $_) } @l; + } + @l; } sub access_cfg (@) { @@ -618,15 +644,19 @@ sub access_gituserhost () { sub access_giturl (;$) { my ($optional) = @_; my $url = access_cfg('git-url','RETURN-UNDEF'); - if (!defined $url) { + my $suffix; + if (!length $url) { my $proto = access_cfg('git-proto', 'RETURN-UNDEF'); return undef unless defined $proto; $url = $proto. access_gituserhost(). access_cfg('git-path'); + } else { + $suffix = access_cfg('git-url-suffix','RETURN-UNDEF'); } - return "$url/$package.git"; + $suffix //= '.git'; + return "$url/$package$suffix"; } sub parsecontrolfh ($$;$) { @@ -1018,13 +1048,32 @@ sub check_for_git () { if ($r =~ m/^divert (\w+)$/) { my $divert=$1; my ($usedistro,) = access_distros(); + # NB that if we are pushing, $usedistro will be $distro/push $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]$/; return $r+0; + } elsif ($how eq 'url') { + my $prefix = access_cfg('git-check-url','git-url'); + my $suffix = access_cfg('git-check-suffix','git-suffix', + 'RETURN-UNDEF') // '.git'; + my $url = "$prefix/$package$suffix"; + my @cmd = (qw(curl -sS -I), $url); + my $result = cmdoutput @cmd; + $result =~ m/^\S+ (404|200) /s or + fail "unexpected results from git check query - ". + Dumper($prefix, $result); + my $code = $1; + if ($code eq '404') { + return 0; + } elsif ($code eq '200') { + return 1; + } else { + die; + } } elsif ($how eq 'true') { return 1; } elsif ($how eq 'false') { @@ -1347,7 +1396,7 @@ sub git_fetch_us () { push @specs, map { "+refs/$_/*:".lrfetchrefs."/$_/*" } qw(tags heads); - runcmd_ordryrun_local @git, qw(fetch -p -n), access_giturl(), @specs; + runcmd_ordryrun_local @git, qw(fetch -p -n -q), access_giturl(), @specs; my %here; my $tagpat = debiantag('*',access_basedistro); @@ -1476,6 +1525,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 () { + 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(); @@ -1486,7 +1567,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 $!; @@ -1505,6 +1586,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"; } @@ -1734,12 +1816,6 @@ sub dopush ($) { failedcmd @diffcmd; } } -#fetch from alioth -#do fast forward check and maybe fake merge -# if (!is_fast_fwd(mainbranch -# runcmd @git, qw(fetch -p ), "$alioth_git/$package.git", -# map { lref($_).":".rref($_) } -# (uploadbranch()); my $head = git_rev_parse('HEAD'); if (!$changesfile) { my $multi = "$buildproductsdir/". @@ -1789,7 +1865,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(); @@ -1902,6 +1977,7 @@ sub cmd_pull { } sub cmd_push { + pushing(); parseopts(); badusage "-p is not allowed with dgit push" if defined $package; check_not_dirty(); @@ -1955,6 +2031,7 @@ sub cmd_push { #---------- remote commands' implementation ---------- sub cmd_remote_push_build_host { + pushing(); my ($nrargs) = shift @ARGV; my (@rargs) = @ARGV[0..$nrargs-1]; @ARGV = @ARGV[$nrargs..$#ARGV]; @@ -2015,6 +2092,7 @@ sub i_method { } sub cmd_rpush { + pushing(); my $host = nextarg; my $dir; if ($host =~ m/^((?:[^][]|\[[^][]*\])*)\:/) { @@ -2600,8 +2678,18 @@ sub quilt_fixup_editor () { sub clean_tree () { if ($cleanmode eq 'dpkg-source') { runcmd_ordryrun_local @dpkgbuildpackage, qw(-T clean); + } elsif ($cleanmode eq 'dpkg-source-d') { + runcmd_ordryrun_local @dpkgbuildpackage, qw(-d -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 'check') { + my $leftovers = cmdoutput @git, qw(clean -xdn); + if (length $leftovers) { + print STDERR $leftovers, "\n" or die $!; + fail "tree contains uncommitted files and --clean=check specified"; + } } elsif ($cleanmode eq 'none') { } else { die "$cleanmode ?"; @@ -2696,6 +2784,9 @@ sub build_source { if ($cleanmode eq 'dpkg-source') { runcmd_ordryrun_local (@dpkgbuildpackage, qw(-us -uc -S)), changesopts(); + } elsif ($cleanmode eq 'dpkg-source-d') { + runcmd_ordryrun_local (@dpkgbuildpackage, qw(-us -uc -S -d)), + changesopts(); } else { my $pwd = must_getcwd(); my $leafdir = basename $pwd; @@ -2720,7 +2811,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) { @@ -2769,6 +2860,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 { @@ -2833,7 +2929,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(?:-d)?|git|git-ff|check|none)$/s) { push @ropts, $_; $cleanmode = $1; } elsif (m/^--clean=(.*)$/s) { @@ -2905,9 +3001,18 @@ 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'; + } elsif (s/^-wdd$//s) { + push @ropts, $&; + $cleanmode = 'dpkg-source-d'; + } elsif (s/^-wc$//s) { + push @ropts, $&; + $cleanmode = 'check'; } else { badusage "unknown short option \`$_'"; }