Rework cvsexportcommit to handle binary files for all cases.
Also adds test cases for adding removing and deleting binary and text files plus two tests for the checks on binary files. Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com> Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
parent
3d12d0cfbb
commit
fe142b3a45
@ -1,10 +1,10 @@
|
|||||||
#!/usr/bin/perl -w
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
# Known limitations:
|
# Known limitations:
|
||||||
# - cannot add or remove binary files
|
|
||||||
# - does not propagate permissions
|
# - does not propagate permissions
|
||||||
# - tells "ready for commit" even when things could not be completed
|
# - 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 strict;
|
||||||
use Getopt::Std;
|
use Getopt::Std;
|
||||||
@ -68,9 +68,9 @@ foreach my $line (@commit) {
|
|||||||
if ($stage eq 'headers') {
|
if ($stage eq 'headers') {
|
||||||
if ($line =~ m/^parent (\w{40})$/) { # found a parent
|
if ($line =~ m/^parent (\w{40})$/) { # found a parent
|
||||||
push @parents, $1;
|
push @parents, $1;
|
||||||
} elsif ($line =~ m/^author (.+) \d+ \+\d+$/) {
|
} elsif ($line =~ m/^author (.+) \d+ [-+]\d+$/) {
|
||||||
$author = $1;
|
$author = $1;
|
||||||
} elsif ($line =~ m/^committer (.+) \d+ \+\d+$/) {
|
} elsif ($line =~ m/^committer (.+) \d+ [-+]\d+$/) {
|
||||||
$committer = $1;
|
$committer = $1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -139,6 +139,17 @@ foreach my $f (@files) {
|
|||||||
push @dfiles, $fields[5];
|
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 "The commit affects:\n ";
|
||||||
$opt_v && print join ("\n ", @afiles,@mfiles,@dfiles) . "\n\n";
|
$opt_v && print join ("\n ", @afiles,@mfiles,@dfiles) . "\n\n";
|
||||||
undef @files; # don't need it anymore
|
undef @files; # don't need it anymore
|
||||||
@ -153,6 +164,10 @@ foreach my $d (@dirs) {
|
|||||||
}
|
}
|
||||||
foreach my $f (@afiles) {
|
foreach my $f (@afiles) {
|
||||||
# This should return only one value
|
# 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));
|
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 (@status > 1) { warn 'Strange! cvs status returned more than one line?'};
|
||||||
if (-d dirname $f and $status[0] !~ m/Status: Unknown$/
|
if (-d dirname $f and $status[0] !~ m/Status: Unknown$/
|
||||||
@ -162,6 +177,7 @@ foreach my $f (@afiles) {
|
|||||||
warn "Status was: $status[0]\n";
|
warn "Status was: $status[0]\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $f (@mfiles, @dfiles) {
|
foreach my $f (@mfiles, @dfiles) {
|
||||||
# TODO:we need to handle removed in cvs
|
# TODO:we need to handle removed in cvs
|
||||||
my @status = grep(m/^File/, safe_pipe_capture('cvs', '-q', 'status' ,$f));
|
my @status = grep(m/^File/, safe_pipe_capture('cvs', '-q', 'status' ,$f));
|
||||||
@ -200,24 +216,31 @@ foreach my $d (@dirs) {
|
|||||||
|
|
||||||
print "'Patching' binary files\n";
|
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) {
|
foreach my $f (@bfiles) {
|
||||||
# check that the file in cvs matches the "old" file
|
# check that the file in cvs matches the "old" file
|
||||||
# extract the file to $tmpdir and compare with cmp
|
# extract the file to $tmpdir and compare with cmp
|
||||||
my $tree = safe_pipe_capture('git-rev-parse', "$parent^{tree}");
|
if (not(grep { $_ eq $f } @afiles)) {
|
||||||
chomp $tree;
|
my $tree = safe_pipe_capture('git-rev-parse', "$parent^{tree}");
|
||||||
my $blob = `git-ls-tree $tree "$f" | cut -f 1 | cut -d ' ' -f 3`;
|
chomp $tree;
|
||||||
chomp $blob;
|
my $blob = `git-ls-tree $tree "$f" | cut -f 1 | cut -d ' ' -f 3`;
|
||||||
`git-cat-file blob $blob > $tmpdir/blob`;
|
chomp $blob;
|
||||||
if (system('cmp', '-s', $f, "$tmpdir/blob")) {
|
`git-cat-file blob $blob > $tmpdir/blob`;
|
||||||
warn "Binary file $f in CVS does not match parent.\n";
|
if (system('cmp', '-s', $f, "$tmpdir/blob")) {
|
||||||
$dirty = 1;
|
warn "Binary file $f in CVS does not match parent.\n";
|
||||||
next;
|
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
|
# TODO: something smart with file modes
|
||||||
|
|
||||||
@ -231,7 +254,10 @@ if ($dirty) {
|
|||||||
my $fuzz = $opt_p ? 0 : 2;
|
my $fuzz = $opt_p ? 0 : 2;
|
||||||
|
|
||||||
print "Patching non-binary files\n";
|
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;
|
my $dirtypatch = 0;
|
||||||
if (($? >> 8) == 2) {
|
if (($? >> 8) == 2) {
|
||||||
@ -242,7 +268,11 @@ if (($? >> 8) == 2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach my $f (@afiles) {
|
foreach my $f (@afiles) {
|
||||||
system('cvs', 'add', $f);
|
if (grep { $_ eq $f } @bfiles) {
|
||||||
|
system('cvs', 'add','-kb',$f);
|
||||||
|
} else {
|
||||||
|
system('cvs', 'add', $f);
|
||||||
|
}
|
||||||
if ($?) {
|
if ($?) {
|
||||||
$dirty = 1;
|
$dirty = 1;
|
||||||
warn "Failed to cvs add $f -- you may need to do it manually";
|
warn "Failed to cvs add $f -- you may need to do it manually";
|
||||||
|
145
t/t9200-git-cvsexportcommit.sh
Executable file
145
t/t9200-git-cvsexportcommit.sh
Executable file
@ -0,0 +1,145 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (c) Robin Rosenberg
|
||||||
|
#
|
||||||
|
test_description='CVS export comit. '
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
cvs >/dev/null 2>&1
|
||||||
|
if test $? -ne 1
|
||||||
|
then
|
||||||
|
test_expect_success 'skipping git-cvsexportcommit tests, cvs not found' :
|
||||||
|
test_done
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
export CVSROOT=$(pwd)/cvsroot
|
||||||
|
export CVSWORK=$(pwd)/cvswork
|
||||||
|
rm -rf "$CVSROOT" "$CVSWORK"
|
||||||
|
mkdir "$CVSROOT" &&
|
||||||
|
cvs init &&
|
||||||
|
cvs -Q co -d "$CVSWORK" . &&
|
||||||
|
export GIT_DIR=$(pwd)/.git &&
|
||||||
|
echo >empty &&
|
||||||
|
git add empty &&
|
||||||
|
git commit -a -m "Initial" 2>/dev/null ||
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'New file' \
|
||||||
|
'mkdir A B C D E F &&
|
||||||
|
echo hello1 >A/newfile1.txt &&
|
||||||
|
echo hello2 >B/newfile2.txt &&
|
||||||
|
cp ../test9200a.png C/newfile3.png &&
|
||||||
|
cp ../test9200a.png D/newfile4.png &&
|
||||||
|
git add A/newfile1.txt &&
|
||||||
|
git add B/newfile2.txt &&
|
||||||
|
git add C/newfile3.png &&
|
||||||
|
git add D/newfile4.png &&
|
||||||
|
git commit -a -m "Test: New file" &&
|
||||||
|
id=$(git rev-list --max-count=1 HEAD) &&
|
||||||
|
(cd "$CVSWORK" &&
|
||||||
|
git cvsexportcommit -c $id &&
|
||||||
|
test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.1/" &&
|
||||||
|
test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "newfile2.txt/1.1/" &&
|
||||||
|
test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "newfile3.png/1.1/-kb" &&
|
||||||
|
test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "newfile4.png/1.1/-kb" &&
|
||||||
|
diff A/newfile1.txt ../A/newfile1.txt &&
|
||||||
|
diff B/newfile2.txt ../B/newfile2.txt &&
|
||||||
|
diff C/newfile3.png ../C/newfile3.png &&
|
||||||
|
diff D/newfile4.png ../D/newfile4.png
|
||||||
|
)'
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'Remove two files, add two and update two' \
|
||||||
|
'echo Hello1 >>A/newfile1.txt &&
|
||||||
|
rm -f B/newfile2.txt &&
|
||||||
|
rm -f C/newfile3.png &&
|
||||||
|
echo Hello5 >E/newfile5.txt &&
|
||||||
|
cp ../test9200b.png D/newfile4.png &&
|
||||||
|
cp ../test9200a.png F/newfile6.png &&
|
||||||
|
git add E/newfile5.txt &&
|
||||||
|
git add F/newfile6.png &&
|
||||||
|
git commit -a -m "Test: Remove, add and update" &&
|
||||||
|
id=$(git rev-list --max-count=1 HEAD) &&
|
||||||
|
(cd "$CVSWORK" &&
|
||||||
|
git cvsexportcommit -c $id &&
|
||||||
|
test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.2/" &&
|
||||||
|
test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
|
||||||
|
test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
|
||||||
|
test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "newfile4.png/1.2/-kb" &&
|
||||||
|
test "$(echo $(sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" &&
|
||||||
|
test "$(echo $(sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" &&
|
||||||
|
diff A/newfile1.txt ../A/newfile1.txt &&
|
||||||
|
diff D/newfile4.png ../D/newfile4.png &&
|
||||||
|
diff E/newfile5.txt ../E/newfile5.txt &&
|
||||||
|
diff F/newfile6.png ../F/newfile6.png
|
||||||
|
)'
|
||||||
|
|
||||||
|
# Should fail (but only on the git-cvsexportcommit stage)
|
||||||
|
test_expect_success \
|
||||||
|
'Fail to change binary more than one generation old' \
|
||||||
|
'cat F/newfile6.png >>D/newfile4.png &&
|
||||||
|
git commit -a -m "generatiion 1" &&
|
||||||
|
cat F/newfile6.png >>D/newfile4.png &&
|
||||||
|
git commit -a -m "generation 2" &&
|
||||||
|
id=$(git rev-list --max-count=1 HEAD) &&
|
||||||
|
(cd "$CVSWORK" &&
|
||||||
|
! git cvsexportcommit -c $id
|
||||||
|
)'
|
||||||
|
|
||||||
|
# Should fail, but only on the git-cvsexportcommit stage
|
||||||
|
test_expect_success \
|
||||||
|
'Fail to remove binary file more than one generation old' \
|
||||||
|
'git reset --hard HEAD^ &&
|
||||||
|
cat F/newfile6.png >>D/newfile4.png &&
|
||||||
|
git commit -a -m "generation 2 (again)" &&
|
||||||
|
rm -f D/newfile4.png &&
|
||||||
|
git commit -a -m "generation 3" &&
|
||||||
|
id=$(git rev-list --max-count=1 HEAD) &&
|
||||||
|
(cd "$CVSWORK" &&
|
||||||
|
! git cvsexportcommit -c $id
|
||||||
|
)'
|
||||||
|
|
||||||
|
# We reuse the state from two tests back here
|
||||||
|
|
||||||
|
# This test is here because a patch for only binary files will
|
||||||
|
# fail with gnu patch, so cvsexportcommit must handle that.
|
||||||
|
test_expect_success \
|
||||||
|
'Remove only binary files' \
|
||||||
|
'git reset --hard HEAD^^^ &&
|
||||||
|
rm -f D/newfile4.png &&
|
||||||
|
git commit -a -m "test: remove only a binary file" &&
|
||||||
|
id=$(git rev-list --max-count=1 HEAD) &&
|
||||||
|
(cd "$CVSWORK" &&
|
||||||
|
git cvsexportcommit -c $id &&
|
||||||
|
test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.2/" &&
|
||||||
|
test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
|
||||||
|
test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
|
||||||
|
test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
|
||||||
|
test "$(echo $(sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" &&
|
||||||
|
test "$(echo $(sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" &&
|
||||||
|
diff A/newfile1.txt ../A/newfile1.txt &&
|
||||||
|
diff E/newfile5.txt ../E/newfile5.txt &&
|
||||||
|
diff F/newfile6.png ../F/newfile6.png
|
||||||
|
)'
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'Remove only a text file' \
|
||||||
|
'rm -f A/newfile1.txt &&
|
||||||
|
git commit -a -m "test: remove only a binary file" &&
|
||||||
|
id=$(git rev-list --max-count=1 HEAD) &&
|
||||||
|
(cd "$CVSWORK" &&
|
||||||
|
git cvsexportcommit -c $id &&
|
||||||
|
test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
|
||||||
|
test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
|
||||||
|
test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
|
||||||
|
test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
|
||||||
|
test "$(echo $(sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" &&
|
||||||
|
test "$(echo $(sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" &&
|
||||||
|
diff E/newfile5.txt ../E/newfile5.txt &&
|
||||||
|
diff F/newfile6.png ../F/newfile6.png
|
||||||
|
)'
|
||||||
|
|
||||||
|
test_done
|
BIN
t/test9200a.png
Normal file
BIN
t/test9200a.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
BIN
t/test9200b.png
Normal file
BIN
t/test9200b.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 275 B |
Loading…
Reference in New Issue
Block a user