chiark / gitweb /
Test suite: orig-include-exclude: Test orig tarball hash mismatch
[dgit.git] / Debian / Dgit.pm
index ac44b9ab4c529f712a0c9322d2c1e2b146702250..57ae99418a1fc79bc4e734d15b18a36f09b5f529 100644 (file)
@@ -1,13 +1,33 @@
 # -*- perl -*-
+# dgit
+# Debian::Dgit: functions common to dgit and its helpers and servers
+#
+# Copyright (C) 2015-2016  Ian Jackson
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Debian::Dgit;
 
 use strict;
 use warnings;
 
+use Carp;
 use POSIX;
 use IO::Handle;
 use Config;
+use Digest::SHA;
+use Data::Dumper;
 
 BEGIN {
     use Exporter   ();
@@ -16,9 +36,13 @@ BEGIN {
     $VERSION     = 1.00;
     @ISA         = qw(Exporter);
     @EXPORT      = qw(setup_sigwarn
-                      debiantag server_branch server_ref
-                      stat_exists fail ensuredir executable_on_path
-                      waitstatusmsg failedcmd
+                      debiantags debiantag_old debiantag_new
+                     server_branch server_ref
+                      stat_exists link_ltarget
+                     hashfile
+                      fail ensuredir executable_on_path
+                      waitstatusmsg failedcmd_waitstatus
+                     failedcmd_report_cmd failedcmd
                       cmdoutput cmdoutput_errok
                       git_rev_parse git_get_ref git_for_each_ref
                       git_for_each_tag_referring is_fast_fwd
@@ -120,12 +144,23 @@ sub debugcmd {
     printcmd(\*DEBUG,$debugprefix.$extraprefix,@_) if $debuglevel>0;
 }
 
-sub debiantag ($$) { 
+sub debiantag_old ($$) { 
     my ($v,$distro) = @_;
     $v =~ y/~:/_%/;
     return "$distro/$v";
 }
 
+sub debiantag_new ($$) { 
+    my ($v,$distro) = @_;
+    $v =~ y/~:/_%/;
+    return "archive/$distro/$v";
+}
+
+sub debiantags ($$) {
+    my ($version,$distro) = @_;
+    map { $_->($version, $distro) } (\&debiantag_new, \&debiantag_old);
+}
+
 sub server_branch ($) { return "$branchprefix/$_[0]"; }
 sub server_ref ($) { return "refs/".server_branch($_[0]); }
 
@@ -142,6 +177,7 @@ sub _us () {
 
 sub fail { 
     my $s = "@_\n";
+    $s =~ s/\n\n$/\n/;
     my $prefix = _us().": ";
     $s =~ s/^/$prefix/gm;
     die $s;
@@ -182,19 +218,40 @@ sub waitstatusmsg () {
     }
 }
 
-sub failedcmd {
-    { local ($!); printcmd \*STDERR, _us().": failed command:", @_ or die $!; };
-    if ($!) {
-       fail "failed to fork/exec: $!";
+sub failedcmd_report_cmd {
+    my $intro = shift @_;
+    $intro //= "failed command";
+    { local ($!); printcmd \*STDERR, _us().": $intro:", @_ or die $!; };
+}
+
+sub failedcmd_waitstatus {
+    if ($? < 0) {
+       return "failed to fork/exec: $!";
     } elsif ($?) {
-       fail "subprocess ".waitstatusmsg();
+       return "subprocess ".waitstatusmsg();
     } else {
-       fail "subprocess produced invalid output";
+       return "subprocess produced invalid output";
     }
 }
 
+sub failedcmd {
+    # Expects $!,$? as set by close - see below.
+    # To use with system(), set $?=-1 first.
+    #
+    # Actual behaviour of perl operations:
+    #   success              $!==0       $?==0       close of piped open
+    #   program failed       $!==0       $? >0       close of piped open
+    #   syscall failure      $! >0       $?=-1       close of piped open
+    #   failure              $! >0       unchanged   close of something else
+    #   success              trashed     $?==0       system
+    #   program failed       trashed     $? >0       system
+    #   syscall failure      $! >0       unchanged   system
+    failedcmd_report_cmd undef, @_;
+    fail failedcmd_waitstatus();
+}
+
 sub cmdoutput_errok {
-    die Dumper(\@_)." ?" if grep { !defined } @_;
+    confess Dumper(\@_)." ?" if grep { !defined } @_;
     debugcmd "|",@_;
     open P, "-|", @_ or die "$_[0] $!";
     my $d;
@@ -219,6 +276,22 @@ sub cmdoutput {
     return $d;
 }
 
+sub link_ltarget ($$) {
+    my ($old,$new) = @_;
+    lstat $old or return undef;
+    if (-l _) {
+       $old = cmdoutput qw(realpath  --), $old;
+    }
+    link $old, $new or die "link $old $new: $!";
+}
+
+sub hashfile ($) {
+    my ($fn) = @_;
+    my $h = Digest::SHA->new(256);
+    $h->addfile($fn);
+    return $h->hexdigest();
+}
+
 sub git_rev_parse ($) {
     return cmdoutput qw(git rev-parse), "$_[0]~0";
 }
@@ -228,7 +301,9 @@ sub git_for_each_ref ($$;$) {
     # calls $func->($objid,$objtype,$fullrefname,$reftail);
     # $reftail is RHS of ref after refs/[^/]+/
     # breaks if $pattern matches any ref `refs/blah' where blah has no `/'
-    my @cmd = (qw(git for-each-ref), $pattern);
+    # $pattern may be an array ref to mean multiple patterns
+    $pattern = [ $pattern ] unless ref $pattern;
+    my @cmd = (qw(git for-each-ref), @$pattern);
     if (defined $gitdir) {
        @cmd = ('sh','-ec','cd "$1"; shift; exec "$@"','x', $gitdir, @cmd);
     }