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.
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):
34 self
._patchset
= patchset
36 self
._tarball
= fetcher
.FetchAsync('tarball/%s/%s' % (issue
, patchset
))
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
))
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
,
53 for path
in self
._files
:
54 tar_path
= 'b/%s' % path
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
63 raise RietveldPatcherError(
64 'Error extracting tarball for issue %s patchset %s file %s.' %
65 (self
._issue
, self
._patchset
, tar_path
))
67 raise FileNotFoundError(
68 'File %s not found in the tarball for issue %s patchset %s' %
69 (tar_path
, self
._issue
, self
._patchset
))
74 self
._value
[path
] = data
78 class RietveldPatcher(Patcher
):
79 ''' Class to fetch resources from a patchset in Rietveld.
85 self
._fetcher
= fetcher
88 # In RietveldPatcher, the version is the latest patchset number.
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.' %
108 return str(patchsets
[-1])
110 def GetPatchedFiles(self
, version
=None):
112 patchset
= self
.GetVersion()
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
,
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
))
132 status
= (files
[f
].get('status') or 'M')
133 # status can be 'A ' or 'A + '
141 raise RietveldPatcherError('Unknown file status for file %s: "%s."' %
144 return (added
, deleted
, modified
)
146 def Apply(self
, paths
, file_system
, version
=None):
148 version
= self
.GetVersion()
149 return Future(delegate
=_AsyncFetchFuture(self
._issue
,
154 def GetIdentity(self
):