| Index: chrome/common/extensions/docs/server2/gitiles_file_system.py
|
| diff --git a/chrome/common/extensions/docs/server2/gitiles_file_system.py b/chrome/common/extensions/docs/server2/gitiles_file_system.py
|
| deleted file mode 100644
|
| index ecfd78c9b59c381c0a5447ecdcd897b41af91413..0000000000000000000000000000000000000000
|
| --- a/chrome/common/extensions/docs/server2/gitiles_file_system.py
|
| +++ /dev/null
|
| @@ -1,251 +0,0 @@
|
| -# Copyright 2014 The Chromium Authors. All rights reserved.
|
| -# Use of this source code is governed by a BSD-style license that can be
|
| -# found in the LICENSE file.
|
| -
|
| -
|
| -from base64 import b64decode
|
| -from itertools import izip
|
| -import json
|
| -import logging
|
| -import posixpath
|
| -import time
|
| -import traceback
|
| -
|
| -from appengine_url_fetcher import AppEngineUrlFetcher
|
| -from appengine_wrappers import IsDownloadError, app_identity
|
| -from docs_server_utils import StringIdentity
|
| -from environment import IsDevServer
|
| -from file_system import (FileNotFoundError,
|
| - FileSystem,
|
| - FileSystemError,
|
| - FileSystemThrottledError,
|
| - StatInfo)
|
| -from future import All, Future
|
| -from path_util import AssertIsValid, IsDirectory, ToDirectory
|
| -from third_party.json_schema_compiler.memoize import memoize
|
| -from url_constants import (GITILES_BASE,
|
| - GITILES_SRC_ROOT,
|
| - GITILES_BRANCHES_PATH,
|
| - GITILES_OAUTH2_SCOPE)
|
| -
|
| -
|
| -_JSON_FORMAT = '?format=JSON'
|
| -_TEXT_FORMAT = '?format=TEXT'
|
| -_AUTH_PATH_PREFIX = '/a'
|
| -
|
| -
|
| -def _ParseGitilesJson(json_data):
|
| - '''json.loads with fix-up for non-executable JSON. Use this to parse any JSON
|
| - data coming from Gitiles views.
|
| - '''
|
| - return json.loads(json_data[json_data.find('{'):])
|
| -
|
| -
|
| -def _CreateStatInfo(json_data):
|
| - '''Returns a StatInfo object comprised of the tree ID for |json_data|,
|
| - as well as the tree IDs for the entries in |json_data|.
|
| - '''
|
| - tree = _ParseGitilesJson(json_data)
|
| - return StatInfo(tree['id'],
|
| - dict((e['name'], e['id']) for e in tree['entries']))
|
| -
|
| -
|
| -class GitilesFileSystem(FileSystem):
|
| - '''Class to fetch filesystem data from the Chromium project's gitiles
|
| - service.
|
| - '''
|
| - _logged_tokens = set()
|
| -
|
| - @classmethod
|
| - def Create(cls, branch='master', commit=None):
|
| - token, _ = app_identity.get_access_token(GITILES_OAUTH2_SCOPE)
|
| -
|
| - # Log the access token (once per token) so that it can be sneakily re-used
|
| - # in development.
|
| - if token not in cls._logged_tokens:
|
| - logging.info('Got token %s for scope %s' % (token, GITILES_OAUTH2_SCOPE))
|
| - cls._logged_tokens.add(token)
|
| -
|
| - # Only include forced-auth (/a/) in the Gitiles URL if we have a token and
|
| - # this is not the development server.
|
| - path_prefix = ('' if token is None or IsDevServer()
|
| - else _AUTH_PATH_PREFIX)
|
| - if commit:
|
| - base_url = '%s%s/%s/%s' % (
|
| - GITILES_BASE, path_prefix, GITILES_SRC_ROOT, commit)
|
| - elif branch is 'master':
|
| - base_url = '%s%s/%s/master' % (
|
| - GITILES_BASE, path_prefix, GITILES_SRC_ROOT)
|
| - else:
|
| - base_url = '%s%s/%s/%s/%s' % (
|
| - GITILES_BASE, path_prefix, GITILES_SRC_ROOT,
|
| - GITILES_BRANCHES_PATH, branch)
|
| - return GitilesFileSystem(AppEngineUrlFetcher(), base_url, branch, commit)
|
| -
|
| - def __init__(self, fetcher, base_url, branch, commit):
|
| - self._fetcher = fetcher
|
| - self._base_url = base_url
|
| - self._branch = branch
|
| - self._commit = commit
|
| -
|
| - def _FetchAsync(self, url):
|
| - '''Convenience wrapper for fetcher.FetchAsync, so callers don't
|
| - need to use posixpath.join.
|
| - '''
|
| - AssertIsValid(url)
|
| - access_token, _ = app_identity.get_access_token(GITILES_OAUTH2_SCOPE)
|
| - return self._fetcher.FetchAsync('%s/%s' % (self._base_url, url),
|
| - access_token=access_token)
|
| -
|
| - def _ResolveFetchContent(self, path, fetch_future, skip_not_found=False):
|
| - '''Returns a future to cleanly resolve |fetch_future|.
|
| - '''
|
| - def handle(e):
|
| - if skip_not_found and IsDownloadError(e):
|
| - return None
|
| - exc_type = FileNotFoundError if IsDownloadError(e) else FileSystemError
|
| - raise exc_type('%s fetching %s for Get from %s: %s' %
|
| - (type(e).__name__, path, self._base_url, traceback.format_exc()))
|
| -
|
| - def get_content(result):
|
| - if result.status_code == 404:
|
| - if skip_not_found:
|
| - return None
|
| - raise FileNotFoundError('Got 404 when fetching %s for Get from %s' %
|
| - (path, self._base_url))
|
| - if result.status_code == 429:
|
| - logging.warning('Access throttled when fetching %s for Get from %s' %
|
| - (path, self._base_url))
|
| - raise FileSystemThrottledError(
|
| - 'Access throttled when fetching %s for Get from %s' %
|
| - (path, self._base_url))
|
| - if result.status_code != 200:
|
| - raise FileSystemError(
|
| - 'Got %s when fetching %s for Get from %s, content %s' %
|
| - (result.status_code, path, self._base_url, result.content))
|
| - return result.content
|
| -
|
| - return fetch_future.Then(get_content, handle)
|
| -
|
| - def Read(self, paths, skip_not_found=False):
|
| - # Directory content is formatted in JSON in Gitiles as follows:
|
| - #
|
| - # {
|
| - # "id": "12a5464de48d2c46bc0b2dc78fafed75aab554fa", # The tree ID.
|
| - # "entries": [
|
| - # {
|
| - # "mode": 33188,
|
| - # "type": "blob",
|
| - # "id": "ab971ca447bc4bce415ed4498369e00164d91cb6", # File ID.
|
| - # "name": ".gitignore"
|
| - # },
|
| - # ...
|
| - # ]
|
| - # }
|
| - def list_dir(json_data):
|
| - entries = _ParseGitilesJson(json_data).get('entries', [])
|
| - return [e['name'] + ('/' if e['type'] == 'tree' else '') for e in entries]
|
| -
|
| - def fixup_url_format(path):
|
| - # By default, Gitiles URLs display resources in HTML. To get resources
|
| - # suitable for our consumption, a '?format=' string must be appended to
|
| - # the URL. The format may be one of 'JSON' or 'TEXT' for directory or
|
| - # text resources, respectively.
|
| - return path + (_JSON_FORMAT if IsDirectory(path) else _TEXT_FORMAT)
|
| -
|
| - # A list of tuples of the form (path, Future).
|
| - fetches = [(path, self._FetchAsync(fixup_url_format(path)))
|
| - for path in paths]
|
| -
|
| - def parse_contents(results):
|
| - value = {}
|
| - for path, content in izip(paths, results):
|
| - if content is None:
|
| - continue
|
| - # Gitiles encodes text content in base64 (see
|
| - # http://tools.ietf.org/html/rfc4648 for info about base64).
|
| - value[path] = (list_dir if IsDirectory(path) else b64decode)(content)
|
| - return value
|
| -
|
| - return All(self._ResolveFetchContent(path, future, skip_not_found)
|
| - for path, future in fetches).Then(parse_contents)
|
| -
|
| - def Refresh(self):
|
| - return Future(value=())
|
| -
|
| - @memoize
|
| - def _GetCommitInfo(self, key):
|
| - '''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'
|
| - # to the branch URL. Note that '<gitiles_url>/<branch>?format=JSON' is
|
| - # different from '<gitiles_url>/<branch>/?format=JSON': the latter serves
|
| - # the root directory JSON content, whereas the former serves the branch
|
| - # commit info JSON content.
|
| -
|
| - access_token, _ = app_identity.get_access_token(GITILES_OAUTH2_SCOPE)
|
| - fetch_future = self._fetcher.FetchAsync(self._base_url + _JSON_FORMAT,
|
| - access_token=access_token)
|
| - content_future = self._ResolveFetchContent(self._base_url, fetch_future)
|
| - return content_future.Then(lambda json: _ParseGitilesJson(json)[key])
|
| -
|
| - def GetCommitID(self):
|
| - '''Returns a future that resolves to the commit ID for this branch.
|
| - '''
|
| - return self._GetCommitInfo('commit')
|
| -
|
| - def GetPreviousCommitID(self):
|
| - '''Returns a future that resolves to the previous commit ID for this branch.
|
| - '''
|
| - return self._GetCommitInfo('parents').Then(lambda parents: parents[0])
|
| -
|
| - def StatAsync(self, path):
|
| - dir_, filename = posixpath.split(path)
|
| - def stat(content):
|
| - stat_info = _CreateStatInfo(content)
|
| - if stat_info.version is None:
|
| - raise FileSystemError('Failed to find version of dir %s' % dir_)
|
| - if IsDirectory(path):
|
| - return stat_info
|
| - if filename not in stat_info.child_versions:
|
| - raise FileNotFoundError(
|
| - '%s from %s was not in child versions for Stat' % (filename, path))
|
| - return StatInfo(stat_info.child_versions[filename])
|
| -
|
| - fetch_future = self._FetchAsync(ToDirectory(dir_) + _JSON_FORMAT)
|
| - return self._ResolveFetchContent(path, fetch_future).Then(stat)
|
| -
|
| - def GetIdentity(self):
|
| - if self._branch == 'master':
|
| - # A master FS always carries the same identity even if pinned to a commit.
|
| - str_id = 'master'
|
| - elif self._commit is not None:
|
| - str_id = self._commit
|
| - else:
|
| - str_id = '%s/%s' % (GITILES_BRANCHES_PATH, self._branch)
|
| - return '@'.join((self.__class__.__name__, StringIdentity(
|
| - '%s/%s/%s' % (GITILES_BASE, GITILES_SRC_ROOT, str_id))))
|
| -
|
| - def GetVersion(self):
|
| - return self._commit
|
|
|