{"thread":{"id":"44723","subject":"[PATCHv2] git-p4: handle symlinked directories","startedAt":"2016-12-17T01:01:03Z","lastAt":"2016-12-17T01:01:40Z","messageCount":2,"participants":["Luke Diamand"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"307938","messageId":"20161217010040.1399-1-luke@diamand.org","threadId":"44723","inReplyTo":null,"subject":"[PATCHv2] git-p4: handle symlinked directories","fromName":"Luke Diamand","fromEmail":"luke@diamand.org","sentAt":"2016-12-17T01:00:39Z","receivedAt":"2016-12-17T01:01:03Z","isPatch":false,"sender":{"key":"luke@diamand.org","avatar":"https://avatars.githubusercontent.com/u/5330967?v=4"},"body":"This is an updated version of my earlier git-p4 symlink fix.\n\nThis one now treats addition of all symlinks in the same way,\nrather than displaying the target file if linking to a file,\nor just the link target name if it's a directory.\n\nThat makes the git-p4 summary behave more like normal git\ncommands (which also treat symlinks uniformaly).\n\nThis is a very slight change in behaviour, but I don't think\nit can break anything since it is only when generating\nthe summary that goes after the P4 change template.\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.8.2.703.g78b384c.dirty\n\n"},{"id":"307939","messageId":"20161217010040.1399-2-luke@diamand.org","threadId":"44723","inReplyTo":"20161217010040.1399-1-luke@diamand.org","subject":"[PATCHv2] git-p4: avoid crash adding symlinked directory","fromName":"Luke Diamand","fromEmail":"luke@diamand.org","sentAt":"2016-12-17T01:00:40Z","receivedAt":"2016-12-17T01:01:40Z","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 symlinks (of any type) and output a description of the symlink\ninstead.\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 fd5ca52..16d0b8a 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+            is_link = os.path.islink(newFile)\n+            expect_link = newFile in symlinks\n+\n+            if is_link and expect_link:\n+                newdiff += \"+%s\\n\" % os.readlink(newFile)\n+            else:\n+                f = open(newFile, \"r\")\n+                for line in f.readlines():\n+                    newdiff += \"+\" + line\n+                f.close()\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 0000000..3dc528b\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.8.2.703.g78b384c.dirty\n\n"}]}