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
28 class RietveldPatcher(Patcher
):
29 ''' Class to fetch resources from a patchset in Rietveld.
35 self
._fetcher
= fetcher
38 # In RietveldPatcher, the version is the latest patchset number.
41 issue_json
= json
.loads(self
._fetcher
.Fetch(
42 'api/%s' % self
._issue
).content
)
43 except Exception as e
:
44 raise RietveldPatcherError(
45 'Failed to fetch information for issue %s.' % self
._issue
)
47 if issue_json
.get('closed'):
48 raise RietveldPatcherError('Issue %s has been closed.' % self
._issue
)
50 patchsets
= issue_json
.get('patchsets')
51 if not isinstance(patchsets
, list) or len(patchsets
) == 0:
52 raise RietveldPatcherError('Cannot parse issue %s.' % self
._issue
)
54 if not issue_json
.get('base_url') in _CHROMIUM_REPO_BASEURLS
:
55 raise RietveldPatcherError('Issue %s\'s base url (%s) is unknown.' %
56 (self
._issue
, issue_json
.get('base_url')))
58 return str(patchsets
[-1])
60 def GetPatchedFiles(self
, version
=None):
62 patchset
= self
.GetVersion()
66 patchset_json
= json
.loads(self
._fetcher
.Fetch(
67 'api/%s/%s' % (self
._issue
, patchset
)).content
)
68 except Exception as e
:
69 raise RietveldPatcherError(
70 'Failed to fetch details for issue %s patchset %s.' % (self
._issue
,
73 files
= patchset_json
.get('files')
74 if files
is None or not isinstance(files
, dict):
75 raise RietveldPatcherError('Failed to parse issue %s patchset %s.' %
76 (self
._issue
, patchset
))
82 status
= (files
[f
].get('status') or 'M')
83 # status can be 'A ' or 'A + '
91 raise RietveldPatcherError('Unknown file status for file %s: "%s."' %
94 return (added
, deleted
, modified
)
96 def Apply(self
, paths
, file_system
, version
=None):
98 version
= self
.GetVersion()
100 def apply_(tarball_result
):
101 if tarball_result
.status_code
!= 200:
102 raise RietveldPatcherError(
103 'Failed to download tarball for issue %s patchset %s. Status: %s' %
104 (self
._issue
, version
, tarball_result
.status_code
))
107 tar
= tarfile
.open(fileobj
=StringIO(tarball_result
.content
))
108 except tarfile
.TarError
as e
:
109 raise RietveldPatcherError(
110 'Error loading tarball for issue %s patchset %s.' % (self
._issue
,
115 tar_path
= 'b/%s' % path
119 patched_file
= tar
.extractfile(tar_path
)
120 data
= patched_file
.read()
121 except tarfile
.TarError
as e
:
122 # Show appropriate error message in the unlikely case that the tarball
124 raise RietveldPatcherError(
125 'Error extracting tarball for issue %s patchset %s file %s.' %
126 (self
._issue
, version
, tar_path
))
127 except KeyError as e
:
128 raise FileNotFoundError(
129 'File %s not found in the tarball for issue %s patchset %s' %
130 (tar_path
, self
._issue
, version
))
138 return self
._fetcher
.FetchAsync('tarball/%s/%s' % (self
._issue
,
139 version
)).Then(apply_
)
141 def GetIdentity(self
):