Skip to content

Commit df8a9e8

Browse files
luked99gitster
authored andcommitted
git-p4: avoid crash adding symlinked directory
When submitting to P4, if git-p4 came across a symlinked directory, then during the generation of the submit diff, it would try to open it as a normal file and fail. Spot symlinks (of any type) and output a description of the symlink instead. Add a test case. Signed-off-by: Luke Diamand <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 454cb6b commit df8a9e8

File tree

2 files changed

+63
-6
lines changed

2 files changed

+63
-6
lines changed

git-p4.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import zipfile
2626
import zlib
2727
import ctypes
28+
import errno
2829

2930
try:
3031
from subprocess import CalledProcessError
@@ -1538,7 +1539,7 @@ def edit_template(self, template_file):
15381539
if response == 'n':
15391540
return False
15401541

1541-
def get_diff_description(self, editedFiles, filesToAdd):
1542+
def get_diff_description(self, editedFiles, filesToAdd, symlinks):
15421543
# diff
15431544
if os.environ.has_key("P4DIFF"):
15441545
del(os.environ["P4DIFF"])
@@ -1553,10 +1554,17 @@ def get_diff_description(self, editedFiles, filesToAdd):
15531554
newdiff += "==== new file ====\n"
15541555
newdiff += "--- /dev/null\n"
15551556
newdiff += "+++ %s\n" % newFile
1556-
f = open(newFile, "r")
1557-
for line in f.readlines():
1558-
newdiff += "+" + line
1559-
f.close()
1557+
1558+
is_link = os.path.islink(newFile)
1559+
expect_link = newFile in symlinks
1560+
1561+
if is_link and expect_link:
1562+
newdiff += "+%s\n" % os.readlink(newFile)
1563+
else:
1564+
f = open(newFile, "r")
1565+
for line in f.readlines():
1566+
newdiff += "+" + line
1567+
f.close()
15601568

15611569
return (diff + newdiff).replace('\r\n', '\n')
15621570

@@ -1574,6 +1582,7 @@ def applyCommit(self, id):
15741582
filesToDelete = set()
15751583
editedFiles = set()
15761584
pureRenameCopy = set()
1585+
symlinks = set()
15771586
filesToChangeExecBit = {}
15781587

15791588
for line in diff:
@@ -1590,6 +1599,11 @@ def applyCommit(self, id):
15901599
filesToChangeExecBit[path] = diff['dst_mode']
15911600
if path in filesToDelete:
15921601
filesToDelete.remove(path)
1602+
1603+
dst_mode = int(diff['dst_mode'], 8)
1604+
if dst_mode == 0120000:
1605+
symlinks.add(path)
1606+
15931607
elif modifier == "D":
15941608
filesToDelete.add(path)
15951609
if path in filesToAdd:
@@ -1727,7 +1741,7 @@ def applyCommit(self, id):
17271741
separatorLine = "######## everything below this line is just the diff #######\n"
17281742
if not self.prepare_p4_only:
17291743
submitTemplate += separatorLine
1730-
submitTemplate += self.get_diff_description(editedFiles, filesToAdd)
1744+
submitTemplate += self.get_diff_description(editedFiles, filesToAdd, symlinks)
17311745

17321746
(handle, fileName) = tempfile.mkstemp()
17331747
tmpFile = os.fdopen(handle, "w+b")

t/t9830-git-p4-symlink-dir.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/bin/sh
2+
3+
test_description='git p4 symlinked directories'
4+
5+
. ./lib-git-p4.sh
6+
7+
test_expect_success 'start p4d' '
8+
start_p4d
9+
'
10+
11+
test_expect_success 'symlinked directory' '
12+
(
13+
cd "$cli" &&
14+
: >first_file.t &&
15+
p4 add first_file.t &&
16+
p4 submit -d "first change"
17+
) &&
18+
git p4 clone --dest "$git" //depot &&
19+
(
20+
cd "$git" &&
21+
mkdir -p some/sub/directory &&
22+
mkdir -p other/subdir2 &&
23+
: > other/subdir2/file.t &&
24+
(cd some/sub/directory && ln -s ../../../other/subdir2 .) &&
25+
git add some other &&
26+
git commit -m "symlinks" &&
27+
git config git-p4.skipSubmitEdit true &&
28+
git p4 submit -v
29+
) &&
30+
(
31+
cd "$cli" &&
32+
p4 sync &&
33+
test -L some/sub/directory/subdir2
34+
test_path_is_file some/sub/directory/subdir2/file.t
35+
)
36+
37+
'
38+
39+
test_expect_success 'kill p4d' '
40+
kill_p4d
41+
'
42+
43+
test_done

0 commit comments

Comments
 (0)