Docserver: Fixes for GitilesFileSystem

This patch resolves a few issues with GitilesFileSystem.

BUG=404239
NOTRY=True

Review URL: https://codereview.chromium.org/498503002

Cr-Commit-Position: refs/heads/master@{#291357}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@291357 0039d316-1c4b-4281-b951-d872f2087c98
parent c457cea4
...@@ -79,14 +79,20 @@ class _FakeSubversionServer(_FakeFetcher): ...@@ -79,14 +79,20 @@ class _FakeSubversionServer(_FakeFetcher):
_GITILES_BASE_RE = re.escape(url_constants.GITILES_BASE) _GITILES_BASE_RE = re.escape(url_constants.GITILES_BASE)
_GITILES_BRANCH_BASE_RE = re.escape(url_constants.GITILES_BRANCH_BASE) _GITILES_BRANCH_BASE_RE = re.escape(url_constants.GITILES_BRANCH_BASE)
_GITILES_URL_TO_PATH_PATTERN = re.compile( # NOTE: _GITILES_BRANCH_BASE_RE must be first, because _GITILES_BASE_RE is
r'(' + _GITILES_BASE_RE + r'|' + _GITILES_BRANCH_BASE_RE + r').+?/(.*)') # a more general pattern.
_GITILES_URL_RE = r'(%s|%s)/' % (_GITILES_BRANCH_BASE_RE, _GITILES_BASE_RE)
_GITILES_URL_TO_COMMIT_PATTERN = re.compile(
r'%s[^/]+\?format=JSON' % _GITILES_URL_RE)
_GITILES_URL_TO_PATH_PATTERN = re.compile(r'%s.+?/(.*)' % _GITILES_URL_RE)
def _ExtractPathFromGitilesUrl(url): def _ExtractPathFromGitilesUrl(url):
return _GITILES_URL_TO_PATH_PATTERN.match(url).group(2) return _GITILES_URL_TO_PATH_PATTERN.match(url).group(2)
class _FakeGitilesServer(_FakeFetcher): class _FakeGitilesServer(_FakeFetcher):
def fetch(self, url): def fetch(self, url):
if _GITILES_URL_TO_COMMIT_PATTERN.match(url) is not None:
return json.dumps({'commit': '1' * 40})
path = _ExtractPathFromGitilesUrl(url) path = _ExtractPathFromGitilesUrl(url)
chromium_path = ChromiumPath(path) chromium_path = ChromiumPath(path)
if self._IsDir(chromium_path): if self._IsDir(chromium_path):
...@@ -97,9 +103,11 @@ class _FakeGitilesServer(_FakeFetcher): ...@@ -97,9 +103,11 @@ class _FakeGitilesServer(_FakeFetcher):
for f in self._ListDir(chromium_path): for f in self._ListDir(chromium_path):
if f.startswith('.'): if f.startswith('.'):
continue continue
f_path = os.path.join(chromium_path, f)
jsn['entries'].append({ jsn['entries'].append({
'id': self._Stat(os.path.join(chromium_path, f)), 'id': self._Stat(f_path),
'name': f 'name': f,
'type': 'tree' if self._IsDir(f_path) else 'blob'
}) })
return json.dumps(jsn) return json.dumps(jsn)
try: try:
......
...@@ -16,7 +16,7 @@ from file_system import (FileNotFoundError, ...@@ -16,7 +16,7 @@ from file_system import (FileNotFoundError,
FileSystemError, FileSystemError,
StatInfo) StatInfo)
from future import All, Future from future import All, Future
from path_util import AssertIsValid, IsDirectory, SplitParent, ToDirectory from path_util import AssertIsValid, IsDirectory, ToDirectory
from third_party.json_schema_compiler.memoize import memoize from third_party.json_schema_compiler.memoize import memoize
from url_constants import GITILES_BASE, GITILES_BRANCH_BASE from url_constants import GITILES_BASE, GITILES_BRANCH_BASE
...@@ -104,9 +104,11 @@ class GitilesFileSystem(FileSystem): ...@@ -104,9 +104,11 @@ class GitilesFileSystem(FileSystem):
# "name": ".gitignore" # "name": ".gitignore"
# }, # },
# ... # ...
# ]
# } # }
def list_dir(json_data): def list_dir(json_data):
return [e['name'] for e in _ParseGitilesJson(json_data)['entries']] entries = _ParseGitilesJson(json_data).get('entries', [])
return [e['name'] + ('/' if e['type'] == 'tree' else '') for e in entries]
def fixup_url_format(path): def fixup_url_format(path):
# By default, Gitiles URLs display resources in HTML. To get resources # By default, Gitiles URLs display resources in HTML. To get resources
...@@ -135,8 +137,29 @@ class GitilesFileSystem(FileSystem): ...@@ -135,8 +137,29 @@ class GitilesFileSystem(FileSystem):
return Future(value=()) return Future(value=())
@memoize @memoize
def GetCommitID(self): def _GetCommitInfo(self, key):
'''Returns a future that resolves to the commit ID for this branch. '''Gets the commit information specified by |key|.
The JSON view for commit info looks like:
{
"commit": "8fd578e1a7b142cd10a4387861f05fb9459b69e2", # Commit ID.
"tree": "3ade65d8a91eadd009a6c9feea8f87db2c528a53", # Tree ID.
"parents": [
"a477c787fe847ae0482329f69b39ce0fde047359" # Previous commit ID.
],
"author": {
"name": "...",
"email": "...",
"time": "Tue Aug 12 17:17:21 2014"
},
"committer": {
"name": "...",
"email": "...",
"time": "Tue Aug 12 17:18:28 2014"
},
"message": "...",
"tree_diff": [...]
}
''' '''
# Commit information for a branch is obtained by appending '?format=JSON' # Commit information for a branch is obtained by appending '?format=JSON'
# to the branch URL. Note that '<gitiles_url>/<branch>?format=JSON' is # to the branch URL. Note that '<gitiles_url>/<branch>?format=JSON' is
...@@ -145,17 +168,12 @@ class GitilesFileSystem(FileSystem): ...@@ -145,17 +168,12 @@ class GitilesFileSystem(FileSystem):
# commit info JSON content. # commit info JSON content.
fetch_future = self._fetcher.FetchAsync(self._base_url + _JSON_FORMAT) fetch_future = self._fetcher.FetchAsync(self._base_url + _JSON_FORMAT)
content_future = self._ResolveFetchContent(self._base_url, fetch_future) content_future = self._ResolveFetchContent(self._base_url, fetch_future)
# The commit info JSON looks like: return content_future.Then(lambda json: _ParseGitilesJson(json)[key])
#
# { def GetCommitID(self):
# "commit": "8fd578e1a7b142cd10a4387861f05fb9459b69e2", # Commit ID. '''Returns a future that resolves to the commit ID for this branch.
# "tree": "3ade65d8a91eadd009a6c9feea8f87db2c528a53", # Tree ID. '''
# "author": {...}, return self._GetCommitInfo('commit')
# "committer": {...},
# "message": <codereview message>,
# ...
# }
return content_future.Then(lambda json: _ParseGitilesJson(json)['commit'])
def StatAsync(self, path): def StatAsync(self, path):
dir_, filename = posixpath.split(path) dir_, filename = posixpath.split(path)
...@@ -173,5 +191,10 @@ class GitilesFileSystem(FileSystem): ...@@ -173,5 +191,10 @@ class GitilesFileSystem(FileSystem):
return self._ResolveFetchContent(path, fetch_future).Then(stat) return self._ResolveFetchContent(path, fetch_future).Then(stat)
def GetIdentity(self): def GetIdentity(self):
return '@'.join((self.__class__.__name__, # NOTE: Do not use commit information to create the string identity.
StringIdentity(self._commit or self._branch))) # Doing so will mess up caching.
if self._commit is None and self._branch != 'master':
str_id = GITILES_BRANCH_BASE
else:
str_id = GITILES_BASE
return '@'.join((self.__class__.__name__, StringIdentity(str_id)))
...@@ -13,12 +13,14 @@ from future import Future ...@@ -13,12 +13,14 @@ from future import Future
from gitiles_file_system import (_CreateStatInfo, from gitiles_file_system import (_CreateStatInfo,
_ParseGitilesJson, _ParseGitilesJson,
GitilesFileSystem) GitilesFileSystem)
from path_util import IsDirectory
from test_file_system import TestFileSystem from test_file_system import TestFileSystem
from test_util import ReadFile from test_util import ReadFile
_BASE_URL = '' _BASE_URL = ''
_REAL_DATA_DIR = 'chrome/common/extensions/docs/templates/public/extensions/' _REAL_DATA_DIR = 'chrome/common/extensions/docs/templates/public/extensions/'
_TEST_DATA = (SERVER2, 'test_data', 'gitiles_file_system', 'public_extensions')
# GitilesFileSystem expects file content to be encoded in base64. # GitilesFileSystem expects file content to be encoded in base64.
_TEST_FS = { _TEST_FS = {
'test1.txt': base64.b64encode('test1'), 'test1.txt': base64.b64encode('test1'),
...@@ -54,8 +56,7 @@ class _FakeGitilesFetcher(object): ...@@ -54,8 +56,7 @@ class _FakeGitilesFetcher(object):
# Fetch urls are of the form <base_url>/<path>. We only want <path>. # Fetch urls are of the form <base_url>/<path>. We only want <path>.
path = path.split('/', 1)[1] path = path.split('/', 1)[1]
if path == _REAL_DATA_DIR: if path == _REAL_DATA_DIR:
return _Response(ReadFile(SERVER2, 'test_data', 'gitiles_file_system', return _Response(ReadFile(*_TEST_DATA))
'public_extensions'))
# ALWAYS skip not found here. # ALWAYS skip not found here.
content = self._fs.Read((path,), content = self._fs.Read((path,),
skip_not_found=True).Get().get(path, None) skip_not_found=True).Get().get(path, None)
...@@ -65,7 +66,11 @@ class _FakeGitilesFetcher(object): ...@@ -65,7 +66,11 @@ class _FakeGitilesFetcher(object):
# GitilesFS expects directory content as a JSON string. # GitilesFS expects directory content as a JSON string.
if 'JSON' in fmt: if 'JSON' in fmt:
content = json.dumps({ content = json.dumps({
'entries': [{'name': name} for name in content] 'entries': [{
# GitilesFS expects directory names to not have a trailing '/'.
'name': name.rstrip('/'),
'type': 'tree' if IsDirectory(name) else 'blob'
} for name in content]
}) })
return _Response(content) return _Response(content)
return Future(callback=resolve) return Future(callback=resolve)
...@@ -74,7 +79,7 @@ class _FakeGitilesFetcher(object): ...@@ -74,7 +79,7 @@ class _FakeGitilesFetcher(object):
class GitilesFileSystemTest(unittest.TestCase): class GitilesFileSystemTest(unittest.TestCase):
def setUp(self): def setUp(self):
fetcher = _FakeGitilesFetcher(TestFileSystem(_TEST_FS)) fetcher = _FakeGitilesFetcher(TestFileSystem(_TEST_FS))
self._gitiles_fs = GitilesFileSystem(fetcher, _BASE_URL, '', '') self._gitiles_fs = GitilesFileSystem(fetcher, _BASE_URL, 'master', None)
def testParseGitilesJson(self): def testParseGitilesJson(self):
test_json = '\n'.join([ test_json = '\n'.join([
...@@ -144,6 +149,15 @@ class GitilesFileSystemTest(unittest.TestCase): ...@@ -144,6 +149,15 @@ class GitilesFileSystemTest(unittest.TestCase):
self.assertEqual(self._gitiles_fs.Stat(_REAL_DATA_DIR).version, self.assertEqual(self._gitiles_fs.Stat(_REAL_DATA_DIR).version,
'ec21e736a3f00db2c0580e3cf71d91951656caec') 'ec21e736a3f00db2c0580e3cf71d91951656caec')
def testGetIdentity(self):
# Test that file systems at different commits still have the same identity.
other_gitiles_fs = GitilesFileSystem.Create(commit='abcdefghijklmnop')
self.assertEqual(self._gitiles_fs.GetIdentity(),
other_gitiles_fs.GetIdentity())
yet_another_gitiles_fs = GitilesFileSystem.Create(branch='different')
self.assertNotEqual(self._gitiles_fs.GetIdentity(),
yet_another_gitiles_fs.GetIdentity())
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment