Merge branch 'pw/git-p4'

Various "git p4" updates.

* pw/git-p4:
  git p4 doc: use two-line style for options with multiple spellings
  git p4 test: examine behavior with locked (+l) files
  git p4: fix an error message when "p4 where" fails
  git p4: handle files with wildcards when doing RCS scrubbing
  git p4 test: do not pollute /tmp
  git p4 test: run as user "author"
  git p4 test: is_cli_file_writeable succeeds
  git p4 test: explicitly check p4 wildcard delete
  git p4: work around p4 bug that causes empty symlinks
  git p4 test: ensure p4 symlink parsing works
  git p4 test: wildcards are supported
This commit is contained in:
Junio C Hamano 2014-01-27 10:45:41 -08:00
commit 523f0a25b9
10 changed files with 342 additions and 44 deletions

View File

@ -168,7 +168,8 @@ All commands except clone accept these options.
--git-dir <dir>:: --git-dir <dir>::
Set the 'GIT_DIR' environment variable. See linkgit:git[1]. Set the 'GIT_DIR' environment variable. See linkgit:git[1].
--verbose, -v:: -v::
--verbose::
Provide more progress information. Provide more progress information.
Sync options Sync options
@ -279,7 +280,8 @@ These options can be used to modify 'git p4 submit' behavior.
Export tags from Git as p4 labels. Tags found in Git are applied Export tags from Git as p4 labels. Tags found in Git are applied
to the perforce working directory. to the perforce working directory.
--dry-run, -n:: -n::
--dry-run::
Show just what commits would be submitted to p4; do not change Show just what commits would be submitted to p4; do not change
state in Git or p4. state in Git or p4.

View File

@ -310,8 +310,8 @@ def split_p4_type(p4type):
# #
# return the raw p4 type of a file (text, text+ko, etc) # return the raw p4 type of a file (text, text+ko, etc)
# #
def p4_type(file): def p4_type(f):
results = p4CmdList(["fstat", "-T", "headType", file]) results = p4CmdList(["fstat", "-T", "headType", wildcard_encode(f)])
return results[0]['headType'] return results[0]['headType']
# #
@ -1220,7 +1220,7 @@ class P4Submit(Command, P4UserMap):
editor = os.environ.get("P4EDITOR") editor = os.environ.get("P4EDITOR")
else: else:
editor = read_pipe("git var GIT_EDITOR").strip() editor = read_pipe("git var GIT_EDITOR").strip()
system(editor + " " + template_file) system([editor, template_file])
# If the file was not saved, prompt to see if this patch should # If the file was not saved, prompt to see if this patch should
# be skipped. But skip this verification step if configured so. # be skipped. But skip this verification step if configured so.
@ -1871,7 +1871,7 @@ class View(object):
# assume error is "... file(s) not in client view" # assume error is "... file(s) not in client view"
continue continue
if "clientFile" not in res: if "clientFile" not in res:
die("No clientFile from 'p4 where %s'" % depot_path) die("No clientFile in 'p4 where' output")
if "unmap" in res: if "unmap" in res:
# it will list all of them, but only one not unmap-ped # it will list all of them, but only one not unmap-ped
continue continue
@ -2075,7 +2075,14 @@ class P4Sync(Command, P4UserMap):
# p4 print on a symlink sometimes contains "target\n"; # p4 print on a symlink sometimes contains "target\n";
# if it does, remove the newline # if it does, remove the newline
data = ''.join(contents) data = ''.join(contents)
if data[-1] == '\n': if not data:
# Some version of p4 allowed creating a symlink that pointed
# to nothing. This causes p4 errors when checking out such
# a change, and errors here too. Work around it by ignoring
# the bad symlink; hopefully a future change fixes it.
print "\nIgnoring empty symlink in %s" % file['depotFile']
return
elif data[-1] == '\n':
contents = [data[:-1]] contents = [data[:-1]]
else: else:
contents = [data] contents = [data]

View File

@ -47,15 +47,22 @@ P4DPORT=$((10669 + ($testid - $git_p4_test_start)))
P4PORT=localhost:$P4DPORT P4PORT=localhost:$P4DPORT
P4CLIENT=client P4CLIENT=client
P4EDITOR=: P4USER=author
P4EDITOR=true
unset P4CHARSET unset P4CHARSET
export P4PORT P4CLIENT P4EDITOR P4CHARSET export P4PORT P4CLIENT P4USER P4EDITOR P4CHARSET
db="$TRASH_DIRECTORY/db" db="$TRASH_DIRECTORY/db"
cli="$TRASH_DIRECTORY/cli" cli="$TRASH_DIRECTORY/cli"
git="$TRASH_DIRECTORY/git" git="$TRASH_DIRECTORY/git"
pidfile="$TRASH_DIRECTORY/p4d.pid" pidfile="$TRASH_DIRECTORY/p4d.pid"
# git p4 submit generates a temp file, which will
# not get cleaned up if the submission fails. Don't
# clutter up /tmp on the test machine.
TMPDIR="$TRASH_DIRECTORY"
export TMPDIR
start_p4d() { start_p4d() {
mkdir -p "$db" "$cli" "$git" && mkdir -p "$db" "$cli" "$git" &&
rm -f "$pidfile" && rm -f "$pidfile" &&
@ -96,12 +103,24 @@ start_p4d() {
return 1 return 1
fi fi
# build a p4 user so author@example.com has an entry
p4_add_user author
# build a client # build a client
client_view "//depot/... //client/..." && client_view "//depot/... //client/..." &&
return 0 return 0
} }
p4_add_user() {
name=$1 &&
p4 user -f -i <<-EOF
User: $name
Email: $name@example.com
FullName: Dr. $name
EOF
}
kill_p4d() { kill_p4d() {
pid=$(cat "$pidfile") pid=$(cat "$pidfile")
# it had better exist for the first kill # it had better exist for the first kill

View File

@ -250,6 +250,89 @@ test_expect_success 'ignore apple' '
) )
' '
test_expect_success SYMLINKS 'create p4 symlink' '
cd "$cli" &&
ln -s symlink-target symlink &&
p4 add symlink &&
p4 submit -d "add symlink"
'
test_expect_success SYMLINKS 'ensure p4 symlink parsed correctly' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot@all &&
(
cd "$git" &&
test -L symlink &&
test $(readlink symlink) = symlink-target
)
'
test_expect_success SYMLINKS 'empty symlink target' '
(
# first create the file as a file
cd "$cli" &&
>empty-symlink &&
p4 add empty-symlink &&
p4 submit -d "add empty-symlink as a file"
) &&
(
# now change it to be a symlink to "target1"
cd "$cli" &&
p4 edit empty-symlink &&
p4 reopen -t symlink empty-symlink &&
rm empty-symlink &&
ln -s target1 empty-symlink &&
p4 add empty-symlink &&
p4 submit -d "make empty-symlink point to target1"
) &&
(
# Hack the p4 depot to make the symlink point to nothing;
# this should not happen in reality, but shows up
# in p4 repos in the wild.
#
# The sed expression changes this:
# @@
# text
# @target1
# @
# to this:
# @@
# text
# @@
#
cd "$db/depot" &&
sed "/@target1/{; s/target1/@/; n; d; }" \
empty-symlink,v >empty-symlink,v.tmp &&
mv empty-symlink,v.tmp empty-symlink,v
) &&
(
# Make sure symlink really is empty. Asking
# p4 to sync here will make it generate errors.
cd "$cli" &&
p4 print -q //depot/empty-symlink#2 >out &&
test ! -s out
) &&
test_when_finished cleanup_git &&
# make sure git p4 handles it without error
git p4 clone --dest="$git" //depot@all &&
# fix the symlink, make it point to "target2"
(
cd "$cli" &&
p4 open empty-symlink &&
rm empty-symlink &&
ln -s target2 empty-symlink &&
p4 submit -d "make empty-symlink point to target2"
) &&
cleanup_git &&
git p4 clone --dest="$git" //depot@all &&
(
cd "$git" &&
test $(readlink empty-symlink) = target2
)
'
test_expect_success 'kill p4d' ' test_expect_success 'kill p4d' '
kill_p4d kill_p4d
' '

View File

@ -17,7 +17,7 @@ test_expect_success 'init depot' '
) )
' '
# this works because EDITOR is set to : # this works because P4EDITOR is set to true
test_expect_success 'no config, unedited, say yes' ' test_expect_success 'no config, unedited, say yes' '
git p4 clone --dest="$git" //depot && git p4 clone --dest="$git" //depot &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
@ -90,7 +90,9 @@ test_expect_success 'no config, edited' '
cd "$git" && cd "$git" &&
echo line >>file1 && echo line >>file1 &&
git commit -a -m "change 5" && git commit -a -m "change 5" &&
P4EDITOR="" EDITOR="\"$TRASH_DIRECTORY/ed.sh\"" git p4 submit && P4EDITOR="$TRASH_DIRECTORY/ed.sh" &&
export P4EDITOR &&
git p4 submit &&
p4 changes //depot/... >wc && p4 changes //depot/... >wc &&
test_line_count = 5 wc test_line_count = 5 wc
) )

View File

@ -17,7 +17,7 @@ test_expect_success 'init depot' '
) )
' '
test_expect_failure 'is_cli_file_writeable function' ' test_expect_success 'is_cli_file_writeable function' '
( (
cd "$cli" && cd "$cli" &&
echo a >a && echo a >a &&

View File

@ -76,28 +76,28 @@ test_expect_success 'init depot' '
' '
# double % for printf # double % for printf
test_expect_success 'unsupported view wildcard %%n' ' test_expect_success 'view wildcard %%n' '
client_view "//depot/%%%%1/sub/... //client/sub/%%%%1/..." && client_view "//depot/%%%%1/sub/... //client/sub/%%%%1/..." &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
test_must_fail git p4 clone --use-client-spec --dest="$git" //depot git p4 clone --use-client-spec --dest="$git" //depot
' '
test_expect_success 'unsupported view wildcard *' ' test_expect_success 'view wildcard *' '
client_view "//depot/*/bar/... //client/*/bar/..." && client_view "//depot/*/bar/... //client/*/bar/..." &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
test_must_fail git p4 clone --use-client-spec --dest="$git" //depot git p4 clone --use-client-spec --dest="$git" //depot
' '
test_expect_success 'wildcard ... only supported at end of spec 1' ' test_expect_success 'wildcard ... in the middle' '
client_view "//depot/.../file11 //client/.../file11" && client_view "//depot/.../file11 //client/.../file11" &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
test_must_fail git p4 clone --use-client-spec --dest="$git" //depot git p4 clone --use-client-spec --dest="$git" //depot
' '
test_expect_success 'wildcard ... only supported at end of spec 2' ' test_expect_success 'wildcard ... in the middle and at the end' '
client_view "//depot/.../a/... //client/.../a/..." && client_view "//depot/.../a/... //client/.../a/..." &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
test_must_fail git p4 clone --use-client-spec --dest="$git" //depot git p4 clone --use-client-spec --dest="$git" //depot
' '
test_expect_success 'basic map' ' test_expect_success 'basic map' '

View File

@ -161,6 +161,56 @@ test_expect_success 'wildcard files submit back to p4, delete' '
) )
' '
test_expect_success 'p4 deleted a wildcard file' '
(
cd "$cli" &&
echo "wild delete test" >wild@delete &&
p4 add -f wild@delete &&
p4 submit -d "add wild@delete"
) &&
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
test_path_is_file wild@delete
) &&
(
cd "$cli" &&
# must use its encoded name
p4 delete wild%40delete &&
p4 submit -d "delete wild@delete"
) &&
(
cd "$git" &&
git p4 sync &&
git merge --ff-only p4/master &&
test_path_is_missing wild@delete
)
'
test_expect_success 'wildcard files requiring keyword scrub' '
(
cd "$cli" &&
cat <<-\EOF >scrub@wild &&
$Id$
line2
EOF
p4 add -t text+k -f scrub@wild &&
p4 submit -d "scrub at wild"
) &&
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
git config git-p4.skipSubmitEdit true &&
git config git-p4.attemptRCSCleanup true &&
sed "s/^line2/line2 edit/" <scrub@wild >scrub@wild.tmp &&
mv -f scrub@wild.tmp scrub@wild &&
git commit -m "scrub at wild line2 edit" scrub@wild &&
git p4 submit
)
'
test_expect_success 'kill p4d' ' test_expect_success 'kill p4d' '
kill_p4d kill_p4d
' '

View File

@ -19,16 +19,6 @@ test_expect_success 'create files' '
) )
' '
p4_add_user() {
name=$1 fullname=$2 &&
p4 user -f -i <<-EOF &&
User: $name
Email: $name@localhost
FullName: $fullname
EOF
p4 passwd -P secret $name
}
p4_grant_admin() { p4_grant_admin() {
name=$1 && name=$1 &&
{ {
@ -51,8 +41,8 @@ make_change_by_user() {
# Test username support, submitting as user 'alice' # Test username support, submitting as user 'alice'
test_expect_success 'preserve users' ' test_expect_success 'preserve users' '
p4_add_user alice Alice && p4_add_user alice &&
p4_add_user bob Bob && p4_add_user bob &&
p4_grant_admin alice && p4_grant_admin alice &&
git p4 clone --dest="$git" //depot && git p4 clone --dest="$git" //depot &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
@ -60,8 +50,8 @@ test_expect_success 'preserve users' '
cd "$git" && cd "$git" &&
echo "username: a change by alice" >>file1 && echo "username: a change by alice" >>file1 &&
echo "username: a change by bob" >>file2 && echo "username: a change by bob" >>file2 &&
git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 && git commit --author "Alice <alice@example.com>" -m "a change by alice" file1 &&
git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 && git commit --author "Bob <bob@example.com>" -m "a change by bob" file2 &&
git config git-p4.skipSubmitEditCheck true && git config git-p4.skipSubmitEditCheck true &&
P4EDITOR=touch P4USER=alice P4PASSWD=secret git p4 commit --preserve-user && P4EDITOR=touch P4USER=alice P4PASSWD=secret git p4 commit --preserve-user &&
p4_check_commit_author file1 alice && p4_check_commit_author file1 alice &&
@ -78,7 +68,7 @@ test_expect_success 'refuse to preserve users without perms' '
cd "$git" && cd "$git" &&
git config git-p4.skipSubmitEditCheck true && git config git-p4.skipSubmitEditCheck true &&
echo "username-noperms: a change by alice" >>file1 && echo "username-noperms: a change by alice" >>file1 &&
git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 && git commit --author "Alice <alice@example.com>" -m "perms: a change by alice" file1 &&
P4EDITOR=touch P4USER=bob P4PASSWD=secret && P4EDITOR=touch P4USER=bob P4PASSWD=secret &&
export P4EDITOR P4USER P4PASSWD && export P4EDITOR P4USER P4PASSWD &&
test_must_fail git p4 commit --preserve-user && test_must_fail git p4 commit --preserve-user &&
@ -94,9 +84,9 @@ test_expect_success 'preserve user where author is unknown to p4' '
cd "$git" && cd "$git" &&
git config git-p4.skipSubmitEditCheck true && git config git-p4.skipSubmitEditCheck true &&
echo "username-bob: a change by bob" >>file1 && echo "username-bob: a change by bob" >>file1 &&
git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 && git commit --author "Bob <bob@example.com>" -m "preserve: a change by bob" file1 &&
echo "username-unknown: a change by charlie" >>file1 && echo "username-unknown: a change by charlie" >>file1 &&
git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 && git commit --author "Charlie <charlie@example.com>" -m "preserve: a change by charlie" file1 &&
P4EDITOR=touch P4USER=alice P4PASSWD=secret && P4EDITOR=touch P4USER=alice P4PASSWD=secret &&
export P4EDITOR P4USER P4PASSWD && export P4EDITOR P4USER P4PASSWD &&
test_must_fail git p4 commit --preserve-user && test_must_fail git p4 commit --preserve-user &&
@ -121,24 +111,24 @@ test_expect_success 'not preserving user with mixed authorship' '
( (
cd "$git" && cd "$git" &&
git config git-p4.skipSubmitEditCheck true && git config git-p4.skipSubmitEditCheck true &&
p4_add_user derek Derek && p4_add_user derek &&
make_change_by_user usernamefile3 Derek derek@localhost && make_change_by_user usernamefile3 Derek derek@example.com &&
P4EDITOR=cat P4USER=alice P4PASSWD=secret && P4EDITOR=cat P4USER=alice P4PASSWD=secret &&
export P4EDITOR P4USER P4PASSWD && export P4EDITOR P4USER P4PASSWD &&
git p4 commit |\ git p4 commit |\
grep "git author derek@localhost does not match" && grep "git author derek@example.com does not match" &&
make_change_by_user usernamefile3 Charlie charlie@localhost && make_change_by_user usernamefile3 Charlie charlie@example.com &&
git p4 commit |\ git p4 commit |\
grep "git author charlie@localhost does not match" && grep "git author charlie@example.com does not match" &&
make_change_by_user usernamefile3 alice alice@localhost && make_change_by_user usernamefile3 alice alice@example.com &&
git p4 commit |\ git p4 commit |\
test_must_fail grep "git author.*does not match" && test_must_fail grep "git author.*does not match" &&
git config git-p4.skipUserNameCheck true && git config git-p4.skipUserNameCheck true &&
make_change_by_user usernamefile3 Charlie charlie@localhost && make_change_by_user usernamefile3 Charlie charlie@example.com &&
git p4 commit |\ git p4 commit |\
test_must_fail grep "git author.*does not match" && test_must_fail grep "git author.*does not match" &&

145
t/t9816-git-p4-locked.sh Executable file
View File

@ -0,0 +1,145 @@
#!/bin/sh
test_description='git p4 locked file behavior'
. ./lib-git-p4.sh
test_expect_success 'start p4d' '
start_p4d
'
# See
# http://www.perforce.com/perforce/doc.current/manuals/p4sag/03_superuser.html#1088563
# for suggestions on how to configure "sitewide pessimistic locking"
# where only one person can have a file open for edit at a time.
test_expect_success 'init depot' '
(
cd "$cli" &&
echo "TypeMap: +l //depot/..." | p4 typemap -i &&
echo file1 >file1 &&
p4 add file1 &&
p4 submit -d "add file1"
)
'
test_expect_success 'edit with lock not taken' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
echo line2 >>file1 &&
git add file1 &&
git commit -m "line2 in file1" &&
git config git-p4.skipSubmitEdit true &&
git p4 submit
)
'
test_expect_failure 'add with lock not taken' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
echo line1 >>add-lock-not-taken &&
git add file2 &&
git commit -m "add add-lock-not-taken" &&
git config git-p4.skipSubmitEdit true &&
git p4 submit --verbose
)
'
lock_in_another_client() {
# build a different client
cli2="$TRASH_DIRECTORY/cli2" &&
mkdir -p "$cli2" &&
test_when_finished "p4 client -f -d client2 && rm -rf \"$cli2\"" &&
(
cd "$cli2" &&
P4CLIENT=client2 &&
cli="$cli2" &&
client_view "//depot/... //client2/..." &&
p4 sync &&
p4 open file1
)
}
test_expect_failure 'edit with lock taken' '
lock_in_another_client &&
test_when_finished cleanup_git &&
test_when_finished "cd \"$cli\" && p4 sync -f file1" &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
echo line3 >>file1 &&
git add file1 &&
git commit -m "line3 in file1" &&
git config git-p4.skipSubmitEdit true &&
git p4 submit --verbose
)
'
test_expect_failure 'delete with lock taken' '
lock_in_another_client &&
test_when_finished cleanup_git &&
test_when_finished "cd \"$cli\" && p4 sync -f file1" &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
git rm file1 &&
git commit -m "delete file1" &&
git config git-p4.skipSubmitEdit true &&
git p4 submit --verbose
)
'
test_expect_failure 'chmod with lock taken' '
lock_in_another_client &&
test_when_finished cleanup_git &&
test_when_finished "cd \"$cli\" && p4 sync -f file1" &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
chmod +x file1 &&
git add file1 &&
git commit -m "chmod +x file1" &&
git config git-p4.skipSubmitEdit true &&
git p4 submit --verbose
)
'
test_expect_failure 'copy with lock taken' '
lock_in_another_client &&
test_when_finished cleanup_git &&
test_when_finished "cd \"$cli\" && p4 revert file2 && rm -f file2" &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
cp file1 file2 &&
git add file2 &&
git commit -m "cp file1 to file2" &&
git config git-p4.skipSubmitEdit true &&
git config git-p4.detectCopies true &&
git p4 submit --verbose
)
'
test_expect_failure 'move with lock taken' '
lock_in_another_client &&
test_when_finished cleanup_git &&
test_when_finished "cd \"$cli\" && p4 sync file1 && rm -f file2" &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
git mv file1 file2 &&
git commit -m "mv file1 to file2" &&
git config git-p4.skipSubmitEdit true &&
git config git-p4.detectRenames true &&
git p4 submit --verbose
)
'
test_expect_success 'kill p4d' '
kill_p4d
'
test_done