X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=Debian%2FDgit.pm;h=455cb10189ebdd57588cd20071bc1909cc771341;hb=0d1f068aa2f32704bda24c57f13f3fec96859d84;hp=f68b7c9113404ae7fb46c0475daaaf90da5cdf31;hpb=d471fbd414ac2d25ae0f6b7693c5f15272cd80ee;p=dgit.git diff --git a/Debian/Dgit.pm b/Debian/Dgit.pm index f68b7c91..455cb101 100644 --- a/Debian/Dgit.pm +++ b/Debian/Dgit.pm @@ -32,6 +32,8 @@ use IPC::Open2; use File::Path; use File::Basename; use Dpkg::Control::Hash; +use Debian::Dgit::ExitStatus; +use Debian::Dgit::I18n; BEGIN { use Exporter (); @@ -41,22 +43,24 @@ BEGIN { @ISA = qw(Exporter); @EXPORT = qw(setup_sigwarn forkcheck_setup forkcheck_mainprocess dep14_version_mangle - debiantags debiantag_old debiantag_new + debiantags debiantag_new debiantag_maintview upstreamversion stripepoch source_file_leafname is_orig_file_of_p_v server_branch server_ref - stat_exists link_ltarget + stat_exists link_ltarget rename_link_xf hashfile fail failmsg ensuredir must_getcwd executable_on_path waitstatusmsg failedcmd_waitstatus failedcmd_report_cmd failedcmd runcmd shell_cmd cmdoutput cmdoutput_errok - git_rev_parse git_cat_file + git_rev_parse changedir_git_toplevel git_cat_file git_get_ref git_get_symref git_for_each_ref git_for_each_tag_referring is_fast_fwd git_check_unmodified git_reflog_action_msg git_update_ref_cmd + make_commit_text + reflog_cache_insert reflog_cache_lookup $package_re $component_re $deliberately_re $distro_re $versiontag_re $series_filename_re $orig_f_comp_re $orig_f_sig_re $orig_f_tail_re @@ -94,7 +98,7 @@ our $distro_re = $component_re; our $versiontag_re = qr{[-+.\%_0-9a-zA-Z/]+}; our $branchprefix = 'dgit'; our $series_filename_re = qr{(?:^|\.)series(?!\n)$}s; -our $extra_orig_namepart_re = qr{[-0-9a-z]+}; +our $extra_orig_namepart_re = qr{[-0-9a-zA-Z]+}; our $orig_f_comp_re = qr{orig(?:-$extra_orig_namepart_re)?}; our $orig_f_sig_re = '\\.(?:asc|gpg|pgp)'; our $orig_f_tail_re = "$orig_f_comp_re\\.tar(?:\\.\\w+)?(?:$orig_f_sig_re)?"; @@ -104,6 +108,11 @@ our $gdrlast_refprefix = 'debrebase-last'; our $printdebug_when_debuglevel = 1; our $debugcmd_when_debuglevel = 1; +# these three all go together, only valid after record_maindir +our $maindir; +our $maindir_gitdir; +our $maindir_gitcommon; + # policy hook exit status bits # see dgit-repos-server head comment for documentation # 1 is reserved in case something fails with `exit 1' and to spot @@ -139,18 +148,18 @@ sub setup_sigwarn () { sub initdebug ($) { ($debugprefix) = @_; - open DEBUG, ">/dev/null" or die $!; + open DEBUG, ">/dev/null" or confess "$!"; } sub enabledebug () { - open DEBUG, ">&STDERR" or die $!; + open DEBUG, ">&STDERR" or confess "$!"; DEBUG->autoflush(1); $debuglevel ||= 1; } sub enabledebuglevel ($) { my ($newlevel) = @_; # may be undef (eg from env var) - die if $debuglevel; + confess if $debuglevel; $newlevel //= 0; $newlevel += 0; return unless $newlevel; @@ -172,7 +181,7 @@ sub printdebug { print DEBUG $debugprefix unless $printdebug_noprefix; pop @_ while @_ and !length $_[-1]; return unless @_; - print DEBUG @_ or die $!; + print DEBUG @_ or confess "$!"; $printdebug_noprefix = $_[-1] !~ m{\n$}; } @@ -189,7 +198,7 @@ sub messagequote ($) { sub shellquote { my @out; local $_; - defined or confess 'internal error' foreach @_; + defined or confess __ 'internal error' foreach @_; foreach my $a (@_) { $_ = $a; if (!length || m{[^-=_./:0-9a-z]}i) { @@ -205,9 +214,9 @@ sub shellquote { sub printcmd { my $fh = shift @_; my $intro = shift @_; - print $fh $intro," " or die $!; - print $fh shellquote @_ or die $!; - print $fh "\n" or die $!; + print $fh $intro," " or confess "$!"; + print $fh shellquote @_ or confess "$!"; + print $fh "\n" or confess "$!"; } sub debugcmd { @@ -224,11 +233,6 @@ sub dep14_version_mangle ($) { return $v; } -sub debiantag_old ($$) { - my ($v,$distro) = @_; - return "$distro/". dep14_version_mangle $v; -} - sub debiantag_new ($$) { my ($v,$distro) = @_; return "archive/$distro/".dep14_version_mangle $v; @@ -241,7 +245,7 @@ sub debiantag_maintview ($$) { sub debiantags ($$) { my ($version,$distro) = @_; - map { $_->($version, $distro) } (\&debiantag_new, \&debiantag_old); + map { $_->($version, $distro) } (\&debiantag_new, \&debiantag_maintview); } sub stripepoch ($) { @@ -275,7 +279,7 @@ sub stat_exists ($) { my ($f) = @_; return 1 if stat $f; return 0 if $!==&ENOENT; - die "stat $f: $!"; + confess "stat $f: $!"; } sub _us () { @@ -283,7 +287,7 @@ sub _us () { } sub failmsg { - my $s = "error: @_\n"; + my $s = f_ "error: %s\n", "@_"; $s =~ s/\n\n$/\n/g; my $prefix = _us().": "; $s =~ s/^/$prefix/gm; @@ -298,12 +302,12 @@ sub ensuredir ($) { my ($dir) = @_; # does not create parents return if mkdir $dir; return if $! == EEXIST; - die "mkdir $dir: $!"; + confess "mkdir $dir: $!"; } sub must_getcwd () { my $d = getcwd(); - defined $d or fail "getcwd failed: $!"; + defined $d or fail f_ "getcwd failed: %s\n", $!; return $d; } @@ -322,32 +326,32 @@ our @signames = split / /, $Config{sig_name}; sub waitstatusmsg () { if (!$?) { - return "terminated, reporting successful completion"; + return __ "terminated, reporting successful completion"; } elsif (!($? & 255)) { - return "failed with error exit status ".WEXITSTATUS($?); + return f_ "failed with error exit status %s", WEXITSTATUS($?); } elsif (WIFSIGNALED($?)) { my $signum=WTERMSIG($?); - return "died due to fatal signal ". + return f_ "died due to fatal signal %s", ($signames[$signum] // "number $signum"). ($? & 128 ? " (core dumped)" : ""); # POSIX(3pm) has no WCOREDUMP } else { - return "failed with unknown wait status ".$?; + return f_ "failed with unknown wait status %s", $?; } } sub failedcmd_report_cmd { my $intro = shift @_; - $intro //= "failed command"; - { local ($!); printcmd \*STDERR, _us().": $intro:", @_ or die $!; }; + $intro //= __ "failed command"; + { local ($!); printcmd \*STDERR, _us().": $intro:", @_ or confess "$!"; }; } sub failedcmd_waitstatus { if ($? < 0) { - return "failed to fork/exec: $!"; + return f_ "failed to fork/exec: %s", $!; } elsif ($?) { - return "subprocess ".waitstatusmsg(); + return f_ "subprocess %s", waitstatusmsg(); } else { - return "subprocess produced invalid output"; + return __ "subprocess produced invalid output"; } } @@ -382,11 +386,11 @@ sub cmdoutput_errok { confess Dumper(\@_)." ?" if grep { !defined } @_; local $printdebug_when_debuglevel = $debugcmd_when_debuglevel; debugcmd "|",@_; - open P, "-|", @_ or die "$_[0] $!"; + open P, "-|", @_ or confess "$_[0] $!"; my $d; $!=0; $?=0; { local $/ = undef; $d =
; }
- die $! if P->error;
+ confess "$!" if P->error;
if (!close P) { printdebug "=>!$?\n"; return undef; }
chomp $d;
if ($debuglevel > 0) {
@@ -413,7 +417,71 @@ sub link_ltarget ($$) {
}
my $r = link $old, $new;
$r = symlink $old, $new if !$r && $!==EXDEV;
- $r or die "(sym)link $old $new: $!";
+ $r or fail "(sym)link $old $new: $!\n";
+}
+
+sub rename_link_xf ($$$) {
+ # renames/moves or links/copies $src to $dst,
+ # even if $dst is on a different fs
+ # (May use the filename "$dst.tmp".);
+ # On success, returns true.
+ # On failure, returns false and sets
+ # $@ to a reason message
+ # $! to an errno value, or -1 if not known
+ # having possibly printed something about mv to stderr.
+ # Not safe to use without $keeporig if $dst might be a symlink
+ # to $src, as it might delete $src leaving $dst invalid.
+ my ($keeporig,$src,$dst) = @_;
+ if ($keeporig
+ ? link $src, $dst
+ : rename $src, $dst) {
+ return 1;
+ }
+ if ($! != EXDEV) {
+ $@ = "$!";
+ return 0;
+ }
+ if (!stat $src) {
+ $@ = f_ "stat source file: %S", $!;
+ return 0;
+ }
+ my @src_stat = (stat _)[0..1];
+
+ my @dst_stat;
+ if (stat $dst) {
+ @dst_stat = (stat _)[0..1];
+ } elsif ($! == ENOENT) {
+ } else {
+ $@ = f_ "stat destination file: %S", $!;
+ return 0;
+ }
+
+ if ("@src_stat" eq "@dst_stat") {
+ # (Symlinks to) the same file. No need for a copy but
+ # we may need to delete the original.
+ printdebug "rename_link_xf $keeporig $src $dst EXDEV but same\n";
+ } else {
+ $!=0; $?=0;
+ my @cmd = (qw(cp --), $src, "$dst.tmp");
+ debugcmd '+',@cmd;
+ if (system @cmd) {
+ failedcmd_report_cmd undef, @cmd;
+ $@ = failedcmd_waitstatus();
+ $! = -1;
+ return 0;
+ }
+ if (!rename "$dst.tmp", $dst) {
+ $@ = f_ "finally install file after cp: %S", $!;
+ return 0;
+ }
+ }
+ if (!$keeporig) {
+ if (!unlink $src) {
+ $@ = f_ "delete old file after cp: %S", $!;
+ return 0;
+ }
+ }
+ return 1;
}
sub hashfile ($) {
@@ -427,6 +495,15 @@ sub git_rev_parse ($) {
return cmdoutput qw(git rev-parse), "$_[0]~0";
}
+sub changedir_git_toplevel () {
+ my $toplevel = cmdoutput qw(git rev-parse --show-toplevel);
+ length $toplevel or fail __ <