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

Side by Side Diff: checkout.py

Issue 11028002: Make apply_issue.py much more verbose about what it's doing. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Fix unit test Created 8 years, 2 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 | « apply_issue.py ('k') | patch.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 # coding=utf8 1 # coding=utf8
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 """Manages a project checkout. 5 """Manages a project checkout.
6 6
7 Includes support for svn, git-svn and git. 7 Includes support for svn, git-svn and git.
8 """ 8 """
9 9
10 import ConfigParser 10 import ConfigParser
(...skipping 29 matching lines...) Expand all
40 return None 40 return None
41 k, v = line.split(':', 1) 41 k, v = line.split(':', 1)
42 settings[k.strip()] = v.strip() 42 settings[k.strip()] = v.strip()
43 finally: 43 finally:
44 settings_file.close() 44 settings_file.close()
45 except IOError: 45 except IOError:
46 return None 46 return None
47 return settings.get(key, None) 47 return settings.get(key, None)
48 48
49 49
50 def align_stdout(stdout):
51 """Returns the aligned output of multiple stdouts."""
52 output = ''
53 for item in stdout:
54 item = item.strip()
55 if not item:
56 continue
57 output += ''.join(' %s\n' % line for line in item.splitlines())
58 return output
59
60
50 class PatchApplicationFailed(Exception): 61 class PatchApplicationFailed(Exception):
51 """Patch failed to be applied.""" 62 """Patch failed to be applied."""
52 def __init__(self, p, status): 63 def __init__(self, p, status):
53 super(PatchApplicationFailed, self).__init__(p, status) 64 super(PatchApplicationFailed, self).__init__(p, status)
54 self.patch = p 65 self.patch = p
55 self.status = status 66 self.status = status
56 67
57 @property 68 @property
58 def filename(self): 69 def filename(self):
59 if self.patch: 70 if self.patch:
60 return self.patch.filename 71 return self.patch.filename
61 72
62 def __str__(self): 73 def __str__(self):
63 out = [] 74 out = []
64 if self.filename: 75 if self.filename:
65 out.append('Failed to apply patch for %s:' % self.filename) 76 out.append('Failed to apply patch for %s:' % self.filename)
66 if self.status: 77 if self.status:
67 out.append(self.status) 78 out.append(self.status)
79 out.append('Patch: %s' % self.patch.dump())
68 return '\n'.join(out) 80 return '\n'.join(out)
69 81
70 82
71 class CheckoutBase(object): 83 class CheckoutBase(object):
72 # Set to None to have verbose output. 84 # Set to None to have verbose output.
73 VOID = subprocess2.VOID 85 VOID = subprocess2.VOID
74 86
75 def __init__(self, root_dir, project_name, post_processors): 87 def __init__(self, root_dir, project_name, post_processors):
76 """ 88 """
77 Args: 89 Args:
(...skipping 20 matching lines...) Expand all
98 """Checks out a clean copy of the tree and removes any local modification. 110 """Checks out a clean copy of the tree and removes any local modification.
99 111
100 This function shouldn't throw unless the remote repository is inaccessible, 112 This function shouldn't throw unless the remote repository is inaccessible,
101 there is no free disk space or hard issues like that. 113 there is no free disk space or hard issues like that.
102 114
103 Args: 115 Args:
104 revision: The revision it should sync to, SCM specific. 116 revision: The revision it should sync to, SCM specific.
105 """ 117 """
106 raise NotImplementedError() 118 raise NotImplementedError()
107 119
108 def apply_patch(self, patches, post_processors=None): 120 def apply_patch(self, patches, post_processors=None, verbose=False):
109 """Applies a patch and returns the list of modified files. 121 """Applies a patch and returns the list of modified files.
110 122
111 This function should throw patch.UnsupportedPatchFormat or 123 This function should throw patch.UnsupportedPatchFormat or
112 PatchApplicationFailed when relevant. 124 PatchApplicationFailed when relevant.
113 125
114 Args: 126 Args:
115 patches: patch.PatchSet object. 127 patches: patch.PatchSet object.
116 """ 128 """
117 raise NotImplementedError() 129 raise NotImplementedError()
118 130
(...skipping 13 matching lines...) Expand all
132 144
133 class RawCheckout(CheckoutBase): 145 class RawCheckout(CheckoutBase):
134 """Used to apply a patch locally without any intent to commit it. 146 """Used to apply a patch locally without any intent to commit it.
135 147
136 To be used by the try server. 148 To be used by the try server.
137 """ 149 """
138 def prepare(self, revision): 150 def prepare(self, revision):
139 """Stubbed out.""" 151 """Stubbed out."""
140 pass 152 pass
141 153
142 def apply_patch(self, patches, post_processors=None): 154 def apply_patch(self, patches, post_processors=None, verbose=False):
143 """Ignores svn properties.""" 155 """Ignores svn properties."""
144 post_processors = post_processors or self.post_processors or [] 156 post_processors = post_processors or self.post_processors or []
145 for p in patches: 157 for p in patches:
146 logging.debug('Applying %s' % p.filename) 158 stdout = []
147 try: 159 try:
148 stdout = '' 160 filepath = os.path.join(self.project_path, p.filename)
149 filename = os.path.join(self.project_path, p.filename)
150 if p.is_delete: 161 if p.is_delete:
151 os.remove(filename) 162 os.remove(filepath)
163 stdout.append('Deleted.')
152 else: 164 else:
153 dirname = os.path.dirname(p.filename) 165 dirname = os.path.dirname(p.filename)
154 full_dir = os.path.join(self.project_path, dirname) 166 full_dir = os.path.join(self.project_path, dirname)
155 if dirname and not os.path.isdir(full_dir): 167 if dirname and not os.path.isdir(full_dir):
156 os.makedirs(full_dir) 168 os.makedirs(full_dir)
169 stdout.append('Created missing directory %s.' % dirname)
157 170
158 filepath = os.path.join(self.project_path, p.filename)
159 if p.is_binary: 171 if p.is_binary:
172 content = p.get()
160 with open(filepath, 'wb') as f: 173 with open(filepath, 'wb') as f:
161 f.write(p.get()) 174 f.write(content)
175 stdout.append('Added binary file %d bytes.' % len(content))
162 else: 176 else:
163 if p.source_filename: 177 if p.source_filename:
164 if not p.is_new: 178 if not p.is_new:
165 raise PatchApplicationFailed( 179 raise PatchApplicationFailed(
166 p, 180 p,
167 'File has a source filename specified but is not new') 181 'File has a source filename specified but is not new')
168 # Copy the file first. 182 # Copy the file first.
169 if os.path.isfile(filepath): 183 if os.path.isfile(filepath):
170 raise PatchApplicationFailed( 184 raise PatchApplicationFailed(
171 p, 'File exist but was about to be overwriten') 185 p, 'File exist but was about to be overwriten')
172 shutil.copy2( 186 shutil.copy2(
173 os.path.join(self.project_path, p.source_filename), filepath) 187 os.path.join(self.project_path, p.source_filename), filepath)
188 stdout.append('Copied %s -> %s' % (p.source_filename, p.filename))
174 if p.diff_hunks: 189 if p.diff_hunks:
175 stdout = subprocess2.check_output( 190 cmd = ['patch', '-u', '--binary', '-p%s' % p.patchlevel]
176 ['patch', '-u', '--binary', '-p%s' % p.patchlevel], 191 if verbose:
177 stdin=p.get(False), 192 cmd.append('--verbose')
178 stderr=subprocess2.STDOUT, 193 stdout.append(
179 cwd=self.project_path) 194 subprocess2.check_output(
195 cmd,
196 stdin=p.get(False),
197 stderr=subprocess2.STDOUT,
198 cwd=self.project_path))
180 elif p.is_new and not os.path.exists(filepath): 199 elif p.is_new and not os.path.exists(filepath):
181 # There is only a header. Just create the file. 200 # There is only a header. Just create the file.
182 open(filepath, 'w').close() 201 open(filepath, 'w').close()
202 stdout.append('Created an empty file.')
183 for post in post_processors: 203 for post in post_processors:
184 post(self, p) 204 post(self, p)
205 if verbose:
206 print p.filename
207 print align_stdout(stdout)
185 except OSError, e: 208 except OSError, e:
186 raise PatchApplicationFailed(p, '%s%s' % (stdout, e)) 209 raise PatchApplicationFailed(p, '%s%s' % (align_stdout(stdout), e))
187 except subprocess.CalledProcessError, e: 210 except subprocess.CalledProcessError, e:
188 raise PatchApplicationFailed( 211 raise PatchApplicationFailed(
189 p, '%s%s' % (stdout, getattr(e, 'stdout', None))) 212 p,
213 'While running %s;\n%s%s' % (
214 ' '.join(e.cmd),
215 align_stdout(stdout),
216 align_stdout([getattr(e, 'stdout', '')])))
190 217
191 def commit(self, commit_message, user): 218 def commit(self, commit_message, user):
192 """Stubbed out.""" 219 """Stubbed out."""
193 raise NotImplementedError('RawCheckout can\'t commit') 220 raise NotImplementedError('RawCheckout can\'t commit')
194 221
195 def revisions(self, _rev1, _rev2): 222 def revisions(self, _rev1, _rev2):
196 return None 223 return None
197 224
198 225
199 class SvnConfig(object): 226 class SvnConfig(object):
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 assert bool(self.commit_user) >= bool(self.commit_pwd) 319 assert bool(self.commit_user) >= bool(self.commit_pwd)
293 320
294 def prepare(self, revision): 321 def prepare(self, revision):
295 # Will checkout if the directory is not present. 322 # Will checkout if the directory is not present.
296 assert self.svn_url 323 assert self.svn_url
297 if not os.path.isdir(self.project_path): 324 if not os.path.isdir(self.project_path):
298 logging.info('Checking out %s in %s' % 325 logging.info('Checking out %s in %s' %
299 (self.project_name, self.project_path)) 326 (self.project_name, self.project_path))
300 return self._revert(revision) 327 return self._revert(revision)
301 328
302 def apply_patch(self, patches, post_processors=None): 329 def apply_patch(self, patches, post_processors=None, verbose=False):
303 post_processors = post_processors or self.post_processors or [] 330 post_processors = post_processors or self.post_processors or []
304 for p in patches: 331 for p in patches:
305 logging.debug('Applying %s' % p.filename) 332 stdout = []
306 try: 333 try:
334 filepath = os.path.join(self.project_path, p.filename)
307 # It is important to use credentials=False otherwise credentials could 335 # It is important to use credentials=False otherwise credentials could
308 # leak in the error message. Credentials are not necessary here for the 336 # leak in the error message. Credentials are not necessary here for the
309 # following commands anyway. 337 # following commands anyway.
310 stdout = ''
311 if p.is_delete: 338 if p.is_delete:
312 stdout += self._check_output_svn( 339 stdout.append(self._check_output_svn(
313 ['delete', p.filename, '--force'], credentials=False) 340 ['delete', p.filename, '--force'], credentials=False))
341 stdout.append('Deleted.')
314 else: 342 else:
315 # svn add while creating directories otherwise svn add on the 343 # svn add while creating directories otherwise svn add on the
316 # contained files will silently fail. 344 # contained files will silently fail.
317 # First, find the root directory that exists. 345 # First, find the root directory that exists.
318 dirname = os.path.dirname(p.filename) 346 dirname = os.path.dirname(p.filename)
319 dirs_to_create = [] 347 dirs_to_create = []
320 while (dirname and 348 while (dirname and
321 not os.path.isdir(os.path.join(self.project_path, dirname))): 349 not os.path.isdir(os.path.join(self.project_path, dirname))):
322 dirs_to_create.append(dirname) 350 dirs_to_create.append(dirname)
323 dirname = os.path.dirname(dirname) 351 dirname = os.path.dirname(dirname)
324 for dir_to_create in reversed(dirs_to_create): 352 for dir_to_create in reversed(dirs_to_create):
325 os.mkdir(os.path.join(self.project_path, dir_to_create)) 353 os.mkdir(os.path.join(self.project_path, dir_to_create))
326 stdout += self._check_output_svn( 354 stdout.append(
327 ['add', dir_to_create, '--force'], credentials=False) 355 self._check_output_svn(
356 ['add', dir_to_create, '--force'], credentials=False))
357 stdout.append('Created missing directory %s.' % dir_to_create)
328 358
329 filepath = os.path.join(self.project_path, p.filename)
330 if p.is_binary: 359 if p.is_binary:
360 content = p.get()
331 with open(filepath, 'wb') as f: 361 with open(filepath, 'wb') as f:
332 f.write(p.get()) 362 f.write(content)
363 stdout.append('Added binary file %d bytes.' % len(content))
333 else: 364 else:
334 if p.source_filename: 365 if p.source_filename:
335 if not p.is_new: 366 if not p.is_new:
336 raise PatchApplicationFailed( 367 raise PatchApplicationFailed(
337 p, 368 p,
338 'File has a source filename specified but is not new') 369 'File has a source filename specified but is not new')
339 # Copy the file first. 370 # Copy the file first.
340 if os.path.isfile(filepath): 371 if os.path.isfile(filepath):
341 raise PatchApplicationFailed( 372 raise PatchApplicationFailed(
342 p, 'File exist but was about to be overwriten') 373 p, 'File exist but was about to be overwriten')
343 self._check_output_svn( 374 stdout.append(
344 ['copy', p.source_filename, p.filename]) 375 self._check_output_svn(
376 ['copy', p.source_filename, p.filename]))
377 stdout.append('Copied %s -> %s' % (p.source_filename, p.filename))
345 if p.diff_hunks: 378 if p.diff_hunks:
346 cmd = [ 379 cmd = [
347 'patch', 380 'patch',
348 '-p%s' % p.patchlevel, 381 '-p%s' % p.patchlevel,
349 '--forward', 382 '--forward',
350 '--force', 383 '--force',
351 '--no-backup-if-mismatch', 384 '--no-backup-if-mismatch',
352 ] 385 ]
353 stdout += subprocess2.check_output( 386 stdout.append(
354 cmd, stdin=p.get(False), cwd=self.project_path) 387 subprocess2.check_output(
388 cmd, stdin=p.get(False), cwd=self.project_path))
355 elif p.is_new and not os.path.exists(filepath): 389 elif p.is_new and not os.path.exists(filepath):
356 # There is only a header. Just create the file if it doesn't 390 # There is only a header. Just create the file if it doesn't
357 # exist. 391 # exist.
358 open(filepath, 'w').close() 392 open(filepath, 'w').close()
393 stdout.append('Created an empty file.')
359 if p.is_new and not p.source_filename: 394 if p.is_new and not p.source_filename:
360 # Do not run it if p.source_filename is defined, since svn copy was 395 # Do not run it if p.source_filename is defined, since svn copy was
361 # using above. 396 # using above.
362 stdout += self._check_output_svn( 397 stdout.append(
363 ['add', p.filename, '--force'], credentials=False) 398 self._check_output_svn(
399 ['add', p.filename, '--force'], credentials=False))
364 for name, value in p.svn_properties: 400 for name, value in p.svn_properties:
365 if value is None: 401 if value is None:
366 stdout += self._check_output_svn( 402 stdout.append(
367 ['propdel', '--quiet', name, p.filename], credentials=False) 403 self._check_output_svn(
404 ['propdel', '--quiet', name, p.filename],
405 credentials=False))
406 stdout.append('Property %s deleted.' % name)
368 else: 407 else:
369 stdout += self._check_output_svn( 408 stdout.append(
370 ['propset', name, value, p.filename], credentials=False) 409 self._check_output_svn(
410 ['propset', name, value, p.filename], credentials=False))
411 stdout.append('Property %s=%s' % (name, value))
371 for prop, values in self.svn_config.auto_props.iteritems(): 412 for prop, values in self.svn_config.auto_props.iteritems():
372 if fnmatch.fnmatch(p.filename, prop): 413 if fnmatch.fnmatch(p.filename, prop):
373 for value in values.split(';'): 414 for value in values.split(';'):
374 if '=' not in value: 415 if '=' not in value:
375 params = [value, '.'] 416 params = [value, '.']
376 else: 417 else:
377 params = value.split('=', 1) 418 params = value.split('=', 1)
378 if params[1] == '*': 419 if params[1] == '*':
379 # Works around crbug.com/150960 on Windows. 420 # Works around crbug.com/150960 on Windows.
380 params[1] = '.' 421 params[1] = '.'
381 stdout += self._check_output_svn( 422 stdout.append(
382 ['propset'] + params + [p.filename], credentials=False) 423 self._check_output_svn(
424 ['propset'] + params + [p.filename], credentials=False))
425 stdout.append('Property (auto) %s' % '='.join(params))
383 for post in post_processors: 426 for post in post_processors:
384 post(self, p) 427 post(self, p)
428 if verbose:
429 print p.filename
430 print align_stdout(stdout)
385 except OSError, e: 431 except OSError, e:
386 raise PatchApplicationFailed(p, '%s%s' % (stdout, e)) 432 raise PatchApplicationFailed(p, '%s%s' % (align_stdout(stdout), e))
387 except subprocess.CalledProcessError, e: 433 except subprocess.CalledProcessError, e:
388 raise PatchApplicationFailed( 434 raise PatchApplicationFailed(
389 p, 435 p,
390 'While running %s;\n%s%s' % ( 436 'While running %s;\n%s%s' % (
391 ' '.join(e.cmd), stdout, getattr(e, 'stdout', ''))) 437 ' '.join(e.cmd),
438 align_stdout(stdout),
439 align_stdout([getattr(e, 'stdout', '')])))
392 440
393 def commit(self, commit_message, user): 441 def commit(self, commit_message, user):
394 logging.info('Committing patch for %s' % user) 442 logging.info('Committing patch for %s' % user)
395 assert self.commit_user 443 assert self.commit_user
396 assert isinstance(commit_message, unicode) 444 assert isinstance(commit_message, unicode)
397 handle, commit_filename = tempfile.mkstemp(text=True) 445 handle, commit_filename = tempfile.mkstemp(text=True)
398 try: 446 try:
399 # Shouldn't assume default encoding is UTF-8. But really, if you are using 447 # Shouldn't assume default encoding is UTF-8. But really, if you are using
400 # anything else, you are living in another world. 448 # anything else, you are living in another world.
401 os.write(handle, commit_message.encode('utf-8')) 449 os.write(handle, commit_message.encode('utf-8'))
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 revision = self._check_output_git(['rev-parse', revision]) 540 revision = self._check_output_git(['rev-parse', revision])
493 self._check_call_git(['checkout', '--force', '--quiet', revision]) 541 self._check_call_git(['checkout', '--force', '--quiet', revision])
494 else: 542 else:
495 branches, active = self._branches() 543 branches, active = self._branches()
496 if active != 'master': 544 if active != 'master':
497 self._check_call_git(['checkout', '--force', '--quiet', 'master']) 545 self._check_call_git(['checkout', '--force', '--quiet', 'master'])
498 self._check_call_git(['pull', self.remote, self.remote_branch, '--quiet']) 546 self._check_call_git(['pull', self.remote, self.remote_branch, '--quiet'])
499 if self.working_branch in branches: 547 if self.working_branch in branches:
500 self._call_git(['branch', '-D', self.working_branch]) 548 self._call_git(['branch', '-D', self.working_branch])
501 549
502 def apply_patch(self, patches, post_processors=None): 550 def apply_patch(self, patches, post_processors=None, verbose=False):
503 """Applies a patch on 'working_branch' and switch to it. 551 """Applies a patch on 'working_branch' and switch to it.
504 552
505 Also commits the changes on the local branch. 553 Also commits the changes on the local branch.
506 554
507 Ignores svn properties and raise an exception on unexpected ones. 555 Ignores svn properties and raise an exception on unexpected ones.
508 """ 556 """
509 post_processors = post_processors or self.post_processors or [] 557 post_processors = post_processors or self.post_processors or []
510 # It this throws, the checkout is corrupted. Maybe worth deleting it and 558 # It this throws, the checkout is corrupted. Maybe worth deleting it and
511 # trying again? 559 # trying again?
512 if self.remote_branch: 560 if self.remote_branch:
513 self._check_call_git( 561 self._check_call_git(
514 ['checkout', '-b', self.working_branch, 562 ['checkout', '-b', self.working_branch,
515 '%s/%s' % (self.remote, self.remote_branch), '--quiet']) 563 '%s/%s' % (self.remote, self.remote_branch), '--quiet'])
516 for index, p in enumerate(patches): 564 for index, p in enumerate(patches):
517 logging.debug('Applying %s' % p.filename) 565 stdout = []
518 try: 566 try:
519 stdout = '' 567 filepath = os.path.join(self.project_path, p.filename)
520 if p.is_delete: 568 if p.is_delete:
521 if (not os.path.exists(p.filename) and 569 if (not os.path.exists(filepath) and
522 any(p1.source_filename == p.filename for p1 in patches[0:index])): 570 any(p1.source_filename == p.filename for p1 in patches[0:index])):
523 # The file could already be deleted if a prior patch with file 571 # The file was already deleted if a prior patch with file rename
524 # rename was already processed. To be sure, look at all the previous 572 # was already processed because 'git apply' did it for us.
525 # patches to see if they were a file rename.
526 pass 573 pass
527 else: 574 else:
528 stdout += self._check_output_git(['rm', p.filename]) 575 stdout.append(self._check_output_git(['rm', p.filename]))
576 stdout.append('Deleted.')
529 else: 577 else:
530 dirname = os.path.dirname(p.filename) 578 dirname = os.path.dirname(p.filename)
531 full_dir = os.path.join(self.project_path, dirname) 579 full_dir = os.path.join(self.project_path, dirname)
532 if dirname and not os.path.isdir(full_dir): 580 if dirname and not os.path.isdir(full_dir):
533 os.makedirs(full_dir) 581 os.makedirs(full_dir)
582 stdout.append('Created missing directory %s.' % dirname)
534 if p.is_binary: 583 if p.is_binary:
535 with open(os.path.join(self.project_path, p.filename), 'wb') as f: 584 content = p.get()
536 f.write(p.get()) 585 with open(filepath, 'wb') as f:
537 stdout += self._check_output_git(['add', p.filename]) 586 f.write(content)
587 stdout.append('Added binary file %d bytes' % len(content))
588 cmd = ['add', p.filename]
589 if verbose:
590 cmd.append('--verbose')
591 stdout.append(self._check_output_git(cmd))
538 else: 592 else:
539 # No need to do anything special with p.is_new or if not 593 # No need to do anything special with p.is_new or if not
540 # p.diff_hunks. git apply manages all that already. 594 # p.diff_hunks. git apply manages all that already.
541 stdout += self._check_output_git( 595 cmd = ['apply', '--index', '-p%s' % p.patchlevel]
542 ['apply', '--index', '-p%s' % p.patchlevel], stdin=p.get(True)) 596 if verbose:
543 for name, _ in p.svn_properties: 597 cmd.append('--verbose')
598 stdout.append(self._check_output_git(cmd, stdin=p.get(True)))
599 for name, value in p.svn_properties:
544 # Ignore some known auto-props flags through .subversion/config, 600 # Ignore some known auto-props flags through .subversion/config,
545 # bails out on the other ones. 601 # bails out on the other ones.
546 # TODO(maruel): Read ~/.subversion/config and detect the rules that 602 # TODO(maruel): Read ~/.subversion/config and detect the rules that
547 # applies here to figure out if the property will be correctly 603 # applies here to figure out if the property will be correctly
548 # handled. 604 # handled.
605 stdout.append('Property %s=%s' % (name, value))
549 if not name in ( 606 if not name in (
550 'svn:eol-style', 'svn:executable', 'svn:mime-type'): 607 'svn:eol-style', 'svn:executable', 'svn:mime-type'):
551 raise patch.UnsupportedPatchFormat( 608 raise patch.UnsupportedPatchFormat(
552 p.filename, 609 p.filename,
553 'Cannot apply svn property %s to file %s.' % ( 610 'Cannot apply svn property %s to file %s.' % (
554 name, p.filename)) 611 name, p.filename))
555 for post in post_processors: 612 for post in post_processors:
556 post(self, p) 613 post(self, p)
614 if verbose:
615 print p.filename
616 print align_stdout(stdout)
557 except OSError, e: 617 except OSError, e:
558 raise PatchApplicationFailed(p, '%s%s' % (stdout, e)) 618 raise PatchApplicationFailed(p, '%s%s' % (align_stdout(stdout), e))
559 except subprocess.CalledProcessError, e: 619 except subprocess.CalledProcessError, e:
560 raise PatchApplicationFailed( 620 raise PatchApplicationFailed(
561 p, '%s%s' % (stdout, getattr(e, 'stdout', None))) 621 p,
622 'While running %s;\n%s%s' % (
623 ' '.join(e.cmd),
624 align_stdout(stdout),
625 align_stdout([getattr(e, 'stdout', '')])))
562 # Once all the patches are processed and added to the index, commit the 626 # Once all the patches are processed and added to the index, commit the
563 # index. 627 # index.
564 self._check_call_git(['commit', '-m', 'Committed patch']) 628 cmd = ['commit', '-m', 'Committed patch']
629 if verbose:
630 cmd.append('--verbose')
631 self._check_call_git(cmd)
565 # TODO(maruel): Weirdly enough they don't match, need to investigate. 632 # TODO(maruel): Weirdly enough they don't match, need to investigate.
566 #found_files = self._check_output_git( 633 #found_files = self._check_output_git(
567 # ['diff', 'master', '--name-only']).splitlines(False) 634 # ['diff', 'master', '--name-only']).splitlines(False)
568 #assert sorted(patches.filenames) == sorted(found_files), ( 635 #assert sorted(patches.filenames) == sorted(found_files), (
569 # sorted(out), sorted(found_files)) 636 # sorted(out), sorted(found_files))
570 637
571 def commit(self, commit_message, user): 638 def commit(self, commit_message, user):
572 """Updates the commit message. 639 """Updates the commit message.
573 640
574 Subclass needs to dcommit or push. 641 Subclass needs to dcommit or push.
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
636 self.checkout = checkout 703 self.checkout = checkout
637 self.post_processors = (post_processors or []) + ( 704 self.post_processors = (post_processors or []) + (
638 self.checkout.post_processors or []) 705 self.checkout.post_processors or [])
639 706
640 def prepare(self, revision): 707 def prepare(self, revision):
641 return self.checkout.prepare(revision) 708 return self.checkout.prepare(revision)
642 709
643 def get_settings(self, key): 710 def get_settings(self, key):
644 return self.checkout.get_settings(key) 711 return self.checkout.get_settings(key)
645 712
646 def apply_patch(self, patches, post_processors=None): 713 def apply_patch(self, patches, post_processors=None, verbose=False):
647 return self.checkout.apply_patch( 714 return self.checkout.apply_patch(
648 patches, post_processors or self.post_processors) 715 patches, post_processors or self.post_processors, verbose)
649 716
650 def commit(self, message, user): # pylint: disable=R0201 717 def commit(self, message, user): # pylint: disable=R0201
651 logging.info('Would have committed for %s with message: %s' % ( 718 logging.info('Would have committed for %s with message: %s' % (
652 user, message)) 719 user, message))
653 return 'FAKE' 720 return 'FAKE'
654 721
655 def revisions(self, rev1, rev2): 722 def revisions(self, rev1, rev2):
656 return self.checkout.revisions(rev1, rev2) 723 return self.checkout.revisions(rev1, rev2)
657 724
658 @property 725 @property
659 def project_name(self): 726 def project_name(self):
660 return self.checkout.project_name 727 return self.checkout.project_name
661 728
662 @property 729 @property
663 def project_path(self): 730 def project_path(self):
664 return self.checkout.project_path 731 return self.checkout.project_path
OLDNEW
« no previous file with comments | « apply_issue.py ('k') | patch.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698