diff --git a/resources/test/webapp.ini b/resources/test/webapp.ini --- a/resources/test/webapp.ini +++ b/resources/test/webapp.ini @@ -17,8 +17,8 @@ # its port port = 6543 -# Upload folder for temporary upload and hash -upload_folder = /tmp/swh-web-ui/uploads +# Max revisions shown in a log +max_log_revs = 25 # Allowed extensions for upload (commented or empty means all is accepted) # Otherwise, comma separated values of extensions. 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 @@ -215,10 +215,12 @@ Information for the revision matching the criterions. """ - - return main.storage().revision_log_by(origin_id, - branch_name, - ts) + rev_list = main.storage().revision_log_by(origin_id, + branch_name, + ts) + if rev_list is None: + return None + return rev_list[:limit] def stat_counters(): diff --git a/swh/web/ui/converters.py b/swh/web/ui/converters.py --- a/swh/web/ui/converters.py +++ b/swh/web/ui/converters.py @@ -197,6 +197,8 @@ """Convert swh content to serializable content dictionary. """ + if content and 'ctime' in content: + del content['ctime'] return from_swh(content, hashess={'sha1', 'sha1_git', 'sha256'}, bytess={}, diff --git a/swh/web/ui/main.py b/swh/web/ui/main.py --- a/swh/web/ui/main.py +++ b/swh/web/ui/main.py @@ -23,9 +23,7 @@ 'host': ('string', '127.0.0.1'), 'port': ('int', 6543), 'secret_key': ('string', 'development key'), - 'max_upload_size': ('int', 16 * 1024 * 1024), - 'upload_folder': ('string', '/tmp/swh-web-ui/uploads'), - 'upload_allowed_extensions': ('list[str]', []) # means all are accepted + 'max_log_revs': ('int', 25), } @@ -44,7 +42,7 @@ dict""" conf = config.read(config_file, DEFAULT_CONFIG) - config.prepare_folders(conf, 'log_dir', 'upload_folder') + config.prepare_folders(conf, 'log_dir') conf['storage'] = get_storage(conf['storage_class'], conf['storage_args']) return conf @@ -100,7 +98,6 @@ app.secret_key = conf['secret_key'] app.config['conf'] = conf - app.config['MAX_CONTENT_LENGTH'] = conf['max_upload_size'] app.config['DEFAULT_RENDERERS'] = RENDERERS logging.basicConfig(filename=os.path.join(conf['log_dir'], 'web-ui.log'), @@ -136,7 +133,6 @@ app.secret_key = conf['secret_key'] app.config['conf'] = conf - app.config['MAX_CONTENT_LENGTH'] = conf['max_upload_size'] app.config['DEFAULT_RENDERERS'] = RENDERERS host = conf.get('host', '127.0.0.1') 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 @@ -30,29 +30,6 @@ return hashes -def hash_and_search(filepath): - """Hash the filepath's content as sha1, then search in storage if - it exists. - - Args: - Filepath of the file to hash and search. - - Returns: - Tuple (hex sha1, found as True or false). - The found boolean, according to whether the sha1 of the file - is present or not. - """ - h = hashutil.hashfile(filepath) - c = backend.content_find('sha1', h['sha1']) - if c: - r = converters.from_content(c) - r['found'] = True - return r - else: - return {'sha1': hashutil.hash_to_hex(h['sha1']), - 'found': False} - - def lookup_hash(q): """Checks if the storage contains a given content checksum @@ -294,7 +271,7 @@ return converters.from_revision(res) -def lookup_revision_log(rev_sha1_git, limit=100): +def lookup_revision_log(rev_sha1_git, limit=25): """Return information about the revision with sha1 revision_sha1_git. Args: @@ -317,7 +294,7 @@ return map(converters.from_revision, revision_entries) -def lookup_revision_log_by(origin_id, branch_name, timestamp): +def lookup_revision_log_by(origin_id, branch_name, timestamp, limit=25): """Return information about the revision with sha1 revision_sha1_git. Args: @@ -336,7 +313,8 @@ """ revision_entries = backend.revision_log_by(origin_id, branch_name, - timestamp) + timestamp, + limit) if not revision_entries: return None return map(converters.from_revision, revision_entries) diff --git a/swh/web/ui/tests/test_app.py b/swh/web/ui/tests/test_app.py --- a/swh/web/ui/tests/test_app.py +++ b/swh/web/ui/tests/test_app.py @@ -48,12 +48,9 @@ # inject the mock data conf = {'storage': storage, - 'upload_folder': '/some/upload-dir', - 'upload_allowed_extensions': ['txt'], - 'max_upload_size': 1024} + 'max_log_revs': 25} main.app.config.update({'conf': conf}) - main.app.config['MAX_CONTENT_LENGTH'] = conf['max_upload_size'] main.app.config['DEFAULT_RENDERERS'] = renderers.RENDERERS if not main.app.config['TESTING']: # HACK: install controllers only once! diff --git a/swh/web/ui/tests/test_service.py b/swh/web/ui/tests/test_service.py --- a/swh/web/ui/tests/test_service.py +++ b/swh/web/ui/tests/test_service.py @@ -351,54 +351,6 @@ mock_backend.stat_origin_visits.assert_called_once_with(6) @patch('swh.web.ui.service.backend') - @patch('swh.web.ui.service.hashutil') - @istest - def hash_and_search(self, mock_hashutil, mock_backend): - # given - bhash = hex_to_hash('456caf10e9535160d90e874b45aa426de762f19f') - mock_hashutil.hashfile.return_value = {'sha1': bhash} - mock_backend.content_find = MagicMock(return_value={ - 'sha1': bhash, - 'sha1_git': bhash, - }) - - # when - actual_content = service.hash_and_search('/some/path') - - # then - self.assertEqual(actual_content, { - 'sha1': '456caf10e9535160d90e874b45aa426de762f19f', - 'sha1_git': '456caf10e9535160d90e874b45aa426de762f19f', - 'found': True, - }) - - mock_hashutil.hashfile.assert_called_once_with('/some/path') - mock_backend.content_find.assert_called_once_with('sha1', bhash) - - @patch('swh.web.ui.service.hashutil') - @istest - def hash_and_search_not_found(self, mock_hashutil): - # given - bhash = hex_to_hash('456caf10e9535160d90e874b45aa426de762f19f') - mock_hashutil.hashfile.return_value = {'sha1': bhash} - mock_hashutil.hash_to_hex = MagicMock( - return_value='456caf10e9535160d90e874b45aa426de762f19f') - self.storage.content_find = MagicMock(return_value=None) - - # when - actual_content = service.hash_and_search('/some/path') - - # then - self.assertEqual(actual_content, { - 'sha1': '456caf10e9535160d90e874b45aa426de762f19f', - 'found': False, - }) - - mock_hashutil.hashfile.assert_called_once_with('/some/path') - self.storage.content_find.assert_called_once_with({'sha1': bhash}) - mock_hashutil.hash_to_hex.assert_called_once_with(bhash) - - @patch('swh.web.ui.service.backend') @istest def lookup_origin(self, mock_backend): # given @@ -1240,7 +1192,7 @@ self.assertEqual(list(actual_revision), [self.SAMPLE_REVISION]) mock_backend.revision_log.assert_called_with( - hex_to_hash('abcdbe353ed3480476f032475e7c233eff7371d5'), 100) + hex_to_hash('abcdbe353ed3480476f032475e7c233eff7371d5'), 25) @patch('swh.web.ui.service.backend') @istest @@ -1252,12 +1204,12 @@ # when actual_log = service.lookup_revision_log_by( - 1, 'refs/heads/master', None) + 1, 'refs/heads/master', None, limit=100) # then self.assertEqual(list(actual_log), [self.SAMPLE_REVISION]) mock_backend.revision_log_by.assert_called_with( - 1, 'refs/heads/master', None) + 1, 'refs/heads/master', None, 100) @patch('swh.web.ui.service.backend') @istest @@ -1267,11 +1219,11 @@ # when res = service.lookup_revision_log_by( - 1, 'refs/heads/master', None) + 1, 'refs/heads/master', None, limit=100) # then self.assertEquals(res, None) mock_backend.revision_log_by.assert_called_with( - 1, 'refs/heads/master', None) + 1, 'refs/heads/master', None, 100) @patch('swh.web.ui.service.backend') @istest 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 @@ -1008,283 +1008,6 @@ mock_utils.enrich_revision.assert_called_once_with( mock_revision) - @patch('swh.web.ui.views.api._revision_directory_by') - @istest - def api_directory_through_rev_with_origin_history_with_rev_not_found_0( - self, mock_rev_dir): - # given - mock_rev_dir.side_effect = NotFoundExc('not found') - - # when - rv = self.app.get('/api/1/revision' - '/origin/1' - '/history/4563' - '/directory/some-path/') - - # then - self.assertEquals(rv.status_code, 404) - self.assertEquals(rv.mimetype, 'application/json') - response_data = json.loads(rv.data.decode('utf-8')) - - self.assertEqual(response_data, { - 'error': - 'not found'}) - - mock_rev_dir.assert_called_once_with( - { - 'origin_id': 1, - 'branch_name': 'refs/heads/master', - 'ts': None, - 'sha1_git': '4563' - }, - 'some-path', - '/api/1/revision' - '/origin/1' - '/history/4563' - '/directory/some-path/', - limit=100, with_data=False) - - @patch('swh.web.ui.views.api._revision_directory_by') - @patch('swh.web.ui.views.api.utils') - @istest - def api_directory_through_revision_with_origin_history( - self, mock_utils, mock_rev_dir): - # given - stub_dir_content = [ - { - 'type': 'dir' - }, - { - 'type': 'file' - }, - ] - mock_rev_dir.return_value = stub_dir_content - - mock_utils.parse_timestamp.return_value = '2016-11-24 00:00:00' - - # when - url = '/api/1/revision' \ - '/origin/999' \ - '/branch/refs/dev' \ - '/ts/2016-11-24' \ - '/history/12-sha1-git' \ - '/directory/some/content/' - rv = self.app.get(url + '?limit=666') - - # then - self.assertEquals(rv.status_code, 200) - self.assertEquals(rv.mimetype, 'application/json') - response_data = json.loads(rv.data.decode('utf-8')) - - self.assertEqual(response_data, stub_dir_content) - - mock_utils.parse_timestamp.assert_called_once_with('2016-11-24') - - mock_rev_dir.assert_called_once_with( - { - 'origin_id': 999, - 'branch_name': 'refs/dev', - 'ts': '2016-11-24 00:00:00', - 'sha1_git': '12-sha1-git' - }, - 'some/content', - url, - limit=666, with_data=False) - - @patch('swh.web.ui.views.api.service') - @istest - def api_revision_history_through_origin_rev_not_found_0( - self, mock_service): - mock_service.lookup_revision_with_context_by.return_value = { - 'id': 'root-rev-id'}, None - - # when - rv = self.app.get('/api/1/revision' - '/origin/1' - '/history/4563/') - - # then - self.assertEquals(rv.status_code, 404) - self.assertEquals(rv.mimetype, 'application/json') - response_data = json.loads(rv.data.decode('utf-8')) - - self.assertEqual(response_data, { - 'error': - "Possibly sha1_git '%s' is not an ancestor of sha1_git_root '%s'" - " sha1_git_root being the revision's identifier pointed to by " - "(origin_id: %s, branch_name: %s, ts: %s)." - % ('4563', - 'root-rev-id', - 1, - 'refs/heads/master', - None)}) - - mock_service.lookup_revision_with_context_by.assert_called_once_with( - 1, 'refs/heads/master', None, '4563', 100) - - @patch('swh.web.ui.views.api.service') - @istest - def api_revision_history_through_origin_rev_not_found_1( - self, mock_service): - # given - mock_service.lookup_revision_with_context_by.return_value = { - 'id': 'root-rev-id'}, None - - # when - rv = self.app.get('/api/1/revision' - '/origin/10' - '/branch/origin/dev' - '/history/213/') - - # then - self.assertEquals(rv.status_code, 404) - self.assertEquals(rv.mimetype, 'application/json') - response_data = json.loads(rv.data.decode('utf-8')) - - self.assertEqual(response_data, { - 'error': - "Possibly sha1_git '%s' is not an ancestor of sha1_git_root '%s'" - " sha1_git_root being the revision's identifier pointed to by " - "(origin_id: %s, branch_name: %s, ts: %s)." - % ('213', - 'root-rev-id', - 10, - 'origin/dev', - None)}) - - mock_service.lookup_revision_with_context_by.assert_called_once_with( - 10, 'origin/dev', None, '213', 100) - - @patch('swh.web.ui.views.api.utils') - @patch('swh.web.ui.views.api.service') - @istest - def api_revision_history_through_origin_rev_not_found_2( - self, mock_service, mock_utils): - # given - mock_service.lookup_revision_with_context_by.return_value = { - 'id': 'root-rev-id'}, None - mock_utils.parse_timestamp.return_value = '2012-11-23 00:00:00' - - # when - rv = self.app.get('/api/1/revision' - '/origin/100' - '/branch/master' - '/ts/2012-11-23' - '/history/876/') - - # then - self.assertEquals(rv.status_code, 404) - self.assertEquals(rv.mimetype, 'application/json') - response_data = json.loads(rv.data.decode('utf-8')) - - self.assertEqual(response_data, { - 'error': - "Possibly sha1_git '%s' is not an ancestor of sha1_git_root '%s'" - " sha1_git_root being the revision's identifier pointed to by " - "(origin_id: %s, branch_name: %s, ts: %s)." - % ('876', - 'root-rev-id', - 100, - 'master', - '2012-11-23 00:00:00')}) - - mock_service.lookup_revision_with_context_by.assert_called_once_with( - 100, 'master', '2012-11-23 00:00:00', '876', 100) - - mock_utils.parse_timestamp.assert_called_once_with('2012-11-23') - - @patch('swh.web.ui.views.api.utils') - @patch('swh.web.ui.views.api.service') - @istest - def api_revision_history_through_origin_rev_not_found_3( - self, mock_service, mock_utils): - # given - mock_service.lookup_revision_with_context_by.return_value = { - 'id': 'root-rev-id'}, None - - mock_service.lookup_revision_with_context.return_value = None - - mock_utils.parse_timestamp.return_value = '2016-11-23 00:00:00' - - # when - rv = self.app.get('/api/1/revision' - '/origin/666' - '/branch/refs/master' - '/ts/2016-11-23' - '/history/123-sha1-git/?limit=1000') - - # then - self.assertEquals(rv.status_code, 404) - self.assertEquals(rv.mimetype, 'application/json') - response_data = json.loads(rv.data.decode('utf-8')) - - self.assertEqual(response_data, { - 'error': - "Possibly sha1_git '%s' is not an ancestor of sha1_git_root '%s'" - " sha1_git_root being the revision's identifier pointed to by " - "(origin_id: %s, branch_name: %s, ts: %s)." - % ('123-sha1-git', - 'root-rev-id', - 666, - 'refs/master', - '2016-11-23 00:00:00')}) - - mock_service.lookup_revision_with_context_by.assert_called_once_with( - 666, 'refs/master', '2016-11-23 00:00:00', '123-sha1-git', 1000) - - mock_utils.parse_timestamp.assert_called_once_with('2016-11-23') - - mock_service.lookup_revision_with_context('456-sha1-git-root', - '123-sha1-git', - 1000) - - @patch('swh.web.ui.views.api.utils') - @patch('swh.web.ui.views.api.service') - @istest - def api_history_through_revision(self, mock_service, mock_utils): - # given - stub_root_rev = { - 'id': '45-sha1-git-root' - } - - stub_revision = { - 'children': [], - } - mock_service.lookup_revision_with_context_by.return_value = ( - stub_root_rev, - stub_revision) - - mock_utils.enrich_revision.return_value = 'some-result' - - mock_utils.parse_timestamp.return_value = '2016-11-24 00:00:00' - - # when - rv = self.app.get('/api/1/revision' - '/origin/999' - '/branch/refs/dev' - '/ts/2016-11-24' - '/history/12-sha1-git/') - - # then - self.assertEquals(rv.status_code, 200) - self.assertEquals(rv.mimetype, 'application/json') - response_data = json.loads(rv.data.decode('utf-8')) - - self.assertEqual(response_data, 'some-result') - - mock_service.lookup_revision_with_context_by.assert_called_once_with( - 999, - 'refs/dev', - '2016-11-24 00:00:00', - '12-sha1-git', - 100) - - mock_utils.parse_timestamp.assert_called_once_with('2016-11-24') - - mock_utils.enrich_revision.assert_called_once_with( - stub_revision, - context='45-sha1-git-root') - @patch('swh.web.ui.views.api.service') @istest def revision_directory_by_ko_raise(self, mock_service): @@ -1691,6 +1414,11 @@ 'synthetic': True, }] + expected_result = { + 'revisions': expected_revisions, + 'next_revs_url': None + } + # when rv = self.app.get('/api/1/revision/origin/1/log/') @@ -1699,59 +1427,63 @@ self.assertEquals(rv.mimetype, 'application/json') response_data = json.loads(rv.data.decode('utf-8')) - self.assertEquals(response_data, expected_revisions) + self.assertEquals(response_data, expected_result) mock_service.lookup_revision_log_by.assert_called_once_with( - 1, 'refs/heads/master', None) + 1, 'refs/heads/master', None, 26) @patch('swh.web.ui.views.api.service') @istest - def api_revision_log_by_norev(self, mock_service): + def api_revision_log_by_with_next(self, mock_service): # given - mock_service.lookup_revision_log_by.side_effect = NotFoundExc( - 'No revision') + stub_revisions = [] + for i in range(27): + stub_revisions.append({'id': i}) + + mock_service.lookup_revision_log_by.return_value = stub_revisions[:26] + + expected_revisions = [x for x in stub_revisions if x['id'] < 25] + for e in expected_revisions: + e['url'] = '/api/1/revision/%s/' % e['id'] + e['history_url'] = '/api/1/revision/%s/log/' % e['id'] + + expected_response = { + 'revisions': expected_revisions, + 'next_revs_url': '/api/1/revision/25/log/' + } # when rv = self.app.get('/api/1/revision/origin/1/log/') # then - self.assertEquals(rv.status_code, 404) + self.assertEquals(rv.status_code, 200) self.assertEquals(rv.mimetype, 'application/json') response_data = json.loads(rv.data.decode('utf-8')) - self.assertEquals(response_data, {'error': 'No revision'}) + self.assertEquals(response_data, expected_response) mock_service.lookup_revision_log_by.assert_called_once_with( - 1, 'refs/heads/master', None) + 1, 'refs/heads/master', None, 26) @patch('swh.web.ui.views.api.service') @istest - def api_revision_history_not_found(self, mock_service): + def api_revision_log_by_norev(self, mock_service): # given - mock_service.lookup_revision_with_context.return_value = None + mock_service.lookup_revision_log_by.side_effect = NotFoundExc( + 'No revision') - # then - rv = self.app.get('/api/1/revision/999/history/338/?limit=5') + # when + rv = self.app.get('/api/1/revision/origin/1/log/') + # then self.assertEquals(rv.status_code, 404) self.assertEquals(rv.mimetype, 'application/json') - mock_service.lookup_revision_with_context.assert_called_once_with( - '999', '338', 5) - - @istest - def api_revision_history_sha1_same_so_redirect(self): - # when - rv = self.app.get('/api/1/revision/123/history/123?limit=10') - # then - self.assertEquals(rv.status_code, 301) - # Ideally we'd like to be able to check the resulting url path - # but does not work, this returns the current url - # also following the redirect would mean to yet mock again the - # destination url... So for now cannot test it + response_data = json.loads(rv.data.decode('utf-8')) + self.assertEquals(response_data, {'error': 'No revision'}) - # self.assertEquals(rv.location, - # 'http://localhost/api/1/revision/123?limit=10') + mock_service.lookup_revision_log_by.assert_called_once_with( + 1, 'refs/heads/master', None, 26) @patch('swh.web.ui.views.api.service') @istest @@ -1886,92 +1618,6 @@ mock_rev_dir.assert_called_once_with( {'sha1_git': '666'}, 'some/other/path', url, with_data=False) - @istest - def api_revision_history_directory_sha1_same_so_redirect(self): - # when - rv = self.app.get( - '/api/1/revision/123/history/123/directory/path/to/?limit=1') - - # then - self.assertEquals(rv.status_code, 301) - - # self.assertEquals(rv.location, - # 'http://localhost/api/1/revision/123/directory/path/to/') - - @patch('swh.web.ui.views.api._revision_directory_by') - @istest - def api_revision_history_directory_ko_revision_not_found(self, - mock_rev_dir): - # given - mock_rev_dir.side_effect = NotFoundExc('not found') - - # then - url = '/api/1/revision/456/history/987/directory/path/to/' - rv = self.app.get(url + '?limit=10') - - self.assertEquals(rv.status_code, 404) - self.assertEquals(rv.mimetype, 'application/json') - - response_data = json.loads(rv.data.decode('utf-8')) - self.assertEquals(response_data, { - 'error': 'not found'}) - - mock_rev_dir.assert_called_once_with( - {'sha1_git_root': '456', 'sha1_git': '987'}, 'path/to', url, - limit=10, with_data=False) - - @patch('swh.web.ui.views.api._revision_directory_by') - @istest - def api_revision_history_directory(self, - mock_rev_dir): - # given - stub_dir = { - 'type': 'dir', - 'revision': 'rev-id', - 'content': [ - { - 'sha1_git': '879', - 'type': 'file', - 'target': '110', - 'target_url': '/api/1/content/sha1_git:110/', - 'name': 'subfile', - 'file_url': '/api/1/revision/354/history/867/directory/' - 'debian/' - 'subfile/', - }, - { - 'sha1_git': '213', - 'type': 'dir', - 'target': '546', - 'target_url': '/api/1/directory/546/', - 'name': 'subdir', - 'dir_url': - '/api/1/revision/354/history/867/directory/debian/subdir/' - }] - } - - # given - mock_rev_dir.return_value = stub_dir - - # then - url = '/api/1/revision/354' \ - '/history/867' \ - '/directory/debian/' - rv = self.app.get(url + '?limit=4') - - self.assertEquals(rv.status_code, 200) - self.assertEquals(rv.mimetype, 'application/json') - - response_data = json.loads(rv.data.decode('utf-8')) - self.assertEquals(response_data, stub_dir) - - mock_rev_dir.assert_called_once_with( - {'sha1_git_root': '354', - 'sha1_git': '867'}, - 'debian', - url, - limit=4, with_data=False) - @patch('swh.web.ui.views.api.service') @istest def api_person(self, mock_service): 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 @@ -308,167 +308,6 @@ @app.route('/api/1/revision' - '/origin/' - '/history//') -@app.route('/api/1/revision' - '/origin/' - '/branch/' - '/history//') -@app.route('/api/1/revision' - '/origin/' - '/branch/' - '/ts/' - '/history//') -def api_revision_history_through_origin(origin_id, - branch_name="refs/heads/master", - ts=None, - sha1_git=None): - """ - Return information about revision sha1_git, limited to the - sub-graph of all transitive parents of the revision root identified - by (origin_id, branch_name, ts). - Given sha1_git_root such root revision's identifier, in other words, - sha1_git is an ancestor of sha1_git_root. - - Args: - origin_id: origin's identifier (default to 1). - branch_name: the optional branch for the given origin (default - to master). - timestamp: optional timestamp (default to the nearest time - crawl of timestamp). - sha1_git: one of sha1_git_root's ancestors. - limit: optional query parameter to limit the revisions log - (default to 100). For now, note that this limit could impede the - transitivity conclusion about sha1_git not being an ancestor of - sha1_git_root (even if it is). - - Returns: - Information on sha1_git if it is an ancestor of sha1_git_root - including children leading to sha1_git_root. - - Raises: - BadInputExc in case of unknown algo_hash or bad hash. - NotFoundExc if either revision is not found or if sha1_git is not an - ancestor of sha1_git_root. - - """ - limit = int(request.args.get('limit', '100')) - - if ts: - ts = utils.parse_timestamp(ts) - - rev_root, revision = service.lookup_revision_with_context_by( - origin_id, branch_name, ts, sha1_git, limit) - - if not revision: - raise NotFoundExc( - "Possibly sha1_git '%s' is not an ancestor of sha1_git_root '%s' " - "sha1_git_root being the revision's identifier pointed to by " - "(origin_id: %s, branch_name: %s, ts: %s)." % (sha1_git, - rev_root['id'], - origin_id, - branch_name, - ts)) - - return utils.enrich_revision(revision, context=rev_root['id']) - - -@app.route('/api/1/revision' - '/origin/' - '/history/' - '/directory/') -@app.route('/api/1/revision' - '/origin/' - '/history/' - '/directory//') -@app.route('/api/1/revision' - '/origin/' - '/branch/' - '/history/' - '/directory/') -@app.route('/api/1/revision' - '/origin/' - '/branch/' - '/history/' - '/directory//') -@app.route('/api/1/revision' - '/origin/' - '/ts/' - '/history/' - '/directory/') -@app.route('/api/1/revision' - '/origin/' - '/ts/' - '/history/' - '/directory//') -@app.route('/api/1/revision' - '/origin/' - '/branch/' - '/ts/' - '/history/' - '/directory/') -@app.route('/api/1/revision' - '/origin/' - '/branch/' - '/ts/' - '/history/' - '/directory//') -def api_directory_through_revision_with_origin_history( - origin_id, - branch_name="refs/heads/master", - ts=None, - sha1_git=None, - path=None, - with_data=False): - """Return information about directory or content pointed to by the - revision defined as: revision sha1_git, limited to the sub-graph - of all transitive parents of sha1_git_root (being the identified - sha1 by looking up origin_id/branch_name/ts) - - Args: - origin_id: origin's identifier (default to 1). - branch_name: the optional branch for the given origin (default - to master). - timestamp: optional timestamp (default to the nearest time - crawl of timestamp). - sha1_git: one of sha1_git_root's ancestors. - path: optional directory or content pointed to by that revision. - limit: optional query parameter to limit the revisions log - (default to 100). For now, note that this limit could impede the - transitivity conclusion about sha1_git not being an ancestor of - sha1_git_root (even if it is). - with_data: indicate to retrieve the content's raw data if path resolves - to a content. - - Returns: - Information on the directory pointed to by that revision. - - Raises: - BadInputExc in case of unknown algo_hash or bad hash. - NotFoundExc if either revision is not found or if sha1_git is not an - ancestor of sha1_git_root or the path referenced does not exist. - - """ - limit = int(request.args.get('limit', '100')) - - if ts: - ts = utils.parse_timestamp(ts) - - return _revision_directory_by( - { - 'origin_id': origin_id, - 'branch_name': branch_name, - 'ts': ts, - 'sha1_git': sha1_git - }, - path, - request.path, - limit=limit, with_data=with_data) - - -@app.route('/api/1/revision' - '/origin/') -@app.route('/api/1/revision' '/origin//') @app.route('/api/1/revision' '/origin/' @@ -610,102 +449,9 @@ with_data=with_data) -@app.route('/api/1/revision//history//') -def api_revision_history(sha1_git_root, sha1_git): - """Return information about revision sha1_git, limited to the - sub-graph of all transitive parents of sha1_git_root. - - In other words, sha1_git is an ancestor of sha1_git_root. - - Args: - sha1_git_root: latest revision of the browsed history. - sha1_git: one of sha1_git_root's ancestors. - limit: optional query parameter to limit the revisions log - (default to 100). For now, note that this limit could impede the - transitivity conclusion about sha1_git not being an ancestor of - sha1_git_root (even if it is). - - Returns: - Information on sha1_git if it is an ancestor of sha1_git_root - including children leading to sha1_git_root. - - Raises: - BadInputExc in case of unknown algo_hash or bad hash. - NotFoundExc if either revision is not found or if sha1_git is not an - ancestor of sha1_git_root. - - """ - limit = int(request.args.get('limit', '100')) - - if sha1_git == sha1_git_root: - return redirect(url_for('api_revision', - sha1_git=sha1_git, - limit=limit)) - - revision = service.lookup_revision_with_context(sha1_git_root, - sha1_git, - limit) - if not revision: - raise NotFoundExc( - "Possibly sha1_git '%s' is not an ancestor of sha1_git_root '%s'" - % (sha1_git, sha1_git_root)) - - return utils.enrich_revision(revision, context=sha1_git_root) - - -@app.route('/api/1/revision/' - '/history/' - '/directory/') -@app.route('/api/1/revision/' - '/history/' - '/directory//') -def api_revision_history_directory(sha1_git_root, sha1_git, - dir_path=None, with_data=False): - """Return information about directory pointed to by the revision - defined as: revision sha1_git, limited to the sub-graph of all - transitive parents of sha1_git_root. - - Args: - sha1_git_root: latest revision of the browsed history. - sha1_git: one of sha1_git_root's ancestors. - dir_path: optional directory pointed to by that revision. - limit: optional query parameter to limit the revisions log - (default to 100). For now, note that this limit could impede the - transitivity conclusion about sha1_git not being an ancestor of - sha1_git_root (even if it is). - with_data: indicate to retrieve the content's raw data if path resolves - to a content. - - Returns: - Information on the directory pointed to by that revision. - - Raises: - BadInputExc in case of unknown algo_hash or bad hash. - NotFoundExc if either revision is not found or if sha1_git is not an - ancestor of sha1_git_root or the path referenced does not exist - - """ - limit = int(request.args.get('limit', '100')) - - if sha1_git == sha1_git_root: - return redirect(url_for('api_revision_directory', - sha1_git=sha1_git, - dir_path=dir_path), - code=301) - - return _revision_directory_by( - { - 'sha1_git_root': sha1_git_root, - 'sha1_git': sha1_git - }, - dir_path, - request.path, - limit=limit, with_data=with_data) - - @app.route('/api/1/revision//log/') @app.route('/api/1/revision//prev//log/') -def api_revision_log(sha1_git, prev_sha1s=None, limit=25): +def api_revision_log(sha1_git, prev_sha1s=None): """Show all revisions (~git log) starting from sha1_git. The first element returned is the given sha1_git. @@ -724,6 +470,7 @@ NotFoundExc if the revision is not found. """ + limit = app.config['conf']['max_log_revs'] response = {'revisions': None, 'next_revs_url': None} revisions = None @@ -797,19 +544,36 @@ Raises: NotFoundExc if the revision is not found. """ + limit = app.config['conf']['max_log_revs'] + response = {'revisions': None, 'next_revs_url': None} + next_revs_url = None + if ts: ts = utils.parse_timestamp(ts) + def lookup_revision_log_by_with_limit(o_id, br, ts, limit=limit+1): + return service.lookup_revision_log_by(o_id, br, ts, limit) + error_msg = 'No revision matching origin %s ' % origin_id error_msg += ', branch name %s' % branch_name error_msg += (' and time stamp %s.' % ts) if ts else '.' - return _api_lookup( - origin_id, - service.lookup_revision_log_by, - error_msg, - utils.enrich_revision, - branch_name, - ts) + + rev_get = _api_lookup(origin_id, + lookup_revision_log_by_with_limit, + error_msg, + utils.enrich_revision, + branch_name, + ts) + if len(rev_get) == limit+1: + revisions = rev_get[:-1] + next_revs_url = url_for('api_revision_log', + sha1_git=rev_get[-1]['id']) + else: + revisions = rev_get + response['revisions'] = revisions + response['next_revs_url'] = next_revs_url + + return response @app.route('/api/1/directory/')