Imports a project from one or more Arch repositories. It will follow branches
and repositories within the namespaces defined by the <archive/branch>
-parameters suppplied. If it cannot find the remote branch a merge comes from
+parameters supplied. If it cannot find the remote branch a merge comes from
it will just import it as a regular commit. If it can find it, it will mark it
as a merge whenever possible.
# $arch_branches:
# values associated with keys:
# =1 - Arch version / git 'branch' detected via abrowse on a limit
-# >1 - Arch version / git 'branch' of an auxilliary branch we've merged
-my %arch_branches = map { $_ => 1 } @ARGV;
+# >1 - Arch version / git 'branch' of an auxiliary branch we've merged
+my %arch_branches = map { my $branch = $_; $branch =~ s/:[^:]*$//; $branch => 1 } @ARGV;
+
+# $branch_name_map:
+# maps arch branches to git branch names
+my %branch_name_map = map { m/^(.*):([^:]*)$/; $1 => $2 } grep { m/:/ } @ARGV;
$ENV{'TMPDIR'} = $opt_t if $opt_t; # $ENV{TMPDIR} will affect tempdir() calls:
my $tmp = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
$opt_v && print "+ Using $tmp as temporary directory\n";
+unless (-d $git_dir) { # initial import needs empty directory
+ opendir DIR, '.' or die "Unable to open current directory: $!\n";
+ while (my $entry = readdir DIR) {
+ $entry =~ /^\.\.?$/ or
+ die "Initial import needs an empty current working directory.\n"
+ }
+ closedir DIR
+}
+
+my $default_archive; # default Arch archive
my %reachable = (); # Arch repositories we can access
my %unreachable = (); # Arch repositories we can't access :<
my @psets = (); # the collection
unless (-d $git_dir) { # initial import
if ($psets[0]{type} eq 'i' || $psets[0]{type} eq 't') {
print "Starting import from $psets[0]{id}\n";
- `git-init-db`;
+ `git-init`;
die $! if $?;
$import = 1;
} else {
return $ret;
}
-*git_branchname = $opt_o ? *old_style_branchname : *tree_dirname;
+*git_default_branchname = $opt_o ? *old_style_branchname : *tree_dirname;
+
+# retrieve default archive, since $branch_name_map keys might not include it
+sub get_default_archive {
+ if (!defined $default_archive) {
+ $default_archive = safe_pipe_capture($TLA,'my-default-archive');
+ chomp $default_archive;
+ }
+ return $default_archive;
+}
+
+sub git_branchname {
+ my $revision = shift;
+ my $name = extract_versionname($revision);
+
+ if (exists $branch_name_map{$name}) {
+ return $branch_name_map{$name};
+
+ } elsif ($name =~ m#^([^/]*)/(.*)$#
+ && $1 eq get_default_archive()
+ && exists $branch_name_map{$2}) {
+ # the names given in the command-line lacked the archive.
+ return $branch_name_map{$2};
+
+ } else {
+ return git_default_branchname($revision);
+ }
+}
sub process_patchset_accurate {
my $ps = shift;
if ($ps->{tag} && (my $branchpoint = eval { ptag($ps->{tag}) })) {
# find where we are supposed to branch from
- system('git-checkout','-f','-b',$ps->{branch},
- $branchpoint) == 0 or die "$! $?\n";
-
+ if (! -e "$git_dir/refs/heads/$ps->{branch}") {
+ system('git-branch',$ps->{branch},$branchpoint) == 0 or die "$! $?\n";
+
+ # We trust Arch with the fact that this is just a tag,
+ # and it does not affect the state of the tree, so
+ # we just tag and move on. If the user really wants us
+ # to consolidate more branches into one, don't tag because
+ # the tag name would be already taken.
+ tag($ps->{id}, $branchpoint);
+ ptag($ps->{id}, $branchpoint);
+ print " * Tagged $ps->{id} at $branchpoint\n";
+ }
+ system('git-checkout','-f',$ps->{branch}) == 0 or die "$! $?\n";
+
# remove any old stuff that got leftover:
my $rm = safe_pipe_capture('git-ls-files','--others','-z');
rmtree(split(/\0/,$rm)) if $rm;
-
- # If we trust Arch with the fact that this is just
- # a tag, and it does not affect the state of the tree
- # then we just tag and move on
- tag($ps->{id}, $branchpoint);
- ptag($ps->{id}, $branchpoint);
- print " * Tagged $ps->{id} at $branchpoint\n";
return 0;
} else {
warn "Tagging from unknown id unsupported\n" if $ps->{tag};
unless $branchpoint;
# find where we are supposed to branch from
- system('git-checkout','-b',$ps->{branch},$branchpoint);
-
- # If we trust Arch with the fact that this is just
- # a tag, and it does not affect the state of the tree
- # then we just tag and move on
- tag($ps->{id}, $branchpoint);
- ptag($ps->{id}, $branchpoint);
- print " * Tagged $ps->{id} at $branchpoint\n";
+ if (! -e "$git_dir/refs/heads/$ps->{branch}") {
+ system('git-branch',$ps->{branch},$branchpoint) == 0 or die "$! $?\n";
+
+ # We trust Arch with the fact that this is just a tag,
+ # and it does not affect the state of the tree, so
+ # we just tag and move on. If the user really wants us
+ # to consolidate more branches into one, don't tag because
+ # the tag name would be already taken.
+ tag($ps->{id}, $branchpoint);
+ ptag($ps->{id}, $branchpoint);
+ print " * Tagged $ps->{id} at $branchpoint\n";
+ }
+ system('git-checkout',$ps->{branch}) == 0 or die "$! $?\n";
return 0;
}
die $! if $?;
my $pid = open2(*READER, *WRITER,'git-commit-tree',$tree,@par)
or die $!;
- print WRITER $ps->{summary},"\n";
+ print WRITER $ps->{summary},"\n\n";
print WRITER $ps->{message},"\n";
# make it easy to backtrack and figure out which Arch revision this was:
if (`find $tmp/changeset/patches -type f -name '*.patch'`) {
# this can be sped up considerably by doing
# (find | xargs cat) | patch
- # but that cna get mucked up by patches
+ # but that can get mucked up by patches
# with missing trailing newlines or the standard
# 'missing newline' flag in the patch - possibly
# produced with an old/buggy diff.
$ps->{tag} = $1;
$key = undef;
} elsif (/^Summary:\s*(.*)$/ ) {
- # summary can be multiline as long as it has a leading space
+ # summary can be multiline as long as it has a leading space.
+ # we squeeze it onto a single line, though.
$ps->{summary} = [ $1 ];
$key = 'summary';
} elsif (/^Creator: (.*)\s*<([^\>]+)>/) {
}
}
- # post-processing:
- $ps->{summary} = join("\n",@{$ps->{summary}})."\n";
+ # drop leading empty lines from the log message
+ while (@$log && $log->[0] eq '') {
+ shift @$log;
+ }
+ if (exists $ps->{summary} && @{$ps->{summary}}) {
+ $ps->{summary} = join(' ', @{$ps->{summary}});
+ }
+ elsif (@$log == 0) {
+ $ps->{summary} = 'empty commit message';
+ } else {
+ $ps->{summary} = $log->[0] . '...';
+ }
$ps->{message} = join("\n",@$log);
# skip Arch control files, unescape pika-escaped files
if ($opt_o) {
$tag =~ s|/|--|g;
} else {
- # don't use subdirs for tags yet, it could screw up other porcelains
- $tag =~ s|/|,|g;
+ my $patchname = $tag;
+ $patchname =~ s/.*--//;
+ $tag = git_branchname ($tag) . '--' . $patchname;
}
if ($commit) {
# now walk up to the mergepoint collecting what patches we have
my $branchtip = git_rev_parse($ps->{branch});
- my @ancestors = `git-rev-list --merge-order $branchtip ^$mergebase`;
+ my @ancestors = `git-rev-list --topo-order $branchtip ^$mergebase`;
my %have; # collected merges this branch has
foreach my $merge (@{$ps->{merges}}) {
$have{$merge} = 1;
# see what the remote branch has - these are the merges we
# will want to have in a consecutive series from the mergebase
my $otherbranchtip = git_rev_parse($branch);
- my @needraw = `git-rev-list --merge-order $otherbranchtip ^$mergebase`;
+ my @needraw = `git-rev-list --topo-order $otherbranchtip ^$mergebase`;
my @need;
foreach my $needps (@needraw) { # get the psets
$needps = commitid2pset($needps);
}
-# an alterative to `command` that allows input to be passed as an array
+# an alternative 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;