| Index: chrome/common/extensions/docs/server2/subversion_file_system.py
|
| diff --git a/chrome/common/extensions/docs/server2/subversion_file_system.py b/chrome/common/extensions/docs/server2/subversion_file_system.py
|
| deleted file mode 100644
|
| index 949bca9bb3a960713584a79db5941abc15e012d3..0000000000000000000000000000000000000000
|
| --- a/chrome/common/extensions/docs/server2/subversion_file_system.py
|
| +++ /dev/null
|
| @@ -1,209 +0,0 @@
|
| -# Copyright (c) 2012 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.
|
| -
|
| -import posixpath
|
| -import traceback
|
| -import xml.dom.minidom as xml
|
| -from xml.parsers.expat import ExpatError
|
| -
|
| -from appengine_url_fetcher import AppEngineUrlFetcher
|
| -from appengine_wrappers import IsDownloadError
|
| -from docs_server_utils import StringIdentity
|
| -from file_system import (
|
| - FileNotFoundError, FileSystem, FileSystemError, StatInfo)
|
| -from future import Future
|
| -import url_constants
|
| -
|
| -
|
| -def _ParseHTML(html):
|
| - '''Unfortunately, the viewvc page has a stray </div> tag, so this takes care
|
| - of all mismatched tags.
|
| - '''
|
| - try:
|
| - return xml.parseString(html)
|
| - except ExpatError as e:
|
| - return _ParseHTML('\n'.join(
|
| - line for (i, line) in enumerate(html.split('\n'))
|
| - if e.lineno != i + 1))
|
| -
|
| -def _InnerText(node):
|
| - '''Like node.innerText in JS DOM, but strips surrounding whitespace.
|
| - '''
|
| - text = []
|
| - if node.nodeValue:
|
| - text.append(node.nodeValue)
|
| - if hasattr(node, 'childNodes'):
|
| - for child_node in node.childNodes:
|
| - text.append(_InnerText(child_node))
|
| - return ''.join(text).strip()
|
| -
|
| -def _CreateStatInfo(html):
|
| - parent_version = None
|
| - child_versions = {}
|
| -
|
| - # Try all of the tables until we find the ones that contain the data (the
|
| - # directory and file versions are in different tables).
|
| - for table in _ParseHTML(html).getElementsByTagName('table'):
|
| - # Within the table there is a list of files. However, there may be some
|
| - # things beforehand; a header, "parent directory" list, etc. We will deal
|
| - # with that below by being generous and just ignoring such rows.
|
| - rows = table.getElementsByTagName('tr')
|
| -
|
| - for row in rows:
|
| - cells = row.getElementsByTagName('td')
|
| -
|
| - # The version of the directory will eventually appear in the soup of
|
| - # table rows, like this:
|
| - #
|
| - # <tr>
|
| - # <td>Directory revision:</td>
|
| - # <td><a href=... title="Revision 214692">214692</a> (of...)</td>
|
| - # </tr>
|
| - #
|
| - # So look out for that.
|
| - if len(cells) == 2 and _InnerText(cells[0]) == 'Directory revision:':
|
| - links = cells[1].getElementsByTagName('a')
|
| - if len(links) != 2:
|
| - raise FileSystemError('ViewVC assumption invalid: directory ' +
|
| - 'revision content did not have 2 <a> ' +
|
| - ' elements, instead %s' % _InnerText(cells[1]))
|
| - this_parent_version = _InnerText(links[0])
|
| - int(this_parent_version) # sanity check
|
| - if parent_version is not None:
|
| - raise FileSystemError('There was already a parent version %s, and ' +
|
| - ' we just found a second at %s' %
|
| - (parent_version, this_parent_version))
|
| - parent_version = this_parent_version
|
| -
|
| - # The version of each file is a list of rows with 5 cells: name, version,
|
| - # age, author, and last log entry. Maybe the columns will change; we're
|
| - # at the mercy viewvc, but this constant can be easily updated.
|
| - if len(cells) != 5:
|
| - continue
|
| - name_element, version_element, _, __, ___ = cells
|
| -
|
| - name = _InnerText(name_element) # note: will end in / for directories
|
| - try:
|
| - version = int(_InnerText(version_element))
|
| - except StandardError:
|
| - continue
|
| - child_versions[name] = str(version)
|
| -
|
| - if parent_version and child_versions:
|
| - break
|
| -
|
| - return StatInfo(parent_version, child_versions)
|
| -
|
| -
|
| -class SubversionFileSystem(FileSystem):
|
| - '''Class to fetch resources from src.chromium.org.
|
| - '''
|
| - @staticmethod
|
| - def Create(branch='trunk', revision=None):
|
| - if branch == 'trunk':
|
| - svn_path = 'trunk/src'
|
| - else:
|
| - svn_path = 'branches/%s/src' % branch
|
| - return SubversionFileSystem(
|
| - AppEngineUrlFetcher('%s/%s' % (url_constants.SVN_URL, svn_path)),
|
| - AppEngineUrlFetcher('%s/%s' % (url_constants.VIEWVC_URL, svn_path)),
|
| - svn_path,
|
| - revision=revision)
|
| -
|
| - def __init__(self, file_fetcher, stat_fetcher, svn_path, revision=None):
|
| - self._file_fetcher = file_fetcher
|
| - self._stat_fetcher = stat_fetcher
|
| - self._svn_path = svn_path
|
| - self._revision = revision
|
| -
|
| - def Read(self, paths, skip_not_found=False):
|
| - args = None
|
| - if self._revision is not None:
|
| - # |fetcher| gets from svn.chromium.org which uses p= for version.
|
| - args = 'p=%s' % self._revision
|
| -
|
| - def apply_args(path):
|
| - return path if args is None else '%s?%s' % (path, args)
|
| -
|
| - def list_dir(directory):
|
| - dom = xml.parseString(directory)
|
| - files = [elem.childNodes[0].data
|
| - for elem in dom.getElementsByTagName('a')]
|
| - if '..' in files:
|
| - files.remove('..')
|
| - return files
|
| -
|
| - # A list of tuples of the form (path, Future).
|
| - fetches = [(path, self._file_fetcher.FetchAsync(apply_args(path)))
|
| - for path in paths]
|
| -
|
| - def resolve():
|
| - value = {}
|
| - for path, future in fetches:
|
| - try:
|
| - result = future.Get()
|
| - except Exception as e:
|
| - if skip_not_found and IsDownloadError(e): continue
|
| - exc_type = (FileNotFoundError if IsDownloadError(e)
|
| - else FileSystemError)
|
| - raise exc_type('%s fetching %s for Get: %s' %
|
| - (type(e).__name__, path, traceback.format_exc()))
|
| - if result.status_code == 404:
|
| - if skip_not_found: continue
|
| - raise FileNotFoundError(
|
| - 'Got 404 when fetching %s for Get, content %s' %
|
| - (path, result.content))
|
| - if result.status_code != 200:
|
| - raise FileSystemError('Got %s when fetching %s for Get, content %s' %
|
| - (result.status_code, path, result.content))
|
| - if path.endswith('/'):
|
| - value[path] = list_dir(result.content)
|
| - else:
|
| - value[path] = result.content
|
| - return value
|
| - return Future(callback=resolve)
|
| -
|
| - def Refresh(self):
|
| - return Future(value=())
|
| -
|
| - def StatAsync(self, path):
|
| - directory, filename = posixpath.split(path)
|
| - if self._revision is not None:
|
| - # |stat_fetch| uses viewvc which uses pathrev= for version.
|
| - directory += '?pathrev=%s' % self._revision
|
| -
|
| - result_future = self._stat_fetcher.FetchAsync(directory)
|
| - def resolve():
|
| - try:
|
| - result = result_future.Get()
|
| - except Exception as e:
|
| - exc_type = FileNotFoundError if IsDownloadError(e) else FileSystemError
|
| - raise exc_type('%s fetching %s for Stat: %s' %
|
| - (type(e).__name__, path, traceback.format_exc()))
|
| -
|
| - if result.status_code == 404:
|
| - raise FileNotFoundError('Got 404 when fetching %s for Stat, '
|
| - 'content %s' % (path, result.content))
|
| - if result.status_code != 200:
|
| - raise FileNotFoundError('Got %s when fetching %s for Stat, content %s' %
|
| - (result.status_code, path, result.content))
|
| -
|
| - stat_info = _CreateStatInfo(result.content)
|
| - if stat_info.version is None:
|
| - raise FileSystemError('Failed to find version of dir %s' % directory)
|
| - if path == '' or path.endswith('/'):
|
| - 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])
|
| -
|
| - return Future(callback=resolve)
|
| -
|
| - def GetIdentity(self):
|
| - # NOTE: no revision here, since it would mess up the caching of reads. It
|
| - # probably doesn't matter since all the caching classes will use the result
|
| - # of Stat to decide whether to re-read - and Stat has a ceiling of the
|
| - # revision - so when the revision changes, so might Stat. That is enough.
|
| - return '@'.join((self.__class__.__name__, StringIdentity(self._svn_path)))
|
|
|