{"thread":{"id":"28417","subject":"[PATCH 0/5] git-p4 filetype handling","startedAt":"2011-09-18T01:26:34Z","lastAt":"2011-09-23T18:01:11Z","messageCount":13,"participants":["Pete Wyckoff","Junio C Hamano","Luke Diamand"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"175702","messageId":"20110918012634.GA4578@arf.padd.com","threadId":"28417","inReplyTo":null,"subject":"[PATCH 0/5] git-p4 filetype handling","fromName":"Pete Wyckoff","fromEmail":"pw@padd.com","sentAt":"2011-09-18T01:26:34Z","receivedAt":"2011-09-18T01:26:34Z","isPatch":true,"sender":{"key":"pw@padd.com","avatar":null},"body":"Here's a series that includes some changes to make\ngit-p4 handle p4 filetypes better.  This work was\ninspired by Chris Li, and includes some refactoring\nof the git-p4 tests that grew out of looking at\nVitor's branch changes.\n\nIt could use review for generic test beauty, as well\nas for the git-p4 filetype specifics in the code.\n\n contrib/fast-import/git-p4 |   91 +++++++++++++-----\n t/lib-git-p4.sh            |   55 +++++++++++\n t/t9800-git-p4.sh          |  108 ++--------------------\n t/t9801-git-p4-branch.sh   |  221 ++++++++++++++++++++++++++++++++++++++++++++\n t/t9802-git-p4-filetype.sh |  107 +++++++++++++++++++++\n 5 files changed, 457 insertions(+), 125 deletions(-)\n\nThanks,\n\n\t\t-- Pete\n"},{"id":"175703","messageId":"20110918012713.GA4619@arf.padd.com","threadId":"28417","inReplyTo":"20110918012634.GA4578@arf.padd.com","subject":"[PATCH 1/5] git-p4 tests: refactor, split out common functions","fromName":"Pete Wyckoff","fromEmail":"pw@padd.com","sentAt":"2011-09-18T01:27:13Z","receivedAt":"2011-09-18T01:27:13Z","isPatch":true,"sender":{"key":"pw@padd.com","avatar":null},"body":"Introduce a library for functions that are common to\nmultiple git-p4 test files.\n\nSeparate the tests related to detecting p4 branches\ninto their own file, and add a few more.\n\nSigned-off-by: Pete Wyckoff <pw@padd.com>\n---\n t/lib-git-p4.sh          |   55 ++++++++++++\n t/t9800-git-p4.sh        |  108 ++---------------------\n t/t9801-git-p4-branch.sh |  221 ++++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 283 insertions(+), 101 deletions(-)\n create mode 100644 t/lib-git-p4.sh\n create mode 100755 t/t9801-git-p4-branch.sh\n\ndiff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh\nnew file mode 100644\nindex 0000000..dbc1499\n--- /dev/null\n+++ b/t/lib-git-p4.sh\n@@ -0,0 +1,55 @@\n+#\n+# Library code for git-p4 tests\n+#\n+\n+. ./test-lib.sh\n+\n+( p4 -h && p4d -h ) >/dev/null 2>&1 || {\n+\tskip_all='skipping git-p4 tests; no p4 or p4d'\n+\ttest_done\n+}\n+\n+GITP4=$GIT_BUILD_DIR/contrib/fast-import/git-p4\n+P4DPORT=10669\n+\n+export P4PORT=localhost:$P4DPORT\n+export P4CLIENT=client\n+\n+db=\"$TRASH_DIRECTORY/db\"\n+cli=\"$TRASH_DIRECTORY/cli\"\n+git=\"$TRASH_DIRECTORY/git\"\n+\n+start_p4d()\n+{\n+\tmkdir -p \"$db\" &&\n+\tp4d -q -d -r \"$db\" -p $P4DPORT &&\n+\tmkdir -p \"$cli\" &&\n+\tmkdir -p \"$git\" &&\n+\tcd \"$cli\" &&\n+\tp4 client -i <<-EOF\n+\tClient: client\n+\tDescription: client\n+\tRoot: $cli\n+\tView: //depot/... //client/...\n+\tEOF\n+}\n+\n+kill_p4d()\n+{\n+\tpid=`pgrep -f p4d` &&\n+\ttest -n \"$pid\" &&\n+\tfor i in {1..5} ; do\n+\t    test_debug \"ps wl `echo $pid`\" &&\n+\t    kill $pid 2>/dev/null &&\n+\t    pgrep -f p4d >/dev/null || break &&\n+\t    sleep 0.2\n+\tdone &&\n+\trm -rf \"$db\" &&\n+\trm -rf \"$cli\"\n+}\n+\n+cleanup_git() {\n+\tcd \"$TRASH_DIRECTORY\" &&\n+\trm -rf \"$git\" &&\n+\tmkdir \"$git\"\n+}\ndiff --git a/t/t9800-git-p4.sh b/t/t9800-git-p4.sh\nindex 01ba041..bb89b63 100755\n--- a/t/t9800-git-p4.sh\n+++ b/t/t9800-git-p4.sh\n@@ -2,40 +2,16 @@\n \n test_description='git-p4 tests'\n \n-. ./test-lib.sh\n+. ./lib-git-p4.sh\n \n-( p4 -h && p4d -h ) >/dev/null 2>&1 || {\n-\tskip_all='skipping git-p4 tests; no p4 or p4d'\n-\ttest_done\n-}\n-\n-GITP4=$GIT_BUILD_DIR/contrib/fast-import/git-p4\n-P4DPORT=10669\n-\n-export P4PORT=localhost:$P4DPORT\n-\n-db=\"$TRASH_DIRECTORY/db\"\n-cli=\"$TRASH_DIRECTORY/cli\"\n-git=\"$TRASH_DIRECTORY/git\"\n-\n-test_debug 'echo p4d -q -d -r \"$db\" -p $P4DPORT'\n-test_expect_success setup '\n-\tmkdir -p \"$db\" &&\n-\tp4d -q -d -r \"$db\" -p $P4DPORT &&\n-\tmkdir -p \"$cli\" &&\n-\tmkdir -p \"$git\" &&\n-\texport P4PORT=localhost:$P4DPORT\n+test_expect_success 'start p4d' '\n+\tkill_p4d || : &&\n+\tstart_p4d &&\n+\tcd \"$TRASH_DIRECTORY\"\n '\n \n test_expect_success 'add p4 files' '\n \tcd \"$cli\" &&\n-\tp4 client -i <<-EOF &&\n-\tClient: client\n-\tDescription: client\n-\tRoot: $cli\n-\tView: //depot/... //client/...\n-\tEOF\n-\texport P4CLIENT=client &&\n \techo file1 >file1 &&\n \tp4 add file1 &&\n \tp4 submit -d \"file1\" &&\n@@ -45,12 +21,6 @@ test_expect_success 'add p4 files' '\n \tcd \"$TRASH_DIRECTORY\"\n '\n \n-cleanup_git() {\n-\tcd \"$TRASH_DIRECTORY\" &&\n-\trm -rf \"$git\" &&\n-\tmkdir \"$git\"\n-}\n-\n test_expect_success 'basic git-p4 clone' '\n \t\"$GITP4\" clone --dest=\"$git\" //depot &&\n \ttest_when_finished cleanup_git &&\n@@ -405,72 +375,8 @@ test_expect_success 'detect copies' '\n \tp4 filelog //depot/file13 | grep -q \"branch from //depot/file\"\n '\n \n-# Create a simple branch structure in P4 depot to check if it is correctly\n-# cloned.\n-test_expect_success 'add simple p4 branches' '\n-\tcd \"$cli\" &&\n-\tmkdir branch1 &&\n-\tcd branch1 &&\n-\techo file1 >file1 &&\n-\techo file2 >file2 &&\n-\tp4 add file1 file2 &&\n-\tp4 submit -d \"branch1\" &&\n-\tp4 integrate //depot/branch1/... //depot/branch2/... &&\n-\tp4 submit -d \"branch2\" &&\n-\techo file3 >file3 &&\n-\tp4 add file3 &&\n-\tp4 submit -d \"add file3 in branch1\" &&\n-\tp4 open file2 &&\n-\techo update >>file2 &&\n-\tp4 submit -d \"update file2 in branch1\" &&\n-\tp4 integrate //depot/branch1/... //depot/branch3/... &&\n-\tp4 submit -d \"branch3\" &&\n-\tcd \"$TRASH_DIRECTORY\"\n-'\n-\n-# Configure branches through git-config and clone them.\n-# All files are tested to make sure branches were cloned correctly.\n-# Finally, make an update to branch1 on P4 side to check if it is imported\n-# correctly by git-p4.\n-test_expect_success 'git-p4 clone simple branches' '\n-\ttest_when_finished cleanup_git &&\n-\ttest_create_repo \"$git\" &&\n-\tcd \"$git\" &&\n-\tgit config git-p4.branchList branch1:branch2 &&\n-\tgit config --add git-p4.branchList branch1:branch3 &&\n-\t\"$GITP4\" clone --dest=. --detect-branches //depot@all &&\n-\tgit log --all --graph --decorate --stat &&\n-\tgit reset --hard p4/depot/branch1 &&\n-\ttest -f file1 &&\n-\ttest -f file2 &&\n-\ttest -f file3 &&\n-\tgrep -q update file2 &&\n-\tgit reset --hard p4/depot/branch2 &&\n-\ttest -f file1 &&\n-\ttest -f file2 &&\n-\ttest ! -f file3 &&\n-\t! grep -q update file2 &&\n-\tgit reset --hard p4/depot/branch3 &&\n-\ttest -f file1 &&\n-\ttest -f file2 &&\n-\ttest -f file3 &&\n-\tgrep -q update file2 &&\n-\tcd \"$cli\" &&\n-\tcd branch1 &&\n-\tp4 edit file2 &&\n-\techo file2_ >>file2 &&\n-\tp4 submit -d \"update file2 in branch1\" &&\n-\tcd \"$git\" &&\n-\tgit reset --hard p4/depot/branch1 &&\n-\t\"$GITP4\" rebase &&\n-\tgrep -q file2_ file2\n-'\n-\n-test_expect_success 'shutdown' '\n-\tpid=`pgrep -f p4d` &&\n-\ttest -n \"$pid\" &&\n-\ttest_debug \"ps wl `echo $pid`\" &&\n-\tkill $pid\n+test_expect_success 'kill p4d' '\n+\tkill_p4d\n '\n \n test_done\ndiff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh\nnew file mode 100755\nindex 0000000..0b6c1d1\n--- /dev/null\n+++ b/t/t9801-git-p4-branch.sh\n@@ -0,0 +1,221 @@\n+#!/bin/sh\n+\n+test_description='git-p4 p4 branching tests'\n+\n+. ./lib-git-p4.sh\n+\n+test_expect_success 'start p4d' '\n+\tkill_p4d || : &&\n+\tstart_p4d &&\n+\tcd \"$TRASH_DIRECTORY\"\n+'\n+\n+#\n+# 1: //depot/main/f1\n+# 2: //depot/main/f2\n+# 3: integrate //depot/main/... -> //depot/branch1/...\n+# 4: //depot/main/f4\n+# 5: //depot/branch1/f5\n+# .: named branch branch2\n+# 6: integrate -b branch2\n+# 7: //depot/branch2/f7\n+# 8: //depot/main/f8\n+#\n+test_expect_success 'basic p4 branches' '\n+\tcd \"$cli\" &&\n+\tmkdir -p main &&\n+\n+\techo f1 >main/f1 &&\n+\tp4 add main/f1 &&\n+\tp4 submit -d \"main/f1\" &&\n+\n+\techo f2 >main/f2 &&\n+\tp4 add main/f2 &&\n+\tp4 submit -d \"main/f2\" &&\n+\n+\tp4 integrate //depot/main/... //depot/branch1/... &&\n+\tp4 submit -d \"integrate main to branch1\" &&\n+\n+\techo f4 >main/f4 &&\n+\tp4 add main/f4 &&\n+\tp4 submit -d \"main/f4\" &&\n+\n+\techo f5 >branch1/f5 &&\n+\tp4 add branch1/f5 &&\n+\tp4 submit -d \"branch1/f5\" &&\n+\n+\tp4 branch -i <<-EOF &&\n+\tBranch: branch2\n+\tView: //depot/main/... //depot/branch2/...\n+\tEOF\n+\n+\tp4 integrate -b branch2 &&\n+\tp4 submit -d \"integrate main to branch2\" &&\n+\n+\techo f7 >branch2/f7 &&\n+\tp4 add branch2/f7 &&\n+\tp4 submit -d \"branch2/f7\" &&\n+\n+\techo f8 >main/f8 &&\n+\tp4 add main/f8 &&\n+\tp4 submit -d \"main/f8\" &&\n+\n+\tcd \"$TRASH_DIRECTORY\"\n+'\n+\n+test_expect_success 'import main, no branch detection' '\n+\ttest_when_finished cleanup_git &&\n+\t\"$GITP4\" clone --dest=\"$git\" //depot/main@all &&\n+\tcd \"$git\" &&\n+\tgit log --oneline --graph --decorate --all &&\n+\tgit rev-list master >wc &&\n+\ttest_line_count = 4 wc\n+'\n+\n+test_expect_success 'import branch1, no branch detection' '\n+\ttest_when_finished cleanup_git &&\n+\t\"$GITP4\" clone --dest=\"$git\" //depot/branch1@all &&\n+\tcd \"$git\" &&\n+\tgit log --oneline --graph --decorate --all &&\n+\tgit rev-list master >wc &&\n+\ttest_line_count = 2 wc\n+'\n+\n+test_expect_success 'import branch2, no branch detection' '\n+\ttest_when_finished cleanup_git &&\n+\t\"$GITP4\" clone --dest=\"$git\" //depot/branch2@all &&\n+\tcd \"$git\" &&\n+\tgit log --oneline --graph --decorate --all &&\n+\tgit rev-list master >wc &&\n+\ttest_line_count = 2 wc\n+'\n+\n+test_expect_success 'import depot, no branch detection' '\n+\ttest_when_finished cleanup_git &&\n+\t\"$GITP4\" clone --dest=\"$git\" //depot@all &&\n+\tcd \"$git\" &&\n+\tgit log --oneline --graph --decorate --all &&\n+\tgit rev-list master >wc &&\n+\ttest_line_count = 8 wc\n+'\n+\n+test_expect_success 'import depot, branch detection' '\n+\ttest_when_finished cleanup_git &&\n+\t\"$GITP4\" clone --dest=\"$git\" --detect-branches //depot@all &&\n+\tcd \"$git\" &&\n+\n+\tgit log --oneline --graph --decorate --all &&\n+\n+\t# 4 main commits\n+\tgit rev-list master >wc &&\n+\ttest_line_count = 4 wc &&\n+\n+\t# 3 main, 1 integrate, 1 on branch2\n+\tgit rev-list p4/depot/branch2 >wc &&\n+\ttest_line_count = 5 wc &&\n+\n+\t# no branch1, since no p4 branch created for it\n+\ttest_must_fail git show-ref p4/depot/branch1\n+'\n+\n+test_expect_success 'import depot, branch detection, branchList branch definition' '\n+\ttest_when_finished cleanup_git &&\n+\ttest_create_repo \"$git\" &&\n+\tcd \"$git\" &&\n+\tgit config git-p4.branchList main:branch1 &&\n+\t\"$GITP4\" clone --dest=. --detect-branches //depot@all &&\n+\n+\tgit log --oneline --graph --decorate --all &&\n+\n+\t# 4 main commits\n+\tgit rev-list master >wc &&\n+\ttest_line_count = 4 wc &&\n+\n+\t# 3 main, 1 integrate, 1 on branch2\n+\tgit rev-list p4/depot/branch2 >wc &&\n+\ttest_line_count = 5 wc &&\n+\n+\t# 2 main, 1 integrate, 1 on branch1\n+\tgit rev-list p4/depot/branch1 >wc &&\n+\ttest_line_count = 4 wc\n+'\n+\n+test_expect_success 'restart p4d' '\n+\tkill_p4d &&\n+\tstart_p4d &&\n+\tcd \"$TRASH_DIRECTORY\"\n+'\n+\n+#\n+# 1: //depot/branch1/file1\n+#    //depot/branch1/file2\n+# 2: integrate //depot/branch1/... -> //depot/branch2/...\n+# 3: //depot/branch1/file3\n+# 4: //depot/branch1/file2 (edit)\n+# 5: integrate //depot/branch1/... -> //depot/branch3/...\n+#\n+## Create a simple branch structure in P4 depot.\n+test_expect_success 'add simple p4 branches' '\n+\tcd \"$cli\" &&\n+\tmkdir branch1 &&\n+\tcd branch1 &&\n+\techo file1 >file1 &&\n+\techo file2 >file2 &&\n+\tp4 add file1 file2 &&\n+\tp4 submit -d \"branch1\" &&\n+\tp4 integrate //depot/branch1/... //depot/branch2/... &&\n+\tp4 submit -d \"branch2\" &&\n+\techo file3 >file3 &&\n+\tp4 add file3 &&\n+\tp4 submit -d \"add file3 in branch1\" &&\n+\tp4 open file2 &&\n+\techo update >>file2 &&\n+\tp4 submit -d \"update file2 in branch1\" &&\n+\tp4 integrate //depot/branch1/... //depot/branch3/... &&\n+\tp4 submit -d \"branch3\" &&\n+\tcd \"$TRASH_DIRECTORY\"\n+'\n+\n+# Configure branches through git-config and clone them.\n+# All files are tested to make sure branches were cloned correctly.\n+# Finally, make an update to branch1 on P4 side to check if it is imported\n+# correctly by git-p4.\n+test_expect_success 'git-p4 clone simple branches' '\n+\ttest_when_finished cleanup_git &&\n+\ttest_create_repo \"$git\" &&\n+\tcd \"$git\" &&\n+\tgit config git-p4.branchList branch1:branch2 &&\n+\tgit config --add git-p4.branchList branch1:branch3 &&\n+\t\"$GITP4\" clone --dest=. --detect-branches //depot@all &&\n+\tgit log --all --graph --decorate --stat &&\n+\tgit reset --hard p4/depot/branch1 &&\n+\ttest -f file1 &&\n+\ttest -f file2 &&\n+\ttest -f file3 &&\n+\tgrep -q update file2 &&\n+\tgit reset --hard p4/depot/branch2 &&\n+\ttest -f file1 &&\n+\ttest -f file2 &&\n+\ttest ! -f file3 &&\n+\ttest_must_fail grep -q update file2 &&\n+\tgit reset --hard p4/depot/branch3 &&\n+\ttest -f file1 &&\n+\ttest -f file2 &&\n+\ttest -f file3 &&\n+\tgrep -q update file2 &&\n+\tcd \"$cli\" &&\n+\tcd branch1 &&\n+\tp4 edit file2 &&\n+\techo file2_ >>file2 &&\n+\tp4 submit -d \"update file2 in branch3\" &&\n+\tcd \"$git\" &&\n+\tgit reset --hard p4/depot/branch1 &&\n+\t\"$GITP4\" rebase &&\n+\tgrep -q file2_ file2\n+'\n+\n+test_expect_success 'kill p4d' '\n+\tkill_p4d\n+'\n+\n+test_done\n-- \n1.7.6.3\n"},{"id":"175704","messageId":"20110918012831.GB4619@arf.padd.com","threadId":"28417","inReplyTo":"20110918012634.GA4578@arf.padd.com","subject":"[PATCH 2/5] git-p4: handle utf16 filetype properly","fromName":"Pete Wyckoff","fromEmail":"pw@padd.com","sentAt":"2011-09-18T01:28:31Z","receivedAt":"2011-09-18T01:28:31Z","isPatch":true,"sender":{"key":"pw@padd.com","avatar":null},"body":"One of the filetypes that p4 supports is utf16.  Its behavior is\nodd in this case.  The data delivered through \"p4 -G print\" is\nnot encoded in utf16, although \"p4 print -o\" will produce the\nproper utf16-encoded file.\n\nWhen dealing with this filetype, discard the data from -G, and\nintstead read the contents directly.\n\nAn alternate approach would be to try to encode the data in\npython.  That worked for true utf16 files, but for other files\nmarked as utf16, p4 delivers mangled text in no recognizable encoding.\n\nAdd a test case to check utf16 handling, and +k and +ko handling.\n\nReported-by: Chris Li <git@chrisli.org>\nSigned-off-by: Pete Wyckoff <pw@padd.com>\n---\n contrib/fast-import/git-p4 |   11 +++++\n t/t9802-git-p4-filetype.sh |  107 ++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 118 insertions(+), 0 deletions(-)\n create mode 100755 t/t9802-git-p4-filetype.sh\n\ndiff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4\nindex 2f7b270..e69caf3 100755\n--- a/contrib/fast-import/git-p4\n+++ b/contrib/fast-import/git-p4\n@@ -1238,6 +1238,15 @@ class P4Sync(Command, P4UserMap):\n             data = ''.join(contents)\n             contents = [data[:-1]]\n \n+        if file['type'].startswith(\"utf16\"):\n+            # p4 delivers different text in the python output to -G\n+            # than it does when using \"print -o\", or normal p4 client\n+            # operations.  utf16 is converted to ascii or utf8, perhaps.\n+            # But ascii text saved as -t utf16 is completely mangled.\n+            # Invoke print -o to get the real contents.\n+            text = p4_read_pipe('print -q -o - \"%s\"' % file['depotFile'])\n+            contents = [ text ]\n+\n         if self.isWindows and file[\"type\"].endswith(\"text\"):\n             mangled = []\n             for data in contents:\n@@ -1245,6 +1254,8 @@ class P4Sync(Command, P4UserMap):\n                 mangled.append(data)\n             contents = mangled\n \n+        # Note that we do not try to de-mangle keywords on utf16 files,\n+        # even though in theory somebody may want that.\n         if file['type'] in ('text+ko', 'unicode+ko', 'binary+ko'):\n             contents = map(lambda text: re.sub(r'(?i)\\$(Id|Header):[^$]*\\$',r'$\\1$', text), contents)\n         elif file['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'):\ndiff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh\nnew file mode 100755\nindex 0000000..f112eaa\n--- /dev/null\n+++ b/t/t9802-git-p4-filetype.sh\n@@ -0,0 +1,107 @@\n+#!/bin/sh\n+\n+test_description='git-p4 p4 filetype tests'\n+\n+. ./lib-git-p4.sh\n+\n+test_expect_success 'start p4d' '\n+\tkill_p4d || : &&\n+\tstart_p4d &&\n+\tcd \"$TRASH_DIRECTORY\"\n+'\n+\n+test_expect_success 'utf-16 file create' '\n+\tcd \"$cli\" &&\n+\n+\t# p4 saves this verbatim\n+\techo -e \"three\\nline\\ntext\" > f-ascii &&\n+\tp4 add -t text f-ascii &&\n+\n+\t# p4 adds \\377\\376 header\n+\tcp f-ascii f-ascii-as-utf16 &&\n+\tp4 add -t utf16 f-ascii-as-utf16 &&\n+\n+\t# p4 saves this exactly as iconv produced it\n+\techo -e \"three\\nline\\ntext\" | iconv -f ascii -t utf-16 > f-utf16 &&\n+\tp4 add -t utf16 f-utf16 &&\n+\n+\t# this also is unchanged\n+\tcp f-utf16 f-utf16-as-text &&\n+\tp4 add -t text f-utf16-as-text &&\n+\n+\tp4 submit -d \"f files\" &&\n+\n+\t# force update of client files\n+\tp4 sync -f &&\n+\tcd \"$TRASH_DIRECTORY\"\n+'\n+\n+test_expect_success 'utf-16 file test' '\n+\ttest_when_finished cleanup_git &&\n+\t\"$GITP4\" clone --dest=\"$git\" //depot@all &&\n+\tcd \"$git\" &&\n+\n+\tcmp \"$cli/f-ascii\" f-ascii &&\n+\tcmp \"$cli/f-ascii-as-utf16\" f-ascii-as-utf16 &&\n+\tcmp \"$cli/f-utf16\" f-utf16 &&\n+\tcmp \"$cli/f-utf16-as-text\" f-utf16-as-text\n+'\n+\n+test_expect_success 'keyword file create' '\n+\tcd \"$cli\" &&\n+\n+\techo -e \"id\\n\\$Id\\$\\n\\$Author\\$\\ntext\" > k-text-k &&\n+\tp4 add -t text+k k-text-k &&\n+\n+\tcp k-text-k k-text-ko &&\n+\tp4 add -t text+ko k-text-ko &&\n+\n+\tcat k-text-k | iconv -f ascii -t utf-16 > k-utf16-k &&\n+\tp4 add -t utf16+k k-utf16-k &&\n+\n+\tcp k-utf16-k k-utf16-ko &&\n+\tp4 add -t utf16+ko k-utf16-ko &&\n+\n+\tp4 submit -d \"k files\" &&\n+\tp4 sync -f &&\n+\tcd \"$TRASH_DIRECTORY\"\n+'\n+\n+ko_smush() {\n+\tcat >smush.py <<-EOF &&\n+\timport re, sys\n+\tsys.stdout.write(re.sub(r'(?i)\\\\\\$(Id|Header):[^$]*\\\\\\$', r'$\\1$', sys.stdin.read()))\n+\tEOF\n+\tpython smush.py < \"$1\"\n+}\n+\n+k_smush() {\n+\tcat >smush.py <<-EOF &&\n+\timport re, sys\n+\tsys.stdout.write(re.sub(r'(?i)\\\\\\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\\\\\\$', r'$\\1$', sys.stdin.read()))\n+\tEOF\n+\tpython smush.py < \"$1\"\n+}\n+\n+test_expect_success 'keyword file test' '\n+\ttest_when_finished cleanup_git &&\n+\t\"$GITP4\" clone --dest=\"$git\" //depot@all &&\n+\tcd \"$git\" &&\n+\n+\t# text, ensure unexpanded\n+\tk_smush \"$cli/k-text-k\" > cli-k-text-k-smush &&\n+\tcmp cli-k-text-k-smush k-text-k &&\n+\tko_smush \"$cli/k-text-ko\" > cli-k-text-ko-smush &&\n+\tcmp cli-k-text-ko-smush k-text-ko &&\n+\n+\t# utf16, even though p4 expands keywords, git-p4 does not\n+\t# try to undo that\n+\tcmp \"$cli/k-utf16-k\" k-utf16-k &&\n+\tcmp \"$cli/k-utf16-ko\" k-utf16-ko\n+'\n+\n+test_expect_success 'kill p4d' '\n+\tkill_p4d\n+'\n+\n+test_done\n-- \n1.7.6.3\n"},{"id":"175705","messageId":"20110918012953.GC4619@arf.padd.com","threadId":"28417","inReplyTo":"20110918012634.GA4578@arf.padd.com","subject":"[PATCH 2/5] git-p4: handle utf16 filetype properly","fromName":"Pete Wyckoff","fromEmail":"pw@padd.com","sentAt":"2011-09-18T01:29:53Z","receivedAt":"2011-09-18T01:29:53Z","isPatch":true,"sender":{"key":"pw@padd.com","avatar":null},"body":"One of the filetypes that p4 supports is utf16.  Its behavior is\nodd in this case.  The data delivered through \"p4 -G print\" is\nnot encoded in utf16, although \"p4 print -o\" will produce the\nproper utf16-encoded file.\n\nWhen dealing with this filetype, discard the data from -G, and\nintstead read the contents directly.\n\nAn alternate approach would be to try to encode the data in\npython.  That worked for true utf16 files, but for other files\nmarked as utf16, p4 delivers mangled text in no recognizable encoding.\n\nAdd a test case to check utf16 handling, and +k and +ko handling.\n\nReported-by: Chris Li <git@chrisli.org>\nSigned-off-by: Pete Wyckoff <pw@padd.com>\n---\n contrib/fast-import/git-p4 |   11 +++++\n t/t9802-git-p4-filetype.sh |  107 ++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 118 insertions(+), 0 deletions(-)\n create mode 100755 t/t9802-git-p4-filetype.sh\n\ndiff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4\nindex 2f7b270..e69caf3 100755\n--- a/contrib/fast-import/git-p4\n+++ b/contrib/fast-import/git-p4\n@@ -1238,6 +1238,15 @@ class P4Sync(Command, P4UserMap):\n             data = ''.join(contents)\n             contents = [data[:-1]]\n \n+        if file['type'].startswith(\"utf16\"):\n+            # p4 delivers different text in the python output to -G\n+            # than it does when using \"print -o\", or normal p4 client\n+            # operations.  utf16 is converted to ascii or utf8, perhaps.\n+            # But ascii text saved as -t utf16 is completely mangled.\n+            # Invoke print -o to get the real contents.\n+            text = p4_read_pipe('print -q -o - \"%s\"' % file['depotFile'])\n+            contents = [ text ]\n+\n         if self.isWindows and file[\"type\"].endswith(\"text\"):\n             mangled = []\n             for data in contents:\n@@ -1245,6 +1254,8 @@ class P4Sync(Command, P4UserMap):\n                 mangled.append(data)\n             contents = mangled\n \n+        # Note that we do not try to de-mangle keywords on utf16 files,\n+        # even though in theory somebody may want that.\n         if file['type'] in ('text+ko', 'unicode+ko', 'binary+ko'):\n             contents = map(lambda text: re.sub(r'(?i)\\$(Id|Header):[^$]*\\$',r'$\\1$', text), contents)\n         elif file['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'):\ndiff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh\nnew file mode 100755\nindex 0000000..f112eaa\n--- /dev/null\n+++ b/t/t9802-git-p4-filetype.sh\n@@ -0,0 +1,107 @@\n+#!/bin/sh\n+\n+test_description='git-p4 p4 filetype tests'\n+\n+. ./lib-git-p4.sh\n+\n+test_expect_success 'start p4d' '\n+\tkill_p4d || : &&\n+\tstart_p4d &&\n+\tcd \"$TRASH_DIRECTORY\"\n+'\n+\n+test_expect_success 'utf-16 file create' '\n+\tcd \"$cli\" &&\n+\n+\t# p4 saves this verbatim\n+\techo -e \"three\\nline\\ntext\" > f-ascii &&\n+\tp4 add -t text f-ascii &&\n+\n+\t# p4 adds \\377\\376 header\n+\tcp f-ascii f-ascii-as-utf16 &&\n+\tp4 add -t utf16 f-ascii-as-utf16 &&\n+\n+\t# p4 saves this exactly as iconv produced it\n+\techo -e \"three\\nline\\ntext\" | iconv -f ascii -t utf-16 > f-utf16 &&\n+\tp4 add -t utf16 f-utf16 &&\n+\n+\t# this also is unchanged\n+\tcp f-utf16 f-utf16-as-text &&\n+\tp4 add -t text f-utf16-as-text &&\n+\n+\tp4 submit -d \"f files\" &&\n+\n+\t# force update of client files\n+\tp4 sync -f &&\n+\tcd \"$TRASH_DIRECTORY\"\n+'\n+\n+test_expect_success 'utf-16 file test' '\n+\ttest_when_finished cleanup_git &&\n+\t\"$GITP4\" clone --dest=\"$git\" //depot@all &&\n+\tcd \"$git\" &&\n+\n+\tcmp \"$cli/f-ascii\" f-ascii &&\n+\tcmp \"$cli/f-ascii-as-utf16\" f-ascii-as-utf16 &&\n+\tcmp \"$cli/f-utf16\" f-utf16 &&\n+\tcmp \"$cli/f-utf16-as-text\" f-utf16-as-text\n+'\n+\n+test_expect_success 'keyword file create' '\n+\tcd \"$cli\" &&\n+\n+\techo -e \"id\\n\\$Id\\$\\n\\$Author\\$\\ntext\" > k-text-k &&\n+\tp4 add -t text+k k-text-k &&\n+\n+\tcp k-text-k k-text-ko &&\n+\tp4 add -t text+ko k-text-ko &&\n+\n+\tcat k-text-k | iconv -f ascii -t utf-16 > k-utf16-k &&\n+\tp4 add -t utf16+k k-utf16-k &&\n+\n+\tcp k-utf16-k k-utf16-ko &&\n+\tp4 add -t utf16+ko k-utf16-ko &&\n+\n+\tp4 submit -d \"k files\" &&\n+\tp4 sync -f &&\n+\tcd \"$TRASH_DIRECTORY\"\n+'\n+\n+ko_smush() {\n+\tcat >smush.py <<-EOF &&\n+\timport re, sys\n+\tsys.stdout.write(re.sub(r'(?i)\\\\\\$(Id|Header):[^$]*\\\\\\$', r'$\\1$', sys.stdin.read()))\n+\tEOF\n+\tpython smush.py < \"$1\"\n+}\n+\n+k_smush() {\n+\tcat >smush.py <<-EOF &&\n+\timport re, sys\n+\tsys.stdout.write(re.sub(r'(?i)\\\\\\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\\\\\\$', r'$\\1$', sys.stdin.read()))\n+\tEOF\n+\tpython smush.py < \"$1\"\n+}\n+\n+test_expect_success 'keyword file test' '\n+\ttest_when_finished cleanup_git &&\n+\t\"$GITP4\" clone --dest=\"$git\" //depot@all &&\n+\tcd \"$git\" &&\n+\n+\t# text, ensure unexpanded\n+\tk_smush \"$cli/k-text-k\" > cli-k-text-k-smush &&\n+\tcmp cli-k-text-k-smush k-text-k &&\n+\tko_smush \"$cli/k-text-ko\" > cli-k-text-ko-smush &&\n+\tcmp cli-k-text-ko-smush k-text-ko &&\n+\n+\t# utf16, even though p4 expands keywords, git-p4 does not\n+\t# try to undo that\n+\tcmp \"$cli/k-utf16-k\" k-utf16-k &&\n+\tcmp \"$cli/k-utf16-ko\" k-utf16-ko\n+'\n+\n+test_expect_success 'kill p4d' '\n+\tkill_p4d\n+'\n+\n+test_done\n-- \n1.7.6.3\n"},{"id":"175706","messageId":"20110918013116.GD4619@arf.padd.com","threadId":"28417","inReplyTo":"20110918012634.GA4578@arf.padd.com","subject":"[PATCH 3/5] git-p4: recognize all p4 filetypes","fromName":"Pete Wyckoff","fromEmail":"pw@padd.com","sentAt":"2011-09-18T01:31:16Z","receivedAt":"2011-09-18T01:31:16Z","isPatch":true,"sender":{"key":"pw@padd.com","avatar":null},"body":"The previous code was approximate in the filetypes it recognized.\nPut in the canonical list and be more careful about matching\nelements of the file type.\n\nThis might change behavior in some cases, hopefully for the\nbetter.  Windows newline mangling will now happen on all\ntext files.  Previously some like \"text+ko\" were oddly exempt.\n\nFiles with multiple combinations of modifiers, like \"text+klx\",\nare now recognized for keyword expansion.  I expect these to be\nseen only rarely.\n\nSigned-off-by: Pete Wyckoff <pw@padd.com>\n---\n contrib/fast-import/git-p4 |   71 ++++++++++++++++++++++++++++++++------------\n 1 files changed, 52 insertions(+), 19 deletions(-)\n\ndiff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4\nindex e69caf3..931cf5f 100755\n--- a/contrib/fast-import/git-p4\n+++ b/contrib/fast-import/git-p4\n@@ -118,13 +118,41 @@ def p4_system(cmd):\n     real_cmd = p4_build_cmd(cmd)\n     return system(real_cmd)\n \n-def isP4Exec(kind):\n-    \"\"\"Determine if a Perforce 'kind' should have execute permission\n+#\n+# Canonicalize the p4 type and return a tuple of the\n+# base type, plus any modifiers.  See \"p4 help filetypes\"\n+# for a list and explanation.\n+#\n+def split_p4_type(p4type):\n+\n+    p4_filetypes_historical = {\n+        \"ctempobj\": \"binary+Sw\",\n+        \"ctext\": \"text+C\",\n+        \"cxtext\": \"text+Cx\",\n+        \"ktext\": \"text+k\",\n+        \"kxtext\": \"text+kx\",\n+        \"ltext\": \"text+F\",\n+        \"tempobj\": \"binary+FSw\",\n+        \"ubinary\": \"binary+F\",\n+        \"uresource\": \"resource+F\",\n+        \"uxbinary\": \"binary+Fx\",\n+        \"xbinary\": \"binary+x\",\n+        \"xltext\": \"text+Fx\",\n+        \"xtempobj\": \"binary+Swx\",\n+        \"xtext\": \"text+x\",\n+        \"xunicode\": \"unicode+x\",\n+        \"xutf16\": \"utf16+x\",\n+    }\n+    if p4type in p4_filetypes_historical:\n+        p4type = p4_filetypes_historical[p4type]\n+    mods = \"\"\n+    s = p4type.split(\"+\")\n+    base = s[0]\n+    mods = \"\"\n+    if len(s) > 1:\n+        mods = s[1]\n+    return (base, mods)\n \n-    'p4 help filetypes' gives a list of the types.  If it starts with 'x',\n-    or x follows one of a few letters.  Otherwise, if there is an 'x' after\n-    a plus sign, it is also executable\"\"\"\n-    return (re.search(r\"(^[cku]?x)|\\+.*x\", kind) != None)\n \n def setP4ExecBit(file, mode):\n     # Reopens an already open file and changes the execute bit to match\n@@ -1229,16 +1257,18 @@ class P4Sync(Command, P4UserMap):\n         if verbose:\n             sys.stderr.write(\"%s\\n\" % relPath)\n \n-        mode = \"644\"\n-        if isP4Exec(file[\"type\"]):\n-            mode = \"755\"\n-        elif file[\"type\"] == \"symlink\":\n-            mode = \"120000\"\n-            # p4 print on a symlink contains \"target\\n\", so strip it off\n+        (type_base, type_mods) = split_p4_type(file[\"type\"])\n+\n+        git_mode = \"100644\"\n+        if \"x\" in type_mods:\n+            git_mode = \"100755\"\n+        if type_base == \"symlink\":\n+            git_mode = \"120000\"\n+            # p4 print on a symlink contains \"target\\n\"; remove the newline \n             data = ''.join(contents)\n             contents = [data[:-1]]\n \n-        if file['type'].startswith(\"utf16\"):\n+        if type_base == \"utf16\":\n             # p4 delivers different text in the python output to -G\n             # than it does when using \"print -o\", or normal p4 client\n             # operations.  utf16 is converted to ascii or utf8, perhaps.\n@@ -1247,7 +1277,9 @@ class P4Sync(Command, P4UserMap):\n             text = p4_read_pipe('print -q -o - \"%s\"' % file['depotFile'])\n             contents = [ text ]\n \n-        if self.isWindows and file[\"type\"].endswith(\"text\"):\n+        # Perhaps windows wants unicode, utf16 newlines translated too;\n+        # but this is not doing it.\n+        if self.isWindows and type_base == \"text\":\n             mangled = []\n             for data in contents:\n                 data = data.replace(\"\\r\\n\", \"\\n\")\n@@ -1256,12 +1288,13 @@ class P4Sync(Command, P4UserMap):\n \n         # Note that we do not try to de-mangle keywords on utf16 files,\n         # even though in theory somebody may want that.\n-        if file['type'] in ('text+ko', 'unicode+ko', 'binary+ko'):\n-            contents = map(lambda text: re.sub(r'(?i)\\$(Id|Header):[^$]*\\$',r'$\\1$', text), contents)\n-        elif file['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'):\n-            contents = map(lambda text: re.sub(r'\\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\\n]*\\$',r'$\\1$', text), contents)\n+        if type_base in (\"text\", \"unicode\", \"binary\"):\n+            if \"ko\" in type_mods:\n+                contents = map(lambda text: re.sub(r'(?i)\\$(Id|Header):[^$]*\\$', r'$\\1$', text), contents)\n+            elif \"k\" in type_mods:\n+                contents = map(lambda text: re.sub(r'\\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\\n]*\\$', r'$\\1$', text), contents)\n \n-        self.gitStream.write(\"M %s inline %s\\n\" % (mode, relPath))\n+        self.gitStream.write(\"M %s inline %s\\n\" % (git_mode, relPath))\n \n         # total length...\n         length = 0\n-- \n1.7.6.3\n"},{"id":"175707","messageId":"20110918013236.GE4619@arf.padd.com","threadId":"28417","inReplyTo":"20110918012634.GA4578@arf.padd.com","subject":"[PATCH 4/5] git-p4: stop ignoring apple filetype","fromName":"Pete Wyckoff","fromEmail":"pw@padd.com","sentAt":"2011-09-18T01:32:36Z","receivedAt":"2011-09-18T01:32:36Z","isPatch":true,"sender":{"key":"pw@padd.com","avatar":null},"body":"Currently \"apple\" filetype is ignored explicitly, and the file is\nnot even included in the git repository.  This seems wrong.\nRemove this, letting it be treated like a \"binary\" filetype.\n\nSigned-off-by: Pete Wyckoff <pw@padd.com>\n---\n contrib/fast-import/git-p4 |    5 -----\n 1 files changed, 0 insertions(+), 5 deletions(-)\n\ndiff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4\nindex 931cf5f..eee288d 100755\n--- a/contrib/fast-import/git-p4\n+++ b/contrib/fast-import/git-p4\n@@ -1247,11 +1247,6 @@ class P4Sync(Command, P4UserMap):\n     # - helper for streamP4Files\n \n     def streamOneP4File(self, file, contents):\n-        if file[\"type\"] == \"apple\":\n-            print \"\\nfile %s is a strange apple file that forks. Ignoring\" % \\\n-                file['depotFile']\n-            return\n-\n         relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)\n         relPath = self.wildcard_decode(relPath)\n         if verbose:\n-- \n1.7.6.3\n"},{"id":"175708","messageId":"20110918013334.GF4619@arf.padd.com","threadId":"28417","inReplyTo":"20110918012634.GA4578@arf.padd.com","subject":"[PATCH 5/5] git-p4: keyword flattening fixes","fromName":"Pete Wyckoff","fromEmail":"pw@padd.com","sentAt":"2011-09-18T01:33:34Z","receivedAt":"2011-09-18T01:33:34Z","isPatch":true,"sender":{"key":"pw@padd.com","avatar":null},"body":"Join the text before looking for keywords.  There is nothing to\nprevent the p4 output marshaller from splitting in the middle of a\nkeyword, although it has never been known to happen.\n\nAlso remove the (?i) regexp modifier; perforce keywords are\ndocumented as case-sensitive.\n\nRemove the \"\\n\" end-character match.  I don't know why that is\nin there, and every keyword in a fairly large production p4 repository\nalways ends with a $.\n\nSigned-off-by: Pete Wyckoff <pw@padd.com>\n---\n contrib/fast-import/git-p4 |    8 ++++++--\n 1 files changed, 6 insertions(+), 2 deletions(-)\n\ndiff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4\nindex eee288d..782b891 100755\n--- a/contrib/fast-import/git-p4\n+++ b/contrib/fast-import/git-p4\n@@ -1285,9 +1285,13 @@ class P4Sync(Command, P4UserMap):\n         # even though in theory somebody may want that.\n         if type_base in (\"text\", \"unicode\", \"binary\"):\n             if \"ko\" in type_mods:\n-                contents = map(lambda text: re.sub(r'(?i)\\$(Id|Header):[^$]*\\$', r'$\\1$', text), contents)\n+                text = ''.join(contents)\n+                text = re.sub(r'\\$(Id|Header):[^$]*\\$', r'$\\1$', text)\n+                contents = [ text ]\n             elif \"k\" in type_mods:\n-                contents = map(lambda text: re.sub(r'\\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\\n]*\\$', r'$\\1$', text), contents)\n+                text = ''.join(contents)\n+                text = re.sub(r'\\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\\$', r'$\\1$', text)\n+                contents = [ text ]\n \n         self.gitStream.write(\"M %s inline %s\\n\" % (git_mode, relPath))\n \n-- \n1.7.6.3\n"},{"id":"175755","messageId":"7v7h55cyis.fsf@alter.siamese.dyndns.org","threadId":"28417","inReplyTo":"20110918012713.GA4619@arf.padd.com","subject":"Re: [PATCH 1/5] git-p4 tests: refactor, split out common functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-09-18T21:48:43Z","receivedAt":"2011-09-18T21:48:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pete Wyckoff <pw@padd.com> writes:\n\n> Introduce a library for functions that are common to\n> multiple git-p4 test files.\n>\n> Separate the tests related to detecting p4 branches\n> into their own file, and add a few more.\n>\n> Signed-off-by: Pete Wyckoff <pw@padd.com>\n> ---\n>  t/lib-git-p4.sh          |   55 ++++++++++++\n>  t/t9800-git-p4.sh        |  108 ++---------------------\n>  t/t9801-git-p4-branch.sh |  221 ++++++++++++++++++++++++++++++++++++++++++++++\n>  3 files changed, 283 insertions(+), 101 deletions(-)\n>  create mode 100644 t/lib-git-p4.sh\n>  create mode 100755 t/t9801-git-p4-branch.sh\n\nI take that you meant \"coding style\" by \"generic test beauty\" in the cover\nletter, so here are some minor nitpicks.\n\n> diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh\n> new file mode 100644\n> index 0000000..dbc1499\n> --- /dev/null\n> +++ b/t/lib-git-p4.sh\n> @@ -0,0 +1,55 @@\n> +#\n> +# Library code for git-p4 tests\n> +#\n> +\n> +. ./test-lib.sh\n> +\n> +( p4 -h && p4d -h ) >/dev/null 2>&1 || {\n> +\tskip_all='skipping git-p4 tests; no p4 or p4d'\n> +\ttest_done\n> +}\n> +\n> +GITP4=$GIT_BUILD_DIR/contrib/fast-import/git-p4\n> +P4DPORT=10669\n\nWhat happens when tests are run in parallel (make -j or prove --jobs) and\n9800 and 9801 are run at the same time?\n\n> +export P4PORT=localhost:$P4DPORT\n> +export P4CLIENT=client\n> +\n> +db=\"$TRASH_DIRECTORY/db\"\n> +cli=\"$TRASH_DIRECTORY/cli\"\n> +git=\"$TRASH_DIRECTORY/git\"\n> +\n> +start_p4d()\n> +{\n\nPrevalent style in t/ and scripted part of Git in general is to begin a\nshell function like this, with SP on both sides of () and opening brace\non the same line.\n\n\tstart_p4d () {\n\n> +\tmkdir -p \"$db\" &&\n> +\tp4d -q -d -r \"$db\" -p $P4DPORT &&\n> +\tmkdir -p \"$cli\" &&\n> +\tmkdir -p \"$git\" &&\n> +\tcd \"$cli\" &&\n> +\tp4 client -i <<-EOF\n> +\tClient: client\n> +\tDescription: client\n> +\tRoot: $cli\n> +\tView: //depot/... //client/...\n> +\tEOF\n> +}\n> +\n> +kill_p4d()\n> +{\n> +\tpid=`pgrep -f p4d` &&\n> +\ttest -n \"$pid\" &&\n\nIt is unfortunate that you have to use pgrep. I am unfamiliar with p4, but\ndo you have any control how p4d is started during this test? If the first\nuse of client automagically starts p4d without your control, that would be\nharder to arrange, but the point I am getting at is that if you know when\nyou start p4d yourself and that is the only p4d process you use, you\nshould be keep its pid in $TRASH_DIRECTORY somewhere and replace these\nwith\n\n\tpid=$(cat \"$TRASH_DIRECTORY/p4d_pid\") &&\n        kill -0 \"$pid\"\n\nto see if that daemon is still alive. \n\nYou call kill_p4d at the very beginning of t9800; what instance of p4d are\nyou trying to kill? Who could have started it? For you to be able to kill\n(and nobody sane would be running the test suite as \"root\", I hope), it\nwould be your process, but would it be possible that you are doing some\nother important thing using p4 that is not related to git-p4 development\nor testing at all, perhaps listening to a port different from 10669? Would\nit be necessary to kill that other p4d to run these tests in a predicatable\nand reproducible environment?\n\nI would very much more prefer if at the very beginning you started p4d at\nthe port assigned for the test and fail the test if it cannot start for\nwhatever reason. Perhaps the reason you cannot start a p4d is because a\nstale p4d instance is hanging around from previous round of test, and if\nthat is the case, then that is the bug we need to fix in the _previous_\ntest, not something we want to sweep under the rug by killing it during\nthis round of test.\n\n> +\tfor i in {1..5} ; do\n\nThat {1..5} does not pass POSIX shells, such as /bin/dash.\n\n\tfor i in 1 2 3 4 5\n\tdo\n\t\t...\n\n> +\t    test_debug \"ps wl `echo $pid`\" &&\n> +\t    kill $pid 2>/dev/null &&\n> +\t    pgrep -f p4d >/dev/null || break &&\n\nYou are saying \"all of these things would hold true if we attempt to kill\nit and it still is alive\" with the chain of \"&&\" up to that last pgrep,\nand then with \"||\", you say \"otherwise we do not have to keep sending the\nsignal to it anymore\". But the extra \"&&\" after \"break\" is unneeded and\nmisleading.\n\n> +\t    sleep 0.2\n\nThat 0.2 does not look like a non-negative decimal interger like POSIX\nwants to have.\n\n> +\tdone &&\n> +\trm -rf \"$db\" &&\n> +\trm -rf \"$cli\"\n> +}\n> +\n> +cleanup_git() {\n> +\tcd \"$TRASH_DIRECTORY\" &&\n> +\trm -rf \"$git\" &&\n> +\tmkdir \"$git\"\n> +}\n> diff --git a/t/t9800-git-p4.sh b/t/t9800-git-p4.sh\n> index 01ba041..bb89b63 100755\n> --- a/t/t9800-git-p4.sh\n> +++ b/t/t9800-git-p4.sh\n> @@ -2,40 +2,16 @@\n>  \n>  test_description='git-p4 tests'\n>  \n> -. ./test-lib.sh\n> +. ./lib-git-p4.sh\n>  \n> +test_expect_success 'start p4d' '\n> +\tkill_p4d || : &&\n> +\tstart_p4d &&\n> +\tcd \"$TRASH_DIRECTORY\"\n>  '\n\nDon't \"chdir\" around in the test, and worse yet hide some \"cd\" in helper\nfunctions. The seemingly unnecessary \"cd $TRASH_DIRECTORY\" at the end,\nwhich may not even happen if start_p4d fails, is because start_p4d has a\nhidden \"cd\" somewhere (which in turn may or may not run depending on where\nin the && chain you have a failure).\n\nOne way to keep the test cleaner is to do the helper functions like the\nfollowing, so that the callers do not have to worry about where they end\nup with:\n\n\tstart_p4d () {\n\t\tmkdir -p \"$db\" \"$cli\" \"$git\" &&\n                p4d -q -d -r \"$db\" -p \"$P4DPORT\" &&\n\t\t(\n\t\t\tcd \"$cli\" &&\n\t\t\tp4 client -i <<-EOF\n\t\t\t...\n\t\t\tEOF\n\t\t)\n\t}\n\n>  test_expect_success 'add p4 files' '\n>  \tcd \"$cli\" &&\n>  \techo file1 >file1 &&\n>  \tp4 add file1 &&\n>  \tp4 submit -d \"file1\" &&\n>  ...\n>  \tcd \"$TRASH_DIRECTORY\"\n>  '\n\nThe same issue here.\n\n\ttest_expect_success 'add p4 files' '\n\t\t(\n\t\t\tcd \"$cli\" &&\n\t\t\techo file1 >file1 &&\n\t\t\t...\n\t\t)\n\t'\n"},{"id":"175910","messageId":"20110921012917.GA27256@arf.padd.com","threadId":"28417","inReplyTo":"7v7h55cyis.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 1/5] git-p4 tests: refactor, split out common functions","fromName":"Pete Wyckoff","fromEmail":"pw@padd.com","sentAt":"2011-09-21T01:29:17Z","receivedAt":"2011-09-21T01:29:17Z","isPatch":true,"sender":{"key":"pw@padd.com","avatar":null},"body":"gitster@pobox.com wrote on Sun, 18 Sep 2011 14:48 -0700:\n> Pete Wyckoff <pw@padd.com> writes:\n> \n> > Introduce a library for functions that are common to\n> > multiple git-p4 test files.\n> >\n> > Separate the tests related to detecting p4 branches\n> > into their own file, and add a few more.\n> >\n> > Signed-off-by: Pete Wyckoff <pw@padd.com>\n> > ---\n> >  t/lib-git-p4.sh          |   55 ++++++++++++\n> >  t/t9800-git-p4.sh        |  108 ++---------------------\n> >  t/t9801-git-p4-branch.sh |  221 ++++++++++++++++++++++++++++++++++++++++++++++\n> >  3 files changed, 283 insertions(+), 101 deletions(-)\n> >  create mode 100644 t/lib-git-p4.sh\n> >  create mode 100755 t/t9801-git-p4-branch.sh\n> \n> I take that you meant \"coding style\" by \"generic test beauty\" in the cover\n> letter, so here are some minor nitpicks.\n\nDefinitely appreciated.\n\n> > diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh\n> > new file mode 100644\n> > index 0000000..dbc1499\n> > --- /dev/null\n> > +++ b/t/lib-git-p4.sh\n> > @@ -0,0 +1,55 @@\n> > +#\n> > +# Library code for git-p4 tests\n> > +#\n> > +\n> > +. ./test-lib.sh\n> > +\n> > +( p4 -h && p4d -h ) >/dev/null 2>&1 || {\n> > +\tskip_all='skipping git-p4 tests; no p4 or p4d'\n> > +\ttest_done\n> > +}\n> > +\n> > +GITP4=$GIT_BUILD_DIR/contrib/fast-import/git-p4\n> > +P4DPORT=10669\n> \n> What happens when tests are run in parallel (make -j or prove --jobs) and\n> 9800 and 9801 are run at the same time?\n\nHard... part of the p4d pain below.\n\n> > +export P4PORT=localhost:$P4DPORT\n> > +export P4CLIENT=client\n> > +\n> > +db=\"$TRASH_DIRECTORY/db\"\n> > +cli=\"$TRASH_DIRECTORY/cli\"\n> > +git=\"$TRASH_DIRECTORY/git\"\n> > +\n> > +start_p4d()\n> > +{\n> \n> Prevalent style in t/ and scripted part of Git in general is to begin a\n> shell function like this, with SP on both sides of () and opening brace\n> on the same line.\n\nThanks, fixed.\n\n> \tstart_p4d () {\n> \n> > +\tmkdir -p \"$db\" &&\n> > +\tp4d -q -d -r \"$db\" -p $P4DPORT &&\n> > +\tmkdir -p \"$cli\" &&\n> > +\tmkdir -p \"$git\" &&\n> > +\tcd \"$cli\" &&\n> > +\tp4 client -i <<-EOF\n> > +\tClient: client\n> > +\tDescription: client\n> > +\tRoot: $cli\n> > +\tView: //depot/... //client/...\n> > +\tEOF\n> > +}\n> > +\n> > +kill_p4d()\n> > +{\n> > +\tpid=`pgrep -f p4d` &&\n> > +\ttest -n \"$pid\" &&\n> \n> It is unfortunate that you have to use pgrep. I am unfamiliar with p4, but\n> do you have any control how p4d is started during this test? If the first\n> use of client automagically starts p4d without your control, that would be\n> harder to arrange, but the point I am getting at is that if you know when\n> you start p4d yourself and that is the only p4d process you use, you\n> should be keep its pid in $TRASH_DIRECTORY somewhere and replace these\n> with\n> \n> \tpid=$(cat \"$TRASH_DIRECTORY/p4d_pid\") &&\n>         kill -0 \"$pid\"\n> \n> to see if that daemon is still alive. \n> \n> You call kill_p4d at the very beginning of t9800; what instance of p4d are\n> you trying to kill? Who could have started it? For you to be able to kill\n> (and nobody sane would be running the test suite as \"root\", I hope), it\n> would be your process, but would it be possible that you are doing some\n> other important thing using p4 that is not related to git-p4 development\n> or testing at all, perhaps listening to a port different from 10669? Would\n> it be necessary to kill that other p4d to run these tests in a predicatable\n> and reproducible environment?\n> \n> I would very much more prefer if at the very beginning you started p4d at\n> the port assigned for the test and fail the test if it cannot start for\n> whatever reason. Perhaps the reason you cannot start a p4d is because a\n> stale p4d instance is hanging around from previous round of test, and if\n> that is the case, then that is the bug we need to fix in the _previous_\n> test, not something we want to sweep under the rug by killing it during\n> this round of test.\n\nYes, this is all very shoddy, and I suspect that I don't need the\ninitial kill_p4d as long as the other tests fail nicely.\n\nBut your point about killing the _wrong_ p4d is good.  But p4d\nisn't friendly like other daemons that will drop a pid file for\nhelp in future cleanup.  I can run it without the \"-d\", in which\ncase it does not daemonize.  Then I should be able to use shell\njob control to kill off the one I started, hopefully.\n\nFinding an unused port is also a pain.  I'll see if p4d produces\nparseable error messages that can indicate a taken port.\nOtherwise, hardcoding a port per test is a good idea, and will\nfix the parallel-run problem.  Hopefully no \"production\" p4d\nalso happens to be running at the same random port with this\napproach.\n\n> > +\tfor i in {1..5} ; do\n> \n> That {1..5} does not pass POSIX shells, such as /bin/dash.\n> \n> \tfor i in 1 2 3 4 5\n> \tdo\n> \t\t...\n\nAh.  Or `seq`, but not sure its existence can be counted on.\nFixed as you suggest for this teensy list.\n\n> > +\t    test_debug \"ps wl `echo $pid`\" &&\n> > +\t    kill $pid 2>/dev/null &&\n> > +\t    pgrep -f p4d >/dev/null || break &&\n> \n> You are saying \"all of these things would hold true if we attempt to kill\n> it and it still is alive\" with the chain of \"&&\" up to that last pgrep,\n> and then with \"||\", you say \"otherwise we do not have to keep sending the\n> signal to it anymore\". But the extra \"&&\" after \"break\" is unneeded and\n> misleading.\n\nYes, that is icky.  I'll send this instead, next time (unless I\ncan fix the p4d issues):\n\n\tkill $pid 2>/dev/null &&\n\tif pgrep -f p4d >/dev/null ; then\n\t    break\n\tfi &&\n\n> > +\t    sleep 0.2\n> \n> That 0.2 does not look like a non-negative decimal interger like POSIX\n> wants to have.\n\nSwitched to 1.  Optimization of 0.2 isn't important.\n\n> > +test_expect_success 'start p4d' '\n> > +\tkill_p4d || : &&\n> > +\tstart_p4d &&\n> > +\tcd \"$TRASH_DIRECTORY\"\n> >  '\n> \n> Don't \"chdir\" around in the test, and worse yet hide some \"cd\" in helper\n> functions. The seemingly unnecessary \"cd $TRASH_DIRECTORY\" at the end,\n> which may not even happen if start_p4d fails, is because start_p4d has a\n> hidden \"cd\" somewhere (which in turn may or may not run depending on where\n> in the && chain you have a failure).\n> \n> One way to keep the test cleaner is to do the helper functions like the\n> following, so that the callers do not have to worry about where they end\n> up with:\n> \n> \tstart_p4d () {\n> \t\tmkdir -p \"$db\" \"$cli\" \"$git\" &&\n>                 p4d -q -d -r \"$db\" -p \"$P4DPORT\" &&\n> \t\t(\n> \t\t\tcd \"$cli\" &&\n> \t\t\tp4 client -i <<-EOF\n> \t\t\t...\n> \t\t\tEOF\n> \t\t)\n> \t}\n\nI see; chdir in a subshell.  Will rework these to remove the\nsilly post-test cd, and put other cds inside shells.\n\n> >  test_expect_success 'add p4 files' '\n> >  \tcd \"$cli\" &&\n> >  \techo file1 >file1 &&\n> >  \tp4 add file1 &&\n> >  \tp4 submit -d \"file1\" &&\n> >  ...\n> >  \tcd \"$TRASH_DIRECTORY\"\n> >  '\n> \n> The same issue here.\n> \n> \ttest_expect_success 'add p4 files' '\n> \t\t(\n> \t\t\tcd \"$cli\" &&\n> \t\t\techo file1 >file1 &&\n> \t\t\t...\n> \t\t)\n> \t'\n\nThanks for the useful critique.  I'll think through the difficult\nissues with p4d, and resubmit the whole series post-release.\n\n\t\t-- Pete\n"},{"id":"175912","messageId":"7vfwjq4o96.fsf@alter.siamese.dyndns.org","threadId":"28417","inReplyTo":"20110921012917.GA27256@arf.padd.com","subject":"Re: [PATCH 1/5] git-p4 tests: refactor, split out common functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-09-21T02:34:29Z","receivedAt":"2011-09-21T02:34:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pete Wyckoff <pw@padd.com> writes:\n\n> Yes, this is all very shoddy, and I suspect that I don't need the\n> initial kill_p4d as long as the other tests fail nicely.\n>\n> But your point about killing the _wrong_ p4d is good.  But p4d\n> isn't friendly like other daemons that will drop a pid file for\n> help in future cleanup.  I can run it without the \"-d\", in which\n> case it does not daemonize.  Then I should be able to use shell\n> job control to kill off the one I started, hopefully.\n\nYeah, something like\n\n\t: start\n\tp4d &\n        echo $! >$pidfile\n\n        : stop\n\twhile kill -0 $pidfile\n        do\n\t        kill $pidfile\n                sleep 1\n\tdone\n\n> Finding an unused port is also a pain.\n\nI think the way t55xx series assign LIB_HTTPD_PORT is an acceptable\ncompromise.\n"},{"id":"175913","messageId":"7vboue4o6s.fsf@alter.siamese.dyndns.org","threadId":"28417","inReplyTo":"7vfwjq4o96.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 1/5] git-p4 tests: refactor, split out common functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-09-21T02:35:55Z","receivedAt":"2011-09-21T02:35:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Yeah, something like\n>\n> \t: start\n> \tp4d &\n>         echo $! >$pidfile\n\nObviously I should have written:\n\n\t: stop\n        pid=$(cat \"$pidfile\")\n\twhile kill -0 $pid\n\tdo\n\t\tkill $pid\n\t\tsleep 1\n\tdone\n\nSorry for the noise.\n\n>         : stop\n> \twhile kill -0 $pidfile\n>         do\n> \t        kill $pidfile\n>                 sleep 1\n> \tdone\n>\n>> Finding an unused port is also a pain.\n>\n> I think the way t55xx series assign LIB_HTTPD_PORT is an acceptable\n> compromise.\n"},{"id":"176078","messageId":"4E7CC843.8080707@diamand.org","threadId":"28417","inReplyTo":"20110918012634.GA4578@arf.padd.com","subject":"Re: [PATCH 0/5] git-p4 filetype handling","fromName":"Luke Diamand","fromEmail":"luke@diamand.org","sentAt":"2011-09-23T17:56:19Z","receivedAt":"2011-09-23T17:56:19Z","isPatch":true,"sender":{"key":"luke@diamand.org","avatar":"https://avatars.githubusercontent.com/u/5330967?v=4"},"body":"On 18/09/11 02:26, Pete Wyckoff wrote:\n> Here's a series that includes some changes to make\n> git-p4 handle p4 filetypes better.  This work was\n> inspired by Chris Li, and includes some refactoring\n> of the git-p4 tests that grew out of looking at\n> Vitor's branch changes.\n>\n> It could use review for generic test beauty, as well\n> as for the git-p4 filetype specifics in the code.\n\nModulo Junio's other comments, this looks sensible to me. I tried it on \na sizeable tree and it didn't scramble anything (but that will only have \ntested the 'normal' filetypes).\n\nDo we use $(some_command) rather than `some_command` now?\n\nA few other small comments to follow.\n\nRegards!\nLuke\n\n\n>\n>   contrib/fast-import/git-p4 |   91 +++++++++++++-----\n>   t/lib-git-p4.sh            |   55 +++++++++++\n>   t/t9800-git-p4.sh          |  108 ++--------------------\n>   t/t9801-git-p4-branch.sh   |  221 ++++++++++++++++++++++++++++++++++++++++++++\n>   t/t9802-git-p4-filetype.sh |  107 +++++++++++++++++++++\n>   5 files changed, 457 insertions(+), 125 deletions(-)\n>\n> Thanks,\n>\n> \t\t-- Pete\n>\n"},{"id":"176080","messageId":"4E7CC967.8010502@diamand.org","threadId":"28417","inReplyTo":"20110918012831.GB4619@arf.padd.com","subject":"Re: [PATCH 2/5] git-p4: handle utf16 filetype properly","fromName":"Luke Diamand","fromEmail":"luke@diamand.org","sentAt":"2011-09-23T18:01:11Z","receivedAt":"2011-09-23T18:01:11Z","isPatch":true,"sender":{"key":"luke@diamand.org","avatar":"https://avatars.githubusercontent.com/u/5330967?v=4"},"body":"On 18/09/11 02:28, Pete Wyckoff wrote:\n> One of the filetypes that p4 supports is utf16.  Its behavior is\n> odd in this case.  The data delivered through \"p4 -G print\" is\n> not encoded in utf16, although \"p4 print -o\" will produce the\n> proper utf16-encoded file.\n>\n> When dealing with this filetype, discard the data from -G, and\n> intstead read the contents directly.\n\n\"intstead\" - should be \"instead\", or perhaps \"int32_tstead\".\n\n\n\n>\n> An alternate approach would be to try to encode the data in\n> python.  That worked for true utf16 files, but for other files\n> marked as utf16, p4 delivers mangled text in no recognizable encoding.\n>\n> Add a test case to check utf16 handling, and +k and +ko handling.\n>\n> Reported-by: Chris Li<git@chrisli.org>\n> Signed-off-by: Pete Wyckoff<pw@padd.com>\n> ---\n>   contrib/fast-import/git-p4 |   11 +++++\n>   t/t9802-git-p4-filetype.sh |  107 ++++++++++++++++++++++++++++++++++++++++++++\n>   2 files changed, 118 insertions(+), 0 deletions(-)\n>   create mode 100755 t/t9802-git-p4-filetype.sh\n>\n> diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4\n> index 2f7b270..e69caf3 100755\n> --- a/contrib/fast-import/git-p4\n> +++ b/contrib/fast-import/git-p4\n> @@ -1238,6 +1238,15 @@ class P4Sync(Command, P4UserMap):\n>               data = ''.join(contents)\n>               contents = [data[:-1]]\n>\n> +        if file['type'].startswith(\"utf16\"):\n> +            # p4 delivers different text in the python output to -G\n> +            # than it does when using \"print -o\", or normal p4 client\n> +            # operations.  utf16 is converted to ascii or utf8, perhaps.\n> +            # But ascii text saved as -t utf16 is completely mangled.\n> +            # Invoke print -o to get the real contents.\n> +            text = p4_read_pipe('print -q -o - \"%s\"' % file['depotFile'])\n> +            contents = [ text ]\n> +\n>           if self.isWindows and file[\"type\"].endswith(\"text\"):\n>               mangled = []\n>               for data in contents:\n> @@ -1245,6 +1254,8 @@ class P4Sync(Command, P4UserMap):\n>                   mangled.append(data)\n>               contents = mangled\n>\n> +        # Note that we do not try to de-mangle keywords on utf16 files,\n> +        # even though in theory somebody may want that.\n>           if file['type'] in ('text+ko', 'unicode+ko', 'binary+ko'):\n>               contents = map(lambda text: re.sub(r'(?i)\\$(Id|Header):[^$]*\\$',r'$\\1$', text), contents)\n>           elif file['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'):\n> diff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh\n> new file mode 100755\n> index 0000000..f112eaa\n> --- /dev/null\n> +++ b/t/t9802-git-p4-filetype.sh\n> @@ -0,0 +1,107 @@\n> +#!/bin/sh\n> +\n> +test_description='git-p4 p4 filetype tests'\n> +\n> +. ./lib-git-p4.sh\n> +\n> +test_expect_success 'start p4d' '\n> +\tkill_p4d || :&&\n> +\tstart_p4d&&\n> +\tcd \"$TRASH_DIRECTORY\"\n> +'\n> +\n> +test_expect_success 'utf-16 file create' '\n> +\tcd \"$cli\"&&\n> +\n> +\t# p4 saves this verbatim\n> +\techo -e \"three\\nline\\ntext\">  f-ascii&&\n> +\tp4 add -t text f-ascii&&\n> +\n> +\t# p4 adds \\377\\376 header\n> +\tcp f-ascii f-ascii-as-utf16&&\n> +\tp4 add -t utf16 f-ascii-as-utf16&&\n> +\n> +\t# p4 saves this exactly as iconv produced it\n> +\techo -e \"three\\nline\\ntext\" | iconv -f ascii -t utf-16>  f-utf16&&\n> +\tp4 add -t utf16 f-utf16&&\n> +\n> +\t# this also is unchanged\n> +\tcp f-utf16 f-utf16-as-text&&\n> +\tp4 add -t text f-utf16-as-text&&\n> +\n> +\tp4 submit -d \"f files\"&&\n> +\n> +\t# force update of client files\n> +\tp4 sync -f&&\n> +\tcd \"$TRASH_DIRECTORY\"\n> +'\n> +\n> +test_expect_success 'utf-16 file test' '\n> +\ttest_when_finished cleanup_git&&\n> +\t\"$GITP4\" clone --dest=\"$git\" //depot@all&&\n> +\tcd \"$git\"&&\n> +\n> +\tcmp \"$cli/f-ascii\" f-ascii&&\n> +\tcmp \"$cli/f-ascii-as-utf16\" f-ascii-as-utf16&&\n> +\tcmp \"$cli/f-utf16\" f-utf16&&\n> +\tcmp \"$cli/f-utf16-as-text\" f-utf16-as-text\n> +'\n> +\n> +test_expect_success 'keyword file create' '\n> +\tcd \"$cli\"&&\n> +\n> +\techo -e \"id\\n\\$Id\\$\\n\\$Author\\$\\ntext\">  k-text-k&&\n> +\tp4 add -t text+k k-text-k&&\n> +\n> +\tcp k-text-k k-text-ko&&\n> +\tp4 add -t text+ko k-text-ko&&\n> +\n> +\tcat k-text-k | iconv -f ascii -t utf-16>  k-utf16-k&&\n> +\tp4 add -t utf16+k k-utf16-k&&\n> +\n> +\tcp k-utf16-k k-utf16-ko&&\n> +\tp4 add -t utf16+ko k-utf16-ko&&\n> +\n> +\tp4 submit -d \"k files\"&&\n> +\tp4 sync -f&&\n> +\tcd \"$TRASH_DIRECTORY\"\n> +'\n> +\n> +ko_smush() {\n> +\tcat>smush.py<<-EOF&&\n> +\timport re, sys\n> +\tsys.stdout.write(re.sub(r'(?i)\\\\\\$(Id|Header):[^$]*\\\\\\$', r'$\\1$', sys.stdin.read()))\n> +\tEOF\n> +\tpython smush.py<  \"$1\"\n> +}\n> +\n> +k_smush() {\n> +\tcat>smush.py<<-EOF&&\n> +\timport re, sys\n> +\tsys.stdout.write(re.sub(r'(?i)\\\\\\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\\\\\\$', r'$\\1$', sys.stdin.read()))\n> +\tEOF\n> +\tpython smush.py<  \"$1\"\n> +}\n> +\n> +test_expect_success 'keyword file test' '\n> +\ttest_when_finished cleanup_git&&\n> +\t\"$GITP4\" clone --dest=\"$git\" //depot@all&&\n> +\tcd \"$git\"&&\n> +\n> +\t# text, ensure unexpanded\n> +\tk_smush \"$cli/k-text-k\">  cli-k-text-k-smush&&\n> +\tcmp cli-k-text-k-smush k-text-k&&\n> +\tko_smush \"$cli/k-text-ko\">  cli-k-text-ko-smush&&\n> +\tcmp cli-k-text-ko-smush k-text-ko&&\n> +\n> +\t# utf16, even though p4 expands keywords, git-p4 does not\n> +\t# try to undo that\n> +\tcmp \"$cli/k-utf16-k\" k-utf16-k&&\n> +\tcmp \"$cli/k-utf16-ko\" k-utf16-ko\n> +'\n> +\n> +test_expect_success 'kill p4d' '\n> +\tkill_p4d\n> +'\n> +\n> +test_done\n"}]}