X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=git-cvsexportcommit.perl;h=7bac16e9463a0d0119218458b853570be6188ff4;hb=0f03ca946142bd656c1af9ff811cb9efbc8314da;hp=5dcb2f9a8ecdf43e73ae31bf8ba7dff27acaa367;hpb=88f0d5d7d95f815d2e8a36a8ceb7459dbd90992c;p=git.git diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl index 5dcb2f9a8..7bac16e94 100755 --- a/git-cvsexportcommit.perl +++ b/git-cvsexportcommit.perl @@ -1,10 +1,10 @@ #!/usr/bin/perl -w # Known limitations: -# - cannot add or remove binary files # - does not propagate permissions # - tells "ready for commit" even when things could not be completed -# (eg addition of a binary file) +# (not sure this is true anymore, more testing is needed) +# - does not handle whitespace in pathnames at all. use strict; use Getopt::Std; @@ -16,9 +16,9 @@ unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){ die "GIT_DIR is not defined or is unreadable"; } -our ($opt_h, $opt_p, $opt_v, $opt_c, $opt_f, $opt_m ); +our ($opt_h, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m ); -getopts('hpvcfm:'); +getopts('hpvcfam:'); $opt_h && usage(); @@ -29,7 +29,6 @@ our ($tmpdir, $tmpdirname) = tempdir('git-cvsapplycommit-XXXXXX', TMPDIR => 1, CLEANUP => 1); -print Dumper(@ARGV); # resolve target commit my $commit; $commit = pop @ARGV; @@ -53,12 +52,32 @@ if (@ARGV) { # find parents from the commit itself my @commit = safe_pipe_capture('git-cat-file', 'commit', $commit); my @parents; -foreach my $p (@commit) { - if ($p =~ m/^$/) { # end of commit headers, we're done - last; +my $committer; +my $author; +my $stage = 'headers'; # headers, msg +my $title; +my $msg = ''; + +foreach my $line (@commit) { + chomp $line; + if ($stage eq 'headers' && $line eq '') { + $stage = 'msg'; + next; } - if ($p =~ m/^parent (\w{40})$/) { # found a parent - push @parents, $1; + + if ($stage eq 'headers') { + if ($line =~ m/^parent (\w{40})$/) { # found a parent + push @parents, $1; + } elsif ($line =~ m/^author (.+) \d+ [-+]\d+$/) { + $author = $1; + } elsif ($line =~ m/^committer (.+) \d+ [-+]\d+$/) { + $committer = $1; + } + } else { + $msg .= $line . "\n"; + unless ($title) { + $title = $line; + } } } @@ -84,12 +103,18 @@ $opt_v && print "Applying to CVS commit $commit from parent $parent\n"; # grab the commit message open(MSG, ">.msg") or die "Cannot open .msg for writing"; -print MSG $opt_m; +if ($opt_m) { + print MSG $opt_m; +} +print MSG $msg; +if ($opt_a) { + print MSG "\n\nAuthor: $author\n"; + if ($author ne $committer) { + print MSG "Committer: $committer\n"; + } +} close MSG; -`git-cat-file commit $commit | sed -e '1,/^\$/d' >> .msg`; -$? && die "Error extracting the commit message"; - my (@afiles, @dfiles, @mfiles, @dirs); my @files = safe_pipe_capture('git-diff-tree', '-r', $parent, $commit); #print @files; @@ -110,10 +135,21 @@ foreach my $f (@files) { if ($fields[4] eq 'M') { push @mfiles, $fields[5]; } - if ($fields[4] eq 'R') { + if ($fields[4] eq 'D') { push @dfiles, $fields[5]; } } +my (@binfiles, @abfiles, @dbfiles, @bfiles, @mbfiles); +@binfiles = grep m/^Binary files/, safe_pipe_capture('git-diff-tree', '-p', $parent, $commit); +map { chomp } @binfiles; +@abfiles = grep s/^Binary files \/dev\/null and b\/(.*) differ$/$1/, @binfiles; +@dbfiles = grep s/^Binary files a\/(.*) and \/dev\/null differ$/$1/, @binfiles; +@mbfiles = grep s/^Binary files a\/(.*) and b\/(.*) differ$/$1/, @binfiles; +push @bfiles, @abfiles; +push @bfiles, @dbfiles; +push @bfiles, @mbfiles; +push @mfiles, @mbfiles; + $opt_v && print "The commit affects:\n "; $opt_v && print join ("\n ", @afiles,@mfiles,@dfiles) . "\n\n"; undef @files; # don't need it anymore @@ -128,6 +164,10 @@ foreach my $d (@dirs) { } foreach my $f (@afiles) { # This should return only one value + if ($f =~ m,(.*)/[^/]*$,) { + my $p = $1; + next if (grep { $_ eq $p } @dirs); + } my @status = grep(m/^File/, safe_pipe_capture('cvs', '-q', 'status' ,$f)); if (@status > 1) { warn 'Strange! cvs status returned more than one line?'}; if (-d dirname $f and $status[0] !~ m/Status: Unknown$/ @@ -137,6 +177,7 @@ foreach my $f (@afiles) { warn "Status was: $status[0]\n"; } } + foreach my $f (@mfiles, @dfiles) { # TODO:we need to handle removed in cvs my @status = grep(m/^File/, safe_pipe_capture('cvs', '-q', 'status' ,$f)); @@ -175,24 +216,31 @@ foreach my $d (@dirs) { print "'Patching' binary files\n"; -my @bfiles = grep(m/^Binary/, safe_pipe_capture('git-diff-tree', '-p', $parent, $commit)); -@bfiles = map { chomp } @bfiles; foreach my $f (@bfiles) { # check that the file in cvs matches the "old" file - # extract the file to $tmpdir and comparre with cmp - my $tree = safe_pipe_capture('git-rev-parse', "$parent^{tree}"); - chomp $tree; - my $blob = `git-ls-tree $tree "$f" | cut -f 1 | cut -d ' ' -f 3`; - chomp $blob; - `git-cat-file blob $blob > $tmpdir/blob`; - if (system('cmp', '-s', $f, "$tmpdir/blob")) { - warn "Binary file $f in CVS does not match parent.\n"; - $dirty = 1; - next; + # extract the file to $tmpdir and compare with cmp + if (not(grep { $_ eq $f } @afiles)) { + my $tree = safe_pipe_capture('git-rev-parse', "$parent^{tree}"); + chomp $tree; + my $blob = `git-ls-tree $tree "$f" | cut -f 1 | cut -d ' ' -f 3`; + chomp $blob; + `git-cat-file blob $blob > $tmpdir/blob`; + if (system('cmp', '-s', $f, "$tmpdir/blob")) { + warn "Binary file $f in CVS does not match parent.\n"; + if (not $opt_f) { + $dirty = 1; + next; + } + } + } + if (not(grep { $_ eq $f } @dfiles)) { + my $tree = safe_pipe_capture('git-rev-parse', "$commit^{tree}"); + chomp $tree; + my $blob = `git-ls-tree $tree "$f" | cut -f 1 | cut -d ' ' -f 3`; + chomp $blob; + # replace with the new file + `git-cat-file blob $blob > $f`; } - - # replace with the new file - `git-cat-file blob $blob > $f`; # TODO: something smart with file modes @@ -206,7 +254,10 @@ if ($dirty) { my $fuzz = $opt_p ? 0 : 2; print "Patching non-binary files\n"; -print `(git-diff-tree -p $parent -p $commit | patch -p1 -F $fuzz ) 2>&1`; + +if (scalar(@afiles)+scalar(@dfiles)+scalar(@mfiles) != scalar(@bfiles)) { + print `(git-diff-tree -p $parent -p $commit | patch -p1 -F $fuzz ) 2>&1`; +} my $dirtypatch = 0; if (($? >> 8) == 2) { @@ -217,7 +268,11 @@ if (($? >> 8) == 2) { } foreach my $f (@afiles) { - system('cvs', 'add', $f); + if (grep { $_ eq $f } @bfiles) { + system('cvs', 'add','-kb',$f); + } else { + system('cvs', 'add', $f); + } if ($?) { $dirty = 1; warn "Failed to cvs add $f -- you may need to do it manually"; @@ -233,6 +288,7 @@ foreach my $f (@dfiles) { } print "Commit to CVS\n"; +print "Patch: $title\n"; my $commitfiles = join(' ', @afiles, @mfiles, @dfiles); my $cmd = "cvs commit -F .msg $commitfiles"; @@ -273,7 +329,7 @@ sub cleanupcvs { } } -# 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 # if the exec returns non-zero we die sub safe_pipe_capture {