OLD | NEW |
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 only for git. | 7 Includes support only for git. |
8 """ | 8 """ |
9 | 9 |
10 import fnmatch | 10 import fnmatch |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 for item in stdout: | 70 for item in stdout: |
71 item = item.strip() | 71 item = item.strip() |
72 if not item: | 72 if not item: |
73 continue | 73 continue |
74 output += ''.join(' %s\n' % line for line in item.splitlines()) | 74 output += ''.join(' %s\n' % line for line in item.splitlines()) |
75 return output | 75 return output |
76 | 76 |
77 | 77 |
78 class PatchApplicationFailed(Exception): | 78 class PatchApplicationFailed(Exception): |
79 """Patch failed to be applied.""" | 79 """Patch failed to be applied.""" |
80 def __init__(self, p, status): | 80 def __init__(self, errors, verbose): |
81 super(PatchApplicationFailed, self).__init__(p, status) | 81 super(PatchApplicationFailed, self).__init__(errors, verbose) |
82 self.patch = p | 82 self.errors = errors |
83 self.status = status | 83 self.verbose = verbose |
84 | |
85 @property | |
86 def filename(self): | |
87 if self.patch: | |
88 return self.patch.filename | |
89 | 84 |
90 def __str__(self): | 85 def __str__(self): |
91 out = [] | 86 out = [] |
92 if self.filename: | 87 for e in self.errors: |
93 out.append('Failed to apply patch for %s:' % self.filename) | 88 p, status = e |
94 if self.status: | 89 if p and p.filename: |
95 out.append(self.status) | 90 out.append('Failed to apply patch for %s:' % p.filename) |
96 if self.patch: | 91 if status: |
97 out.append('Patch: %s' % self.patch.dump()) | 92 out.append(status) |
| 93 if p and self.verbose: |
| 94 out.append('Patch: %s' % p.dump()) |
98 return '\n'.join(out) | 95 return '\n'.join(out) |
99 | 96 |
100 | 97 |
101 class CheckoutBase(object): | 98 class CheckoutBase(object): |
102 # Set to None to have verbose output. | 99 # Set to None to have verbose output. |
103 VOID = subprocess2.VOID | 100 VOID = subprocess2.VOID |
104 | 101 |
105 def __init__(self, root_dir, project_name, post_processors): | 102 def __init__(self, root_dir, project_name, post_processors): |
106 """ | 103 """ |
107 Args: | 104 Args: |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 The changes remain staged on the current branch. | 241 The changes remain staged on the current branch. |
245 """ | 242 """ |
246 post_processors = post_processors or self.post_processors or [] | 243 post_processors = post_processors or self.post_processors or [] |
247 # It this throws, the checkout is corrupted. Maybe worth deleting it and | 244 # It this throws, the checkout is corrupted. Maybe worth deleting it and |
248 # trying again? | 245 # trying again? |
249 if self.remote_branch: | 246 if self.remote_branch: |
250 self._check_call_git( | 247 self._check_call_git( |
251 ['checkout', '-b', self.working_branch, '-t', self.remote_branch, | 248 ['checkout', '-b', self.working_branch, '-t', self.remote_branch, |
252 '--quiet']) | 249 '--quiet']) |
253 | 250 |
| 251 errors = [] |
254 for index, p in enumerate(patches): | 252 for index, p in enumerate(patches): |
255 stdout = [] | 253 stdout = [] |
256 try: | 254 try: |
257 filepath = os.path.join(self.project_path, p.filename) | 255 filepath = os.path.join(self.project_path, p.filename) |
258 if p.is_delete: | 256 if p.is_delete: |
259 if (not os.path.exists(filepath) and | 257 if (not os.path.exists(filepath) and |
260 any(p1.source_filename == p.filename for p1 in patches[0:index])): | 258 any(p1.source_filename == p.filename for p1 in patches[0:index])): |
261 # The file was already deleted if a prior patch with file rename | 259 # The file was already deleted if a prior patch with file rename |
262 # was already processed because 'git apply' did it for us. | 260 # was already processed because 'git apply' did it for us. |
263 pass | 261 pass |
(...skipping 22 matching lines...) Expand all Loading... |
286 cmd = ['apply', '--index', '-3', '-p%s' % p.patchlevel] | 284 cmd = ['apply', '--index', '-3', '-p%s' % p.patchlevel] |
287 if verbose: | 285 if verbose: |
288 cmd.append('--verbose') | 286 cmd.append('--verbose') |
289 stdout.append(self._check_output_git(cmd, stdin=p.get(True))) | 287 stdout.append(self._check_output_git(cmd, stdin=p.get(True))) |
290 for post in post_processors: | 288 for post in post_processors: |
291 post(self, p) | 289 post(self, p) |
292 if verbose: | 290 if verbose: |
293 print p.filename | 291 print p.filename |
294 print align_stdout(stdout) | 292 print align_stdout(stdout) |
295 except OSError, e: | 293 except OSError, e: |
296 raise PatchApplicationFailed(p, '%s%s' % (align_stdout(stdout), e)) | 294 errors.append((p, '%s%s' % (align_stdout(stdout), e))) |
297 except subprocess.CalledProcessError, e: | 295 except subprocess.CalledProcessError, e: |
298 raise PatchApplicationFailed( | 296 errors.append((p, |
299 p, | |
300 'While running %s;\n%s%s' % ( | 297 'While running %s;\n%s%s' % ( |
301 ' '.join(e.cmd), | 298 ' '.join(e.cmd), |
302 align_stdout(stdout), | 299 align_stdout(stdout), |
303 align_stdout([getattr(e, 'stdout', '')]))) | 300 align_stdout([getattr(e, 'stdout', '')])))) |
| 301 if errors: |
| 302 raise PatchApplicationFailed(errors, verbose) |
304 found_files = self._check_output_git( | 303 found_files = self._check_output_git( |
305 ['diff', '--ignore-submodules', | 304 ['diff', '--ignore-submodules', |
306 '--name-only', '--staged']).splitlines(False) | 305 '--name-only', '--staged']).splitlines(False) |
307 if sorted(patches.filenames) != sorted(found_files): | 306 if sorted(patches.filenames) != sorted(found_files): |
308 extra_files = sorted(set(found_files) - set(patches.filenames)) | 307 extra_files = sorted(set(found_files) - set(patches.filenames)) |
309 unpatched_files = sorted(set(patches.filenames) - set(found_files)) | 308 unpatched_files = sorted(set(patches.filenames) - set(found_files)) |
310 if extra_files: | 309 if extra_files: |
311 print 'Found extra files: %r' % (extra_files,) | 310 print 'Found extra files: %r' % (extra_files,) |
312 if unpatched_files: | 311 if unpatched_files: |
313 print 'Found unpatched files: %r' % (unpatched_files,) | 312 print 'Found unpatched files: %r' % (unpatched_files,) |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 def revisions(self, rev1, rev2): | 422 def revisions(self, rev1, rev2): |
424 return self.checkout.revisions(rev1, rev2) | 423 return self.checkout.revisions(rev1, rev2) |
425 | 424 |
426 @property | 425 @property |
427 def project_name(self): | 426 def project_name(self): |
428 return self.checkout.project_name | 427 return self.checkout.project_name |
429 | 428 |
430 @property | 429 @property |
431 def project_path(self): | 430 def project_path(self): |
432 return self.checkout.project_path | 431 return self.checkout.project_path |
OLD | NEW |