{"thread":{"id":"44701","subject":"[PATCHv1 0/1] git-p4: handle symlinked directories","startedAt":"2016-12-14T08:24:08Z","lastAt":"2016-12-14T08:24:12Z","messageCount":2,"participants":["Luke Diamand"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"307740","messageId":"20161214081724.16663-1-luke@diamand.org","threadId":"44701","inReplyTo":null,"subject":"[PATCHv1 0/1] git-p4: handle symlinked directories","fromName":"Luke Diamand","fromEmail":"luke@diamand.org","sentAt":"2016-12-14T08:17:23Z","receivedAt":"2016-12-14T08:24:08Z","isPatch":false,"sender":{"key":"luke@diamand.org","avatar":"https://avatars.githubusercontent.com/u/5330967?v=4"},"body":"There's a long-standing bug around handling of symlinked directories\nin git-p4.\n\nIf in git you create a directory, and then symlink it, when git-p4\ntries to create the diff-summary of what it's about to do, it\ntries to open the symlink as a regular file, and fails.\n\nLuke Diamand (1):\n  git-p4: avoid crash adding symlinked directory\n\n git-p4.py                     | 26 ++++++++++++++++++++------\n t/t9830-git-p4-symlink-dir.sh | 43 +++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 63 insertions(+), 6 deletions(-)\n create mode 100755 t/t9830-git-p4-symlink-dir.sh\n\n-- \n2.11.0.274.g0ea315c\n\n"},{"id":"307741","messageId":"20161214081724.16663-2-luke@diamand.org","threadId":"44701","inReplyTo":"20161214081724.16663-1-luke@diamand.org","subject":"[PATCHv1 1/1] git-p4: avoid crash adding symlinked directory","fromName":"Luke Diamand","fromEmail":"luke@diamand.org","sentAt":"2016-12-14T08:17:24Z","receivedAt":"2016-12-14T08:24:12Z","isPatch":false,"sender":{"key":"luke@diamand.org","avatar":"https://avatars.githubusercontent.com/u/5330967?v=4"},"body":"When submitting to P4, if git-p4 came across a symlinked\ndirectory, then during the generation of the submit diff, it would\ntry to open it as a normal file and fail.\n\nSpot this case, and instead output the target of the symlink in\nthe submit diff.\n\nAdd a test case.\n\nSigned-off-by: Luke Diamand <luke@diamand.org>\n---\n git-p4.py                     | 26 ++++++++++++++++++++------\n t/t9830-git-p4-symlink-dir.sh | 43 +++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 63 insertions(+), 6 deletions(-)\n create mode 100755 t/t9830-git-p4-symlink-dir.sh\n\ndiff --git a/git-p4.py b/git-p4.py\nindex fd5ca5246..d2f59bd91 100755\n--- a/git-p4.py\n+++ b/git-p4.py\n@@ -25,6 +25,7 @@ import stat\n import zipfile\n import zlib\n import ctypes\n+import errno\n \n try:\n     from subprocess import CalledProcessError\n@@ -1538,7 +1539,7 @@ class P4Submit(Command, P4UserMap):\n             if response == 'n':\n                 return False\n \n-    def get_diff_description(self, editedFiles, filesToAdd):\n+    def get_diff_description(self, editedFiles, filesToAdd, symlinks):\n         # diff\n         if os.environ.has_key(\"P4DIFF\"):\n             del(os.environ[\"P4DIFF\"])\n@@ -1553,10 +1554,17 @@ class P4Submit(Command, P4UserMap):\n             newdiff += \"==== new file ====\\n\"\n             newdiff += \"--- /dev/null\\n\"\n             newdiff += \"+++ %s\\n\" % newFile\n-            f = open(newFile, \"r\")\n-            for line in f.readlines():\n-                newdiff += \"+\" + line\n-            f.close()\n+\n+            try:\n+                f = open(newFile, \"r\")\n+                for line in f.readlines():\n+                    newdiff += \"+\" + line\n+                f.close()\n+            except IOError as e:\n+                if e.errno == errno.EISDIR and newFile in symlinks:\n+                    newdiff += \"+%s\\n\" % os.readlink(newFile)\n+                else:\n+                    raise\n \n         return (diff + newdiff).replace('\\r\\n', '\\n')\n \n@@ -1574,6 +1582,7 @@ class P4Submit(Command, P4UserMap):\n         filesToDelete = set()\n         editedFiles = set()\n         pureRenameCopy = set()\n+        symlinks = set()\n         filesToChangeExecBit = {}\n \n         for line in diff:\n@@ -1590,6 +1599,11 @@ class P4Submit(Command, P4UserMap):\n                 filesToChangeExecBit[path] = diff['dst_mode']\n                 if path in filesToDelete:\n                     filesToDelete.remove(path)\n+\n+                dst_mode = int(diff['dst_mode'], 8)\n+                if dst_mode == 0120000:\n+                    symlinks.add(path)\n+\n             elif modifier == \"D\":\n                 filesToDelete.add(path)\n                 if path in filesToAdd:\n@@ -1727,7 +1741,7 @@ class P4Submit(Command, P4UserMap):\n         separatorLine = \"######## everything below this line is just the diff #######\\n\"\n         if not self.prepare_p4_only:\n             submitTemplate += separatorLine\n-            submitTemplate += self.get_diff_description(editedFiles, filesToAdd)\n+            submitTemplate += self.get_diff_description(editedFiles, filesToAdd, symlinks)\n \n         (handle, fileName) = tempfile.mkstemp()\n         tmpFile = os.fdopen(handle, \"w+b\")\ndiff --git a/t/t9830-git-p4-symlink-dir.sh b/t/t9830-git-p4-symlink-dir.sh\nnew file mode 100755\nindex 000000000..3dc528bb1\n--- /dev/null\n+++ b/t/t9830-git-p4-symlink-dir.sh\n@@ -0,0 +1,43 @@\n+#!/bin/sh\n+\n+test_description='git p4 symlinked directories'\n+\n+. ./lib-git-p4.sh\n+\n+test_expect_success 'start p4d' '\n+\tstart_p4d\n+'\n+\n+test_expect_success 'symlinked directory' '\n+\t(\n+\t\tcd \"$cli\" &&\n+\t\t: >first_file.t &&\n+\t\tp4 add first_file.t &&\n+\t\tp4 submit -d \"first change\"\n+\t) &&\n+\tgit p4 clone --dest \"$git\" //depot &&\n+\t(\n+\t\tcd \"$git\" &&\n+\t\tmkdir -p some/sub/directory &&\n+\t\tmkdir -p other/subdir2 &&\n+\t\t: > other/subdir2/file.t &&\n+\t\t(cd some/sub/directory && ln -s ../../../other/subdir2 .) &&\n+\t\tgit add some other &&\n+\t\tgit commit -m \"symlinks\" &&\n+\t\tgit config git-p4.skipSubmitEdit true &&\n+\t\tgit p4 submit -v\n+\t) &&\n+\t(\n+\t\tcd \"$cli\" &&\n+\t\tp4 sync &&\n+\t\ttest -L some/sub/directory/subdir2\n+\t\ttest_path_is_file some/sub/directory/subdir2/file.t\n+\t)\n+\n+'\n+\n+test_expect_success 'kill p4d' '\n+\tkill_p4d\n+'\n+\n+test_done\n-- \n2.11.0.274.g0ea315c\n\n"}]}