| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import posixpath | 5 import posixpath |
| 6 import traceback | 6 import traceback |
| 7 import xml.dom.minidom as xml | 7 import xml.dom.minidom as xml |
| 8 from xml.parsers.expat import ExpatError | 8 from xml.parsers.expat import ExpatError |
| 9 | 9 |
| 10 from appengine_url_fetcher import AppEngineUrlFetcher | 10 from appengine_url_fetcher import AppEngineUrlFetcher |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 version = int(_InnerText(version_element)) | 88 version = int(_InnerText(version_element)) |
| 89 except StandardError: | 89 except StandardError: |
| 90 continue | 90 continue |
| 91 child_versions[name] = str(version) | 91 child_versions[name] = str(version) |
| 92 | 92 |
| 93 if parent_version and child_versions: | 93 if parent_version and child_versions: |
| 94 break | 94 break |
| 95 | 95 |
| 96 return StatInfo(parent_version, child_versions) | 96 return StatInfo(parent_version, child_versions) |
| 97 | 97 |
| 98 def _GetAsyncFetchCallback(paths, fetcher, args=None, skip_not_found=False): | |
| 99 def apply_args(path): | |
| 100 return path if args is None else '%s?%s' % (path, args) | |
| 101 | |
| 102 def list_dir(directory): | |
| 103 dom = xml.parseString(directory) | |
| 104 files = [elem.childNodes[0].data for elem in dom.getElementsByTagName('a')] | |
| 105 if '..' in files: | |
| 106 files.remove('..') | |
| 107 return files | |
| 108 | |
| 109 # A list of tuples of the form (path, Future). | |
| 110 fetches = [(path, fetcher.FetchAsync(apply_args(path))) for path in paths] | |
| 111 | |
| 112 def resolve(): | |
| 113 value = {} | |
| 114 for path, future in fetches: | |
| 115 try: | |
| 116 result = future.Get() | |
| 117 except Exception as e: | |
| 118 if skip_not_found and IsDownloadError(e): continue | |
| 119 exc_type = FileNotFoundError if IsDownloadError(e) else FileSystemError | |
| 120 raise exc_type('%s fetching %s for Get: %s' % | |
| 121 (type(e).__name__, path, traceback.format_exc())) | |
| 122 if result.status_code == 404: | |
| 123 if skip_not_found: continue | |
| 124 raise FileNotFoundError('Got 404 when fetching %s for Get, content %s' % | |
| 125 (path, result.content)) | |
| 126 if result.status_code != 200: | |
| 127 raise FileSystemError('Got %s when fetching %s for Get, content %s' % | |
| 128 (result.status_code, path, result.content)) | |
| 129 if path.endswith('/'): | |
| 130 value[path] = list_dir(result.content) | |
| 131 else: | |
| 132 value[path] = result.content | |
| 133 return value | |
| 134 | |
| 135 return resolve | |
| 136 | 98 |
| 137 class SubversionFileSystem(FileSystem): | 99 class SubversionFileSystem(FileSystem): |
| 138 '''Class to fetch resources from src.chromium.org. | 100 '''Class to fetch resources from src.chromium.org. |
| 139 ''' | 101 ''' |
| 140 @staticmethod | 102 @staticmethod |
| 141 def Create(branch='trunk', revision=None): | 103 def Create(branch='trunk', revision=None): |
| 142 if branch == 'trunk': | 104 if branch == 'trunk': |
| 143 svn_path = 'trunk/src' | 105 svn_path = 'trunk/src' |
| 144 else: | 106 else: |
| 145 svn_path = 'branches/%s/src' % branch | 107 svn_path = 'branches/%s/src' % branch |
| 146 return SubversionFileSystem( | 108 return SubversionFileSystem( |
| 147 AppEngineUrlFetcher('%s/%s' % (url_constants.SVN_URL, svn_path)), | 109 AppEngineUrlFetcher('%s/%s' % (url_constants.SVN_URL, svn_path)), |
| 148 AppEngineUrlFetcher('%s/%s' % (url_constants.VIEWVC_URL, svn_path)), | 110 AppEngineUrlFetcher('%s/%s' % (url_constants.VIEWVC_URL, svn_path)), |
| 149 svn_path, | 111 svn_path, |
| 150 revision=revision) | 112 revision=revision) |
| 151 | 113 |
| 152 def __init__(self, file_fetcher, stat_fetcher, svn_path, revision=None): | 114 def __init__(self, file_fetcher, stat_fetcher, svn_path, revision=None): |
| 153 self._file_fetcher = file_fetcher | 115 self._file_fetcher = file_fetcher |
| 154 self._stat_fetcher = stat_fetcher | 116 self._stat_fetcher = stat_fetcher |
| 155 self._svn_path = svn_path | 117 self._svn_path = svn_path |
| 156 self._revision = revision | 118 self._revision = revision |
| 157 | 119 |
| 158 def Read(self, paths, skip_not_found=False): | 120 def Read(self, paths, skip_not_found=False): |
| 159 args = None | 121 args = None |
| 160 if self._revision is not None: | 122 if self._revision is not None: |
| 161 # |fetcher| gets from svn.chromium.org which uses p= for version. | 123 # |fetcher| gets from svn.chromium.org which uses p= for version. |
| 162 args = 'p=%s' % self._revision | 124 args = 'p=%s' % self._revision |
| 163 return Future(callback=_GetAsyncFetchCallback( | 125 |
| 164 paths, | 126 def apply_args(path): |
| 165 self._file_fetcher, | 127 return path if args is None else '%s?%s' % (path, args) |
| 166 args=args, | 128 |
| 167 skip_not_found=skip_not_found)) | 129 def list_dir(directory): |
| 130 dom = xml.parseString(directory) |
| 131 files = [elem.childNodes[0].data |
| 132 for elem in dom.getElementsByTagName('a')] |
| 133 if '..' in files: |
| 134 files.remove('..') |
| 135 return files |
| 136 |
| 137 # A list of tuples of the form (path, Future). |
| 138 fetches = [(path, self._file_fetcher.FetchAsync(apply_args(path))) |
| 139 for path in paths] |
| 140 |
| 141 def resolve(): |
| 142 value = {} |
| 143 for path, future in fetches: |
| 144 try: |
| 145 result = future.Get() |
| 146 except Exception as e: |
| 147 if skip_not_found and IsDownloadError(e): continue |
| 148 exc_type = (FileNotFoundError if IsDownloadError(e) |
| 149 else FileSystemError) |
| 150 raise exc_type('%s fetching %s for Get: %s' % |
| 151 (type(e).__name__, path, traceback.format_exc())) |
| 152 if result.status_code == 404: |
| 153 if skip_not_found: continue |
| 154 raise FileNotFoundError( |
| 155 'Got 404 when fetching %s for Get, content %s' % |
| 156 (path, result.content)) |
| 157 if result.status_code != 200: |
| 158 raise FileSystemError('Got %s when fetching %s for Get, content %s' % |
| 159 (result.status_code, path, result.content)) |
| 160 if path.endswith('/'): |
| 161 value[path] = list_dir(result.content) |
| 162 else: |
| 163 value[path] = result.content |
| 164 return value |
| 165 return Future(callback=resolve) |
| 168 | 166 |
| 169 def Refresh(self): | 167 def Refresh(self): |
| 170 return Future(value=()) | 168 return Future(value=()) |
| 171 | 169 |
| 172 def Stat(self, path): | 170 def Stat(self, path): |
| 173 return self.StatAsync(path).Get() | 171 return self.StatAsync(path).Get() |
| 174 | 172 |
| 175 def StatAsync(self, path): | 173 def StatAsync(self, path): |
| 176 directory, filename = posixpath.split(path) | 174 directory, filename = posixpath.split(path) |
| 177 if self._revision is not None: | 175 if self._revision is not None: |
| (...skipping 27 matching lines...) Expand all Loading... |
| 205 return StatInfo(stat_info.child_versions[filename]) | 203 return StatInfo(stat_info.child_versions[filename]) |
| 206 | 204 |
| 207 return Future(callback=resolve) | 205 return Future(callback=resolve) |
| 208 | 206 |
| 209 def GetIdentity(self): | 207 def GetIdentity(self): |
| 210 # NOTE: no revision here, since it would mess up the caching of reads. It | 208 # NOTE: no revision here, since it would mess up the caching of reads. It |
| 211 # probably doesn't matter since all the caching classes will use the result | 209 # probably doesn't matter since all the caching classes will use the result |
| 212 # of Stat to decide whether to re-read - and Stat has a ceiling of the | 210 # of Stat to decide whether to re-read - and Stat has a ceiling of the |
| 213 # revision - so when the revision changes, so might Stat. That is enough. | 211 # revision - so when the revision changes, so might Stat. That is enough. |
| 214 return '@'.join((self.__class__.__name__, StringIdentity(self._svn_path))) | 212 return '@'.join((self.__class__.__name__, StringIdentity(self._svn_path))) |
| OLD | NEW |