Skip to content

Commit 9b21bc3

Browse files
authored
Merge pull request #406 from fcollonval/plaintextdiff-cm
Plain text diff
2 parents a656567 + e05b9f3 commit 9b21bc3

29 files changed

+4333
-1912
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
.DS_Store
12
# Byte-compiled / optimized / DLL files
23
__pycache__/
34
*.py[cod]
@@ -109,3 +110,4 @@ MANIFEST
109110
jupyterlab_git/labextension/*.tgz
110111
.pytest_cache/
111112
*.tsbuildinfo
113+
.pytest_cache/

jupyterlab_git/__init__.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,10 @@ def _jupyter_server_extension_paths():
1212
return [{"module": "jupyterlab_git"}]
1313

1414

15-
def _jupyter_nbextension_paths():
16-
"""
17-
Declare the Jupyter notebook extension paths.
18-
"""
19-
return [{"section": "notebook", "dest": "jupyterlab_git"}]
20-
21-
2215
def load_jupyter_server_extension(nbapp):
2316
"""
2417
Load the Jupyter server extension.
2518
"""
26-
git = Git(nbapp.web_app.settings.get('server_root_dir'))
19+
git = Git(nbapp.web_app.settings['contents_manager'])
2720
nbapp.web_app.settings["git"] = git
2821
setup_handlers(nbapp.web_app)

jupyterlab_git/git.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def __init__(self, command, cwd, env, username, password):
2424
self.env = env
2525
self.username = username
2626
self.password = password
27+
2728
def communicate(self):
2829
try:
2930
p = pexpect.spawn(
@@ -64,8 +65,9 @@ class Git:
6465
A single parent class containing all of the individual git methods in it.
6566
"""
6667

67-
def __init__(self, root_dir):
68-
self.root_dir = os.path.expanduser(root_dir)
68+
def __init__(self, contents_manager):
69+
self.contents_manager = contents_manager
70+
self.root_dir = os.path.realpath(os.path.expanduser(contents_manager.root_dir))
6971

7072
def config(self, top_repo_path, **kwargs):
7173
"""Get or set Git options.
@@ -892,3 +894,55 @@ def _get_tag(self, current_path, commit_sha):
892894
error.decode("utf-8"), " ".join(command)
893895
)
894896
)
897+
898+
def show(self, filename, ref, top_repo_path):
899+
"""
900+
Execute git show <ref:filename> command & return the result.
901+
"""
902+
command = ["git", "show", '{}:{}'.format(ref, filename)]
903+
p = subprocess.Popen(
904+
command,
905+
stdout=PIPE,
906+
stderr=PIPE,
907+
cwd=top_repo_path
908+
)
909+
output, error = p.communicate()
910+
911+
error_messages = map(lambda n: n.lower(), [
912+
"fatal: Path '{}' exists on disk, but not in '{}'".format(filename, ref),
913+
"fatal: Path '{}' does not exist (neither on disk nor in the index)".format(filename)
914+
])
915+
lower_error = error.decode('utf-8').lower()
916+
if p.returncode == 0:
917+
return output.decode('utf-8')
918+
elif any([msg in lower_error for msg in error_messages]):
919+
return ""
920+
else:
921+
raise HTTPError(log_message='Error [{}] occurred while executing [{}] command to retrieve plaintext diff.'.format(
922+
error.decode('utf-8'),
923+
' '.join(command)
924+
))
925+
926+
def get_content(self, filename, top_repo_path):
927+
"""
928+
Get the file content of filename.
929+
"""
930+
relative_repo = os.path.relpath(top_repo_path, self.root_dir)
931+
model = self.contents_manager.get(path=os.path.join(relative_repo, filename))
932+
return model['content']
933+
934+
def diff_content(self, filename, prev_ref, curr_ref, top_repo_path):
935+
"""
936+
Collect get content of prev and curr and return.
937+
"""
938+
prev_content = self.show(filename, prev_ref["git"], top_repo_path)
939+
if "special" in curr_ref:
940+
if curr_ref["special"] == "WORKING":
941+
curr_content = self.get_content(filename, top_repo_path)
942+
elif curr_ref["special"] == "INDEX":
943+
curr_content = self.show(filename, "", top_repo_path)
944+
else:
945+
raise HTTPError(log_message="Error while retrieving plaintext diff, unknown special ref '{}'.".format(curr_ref["special"]))
946+
else:
947+
curr_content = self.show(filename, curr_ref["git"], top_repo_path)
948+
return {"prev_content": prev_content, "curr_content": curr_content}

jupyterlab_git/handlers.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
Module with all the individual handlers, which execute git commands and return the results to the frontend.
33
"""
44
import json
5+
import os
56

6-
from notebook.utils import url_path_join as ujoin
7+
from notebook.utils import url_path_join as ujoin, url2path
78
from notebook.base.handlers import APIHandler
89

910

@@ -470,6 +471,22 @@ def post(self):
470471
self.set_status(201)
471472
self.finish(json.dumps(response))
472473

474+
class GitDiffContentHandler(GitHandler):
475+
"""
476+
Handler for plain text diffs. Uses git show $REF:$FILE
477+
Returns `prev_content` and `curr_content` with content of given file.
478+
"""
479+
480+
def post(self):
481+
cm = self.contents_manager
482+
data = self.get_json_body()
483+
filename = data["filename"]
484+
prev_ref = data["prev_ref"]
485+
curr_ref = data["curr_ref"]
486+
top_repo_path = os.path.join(cm.root_dir, url2path(data["top_repo_path"]))
487+
response = self.git.diff_content(filename, prev_ref, curr_ref, top_repo_path)
488+
self.finish(json.dumps(response))
489+
473490

474491
class GitServerRootHandler(GitHandler):
475492

@@ -509,7 +526,8 @@ def setup_handlers(web_app):
509526
("/git/upstream", GitUpstreamHandler),
510527
("/git/config", GitConfigHandler),
511528
("/git/changed_files", GitChangedFilesHandler),
512-
("/git/server_root", GitServerRootHandler)
529+
("/git/server_root", GitServerRootHandler),
530+
("/git/diffcontent", GitDiffContentHandler)
513531
]
514532

515533
# add the baseurl to our paths

0 commit comments

Comments
 (0)