Code

sscanf/strtoul: parse integers robustly
[git.git] / git-archimport.perl
index 740bc1fd52286dfb486570bf6ea727e9cbaefbfc..c1e7c1ddcbbf45995b53785a0f39314f6d499d2c 100755 (executable)
@@ -14,7 +14,7 @@
 
 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.
 
@@ -88,13 +88,27 @@ usage if $opt_h;
 # $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
@@ -226,7 +240,7 @@ my $import = 0;
 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 {
@@ -294,7 +308,34 @@ sub old_style_branchname {
     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;
@@ -324,19 +365,23 @@ sub process_patchset_accurate {
         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};
@@ -376,14 +421,19 @@ sub process_patchset_fast {
                 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 $?;
@@ -544,7 +594,7 @@ foreach my $ps (@psets) {
 
     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:
@@ -667,7 +717,7 @@ sub apply_cset {
     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.
@@ -746,7 +796,8 @@ sub parselog {
             $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*<([^\>]+)>/) {
@@ -778,8 +829,18 @@ sub parselog {
         }
     }
    
-    # 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
@@ -810,8 +871,9 @@ sub tag {
     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) {
@@ -1026,7 +1088,7 @@ sub commitid2pset {
 }
 
 
-# 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;