From 52a4880bcda7780eeda5a884f73ffa83726dc982 Mon Sep 17 00:00:00 2001 From: Luke Diamand Date: Thu, 19 Jan 2012 09:52:25 +0000 Subject: [PATCH 1/5] git-p4: handle p4 branches and labels containing shell chars Don't use shell expansion when detecting branches, as it will fail if the branch name contains a shell metachar. Similarly for labels. Add additional test for branches with shell metachars. Signed-off-by: Luke Diamand Acked-by: Pete Wyckoff Signed-off-by: Junio C Hamano --- contrib/fast-import/git-p4 | 8 +++--- t/t9803-git-p4-shell-metachars.sh | 48 +++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 3e1aa276cf..e8c586e242 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -799,7 +799,7 @@ class P4Submit(Command, P4UserMap): def canChangeChangelists(self): # check to see if we have p4 admin or super-user permissions, either of # which are required to modify changelists. - results = p4CmdList("protects %s" % self.depotPath) + results = p4CmdList(["protects", self.depotPath]) for r in results: if r.has_key('perm'): if r['perm'] == 'admin': @@ -1758,7 +1758,7 @@ class P4Sync(Command, P4UserMap): def getLabels(self): self.labels = {} - l = p4CmdList("labels %s..." % ' '.join (self.depotPaths)) + l = p4CmdList(["labels"] + ["%s..." % p for p in self.depotPaths]) if len(l) > 0 and not self.silent: print "Finding files belonging to labels in %s" % `self.depotPaths` @@ -1800,7 +1800,7 @@ class P4Sync(Command, P4UserMap): command = "branches" for info in p4CmdList(command): - details = p4Cmd("branch -o %s" % info["branch"]) + details = p4Cmd(["branch", "-o", info["branch"]]) viewIdx = 0 while details.has_key("View%s" % viewIdx): paths = details["View%s" % viewIdx].split(" ") @@ -1938,7 +1938,7 @@ class P4Sync(Command, P4UserMap): sourceRef = self.gitRefForBranch(sourceBranch) #print "source " + sourceBranch - branchParentChange = int(p4Cmd("changes -m 1 %s...@1,%s" % (sourceDepotPath, firstChange))["change"]) + branchParentChange = int(p4Cmd(["changes", "-m", "1", "%s...@1,%s" % (sourceDepotPath, firstChange)])["change"]) #print "branch parent: %s" % branchParentChange gitParent = self.gitCommitByP4Change(sourceRef, branchParentChange) if len(gitParent) > 0: diff --git a/t/t9803-git-p4-shell-metachars.sh b/t/t9803-git-p4-shell-metachars.sh index db04375a13..db670207bd 100755 --- a/t/t9803-git-p4-shell-metachars.sh +++ b/t/t9803-git-p4-shell-metachars.sh @@ -57,6 +57,54 @@ test_expect_success 'deleting with shell metachars' ' ) ' +# Create a branch with a shell metachar in its name +# +# 1. //depot/main +# 2. //depot/branch$3 + +test_expect_success 'branch with shell char' ' + test_when_finished cleanup_git && + test_create_repo "$git" && + ( + cd "$cli" && + + mkdir -p main && + + echo f1 >main/f1 && + p4 add main/f1 && + p4 submit -d "main/f1" && + + p4 integrate //depot/main/... //depot/branch\$3/... && + p4 submit -d "integrate main to branch\$3" && + + echo f1 >branch\$3/shell_char_branch_file && + p4 add branch\$3/shell_char_branch_file && + p4 submit -d "branch\$3/shell_char_branch_file" && + + p4 branch -i <<-EOF && + Branch: branch\$3 + View: //depot/main/... //depot/branch\$3/... + EOF + + p4 edit main/f1 && + echo "a change" >> main/f1 && + p4 submit -d "a change" main/f1 && + + p4 integrate -b branch\$3 && + p4 resolve -am branch\$3/... && + p4 submit -d "integrate main to branch\$3" && + + cd "$git" && + + git config git-p4.branchList main:branch\$3 && + "$GITP4" clone --dest=. --detect-branches //depot@all && + git log --all --graph --decorate --stat && + git reset --hard p4/depot/branch\$3 && + test -f shell_char_branch_file && + test -f f1 + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' From a37a8de8d61f5af3a2d347c6d6668f4316f48383 Mon Sep 17 00:00:00 2001 From: Luke Diamand Date: Thu, 19 Jan 2012 09:52:26 +0000 Subject: [PATCH 2/5] git-p4: cope with labels with empty descriptions Use an explicit length for the data in a label, rather than EOT, so that labels with empty descriptions are passed through correctly. Signed-off-by: Luke Diamand Acked-by: Pete Wyckoff Signed-off-by: Junio C Hamano --- contrib/fast-import/git-p4 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index e8c586e242..8aa84f2caf 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -1741,9 +1741,11 @@ class P4Sync(Command, P4UserMap): else: tagger = "%s %s %s" % (owner, epoch, self.tz) self.gitStream.write("tagger %s\n" % tagger) - self.gitStream.write("data < Date: Thu, 19 Jan 2012 09:52:27 +0000 Subject: [PATCH 3/5] git-p4: importing labels should cope with missing owner In p4, the Owner field is optional. If it is missing, construct something sensible rather than crashing. Signed-off-by: Luke Diamand Acked-by: Pete Wyckoff Signed-off-by: Junio C Hamano --- contrib/fast-import/git-p4 | 63 +++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 8aa84f2caf..bcb0e6cd23 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -563,6 +563,26 @@ class Command: class P4UserMap: def __init__(self): self.userMapFromPerforceServer = False + self.myP4UserId = None + + def p4UserId(self): + if self.myP4UserId: + return self.myP4UserId + + results = p4CmdList("user -o") + for r in results: + if r.has_key('User'): + self.myP4UserId = r['User'] + return r['User'] + die("Could not find your p4 user id") + + def p4UserIsMe(self, p4User): + # return True if the given p4 user is actually me + me = self.p4UserId() + if not p4User or p4User != me: + return False + else: + return True def getUserCacheFilename(self): home = os.environ.get("HOME", os.environ.get("USERPROFILE")) @@ -700,7 +720,6 @@ class P4Submit(Command, P4UserMap): self.verbose = False self.preserveUser = gitConfig("git-p4.preserveUser").lower() == "true" self.isWindows = (platform.system() == "Windows") - self.myP4UserId = None def check(self): if len(p4CmdList("opened ...")) > 0: @@ -808,25 +827,6 @@ class P4Submit(Command, P4UserMap): return 1 return 0 - def p4UserId(self): - if self.myP4UserId: - return self.myP4UserId - - results = p4CmdList("user -o") - for r in results: - if r.has_key('User'): - self.myP4UserId = r['User'] - return r['User'] - die("Could not find your p4 user id") - - def p4UserIsMe(self, p4User): - # return True if the given p4 user is actually me - me = self.p4UserId() - if not p4User or p4User != me: - return False - else: - return True - def prepareSubmitTemplate(self): # remove lines in the Files section that show changes to files outside the depot path we're committing into template = "" @@ -1664,6 +1664,12 @@ class P4Sync(Command, P4UserMap): if self.stream_file.has_key('depotFile'): self.streamOneP4File(self.stream_file, self.stream_contents) + def make_email(self, userid): + if userid in self.users: + return self.users[userid] + else: + return "%s " % userid + def commit(self, details, files, branch, branchPrefixes, parent = ""): epoch = details["time"] author = details["user"] @@ -1687,10 +1693,7 @@ class P4Sync(Command, P4UserMap): committer = "" if author not in self.users: self.getUserMapFromPerforceServer() - if author in self.users: - committer = "%s %s %s" % (self.users[author], epoch, self.tz) - else: - committer = "%s %s %s" % (author, epoch, self.tz) + committer = "%s %s %s" % (self.make_email(author), epoch, self.tz) self.gitStream.write("committer %s\n" % committer) @@ -1735,11 +1738,15 @@ class P4Sync(Command, P4UserMap): self.gitStream.write("from %s\n" % branch) owner = labelDetails["Owner"] - tagger = "" - if author in self.users: - tagger = "%s %s %s" % (self.users[owner], epoch, self.tz) + + # Try to use the owner of the p4 label, or failing that, + # the current p4 user id. + if owner: + email = self.make_email(owner) else: - tagger = "%s %s %s" % (owner, epoch, self.tz) + email = self.make_email(self.p4UserId()) + tagger = "%s %s %s" % (email, epoch, self.tz) + self.gitStream.write("tagger %s\n" % tagger) description = labelDetails["Description"] From 4139ecc2f0d18eef54666c660285136488b90c03 Mon Sep 17 00:00:00 2001 From: Luke Diamand Date: Thu, 19 Jan 2012 09:52:28 +0000 Subject: [PATCH 4/5] git-p4: add test for p4 labels Add basic test of p4 label import. Checks label import and import with shell metachars; labels with different length descriptions. Signed-off-by: Luke Diamand Acked-by: Pete Wyckoff Signed-off-by: Junio C Hamano --- t/t9804-git-p4-label.sh | 72 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100755 t/t9804-git-p4-label.sh diff --git a/t/t9804-git-p4-label.sh b/t/t9804-git-p4-label.sh new file mode 100755 index 0000000000..5fa2bcfa97 --- /dev/null +++ b/t/t9804-git-p4-label.sh @@ -0,0 +1,72 @@ +test_description='git-p4 p4 label tests' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +# Basic p4 label tests. +# +# Note: can't have more than one label per commit - others +# are silently discarded. +# +test_expect_success 'basic p4 labels' ' + test_when_finished cleanup_git && + ( + cd "$cli" && + mkdir -p main && + + echo f1 >main/f1 && + p4 add main/f1 && + p4 submit -d "main/f1" && + + echo f2 >main/f2 && + p4 add main/f2 && + p4 submit -d "main/f2" && + + echo f3 >main/file_with_\$metachar && + p4 add main/file_with_\$metachar && + p4 submit -d "file with metachar" && + + p4 tag -l tag_f1_only main/f1 && + p4 tag -l tag_with\$_shell_char main/... && + + echo f4 >main/f4 && + p4 add main/f4 && + p4 submit -d "main/f4" && + + p4 label -i <<-EOF && + Label: long_label + Description: + A Label first line + A Label second line + View: //depot/... + EOF + + p4 tag -l long_label ... && + + p4 labels ... && + + "$GITP4" clone --dest="$git" --detect-labels //depot@all && + cd "$git" && + + git tag && + git tag >taglist && + test_line_count = 3 taglist && + + cd main && + git checkout tag_tag_f1_only && + ! test -f f2 && + git checkout tag_tag_with\$_shell_char && + test -f f1 && test -f f2 && test -f file_with_\$metachar && + + git show tag_long_label | grep -q "A Label second line" + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done From a080558ed77952b2394499531edc324eb2885d67 Mon Sep 17 00:00:00 2001 From: Luke Diamand Date: Thu, 19 Jan 2012 09:52:29 +0000 Subject: [PATCH 5/5] git-p4: label import fails with multiple labels at the same changelist git-p4 has an array of changelists with one label per changelist. But you can have multiple labels on a single changelist and so this code fails. Add a test case demonstrating the problem. Signed-off-by: Luke Diamand Acked-by: Pete Wyckoff Signed-off-by: Junio C Hamano --- t/t9804-git-p4-label.sh | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/t/t9804-git-p4-label.sh b/t/t9804-git-p4-label.sh index 5fa2bcfa97..80d01ea438 100755 --- a/t/t9804-git-p4-label.sh +++ b/t/t9804-git-p4-label.sh @@ -65,6 +65,47 @@ test_expect_success 'basic p4 labels' ' ) ' +# Test some label corner cases: +# +# - two tags on the same file; both should be available +# - a tag that is only on one file; this kind of tag +# cannot be imported (at least not easily). + +test_expect_failure 'two labels on the same changelist' ' + test_when_finished cleanup_git && + ( + cd "$cli" && + mkdir -p main && + + p4 edit main/f1 main/f2 && + echo "hello world" >main/f1 && + echo "not in the tag" >main/f2 && + p4 submit -d "main/f[12]: testing two labels" && + + p4 tag -l tag_f1_1 main/... && + p4 tag -l tag_f1_2 main/... && + + p4 labels ... && + + "$GITP4" clone --dest="$git" --detect-labels //depot@all && + cd "$git" && + + git tag | grep tag_f1 && + git tag | grep -q tag_f1_1 && + git tag | grep -q tag_f1_2 && + + cd main && + + git checkout tag_tag_f1_1 && + ls && + test -f f1 && + + git checkout tag_tag_f1_2 && + ls && + test -f f1 + ) +' + test_expect_success 'kill p4d' ' kill_p4d '