diff --git a/swh/web/ui/backend.py b/swh/web/ui/backend.py --- a/swh/web/ui/backend.py +++ b/swh/web/ui/backend.py @@ -179,6 +179,7 @@ Raises: ValueError if the identifier provided is not of sha1 nature. """ + print(sha1_git_bin_list) res = main.storage().revision_get(sha1_git_bin_list) if res and len(res) >= 1: return res diff --git a/swh/web/ui/service.py b/swh/web/ui/service.py --- a/swh/web/ui/service.py +++ b/swh/web/ui/service.py @@ -253,9 +253,9 @@ 'Only sha1_git is supported.') return sha1_git_bin - sha1_bin_list = map(to_sha1_bin, sha1_git_list) + sha1_bin_list = (to_sha1_bin(x) for x in sha1_git_list) revisions = backend.revision_get_multiple(sha1_bin_list) - return map(converters.from_revision, revisions) + return (converters.from_revision(x) for x in revisions) def lookup_revision_message(rev_sha1_git): diff --git a/swh/web/ui/templates/revision-log.html b/swh/web/ui/templates/revision-log.html --- a/swh/web/ui/templates/revision-log.html +++ b/swh/web/ui/templates/revision-log.html @@ -39,6 +39,13 @@ {% endif %} + {% if revision['history_context_url'] is not none %} +
+
Contextual Revision Log
+

{{ revision['history_context_url'] }}

+
+ {% endif %} + {% if revision['directory_url'] is not none %}
directory
diff --git a/swh/web/ui/templates/revision.html b/swh/web/ui/templates/revision.html --- a/swh/web/ui/templates/revision.html +++ b/swh/web/ui/templates/revision.html @@ -22,6 +22,13 @@
{% endif %} + {% if revision['history_context_url'] is not none %} +
+
Contextual Revision Log
+

{{ revision['history_context_url'] }}

+
+ {% endif %} + {% if revision['directory_url'] is not none %}
directory
diff --git a/swh/web/ui/tests/test_utils.py b/swh/web/ui/tests/test_utils.py --- a/swh/web/ui/tests/test_utils.py +++ b/swh/web/ui/tests/test_utils.py @@ -476,15 +476,26 @@ call('api_entity_by_uuid', uuid='uuid-parent')]) + @nottest + def url_for_context_test(self, fn, **data): + if fn == 'api_revision': + if 'context' in data and data['context'] is not None: + return '/api/revision/%s/prev/%s/' % (data['sha1_git'], data['context']) # noqa + else: + return '/api/revision/%s/' % data['sha1_git'] + elif fn == 'api_revision_log': + if 'prev_sha1s' in data: + return '/api/revision/%s/prev/%s/log/' % (data['sha1_git'], data['prev_sha1s']) # noqa + else: + return '/api/revision/%s/log/' % data['sha1_git'] + @patch('swh.web.ui.utils.flask') @istest def enrich_revision_without_children_or_parent(self, mock_flask): # given def url_for_test(fn, **data): - if fn == 'api_revision': - return '/api/revision/' + data['sha1_git'] + '/' - elif fn == 'api_revision_log': - return '/api/revision/' + data['sha1_git'] + '/log/' + if fn == 'api_revision' or fn == 'api_revision_log': + return self.url_for_context_test(fn, **data) elif fn == 'api_directory': return '/api/directory/' + data['sha1_git'] + '/' elif fn == 'api_person': @@ -500,8 +511,7 @@ 'committer': {'id': '2'}, }) - # then - self.assertEqual(actual_revision, { + expected_revision = { 'id': 'rev-id', 'directory': '123', 'url': '/api/revision/rev-id/', @@ -511,18 +521,22 @@ 'author_url': '/api/person/1/', 'committer': {'id': '2'}, 'committer_url': '/api/person/2/' - }) + } + + # then + self.assertEqual(actual_revision, expected_revision) - mock_flask.url_for.assert_has_calls([call('api_revision', - sha1_git='rev-id'), - call('api_revision_log', - sha1_git='rev-id'), - call('api_person', - person_id='1'), - call('api_person', - person_id='2'), - call('api_directory', - sha1_git='123')]) + mock_flask.url_for.assert_has_calls( + [call('api_revision', + sha1_git='rev-id'), + call('api_revision_log', + sha1_git='rev-id'), + call('api_person', + person_id='1'), + call('api_person', + person_id='2'), + call('api_directory', + sha1_git='123')]) @patch('swh.web.ui.utils.flask') @istest @@ -530,10 +544,8 @@ mock_flask): # given def url_for_test(fn, **data): - if fn == 'api_revision': - return '/api/revision/' + data['sha1_git'] + '/' - elif fn == 'api_revision_log': - return '/api/revision/' + data['sha1_git'] + '/log/' + if fn == 'api_revision' or fn == 'api_revision_log': + return self.url_for_context_test(fn, **data) else: return '/api/revision/' + data['sha1_git_root'] + '/history/' + data['sha1_git'] + '/' # noqa @@ -544,37 +556,182 @@ 'id': 'rev-id', 'parents': ['123'], 'children': ['456'], - }, context='sha1_git_root') + }, context='prev-rev') - # then - self.assertEqual(actual_revision, { + expected_revision = { 'id': 'rev-id', 'url': '/api/revision/rev-id/', 'history_url': '/api/revision/rev-id/log/', + 'history_context_url': '/api/revision/rev-id/prev/prev-rev/log/', + 'parents': ['123'], + 'parent_urls': ['/api/revision/123/prev/prev-rev/rev-id/'], + 'children': ['456'], + 'children_urls': ['/api/revision/456/', + '/api/revision/prev-rev/'], + } + + # then + self.assertEqual(actual_revision, expected_revision) + + mock_flask.url_for.assert_has_calls( + [call('api_revision', + sha1_git='prev-rev'), + call('api_revision', + sha1_git='rev-id'), + call('api_revision_log', + sha1_git='rev-id'), + call('api_revision_log', + sha1_git='rev-id', + prev_sha1s='prev-rev'), + call('api_revision', + sha1_git='123', + context='prev-rev/rev-id'), + call('api_revision', + sha1_git='456')]) + + @patch('swh.web.ui.utils.flask') + @istest + def enrich_revision_no_context(self, mock_flask): + # given + def url_for_test(fn, **data): + if fn == 'api_revision' or fn == 'api_revision_log': + return self.url_for_context_test(fn, **data) + else: + return '/api/revision/' + data['sha1_git_root'] + '/history/' + data['sha1_git'] + '/' # noqa + + mock_flask.url_for.side_effect = url_for_test + + # when + actual_revision = utils.enrich_revision({ + 'id': 'rev-id', 'parents': ['123'], - 'parent_urls': ['/api/revision/sha1_git_root/history/123/'], 'children': ['456'], - 'children_urls': ['/api/revision/sha1_git_root/history/456/'], }) + expected_revision = { + 'id': 'rev-id', + 'url': '/api/revision/rev-id/', + 'history_url': '/api/revision/rev-id/log/', + 'parents': ['123'], + 'parent_urls': ['/api/revision/123/prev/rev-id/'], + 'children': ['456'], + 'children_urls': ['/api/revision/456/'] + } + + # then + self.assertEqual(actual_revision, expected_revision) + mock_flask.url_for.assert_has_calls( [call('api_revision', sha1_git='rev-id'), call('api_revision_log', sha1_git='rev-id'), - call('api_revision_history', - sha1_git_root='sha1_git_root', - sha1_git='123'), - call('api_revision_history', - sha1_git_root='sha1_git_root', + call('api_revision', + sha1_git='123', + context='rev-id'), + call('api_revision', + sha1_git='456')]) + + @patch('swh.web.ui.utils.flask') + @istest + def enrich_revision_context_empty_prev_list(self, mock_flask): + # given + mock_flask.url_for.side_effect = self.url_for_context_test + + # when + expected_revision = { + 'id': 'rev-id', + 'url': '/api/revision/rev-id/', + 'history_url': '/api/revision/rev-id/log/', + 'history_context_url': ('/api/revision/rev-id/' + 'prev/prev-rev/log/'), + 'parents': ['123'], + 'parent_urls': ['/api/revision/123/prev/prev-rev/rev-id/'], + 'children': ['456'], + 'children_urls': ['/api/revision/456/', '/api/revision/prev-rev/'], + } + + actual_revision = utils.enrich_revision({ + 'id': 'rev-id', + 'url': '/api/revision/rev-id/', + 'parents': ['123'], + 'children': ['456']}, context='prev-rev') + + # then + self.assertEqual(actual_revision, expected_revision) + mock_flask.url_for.assert_has_calls( + [call('api_revision', + sha1_git='prev-rev'), + call('api_revision', + sha1_git='rev-id'), + call('api_revision_log', + sha1_git='rev-id'), + call('api_revision_log', + sha1_git='rev-id', + prev_sha1s='prev-rev'), + call('api_revision', + sha1_git='123', + context='prev-rev/rev-id'), + call('api_revision', + sha1_git='456')]) + + @patch('swh.web.ui.utils.flask') + @istest + def enrich_revision_context_some_prev_list(self, mock_flask): + # given + mock_flask.url_for.side_effect = self.url_for_context_test + + # when + expected_revision = { + 'id': 'rev-id', + 'url': '/api/revision/rev-id/', + 'history_url': '/api/revision/rev-id/log/', + 'history_context_url': ('/api/revision/rev-id/' + 'prev/prev1-rev/prev0-rev/log/'), + 'parents': ['123'], + 'parent_urls': ['/api/revision/123/prev/' + 'prev1-rev/prev0-rev/rev-id/'], + 'children': ['456'], + 'children_urls': ['/api/revision/456/', + '/api/revision/prev0-rev/prev/prev1-rev/'], + } + + actual_revision = utils.enrich_revision({ + 'id': 'rev-id', + 'parents': ['123'], + 'children': ['456']}, context='prev1-rev/prev0-rev') + + # then + self.assertEqual(actual_revision, expected_revision) + mock_flask.url_for.assert_has_calls( + [call('api_revision', + sha1_git='prev0-rev', + context='prev1-rev'), + call('api_revision', + sha1_git='rev-id'), + call('api_revision_log', + sha1_git='rev-id'), + call('api_revision_log', + sha1_git='rev-id', + prev_sha1s='prev1-rev/prev0-rev'), + call('api_revision', + sha1_git='123', + context='prev1-rev/prev0-rev/rev-id'), + call('api_revision', sha1_git='456')]) @nottest def _url_for_rev_message_test(self, fn, **data): if fn == 'api_revision': - return '/api/revision/' + data['sha1_git'] + '/' + if 'context' in data and data['context'] is not None: + return '/api/revision/%s/prev/%s/' % (data['sha1_git'], data['context']) # noqa + else: + return '/api/revision/%s/' % data['sha1_git'] elif fn == 'api_revision_log': - return '/api/revision/' + data['sha1_git'] + '/log/' + if 'prev_sha1s' in data and data['prev_sha1s'] is not None: + return '/api/revision/%s/prev/%s/log/' % (data['sha1_git'], data['prev_sha1s']) # noqa + else: + return '/api/revision/%s/log/' % data['sha1_git'] elif fn == 'api_revision_raw_message': return '/api/revision/' + data['sha1_git'] + '/raw/' else: @@ -587,35 +744,43 @@ mock_flask.url_for.side_effect = self._url_for_rev_message_test # when - actual_revision = utils.enrich_revision({ + expected_revision = { 'id': 'rev-id', + 'url': '/api/revision/rev-id/', + 'history_url': '/api/revision/rev-id/log/', + 'history_context_url': ('/api/revision/rev-id/' + 'prev/prev-rev/log/'), 'message': None, 'parents': ['123'], + 'parent_urls': ['/api/revision/123/prev/prev-rev/rev-id/'], 'children': ['456'], - }, context='sha1_git_root') + 'children_urls': ['/api/revision/456/', '/api/revision/prev-rev/'], + } - # then - self.assertEqual(actual_revision, { + actual_revision = utils.enrich_revision({ 'id': 'rev-id', - 'url': '/api/revision/rev-id/', 'message': None, - 'history_url': '/api/revision/rev-id/log/', 'parents': ['123'], - 'parent_urls': ['/api/revision/sha1_git_root/history/123/'], 'children': ['456'], - 'children_urls': ['/api/revision/sha1_git_root/history/456/'], - }) + }, context='prev-rev') + + # then + self.assertEqual(actual_revision, expected_revision) mock_flask.url_for.assert_has_calls( [call('api_revision', + sha1_git='prev-rev'), + call('api_revision', sha1_git='rev-id'), call('api_revision_log', sha1_git='rev-id'), - call('api_revision_history', - sha1_git_root='sha1_git_root', - sha1_git='123'), - call('api_revision_history', - sha1_git_root='sha1_git_root', + call('api_revision_log', + sha1_git='rev-id', + prev_sha1s='prev-rev'), + call('api_revision', + sha1_git='123', + context='prev-rev/rev-id'), + call('api_revision', sha1_git='456')]) @patch('swh.web.ui.utils.flask') @@ -631,30 +796,38 @@ 'message_decoding_failed': True, 'parents': ['123'], 'children': ['456'], - }, context='sha1_git_root') + }, context='prev-rev') - # then - self.assertEqual(actual_revision, { + expected_revision = { 'id': 'rev-id', 'url': '/api/revision/rev-id/', + 'history_url': '/api/revision/rev-id/log/', + 'history_context_url': ('/api/revision/rev-id/' + 'prev/prev-rev/log/'), 'message': None, 'message_decoding_failed': True, 'message_url': '/api/revision/rev-id/raw/', - 'history_url': '/api/revision/rev-id/log/', 'parents': ['123'], - 'parent_urls': ['/api/revision/sha1_git_root/history/123/'], + 'parent_urls': ['/api/revision/123/prev/prev-rev/rev-id/'], 'children': ['456'], - 'children_urls': ['/api/revision/sha1_git_root/history/456/'], - }) + 'children_urls': ['/api/revision/456/', '/api/revision/prev-rev/'], + } + + # then + self.assertEqual(actual_revision, expected_revision) mock_flask.url_for.assert_has_calls( [call('api_revision', + sha1_git='prev-rev'), + call('api_revision', sha1_git='rev-id'), call('api_revision_log', sha1_git='rev-id'), - call('api_revision_history', - sha1_git_root='sha1_git_root', - sha1_git='123'), - call('api_revision_history', - sha1_git_root='sha1_git_root', + call('api_revision_log', + sha1_git='rev-id', + prev_sha1s='prev-rev'), + call('api_revision', + sha1_git='123', + context='prev-rev/rev-id'), + call('api_revision', sha1_git='456')]) diff --git a/swh/web/ui/tests/views/test_api.py b/swh/web/ui/tests/views/test_api.py --- a/swh/web/ui/tests/views/test_api.py +++ b/swh/web/ui/tests/views/test_api.py @@ -679,8 +679,8 @@ '8734ef7e7c357ce2af928115c6c6a42b7e2a44e7' ], 'parent_urls': [ - '/api/1/revision/18d8be353ed3480476f032475e7c233eff7371d5' - '/history/8734ef7e7c357ce2af928115c6c6a42b7e2a44e7/' + '/api/1/revision/8734ef7e7c357ce2af928115c6c6a42b7e2a44e7' + '/prev/18d8be353ed3480476f032475e7c233eff7371d5/' ], 'type': 'tar', 'synthetic': True, @@ -1416,8 +1416,8 @@ '7834ef7e7c357ce2af928115c6c6a42b7e2a4345' ], 'parent_urls': [ - '/api/1/revision/18d8be353ed3480476f032475e7c233eff7371d5' - '/history/7834ef7e7c357ce2af928115c6c6a42b7e2a4345/' + '/api/1/revision/7834ef7e7c357ce2af928115c6c6a42b7e2a4345' + '/prev/18d8be353ed3480476f032475e7c233eff7371d5/' ], 'type': 'tar', 'synthetic': True, @@ -1521,8 +1521,8 @@ 'committer_date_offset': 0, 'parents': ['adc83b19e793491b1c6ea0fd8b46cd9f32e592fc'], 'parent_urls': [ - '/api/1/revision/7834ef7e7c357ce2af928115c6c6a42b7e2a44e6' - '/history/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc/' + '/api/1/revision/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc' + '/prev/7834ef7e7c357ce2af928115c6c6a42b7e2a44e6/' ], 'type': 'tar', 'synthetic': True, @@ -1545,8 +1545,8 @@ 'committer_date_offset': 0, 'parents': ['7834ef7e7c357ce2af928115c6c6a42b7e2a4345'], 'parent_urls': [ - '/api/1/revision/18d8be353ed3480476f032475e7c233eff7371d5' - '/history/7834ef7e7c357ce2af928115c6c6a42b7e2a4345/' + '/api/1/revision/7834ef7e7c357ce2af928115c6c6a42b7e2a4345' + '/prev/18d8be353ed3480476f032475e7c233eff7371d5/' ], 'type': 'tar', 'synthetic': True, @@ -1596,8 +1596,8 @@ '7834ef7e7c357ce2af928115c6c6a42b7e2a4345' ], 'parent_urls': [ - '/api/1/revision/18d8be353ed3480476f032475e7c233eff7371d5' - '/history/7834ef7e7c357ce2af928115c6c6a42b7e2a4345/' + '/api/1/revision/7834ef7e7c357ce2af928115c6c6a42b7e2a4345' + '/prev/18d8be353ed3480476f032475e7c233eff7371d5/' ], 'type': 'tar', 'synthetic': True, @@ -1680,10 +1680,10 @@ 'directory': '272' } - mock_service.lookup_revision_with_context.return_value = stub_revision + mock_service.lookup_revision.return_value = stub_revision # then - rv = self.app.get('/api/1/revision/666/history/883/') + rv = self.app.get('/api/1/revision/883/prev/999/') self.assertEquals(rv.status_code, 200) self.assertEquals(rv.mimetype, 'application/json') @@ -1693,17 +1693,17 @@ 'id': '883', 'url': '/api/1/revision/883/', 'history_url': '/api/1/revision/883/log/', + 'history_context_url': '/api/1/revision/883/prev/999/log/', 'children': ['777', '999'], - 'children_urls': ['/api/1/revision/666/history/777/', - '/api/1/revision/666/history/999/'], + 'children_urls': ['/api/1/revision/777/', + '/api/1/revision/999/'], 'parents': [], 'parent_urls': [], 'directory': '272', 'directory_url': '/api/1/directory/272/' }) - mock_service.lookup_revision_with_context.assert_called_once_with( - '666', '883', 100) + mock_service.lookup_revision.assert_called_once_with('883') @patch('swh.web.ui.views.api._revision_directory_by') @istest diff --git a/swh/web/ui/tests/views/test_browse.py b/swh/web/ui/tests/views/test_browse.py --- a/swh/web/ui/tests/views/test_browse.py +++ b/swh/web/ui/tests/views/test_browse.py @@ -760,7 +760,7 @@ 'Not found!') self.assertIsNone(self.get_context_variable('revision')) - mock_api.api_revision.assert_called_once_with('1') + mock_api.api_revision.assert_called_once_with('1', None) @patch('swh.web.ui.views.browse.api') @istest @@ -780,7 +780,7 @@ 'wrong input!') self.assertIsNone(self.get_context_variable('revision')) - mock_api.api_revision.assert_called_once_with('426') + mock_api.api_revision.assert_called_once_with('426', None) @patch('swh.web.ui.views.browse.api') @istest @@ -842,7 +842,7 @@ expected_revision) self.assertIsNone(self.get_context_variable('message')) - mock_api.api_revision.assert_called_once_with('426') + mock_api.api_revision.assert_called_once_with('426', None) @patch('swh.web.ui.views.browse.api') @istest @@ -875,7 +875,7 @@ 'Not found!') self.assertEqual(self.get_context_variable('revisions'), []) - mock_api.api_revision_log.assert_called_once_with('sha1') + mock_api.api_revision_log.assert_called_once_with('sha1', None) @patch('swh.web.ui.views.browse.api') @istest @@ -895,7 +895,7 @@ 'wrong input!') self.assertEqual(self.get_context_variable('revisions'), []) - mock_api.api_revision_log.assert_called_once_with('426') + mock_api.api_revision_log.assert_called_once_with('426', None) @patch('swh.web.ui.views.browse.api') @istest @@ -935,7 +935,7 @@ isinstance(self.get_context_variable('revisions'), map)) self.assertIsNone(self.get_context_variable('message')) - mock_api.api_revision_log.assert_called_once_with('426') + mock_api.api_revision_log.assert_called_once_with('426', None) @patch('swh.web.ui.views.browse.api') @istest @@ -976,7 +976,7 @@ 'wrong input!') self.assertEqual(self.get_context_variable('revisions'), []) - mock_api.api_revision_log.assert_called_once_with('abcd') + mock_api.api_revision_log.assert_called_once_with('abcd', None) @patch('swh.web.ui.views.browse.api') @istest diff --git a/swh/web/ui/utils.py b/swh/web/ui/utils.py --- a/swh/web/ui/utils.py +++ b/swh/web/ui/utils.py @@ -200,14 +200,45 @@ def enrich_revision(revision, context=None): """Enrich revision with links where it makes sense (directory, parents). + Keep track of the navigation breadcrumbs if they are specified. + Args: + revision: the revision as a dict + context: the navigation breadcrumbs as a /-separated string of revision + sha1_git """ + + context_for_parents = None + context_for_children = None + url_imm_child = None + if not context: - context = revision['id'] + context_for_parents = revision['id'] + else: + context_for_parents = '%s/%s' % (context, revision['id']) + prev_for_children = context.split('/')[:-1] + if len(prev_for_children) > 0: + context_for_children = '/'.join(prev_for_children) + # This commit is not the first commit in the path + if context_for_children: + url_imm_child = flask.url_for( + 'api_revision', + sha1_git=context.split('/')[-1], + context=context_for_children) + # This commit is the first commit in the path + else: + url_imm_child = flask.url_for( + 'api_revision', + sha1_git=context.split('/')[-1]) revision['url'] = flask.url_for('api_revision', sha1_git=revision['id']) revision['history_url'] = flask.url_for('api_revision_log', sha1_git=revision['id']) + if context is not None: + revision['history_context_url'] = flask.url_for( + 'api_revision_log', + sha1_git=revision['id'], + prev_sha1s=context) if 'author' in revision: author = revision['author'] @@ -227,21 +258,30 @@ if 'parents' in revision: parents = [] for parent in revision['parents']: - parents.append(flask.url_for('api_revision_history', - sha1_git_root=context, - sha1_git=parent)) - + parents.append(flask.url_for('api_revision', + sha1_git=parent, + context=context_for_parents)) revision['parent_urls'] = parents if 'children' in revision: children = [] for child in revision['children']: - children.append(flask.url_for('api_revision_history', - sha1_git_root=context, - sha1_git=child)) - + # child not the breadcrumb-indicated child > new breadcrumb start + if context: + if child != context.split('/')[-1]: + children.append(flask.url_for('api_revision', + sha1_git=child)) + else: + children.append(flask.url_for('api_revision', sha1_git=child)) + + if url_imm_child: + children.append(url_imm_child) revision['children_urls'] = children + else: + if url_imm_child: + revision['children_urls'] = [url_imm_child] + if 'message_decoding_failed' in revision: revision['message_url'] = flask.url_for( 'api_revision_raw_message', diff --git a/swh/web/ui/views/api.py b/swh/web/ui/views/api.py --- a/swh/web/ui/views/api.py +++ b/swh/web/ui/views/api.py @@ -507,7 +507,8 @@ @app.route('/api/1/revision/') @app.route('/api/1/revision//') -def api_revision(sha1_git): +@app.route('/api/1/revision//prev//') +def api_revision(sha1_git, context=None): """Return information about revision with id sha1_git. Args: @@ -522,14 +523,13 @@ Example: GET /api/1/revision/baf18f9fc50a0b6fef50460a76c33b2ddc57486e - """ - return _api_lookup( - sha1_git, - lookup_fn=service.lookup_revision, - error_msg_if_not_found='Revision with sha1_git %s not' - ' found.' % sha1_git, - enrich_fn=utils.enrich_revision) + + revision = service.lookup_revision(sha1_git) + if not revision: + error_msg = 'Revision with sha1_git %s not found.' % sha1_git + raise NotFoundExc(error_msg) + return utils.enrich_revision(revision, context=context) @app.route('/api/1/revision//raw/') diff --git a/swh/web/ui/views/browse.py b/swh/web/ui/views/browse.py --- a/swh/web/ui/views/browse.py +++ b/swh/web/ui/views/browse.py @@ -298,17 +298,32 @@ @app.route('/browse/revision/') @app.route('/browse/revision//') +@app.route('/browse/revision//prev//') @set_renderers(HTMLRenderer) -def browse_revision(sha1_git): - """Browse revision with sha1_git. +def browse_revision(sha1_git, prev_sha1s=None): + """Browse the revision with git SHA1 sha1_git_cur, while optionally keeping + the context from which we came as a list of previous (i.e. later) + revisions' sha1s. + Args: + sha1_git: the requested revision's sha1_git. + prev_sha1s: an optional string of /-separated sha1s representing our + context, ordered by descending revision date. + + Returns: + Information about revision of git SHA1 sha1_git_cur, with relevant URLS + pointing to the context augmented with sha1_git_cur. + + Example: + GET /browse/revision/ """ + env = {'sha1_git': sha1_git, 'message': None, 'revision': None} try: - rev = api.api_revision(sha1_git) + rev = api.api_revision(sha1_git, prev_sha1s) env['revision'] = utils.prepare_data_for_view(rev) except (NotFoundExc, BadInputExc) as e: env['message'] = str(e) @@ -325,10 +340,16 @@ @app.route('/browse/revision//log/') +@app.route('/browse/revision//prev//log/') @set_renderers(HTMLRenderer) -def browse_revision_log(sha1_git): - """Browse revision with sha1_git's log. +def browse_revision_log(sha1_git, prev_sha1s=None): + """Browse revision with sha1_git's log. If the navigation path throught the + commit tree is specified, we intersect the earliest revision's log with the + revisions the user browsed through (ie his path) to the specified revision. + Args: + sha1_git: the current revision's SHA1_git checksum + prev_sha1s: optionally, the path through which we want log information """ env = {'sha1_git': sha1_git, 'sha1_url': '/browse/revision/%s/' % sha1_git, @@ -336,7 +357,7 @@ 'revisions': []} try: - revisions = api.api_revision_log(sha1_git) + revisions = api.api_revision_log(sha1_git, prev_sha1s) env['revisions'] = map(utils.prepare_data_for_view, revisions) except (NotFoundExc, BadInputExc) as e: env['message'] = str(e) @@ -392,6 +413,40 @@ return render_template('revision-log.html', **env) +@app.route('/browse/revision//prev//') +@set_renderers(HTMLRenderer) +def browse_with_rev_context(sha1_git_cur, sha1s): + """Browse the revision with git SHA1 sha1_git_cur, while keeping the context + from which we came as a list of previous (i.e. later) revisions' sha1s. + + Args: + sha1_git_cur: the requested revision's sha1_git. + sha1s: a string of /-separated sha1s representing our context, ordered + by descending revision date. + + Returns: + Information about revision of git SHA1 sha1_git_cur, with relevant URLS + pointing to the context augmented with sha1_git_cur. + + Example: + GET /browse/revision/ + """ + # in service: change enrichment function to prepare data with context + + env = {'sha1_git': sha1_git_cur, + 'message': None, + 'revision': None} + + try: + revision = api.api_revision( + sha1_git_cur, '%s' % sha1s) + env['revision'] = utils.prepare_data_for_view(revision) + except (BadInputExc, NotFoundExc) as e: + env['message'] = str(e) + + return render_template('revision.html', **env) + + @app.route('/browse/revision//history//') @set_renderers(HTMLRenderer) def browse_revision_history(sha1_git_root, sha1_git):