Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / common / extensions / docs / server2 / rietveld_patcher.py
blob0743138ff09b31fdcdf47eebc87263f010a658eb
1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 import json
6 import tarfile
7 from StringIO import StringIO
9 from file_system import FileNotFoundError
10 from future import Future
11 from patcher import Patcher
14 _CHROMIUM_REPO_BASEURLS = [
15 'https://src.chromium.org/svn/trunk/src/',
16 'http://src.chromium.org/svn/trunk/src/',
17 'svn://svn.chromium.org/chrome/trunk/src',
18 'https://chromium.googlesource.com/chromium/src.git@master',
19 'http://git.chromium.org/chromium/src.git@master',
23 class RietveldPatcherError(Exception):
24 def __init__(self, message):
25 self.message = message
27 class _AsyncFetchFuture(object):
28 def __init__(self,
29 issue,
30 patchset,
31 files,
32 fetcher):
33 self._issue = issue
34 self._patchset = patchset
35 self._files = files
36 self._tarball = fetcher.FetchAsync('tarball/%s/%s' % (issue, patchset))
38 def Get(self):
39 tarball_result = self._tarball.Get()
40 if tarball_result.status_code != 200:
41 raise RietveldPatcherError(
42 'Failed to download tarball for issue %s patchset %s. Status: %s' %
43 (self._issue, self._patchset, tarball_result.status_code))
45 try:
46 tar = tarfile.open(fileobj=StringIO(tarball_result.content))
47 except tarfile.TarError as e:
48 raise RietveldPatcherError(
49 'Error loading tarball for issue %s patchset %s.' % (self._issue,
50 self._patchset))
52 self._value = {}
53 for path in self._files:
54 tar_path = 'b/%s' % path
56 patched_file = None
57 try:
58 patched_file = tar.extractfile(tar_path)
59 data = patched_file.read()
60 except tarfile.TarError as e:
61 # Show appropriate error message in the unlikely case that the tarball
62 # is corrupted.
63 raise RietveldPatcherError(
64 'Error extracting tarball for issue %s patchset %s file %s.' %
65 (self._issue, self._patchset, tar_path))
66 except KeyError as e:
67 raise FileNotFoundError(
68 'File %s not found in the tarball for issue %s patchset %s' %
69 (tar_path, self._issue, self._patchset))
70 finally:
71 if patched_file:
72 patched_file.close()
74 self._value[path] = data
76 return self._value
78 class RietveldPatcher(Patcher):
79 ''' Class to fetch resources from a patchset in Rietveld.
80 '''
81 def __init__(self,
82 issue,
83 fetcher):
84 self._issue = issue
85 self._fetcher = fetcher
86 self._cache = None
88 # In RietveldPatcher, the version is the latest patchset number.
89 def GetVersion(self):
90 try:
91 issue_json = json.loads(self._fetcher.Fetch(
92 'api/%s' % self._issue).content)
93 except Exception as e:
94 raise RietveldPatcherError(
95 'Failed to fetch information for issue %s.' % self._issue)
97 if issue_json.get('closed'):
98 raise RietveldPatcherError('Issue %s has been closed.' % self._issue)
100 patchsets = issue_json.get('patchsets')
101 if not isinstance(patchsets, list) or len(patchsets) == 0:
102 raise RietveldPatcherError('Cannot parse issue %s.' % self._issue)
104 if not issue_json.get('base_url') in _CHROMIUM_REPO_BASEURLS:
105 raise RietveldPatcherError('Issue %s\'s base url is unknown.' %
106 self._issue)
108 return str(patchsets[-1])
110 def GetPatchedFiles(self, version=None):
111 if version is None:
112 patchset = self.GetVersion()
113 else:
114 patchset = version
115 try:
116 patchset_json = json.loads(self._fetcher.Fetch(
117 'api/%s/%s' % (self._issue, patchset)).content)
118 except Exception as e:
119 raise RietveldPatcherError(
120 'Failed to fetch details for issue %s patchset %s.' % (self._issue,
121 patchset))
123 files = patchset_json.get('files')
124 if files is None or not isinstance(files, dict):
125 raise RietveldPatcherError('Failed to parse issue %s patchset %s.' %
126 (self._issue, patchset))
128 added = []
129 deleted = []
130 modified = []
131 for f in files:
132 status = (files[f].get('status') or 'M')
133 # status can be 'A ' or 'A + '
134 if 'A' in status:
135 added.append(f)
136 elif 'D' in status:
137 deleted.append(f)
138 elif 'M' in status:
139 modified.append(f)
140 else:
141 raise RietveldPatcherError('Unknown file status for file %s: "%s."' %
142 (key, status))
144 return (added, deleted, modified)
146 def Apply(self, paths, file_system, version=None):
147 if version is None:
148 version = self.GetVersion()
149 return Future(delegate=_AsyncFetchFuture(self._issue,
150 version,
151 paths,
152 self._fetcher))
154 def GetIdentity(self):
155 return self._issue