Skip to content

Commit

Permalink
Merge pull request #1 from ianhi/non-ascii-z
Browse files Browse the repository at this point in the history
Non ascii z
  • Loading branch information
ianhi authored Mar 11, 2020
2 parents 6f4d215 + 9772317 commit 0cbfa4f
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 48 deletions.
57 changes: 29 additions & 28 deletions jupyterlab_git/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import re
import subprocess
from urllib.parse import unquote
from codecs import decode, escape_decode

import pexpect
import tornado
Expand Down Expand Up @@ -169,14 +168,14 @@ async def changed_files(self, base=None, remote=None, single_commit=None):
}
"""
if single_commit:
cmd = ["git", "diff", "{}^!".format(single_commit), "--name-only"]
cmd = ["git", "diff", "{}^!".format(single_commit), "--name-only", "-z"]
elif base and remote:
if base == "WORKING":
cmd = ["git", "diff", remote, "--name-only"]
cmd = ["git", "diff", remote, "--name-only", "-z"]
elif base == "INDEX":
cmd = ["git", "diff", "--staged", remote, "--name-only"]
cmd = ["git", "diff", "--staged", remote, "--name-only", "-z"]
else:
cmd = ["git", "diff", base, remote, "--name-only"]
cmd = ["git", "diff", base, remote, "--name-only", "-z"]
else:
raise tornado.web.HTTPError(
400, "Either single_commit or (base and remote) must be provided"
Expand All @@ -194,7 +193,7 @@ async def changed_files(self, base=None, remote=None, single_commit=None):
response["command"] = " ".join(cmd)
response["message"] = error
else:
response["files"] = output.strip().split("\n")
response["files"] = output.strip("\x00").split("\x00")

return response

Expand Down Expand Up @@ -237,7 +236,7 @@ async def status(self, current_path):
"""
Execute git status command & return the result.
"""
cmd = ["git", "status", "--porcelain", "-u"]
cmd = ["git", "status", "--porcelain", "-u", "-z"]
code, my_output, my_error = await execute(
cmd, cwd=os.path.join(self.root_dir, current_path),
)
Expand All @@ -250,22 +249,24 @@ async def status(self, current_path):
}

result = []
line_array = my_output.splitlines()
for line in line_array:
to1 = None
from_path = line[3:]
if line[0] == "R":
to0 = line[3:].split(" -> ")
to1 = to0[len(to0) - 1]
line_iterable = iter(my_output.strip("\x00").split('\x00'))
result = []
for line in line_iterable:
x = line[0]
y = line[1]
if line[0]=='R':
#If file was renamed then we need both this line
#and the next line, then we want to move onto the subsequent
#line. We can accomplish this by calling next on the iterable
to = line[3:]
from_path = next(line_iterable)
else:
to1 = line[3:]
if to1.startswith('"'):
to1 = to1[1:]
if to1.endswith('"'):
to1 = to1[:-1]
to1 = decode(escape_decode(to1)[0],'utf-8')
from_path = decode(escape_decode(from_path)[0],'utf-8')
result.append({"x": line[0], "y": line[1], "to": to1, "from": from_path})
#to and from_path are the same
from_path = line[3:]
to = line[3:]
result.append({"x": x, "y": y, "to": to, "from": from_path})


return {"code": code, "files": result}

async def log(self, current_path, history_count=10):
Expand Down Expand Up @@ -314,10 +315,10 @@ async def log(self, current_path, history_count=10):

async def detailed_log(self, selected_hash, current_path):
"""
Execute git log -1 --stat --numstat --oneline command (used to get
Execute git log -1 --stat --numstat --oneline -z command (used to get
insertions & deletions per file) & return the result.
"""
cmd = ["git", "log", "-1", "--stat", "--numstat", "--oneline", selected_hash]
cmd = ["git", "log", "-1", "--stat", "--numstat", "--oneline", "-z", selected_hash]
code, my_output, my_error = await execute(
cmd, cwd=os.path.join(self.root_dir, current_path),
)
Expand All @@ -329,7 +330,7 @@ async def detailed_log(self, selected_hash, current_path):
note = [0] * 3
count = 0
temp = ""
line_array = my_output.splitlines()
line_array = re.split("\x00|\n|\r\n|\r", my_output)
length = len(line_array)
INSERTION_INDEX = 0
DELETION_INDEX = 1
Expand All @@ -342,7 +343,7 @@ async def detailed_log(self, selected_hash, current_path):
note[count] = words[i]
count += 1
for num in range(1, int(length / 2)):
line_info = line_array[num].split(maxsplit=2)
line_info = line_array[num].split('\t', maxsplit=2)
words = line_info[2].split("/")
length = len(words)
result.append(
Expand Down Expand Up @@ -373,14 +374,14 @@ async def diff(self, top_repo_path):
"""
Execute git diff command & return the result.
"""
cmd = ["git", "diff", "--numstat"]
cmd = ["git", "diff", "--numstat", "-z"]
code, my_output, my_error = await execute(cmd, cwd=top_repo_path)

if code != 0:
return {"code": code, "command": " ".join(cmd), "message": my_error}

result = []
line_array = my_output.splitlines()
line_array = my_output.strip('\x00').split('\x00')
for line in line_array:
linesplit = line.split()
result.append(
Expand Down
38 changes: 26 additions & 12 deletions jupyterlab_git/tests/test_detailed_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,35 @@
async def test_detailed_log():
with patch("jupyterlab_git.git.execute") as mock_execute:
# Given
process_output = [
process_output_first_half = [
"f29660a (HEAD, origin/feature) Commit message",
"10 3 notebook_without_spaces.ipynb",
"11 4 Notebook with spaces.ipynb",
"12 5 path/notebook_without_spaces.ipynb",
"13 6 path/Notebook with spaces.ipynb",
"10\t3\tnotebook_without_spaces.ipynb",
"11\t4\tNotebook with spaces.ipynb",
"12\t5\tpath/notebook_without_spaces.ipynb",
"13\t6\tpath/Notebook with spaces.ipynb",
"14\t1\tpath/Notebook with λ.ipynb",
]
process_output_second_half = [
" notebook_without_spaces.ipynb | 13 ++++++++---",
" Notebook with spaces.ipynb | 15 +++++++++----",
" path/notebook_without_spaces.ipynb | 17 ++++++++++-----",
" path/Notebook with spaces.ipynb | 19 +++++++++++------",
" 4 files changed, 46 insertions(+), 18 deletions(-)",
" path/Notebook with \\316\\273.ipynb | 15 +++++++++++-",
" 5 files changed, 50 insertions(+), 19 deletions(-)",
]
mock_execute.return_value = tornado.gen.maybe_future(
(0, "\n".join(process_output), "")
process_output_first_half = "\x00".join(process_output_first_half)
process_output_second_half = "\n".join(process_output_second_half)
process_output = process_output_first_half + "\x00" + process_output_second_half
mock_execute._mock_return_value = tornado.gen.maybe_future(
(0, process_output, "")
)

expected_response = {
"code": 0,
"modified_file_note": " 4 files changed, 46 insertions(+), 18 deletions(-)",
"modified_files_count": "4",
"number_of_insertions": "46",
"number_of_deletions": "18",
"modified_file_note": " 5 files changed, 50 insertions(+), 19 deletions(-)",
"modified_files_count": "5",
"number_of_insertions": "50",
"number_of_deletions": "19",
"modified_files": [
{
"modified_file_path": "notebook_without_spaces.ipynb",
Expand All @@ -62,6 +69,12 @@ async def test_detailed_log():
"insertion": "13",
"deletion": "6",
},
{
"modified_file_path": "path/Notebook with λ.ipynb",
"modified_file_name": "Notebook with λ.ipynb",
"insertion": "14",
"deletion": "1",
},
],
}

Expand All @@ -83,6 +96,7 @@ async def test_detailed_log():
"--stat",
"--numstat",
"--oneline",
"-z",
"f29660a2472e24164906af8653babeb48e4bf2ab",
],
cwd=os.path.join("/bin", "test_curr_path"),
Expand Down
17 changes: 9 additions & 8 deletions jupyterlab_git/tests/test_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ async def test_changed_files_single_commit():
with patch("jupyterlab_git.git.execute") as mock_execute:
# Given
mock_execute.return_value = tornado.gen.maybe_future(
(0, "file1.ipynb\nfile2.py", "")
(0, "file1.ipynb\x00file2.py", "")
)

# When
Expand All @@ -39,6 +39,7 @@ async def test_changed_files_single_commit():
"diff",
"64950a634cd11d1a01ddfedaeffed67b531cb11e^!",
"--name-only",
"-z",
],
cwd="/bin",
)
Expand All @@ -50,7 +51,7 @@ async def test_changed_files_working_tree():
with patch("jupyterlab_git.git.execute") as mock_execute:
# Given
mock_execute.return_value = tornado.gen.maybe_future(
(0, "file1.ipynb\nfile2.py", "")
(0, "file1.ipynb\x00file2.py", "")
)

# When
Expand All @@ -60,7 +61,7 @@ async def test_changed_files_working_tree():

# Then
mock_execute.assert_called_once_with(
["git", "diff", "HEAD", "--name-only"], cwd="/bin"
["git", "diff", "HEAD", "--name-only", "-z"], cwd="/bin"
)
assert {"code": 0, "files": ["file1.ipynb", "file2.py"]} == actual_response

Expand All @@ -70,7 +71,7 @@ async def test_changed_files_index():
with patch("jupyterlab_git.git.execute") as mock_execute:
# Given
mock_execute.return_value = tornado.gen.maybe_future(
(0, "file1.ipynb\nfile2.py", "")
(0, "file1.ipynb\x00file2.py", "")
)

# When
Expand All @@ -80,7 +81,7 @@ async def test_changed_files_index():

# Then
mock_execute.assert_called_once_with(
["git", "diff", "--staged", "HEAD", "--name-only"], cwd="/bin"
["git", "diff", "--staged", "HEAD", "--name-only", "-z"], cwd="/bin"
)
assert {"code": 0, "files": ["file1.ipynb", "file2.py"]} == actual_response

Expand All @@ -90,7 +91,7 @@ async def test_changed_files_two_commits():
with patch("jupyterlab_git.git.execute") as mock_execute:
# Given
mock_execute.return_value = tornado.gen.maybe_future(
(0, "file1.ipynb\nfile2.py", "")
(0, "file1.ipynb\x00file2.py", "")
)

# When
Expand All @@ -100,7 +101,7 @@ async def test_changed_files_two_commits():

# Then
mock_execute.assert_called_once_with(
["git", "diff", "HEAD", "origin/HEAD", "--name-only"], cwd="/bin"
["git", "diff", "HEAD", "origin/HEAD", "--name-only", "-z"], cwd="/bin"
)
assert {"code": 0, "files": ["file1.ipynb", "file2.py"]} == actual_response

Expand All @@ -118,6 +119,6 @@ async def test_changed_files_git_diff_error():

# Then
mock_execute.assert_called_once_with(
["git", "diff", "HEAD", "origin/HEAD", "--name-only"], cwd="/bin"
["git", "diff", "HEAD", "origin/HEAD", "--name-only", "-z"], cwd="/bin"
)
assert {"code": 128, "message": "error message"} == actual_response
46 changes: 46 additions & 0 deletions jupyterlab_git/tests/test_status.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# python lib
import os
from unittest.mock import Mock, call, patch

import pytest
import tornado

# local lib
from jupyterlab_git.git import Git

from .testutils import FakeContentManager

@pytest.mark.asyncio
async def test_status():
with patch("jupyterlab_git.git.execute") as mock_execute:
# Given
process_output = (
"A notebook with spaces.ipynb",
"M notebook with λ.ipynb",
"R renamed_to_θ.py",
"originally_named_π.py",
"?? untracked.ipynb",
)

expected_resonse = [
{"x": "A", "y": " ", "to": "notebook with spaces.ipynb", "from": "notebook with spaces.ipynb"},
{"x": "M", "y": " ", "to": "notebook with λ.ipynb", "from": "notebook with λ.ipynb"},
{"x": "R", "y": " ", "to": "renamed_to_θ.py", "from": "originally_named_π.py"},
{"x": "?", "y": "?", "to": "untracked.ipynb", "from": "untracked.ipynb"},
]
mock_execute.return_value = tornado.gen.maybe_future(
(0, "\x00".join(process_output), "")

)

# When
actual_response = await Git(FakeContentManager("/bin")).status(
current_path="test_curr_path"
)

# Then
mock_execute.assert_called_once_with(
["git", "status", "--porcelain" , "-u", "-z"], cwd="/bin/test_curr_path"
)

assert {"code": 0, "files": expected_resonse} == actual_response

0 comments on commit 0cbfa4f

Please sign in to comment.