Skip to content

Commit

Permalink
Add a %revisions magic to display document revisions #74
Browse files Browse the repository at this point in the history
  • Loading branch information
Bo Peng committed May 18, 2018
1 parent d1c0238 commit 6fb28d6
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/sos_notebook/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,8 @@ define([
// Running %sossave --to html needs to save notebook
nb.save_notebook();
options.sos.workflow = getNotebookWorkflow(cells);
options.sos.filename = window.document.getElementById("notebook_name").innerHTML;
}
options.sos.filename = window.document.getElementById("notebook_name").innerHTML;
options.sos.use_panel = nb.metadata["sos"]["panel"].displayed;
options.sos.default_kernel = nb.metadata["sos"].default_kernel;
options.sos.rerun = false;
Expand Down
71 changes: 71 additions & 0 deletions src/sos_notebook/kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ class SoS_Kernel(IPythonKernel):
'put',
'render',
'rerun',
'revisions',
'run',
'save',
'sandbox',
Expand Down Expand Up @@ -417,6 +418,7 @@ class SoS_Kernel(IPythonKernel):
MAGIC_PUT = re.compile('^%put(\s|$)')
MAGIC_RENDER = re.compile('^%render(\s|$)')
MAGIC_RERUN = re.compile('^%rerun(\s|$)')
MAGIC_REVISIONS = re.compile('^%revisions(\s|$)')
MAGIC_RUN = re.compile('^%run(\s|$)')
MAGIC_SAVE = re.compile('^%save(\s|$)')
MAGIC_SANDBOX = re.compile('^%sandbox(\s|$)')
Expand Down Expand Up @@ -613,6 +615,19 @@ def get_run_parser(self):
parser.error = self._parse_error
return parser

def get_revisions_parser(self):
parser = argparse.ArgumentParser(prog='%revision',
description='''Revision history of the document, parsed from the log
message of the notebook if it is kept in a git repository. Additional parameters to git log command
(e.g. -n 5 --since --after) to limit the revisions to display.''')
parser.add_argument('-s', '--source', help='''Source URL with revision interpolated with revision ID
and filename as current filename. Because sos interpolates command line by default, revision should be
included with double braceses (e.g. --source https://github.com/ORG/USER/blob/{{revision}}/analysis/{{filename}}).''')
parser.add_argument('-l', '--links', nargs='+', help='''Name and URL or additional links for related
files (e.g. --links report URL_to_repo ) with URL interpolated as option --source.''')
parser.error = self._parse_error
return parser

def get_save_parser(self):
parser = argparse.ArgumentParser(prog='%save',
description='''Save the content of the cell (after the magic itself) to specified file''')
Expand Down Expand Up @@ -883,6 +898,50 @@ def __init__(self, **kwargs):
_workflow_mode = property(lambda self: self._meta['workflow_mode'])
_resume_execution = property(lambda self: self._meta['resume_execution'])

def handle_magic_revisions(self, args, unknown_args):
import git
# default
repo = git.Git()
filename = self._meta['notebook_name'] + '.ipynb'
revisions = repo.log(*(unknown_args + ['--date=short', '--pretty=%h!%cN!%cd!%s',
'--', filename])).splitlines()
if not revisions:
return
text = '''
<table>
<tr>
<th>Revision</th>
<th>Author</th>
<th>Date</th>
<th>Message</th>
<tr>
'''
for line in revisions:
fields = line.split('!', 3)
revision = fields[0]
if args.source:
# source URL
URL = interpolate(args.source, {'revision': revision, 'filename': filename})
fields[0] = f'<a target="_blank" href="{URL}">{revision}</a>'
links = []
if args.links:
for i in range(len(args.links) // 2):
name = args.links[2 * i]
if len(args.links) == 2 * i + 1:
continue
URL = interpolate(args.links[2 * i + 1],
{'revision': revision, 'filename': filename})
links.append(f'<a target="_blank" href="{URL}">{name}</a>')
if links:
fields[0] += ' (' + ', '.join(links) + ')'
text += '<tr>' + '\n'.join(f'<td>{x}</td>' for x in fields) + '</tr>'
text += '</table>'
self.send_response(self.iopub_socket, 'display_data',
{
'metadata': {},
'data': {'text/html': HTML(text).data}
})

def handle_taskinfo(self, task_id, task_queue, side_panel=None):
# requesting information on task
from sos.hosts import Host
Expand Down Expand Up @@ -2899,6 +2958,18 @@ def _do_execute(self, code, silent, store_history=True, user_expressions=None,
env.sos_dict = old_dict
self._meta['workflow_mode'] = False
self.options = old_options
elif self.MAGIC_REVISIONS.match(code):
options, remaining_code = self.get_magic_and_code(code, True)
parser = self.get_revisions_parser()
try:
args, unknown_args = parser.parse_known_args(shlex.split(options))
except SystemExit:
return
try:
self.handle_magic_revisions(args, unknown_args)
except Exception as e:
self.warn(f'Failed to retrieve revisions of notebook: {e}')
return self._do_execute(self.remaining_code, silent, store_history, user_expressions, allow_stdin)
elif self.MAGIC_SANDBOX.match(code):
import tempfile
import shutil
Expand Down

0 comments on commit 6fb28d6

Please sign in to comment.