Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: rietveld.py

Issue 7776015: Implement reverse mangling of svn properties. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Clarify text, use more named variables Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/rietveld_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2011 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 """Defines class Rietveld to easily access a rietveld instance. 4 """Defines class Rietveld to easily access a rietveld instance.
5 5
6 Security implications: 6 Security implications:
7 7
8 The following hypothesis are made: 8 The following hypothesis are made:
9 - Rietveld enforces: 9 - Rietveld enforces:
10 - Nobody else than issue owner can upload a patch set 10 - Nobody else than issue owner can upload a patch set
11 - Verifies the issue owner credentials when creating new issues 11 - Verifies the issue owner credentials when creating new issues
12 - A issue owner can't change once the issue is created 12 - A issue owner can't change once the issue is created
13 - A patch set cannot be modified 13 - A patch set cannot be modified
14 """ 14 """
15 15
16 import logging 16 import logging
17 import os 17 import os
18 import re
18 import sys 19 import sys
19 import time 20 import time
20 import urllib2 21 import urllib2
21 22
22 try: 23 try:
23 import simplejson as json # pylint: disable=F0401 24 import simplejson as json # pylint: disable=F0401
24 except ImportError: 25 except ImportError:
25 try: 26 try:
26 import json # pylint: disable=F0401 27 import json # pylint: disable=F0401
27 except ImportError: 28 except ImportError:
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 raise patch.UnsupportedPatchFormat( 125 raise patch.UnsupportedPatchFormat(
125 filename, 'File\'s status is None, patchset upload is incomplete.') 126 filename, 'File\'s status is None, patchset upload is incomplete.')
126 127
127 # TODO(maruel): That's bad, it confuses property change. 128 # TODO(maruel): That's bad, it confuses property change.
128 status = status.strip() 129 status = status.strip()
129 130
130 if status == 'D': 131 if status == 'D':
131 # Ignore the diff. 132 # Ignore the diff.
132 out.append(patch.FilePatchDelete(filename, state['is_binary'])) 133 out.append(patch.FilePatchDelete(filename, state['is_binary']))
133 elif status in ('A', 'M'): 134 elif status in ('A', 'M'):
134 # TODO(maruel): Rietveld support is still weird, add this line once it's 135 svn_props = self.parse_svn_properties(
135 # safe to use. 136 state.get('property_changes', ''), filename)
136 # props = state.get('property_changes', '').splitlines() or []
137 props = []
138 if state['is_binary']: 137 if state['is_binary']:
139 out.append(patch.FilePatchBinary( 138 out.append(patch.FilePatchBinary(
140 filename, 139 filename,
141 self.get_file_content(issue, patchset, state['id']), 140 self.get_file_content(issue, patchset, state['id']),
142 props, 141 svn_props,
143 is_new=(status[0] == 'A'))) 142 is_new=(status[0] == 'A')))
144 else: 143 else:
145 # Ignores num_chunks since it may only contain an header. 144 # Ignores num_chunks since it may only contain an header.
146 try: 145 try:
147 diff = self.get_file_diff(issue, patchset, state['id']) 146 diff = self.get_file_diff(issue, patchset, state['id'])
148 except urllib2.HTTPError, e: 147 except urllib2.HTTPError, e:
149 if e.code == 404: 148 if e.code == 404:
150 raise patch.UnsupportedPatchFormat( 149 raise patch.UnsupportedPatchFormat(
151 filename, 'File doesn\'t have a diff.') 150 filename, 'File doesn\'t have a diff.')
152 out.append(patch.FilePatchDiff(filename, diff, props)) 151 out.append(patch.FilePatchDiff(filename, diff, svn_props))
153 if status[0] == 'A': 152 if status[0] == 'A':
154 # It won't be set for empty file. 153 # It won't be set for empty file.
155 out[-1].is_new = True 154 out[-1].is_new = True
156 else: 155 else:
157 # Line too long (N/80) 156 # TODO(maruel): Add support for MM, A+, etc. Rietveld removes the svn
158 # pylint: disable=C0301 157 # properties from the diff.
159 # TODO: Add support for MM, A+, etc. Rietveld removes the svn properties
160 # from the diff.
161 # Example of mergeinfo across branches:
162 # http://codereview.chromium.org/202046/diff/1/third_party/libxml/xmlcat alog_dummy.cc
163 # svn:eol-style property that is lost in the diff
164 # http://codereview.chromium.org/202046/diff/1/third_party/libxml/xmllin t_dummy.cc
165 # Change with no diff, only svn property change:
166 # http://codereview.chromium.org/6462019/
167 raise patch.UnsupportedPatchFormat(filename, status) 158 raise patch.UnsupportedPatchFormat(filename, status)
168 return patch.PatchSet(out) 159 return patch.PatchSet(out)
169 160
161 @staticmethod
162 def parse_svn_properties(rietveld_svn_props, filename):
163 """Returns a list of tuple [('property', 'newvalue')].
164
165 rietveld_svn_props is the exact format from 'svn diff'.
166 """
167 rietveld_svn_props = rietveld_svn_props.splitlines()
168 svn_props = []
169 if not rietveld_svn_props:
170 return svn_props
171 # 1. Ignore svn:mergeinfo.
172 # 2. Accept svn:eol-style and svn:executable.
173 # 3. Refuse any other.
174 # \n
175 # Added: svn:ignore\n
176 # + LF\n
177 while rietveld_svn_props:
178 spacer = rietveld_svn_props.pop(0)
179 if spacer or not rietveld_svn_props:
180 # svn diff always put a spacer between the unified diff and property
181 # diff
182 raise patch.UnsupportedPatchFormat(
183 filename, 'Failed to parse svn properties.')
184
185 # Something like 'Added: svn:eol-style'. Note the action is localized.
186 # *sigh*.
187 action = rietveld_svn_props.pop(0)
188 match = re.match(r'^(\w+): (.+)$', action)
189 if not match or not rietveld_svn_props:
190 raise patch.UnsupportedPatchFormat(
191 filename, 'Failed to parse svn properties.')
192
193 if match.group(2) == 'svn:mergeinfo':
194 # Silently ignore the content.
195 rietveld_svn_props.pop(0)
196 continue
197
198 if match.group(1) not in ('Added', 'Modified'):
199 # Will fail for our French friends.
200 raise patch.UnsupportedPatchFormat(
201 filename, 'Unsupported svn property operation.')
202
203 if match.group(2) in ('svn:eol-style', 'svn:executable'):
204 # ' + foo' where foo is the new value. That's fragile.
205 content = rietveld_svn_props.pop(0)
206 match2 = re.match(r'^ \+ (.*)$', content)
207 if not match2:
208 raise patch.UnsupportedPatchFormat(
209 filename, 'Unsupported svn property format.')
210 svn_props.append((match.group(2), match2.group(1)))
211 return svn_props
212
170 def update_description(self, issue, description): 213 def update_description(self, issue, description):
171 """Sets the description for an issue on Rietveld.""" 214 """Sets the description for an issue on Rietveld."""
172 logging.info('new description for issue %s' % issue) 215 logging.info('new description for issue %s' % issue)
173 self.post('/%s/description' % issue, [ 216 self.post('/%s/description' % issue, [
174 ('description', description), 217 ('description', description),
175 ('xsrf_token', self.xsrf_token())]) 218 ('xsrf_token', self.xsrf_token())])
176 219
177 def add_comment(self, issue, message): 220 def add_comment(self, issue, message):
178 logging.info('issue %s; comment: %s' % (issue, message)) 221 logging.info('issue %s; comment: %s' % (issue, message))
179 return self.post('/%s/publish' % issue, [ 222 return self.post('/%s/publish' % issue, [
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 if retry >= (maxtries - 1): 259 if retry >= (maxtries - 1):
217 raise 260 raise
218 if not 'Name or service not known' in e.reason: 261 if not 'Name or service not known' in e.reason:
219 # Usually internal GAE flakiness. 262 # Usually internal GAE flakiness.
220 raise 263 raise
221 # If reaching this line, loop again. Uses a small backoff. 264 # If reaching this line, loop again. Uses a small backoff.
222 time.sleep(1+maxtries*2) 265 time.sleep(1+maxtries*2)
223 266
224 # DEPRECATED. 267 # DEPRECATED.
225 Send = get 268 Send = get
OLDNEW
« no previous file with comments | « no previous file | tests/rietveld_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698