X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=git-archimport.perl;h=b5f8a2c64b080697e34a0efea44dbbe05210a6cf;hb=2777ef76be7174f698b3f53cc4ff38b4118de320;hp=e22c81628dbde8a16c0bef5f64d3e6b34fba4f26;hpb=f84f9d38ebd809ecab89d2d4926c3ff6bc3c60f5;p=git.git diff --git a/git-archimport.perl b/git-archimport.perl index e22c8162..b5f8a2c6 100755 --- a/git-archimport.perl +++ b/git-archimport.perl @@ -30,6 +30,24 @@ See man (1) git-archimport for more details. Add print in front of the shell commands invoked via backticks. +=head1 Devel Notes + +There are several places where Arch and git terminology are intermixed +and potentially confused. + +The notion of a "branch" in git is approximately equivalent to +a "archive/category--branch--version" in Arch. Also, it should be noted +that the "--branch" portion of "archive/category--branch--version" is really +optional in Arch although not many people (nor tools!) seem to know this. +This means that "archive/category--version" is also a valid "branch" +in git terms. + +We always refer to Arch names by their fully qualified variant (which +means the "archive" name is prefixed. + +For people unfamiliar with Arch, an "archive" is the term for "repository", +and can contain multiple, unrelated branches. + =cut use strict; @@ -52,14 +70,14 @@ $ENV{'TZ'}="UTC"; my $git_dir = $ENV{"GIT_DIR"} || ".git"; $ENV{"GIT_DIR"} = $git_dir; +my $ptag_dir = "$git_dir/archimport/tags"; -our($opt_h,$opt_v, $opt_T, - $opt_C,$opt_t); +our($opt_h,$opt_v, $opt_T,$opt_t,$opt_o); sub usage() { print STDERR < part: +sub old_style_branchname { + my $id = shift; + my $ret = safe_pipe_capture($TLA,'parse-package-name','-p',$id); + chomp $ret; + return $ret; +} - $ps->{branch} = branchname($ps->{id}); +*git_branchname = $opt_o ? *old_style_branchname : *tree_dirname; + +# process patchsets +foreach my $ps (@psets) { + $ps->{branch} = git_branchname($ps->{id}); # # ensure we have a clean state @@ -410,8 +472,7 @@ foreach my $ps (@psets) { open HEAD, ">$git_dir/refs/heads/$ps->{branch}"; print HEAD $commitid; close HEAD; - unlink ("$git_dir/HEAD"); - symlink("refs/heads/$ps->{branch}","$git_dir/HEAD"); + system('git-update-ref', 'HEAD', "$ps->{branch}"); # tag accordingly ptag($ps->{id}, $commitid); # private tag @@ -425,16 +486,9 @@ foreach my $ps (@psets) { $opt_v && print " + parents: $par \n"; } -sub branchname { - my $id = shift; - $id =~ s#^.+?/##; - my @parts = split(m/--/, $id); - return join('--', @parts[0..1]); -} - sub apply_import { my $ps = shift; - my $bname = branchname($ps->{id}); + my $bname = git_branchname($ps->{id}); `mkdir -p $tmp`; @@ -582,19 +636,24 @@ sub parselog { # write/read a tag sub tag { my ($tag, $commit) = @_; - $tag =~ s|/|--|g; - $tag = shell_quote($tag); + + if ($opt_o) { + $tag =~ s|/|--|g; + } else { + # don't use subdirs for tags yet, it could screw up other porcelains + $tag =~ s|/|,|g; + } if ($commit) { - open(C,">$git_dir/refs/tags/$tag") + open(C,">","$git_dir/refs/tags/$tag") or die "Cannot create tag $tag: $!\n"; print C "$commit\n" or die "Cannot write tag $tag: $!\n"; close(C) or die "Cannot write tag $tag: $!\n"; - print " * Created tag ' $tag' on '$commit'\n" if $opt_v; + print " * Created tag '$tag' on '$commit'\n" if $opt_v; } else { # read - open(C,"<$git_dir/refs/tags/$tag") + open(C,"<","$git_dir/refs/tags/$tag") or die "Cannot read tag $tag: $!\n"; $commit = ; chomp $commit; @@ -609,15 +668,16 @@ sub tag { # reads fail softly if the tag isn't there sub ptag { my ($tag, $commit) = @_; - $tag =~ s|/|--|g; - $tag = shell_quote($tag); + + # don't use subdirs for tags yet, it could screw up other porcelains + $tag =~ s|/|,|g; - unless (-d "$git_dir/archimport/tags") { - mkpath("$git_dir/archimport/tags"); - } + my $tag_file = "$ptag_dir/$tag"; + my $tag_branch_dir = dirname($tag_file); + mkpath($tag_branch_dir) unless (-d $tag_branch_dir); if ($commit) { # write - open(C,">$git_dir/archimport/tags/$tag") + open(C,">",$tag_file) or die "Cannot create tag $tag: $!\n"; print C "$commit\n" or die "Cannot write tag $tag: $!\n"; @@ -627,10 +687,10 @@ sub ptag { unless $tag =~ m/--base-0$/; } else { # read # if the tag isn't there, return 0 - unless ( -s "$git_dir/archimport/tags/$tag") { + unless ( -s $tag_file) { return 0; } - open(C,"<$git_dir/archimport/tags/$tag") + open(C,"<",$tag_file) or die "Cannot read tag $tag: $!\n"; $commit = ; chomp $commit; @@ -663,7 +723,7 @@ sub find_parents { # simple loop to split the merges # per branch foreach my $merge (@{$ps->{merges}}) { - my $branch = branchname($merge); + my $branch = git_branchname($merge); unless (defined $branches{$branch} ){ $branches{$branch} = []; } @@ -687,7 +747,13 @@ sub find_parents { next unless -e "$git_dir/refs/heads/$branch"; my $mergebase = `git-merge-base $branch $ps->{branch}`; - die "Cannot find merge base for $branch and $ps->{branch}" if $?; + if ($?) { + # Don't die here, Arch supports one-way cherry-picking + # between branches with no common base (or any relationship + # at all beforehand) + warn "Cannot find merge base for $branch and $ps->{branch}"; + next; + } chomp $mergebase; # now walk up to the mergepoint collecting what patches we have @@ -780,13 +846,23 @@ sub commitid2pset { chomp $commitid; my $name = $rptags{$commitid} || die "Cannot find reverse tag mapping for $commitid"; - # the keys in %rptag are slightly munged; unmunge - # reconvert the 3rd '--' sequence from the end - # into a slash - $name = reverse $name; - $name =~ s!^(.+?--.+?--.+?--.+?)--(.+)$!$1/$2!; - $name = reverse $name; + $name =~ s|,|/|; my $ps = $psets{$name} || (print Dumper(sort keys %psets)) && die "Cannot find patchset for $name"; return $ps; } + +# an alterative to `command` that allows input to be passed as an array +# to work around shell problems with weird characters in arguments +sub safe_pipe_capture { + my @output; + if (my $pid = open my $child, '-|') { + @output = (<$child>); + close $child or die join(' ',@_).": $! $?"; + } else { + exec(@_) or die $?; # exec() can fail the executable can't be found + } + return wantarray ? @output : join('',@output); +} + +