Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for standalone diffs of images #1223

Merged
merged 37 commits into from
Jun 4, 2023
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f8e5d40
add ImageDiff component with stub methods
Damans227 Oct 27, 2022
f05ec9c
register image diff and add git widget
Damans227 Nov 10, 2022
3ad0b69
handle image files in the backend
Damans227 Nov 16, 2022
545a910
convert binary file to base64
Damans227 Nov 23, 2022
c2cbb53
return content from binary file condition
Damans227 Nov 30, 2022
ebba03f
Load image from git db
fcollonval Dec 5, 2022
6c623eb
Merge pull request #1 from fcollonval/load-image
Damans227 Dec 6, 2022
414428f
Merge branch 'jupyterlab:master' into add-image-diff
basokant Feb 13, 2023
f9fa937
add react-compare-image widget for viewing image diff
basokant Feb 13, 2023
638d674
remove commented out diff images
basokant Feb 13, 2023
dfb83d5
fix formatting
basokant Feb 15, 2023
b5483a0
migrate to react-image-diff (not working)
basokant Mar 23, 2023
bc1b8c3
basic image diff view logic
basokant Apr 13, 2023
d5865ce
use mui tabs/tab components for diff modes
basokant Apr 13, 2023
806f100
change switch image diff mode logic
basokant Apr 13, 2023
6f43581
add image size constraints in 2-up image diff mode
basokant Apr 13, 2023
773fed0
finish minimum working onion skin image diff view
basokant Apr 14, 2023
daa0c47
add image width and height to the 2-up image diff view
basokant Apr 14, 2023
f575b67
add file sizes to 2-up image diff view
basokant Apr 14, 2023
b1cf23c
fix label and image border colours
basokant Apr 14, 2023
0ee3848
finish working swipe image diff view
basokant Apr 14, 2023
d0e4be5
Merge branch 'jupyterlab:master' into add-image-diff
basokant Apr 15, 2023
9fc3c4f
add reference and challenger indicators to the slider component, and …
basokant Apr 18, 2023
0121288
make sliders have the same width as the image for the swipe and onion…
basokant Apr 19, 2023
45e2460
fix order of slider labels for swipe image diff view
basokant Apr 19, 2023
fd42cd6
fix git.py formatting
basokant Apr 19, 2023
7eba07d
fix ref and chall having different aspect ratios styling and behaviou…
basokant Apr 19, 2023
5d9fd16
add support for jpg and jpeg images
basokant Apr 19, 2023
34019db
fix 3 failing tests to reflect binary file support
basokant Apr 20, 2023
4d7f8c6
fix test_content_binary to reflect support for binary files
basokant Apr 20, 2023
575ce49
handle empty base64 image with placeholder
basokant Apr 20, 2023
a9f76ee
remove react-compare-image and react-image-diff dependencies
basokant Apr 21, 2023
604ec3c
fix image diffs from the initial commit
basokant Apr 21, 2023
c329bbc
Some clean ups
fcollonval Jun 1, 2023
4cc01b9
Add integration test
fcollonval Jun 1, 2023
f41c323
Lint the code
fcollonval Jun 2, 2023
3538779
Fix tests
fcollonval Jun 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions jupyterlab_git/git.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Module for executing git commands, sending results back to the handlers
"""
import base64
import datetime
import os
import pathlib
Expand Down Expand Up @@ -51,6 +52,7 @@ async def execute(
env: "Optional[Dict[str, str]]" = None,
username: "Optional[str]" = None,
password: "Optional[str]" = None,
is_binary=False,
) -> "Tuple[int, str, str]":
"""Asynchronously execute a command.

Expand Down Expand Up @@ -110,12 +112,20 @@ def call_subprocess(
cmdline: "List[str]",
cwd: "Optional[str]" = None,
env: "Optional[Dict[str, str]]" = None,
is_binary=is_binary,
) -> "Tuple[int, str, str]":
process = subprocess.Popen(
cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd, env=env
)
output, error = process.communicate()
return (process.returncode, output.decode("utf-8"), error.decode("utf-8"))
if is_binary == False:
return (process.returncode, output.decode("utf-8"), error.decode("utf-8"))
else:
return (
process.returncode,
base64.encodebytes(output).decode("ascii"),
error.decode("utf-8"),
)
fcollonval marked this conversation as resolved.
Show resolved Hide resolved

try:
await execution_lock.acquire(
Expand Down Expand Up @@ -1325,7 +1335,7 @@ async def _get_base_ref(self, path, filename):

return split_line[1] if len(split_line) > 1 else None

async def show(self, path, ref, filename=None):
async def show(self, path, ref, filename=None, is_binary=False):
"""
Execute
git show <ref:filename>
Expand All @@ -1341,7 +1351,7 @@ async def show(self, path, ref, filename=None):
else:
command.append(f"{ref}:{filename}")

code, output, error = await execute(command, cwd=path)
code, output, error = await execute(command, cwd=path, is_binary=is_binary)

error_messages = map(
lambda n: n.lower(),
Expand Down Expand Up @@ -1402,11 +1412,11 @@ async def get_content_at_reference(
elif reference["special"] == "INDEX":
is_binary = await self._is_binary(filename, "INDEX", path)
if is_binary:
raise tornado.web.HTTPError(
log_message="Error occurred while executing command to retrieve plaintext content as file is not UTF-8."
content = await self.show(
path, reference["git"], filename, is_binary=True
)

content = await self.show(path, "", filename)
else:
content = await self.show(path, "", filename)
elif reference["special"] == "BASE":
# Special case of file in merge conflict for which we want the base (aka common ancestor) version
ref = await self._get_base_ref(path, filename)
Expand All @@ -1417,14 +1427,14 @@ async def get_content_at_reference(
reference["special"]
)
)
elif reference["git"]:
elif "git" in reference:
is_binary = await self._is_binary(filename, reference["git"], path)
if is_binary:
raise tornado.web.HTTPError(
log_message="Error occurred while executing command to retrieve plaintext content as file is not UTF-8."
content = await self.show(
path, reference["git"], filename, is_binary=True
)

content = await self.show(path, reference["git"], filename)
else:
content = await self.show(path, reference["git"], filename)
else:
content = ""

Expand Down
67 changes: 59 additions & 8 deletions jupyterlab_git/tests/test_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -678,11 +678,24 @@ async def test_content(mock_execute, jp_fetch, jp_root_dir):
assert payload["content"] == content
mock_execute.assert_has_calls(
[
call(
[
"git",
"diff",
"--numstat",
"4b825dc642cb6eb9a060e54bf8d69288fbee4904",
"previous",
"--",
filename,
],
cwd=str(local_path),
),
call(
["git", "show", "{}:{}".format("previous", filename)],
cwd=str(local_path),
is_binary=False,
),
],
]
)


Expand Down Expand Up @@ -779,9 +792,22 @@ async def test_content_index(mock_execute, jp_fetch, jp_root_dir):
assert payload["content"] == content
mock_execute.assert_has_calls(
[
call(
[
"git",
"diff",
"--numstat",
"--cached",
"4b825dc642cb6eb9a060e54bf8d69288fbee4904",
"--",
filename,
],
cwd=str(local_path),
),
call(
["git", "show", "{}:{}".format("", filename)],
cwd=str(local_path),
is_binary=False,
),
],
)
Expand Down Expand Up @@ -824,10 +850,15 @@ async def test_content_base(mock_execute, jp_fetch, jp_root_dir):
mock_execute.assert_has_calls(
[
call(
["git", "show", obj_ref],
["git", "ls-files", "-u", "-z", filename],
cwd=str(local_path),
),
],
call(
["git", "show", "915bb14609daab65e5304e59d89c626283ae49fc"],
cwd=str(local_path),
is_binary=False,
),
]
)


Expand Down Expand Up @@ -902,11 +933,31 @@ async def test_content_binary(mock_execute, jp_fetch, jp_root_dir):
}

# Then
with pytest.raises(tornado.httpclient.HTTPClientError) as e:
await jp_fetch(
NAMESPACE, local_path.name, "content", body=json.dumps(body), method="POST"
)
assert_http_error(e, 500, expected_message="file is not UTF-8")
response = await jp_fetch(
NAMESPACE, local_path.name, "content", body=json.dumps(body), method="POST"
)

mock_execute.assert_has_calls(
[
call(
[
"git",
"diff",
"--numstat",
"4b825dc642cb6eb9a060e54bf8d69288fbee4904",
"current",
"--",
filename,
],
cwd=str(local_path),
),
call(
["git", "show", "{}:{}".format("current", filename)],
cwd=str(local_path),
is_binary=True,
),
]
)


@patch("jupyterlab_git.git.execute")
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"@material-ui/lab": "^4.0.0-alpha.54",
"@playwright/test": "^1.32.1",
"diff-match-patch": "^1.0.4",
"filesize": "^10.0.7",
"nbdime": "^6.1.1",
"nbdime-jupyterlab": "^2.1.0",
"react": "^17.0.1",
Expand Down
Loading