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 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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 class PatchApplicationFailed(Exception): | 50 class PatchApplicationFailed(Exception): |
51 """Patch failed to be applied.""" | 51 """Patch failed to be applied.""" |
52 def __init__(self, filename, status): | 52 def __init__(self, p, status): |
53 super(PatchApplicationFailed, self).__init__(filename, status) | 53 super(PatchApplicationFailed, self).__init__(p, status) |
54 self.filename = filename | 54 self.patch = p |
55 self.status = status | 55 self.status = status |
56 | 56 |
| 57 @property |
| 58 def filename(self): |
| 59 if self.patch: |
| 60 return self.patch.filename |
| 61 |
| 62 def __str__(self): |
| 63 out = [] |
| 64 if self.filename: |
| 65 out.append('Failed to apply patch for %s:' % self.filename) |
| 66 if self.status: |
| 67 out.append(self.status) |
| 68 return '\n'.join(out) |
| 69 |
57 | 70 |
58 class CheckoutBase(object): | 71 class CheckoutBase(object): |
59 # Set to None to have verbose output. | 72 # Set to None to have verbose output. |
60 VOID = subprocess2.VOID | 73 VOID = subprocess2.VOID |
61 | 74 |
62 def __init__(self, root_dir, project_name, post_processors): | 75 def __init__(self, root_dir, project_name, post_processors): |
63 """ | 76 """ |
64 Args: | 77 Args: |
65 post_processor: list of lambda(checkout, patches) to call on each of the | 78 post_processor: list of lambda(checkout, patches) to call on each of the |
66 modified files. | 79 modified files. |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 os.makedirs(full_dir) | 146 os.makedirs(full_dir) |
134 | 147 |
135 filepath = os.path.join(self.project_path, p.filename) | 148 filepath = os.path.join(self.project_path, p.filename) |
136 if p.is_binary: | 149 if p.is_binary: |
137 with open(filepath, 'wb') as f: | 150 with open(filepath, 'wb') as f: |
138 f.write(p.get()) | 151 f.write(p.get()) |
139 else: | 152 else: |
140 if p.source_filename: | 153 if p.source_filename: |
141 if not p.is_new: | 154 if not p.is_new: |
142 raise PatchApplicationFailed( | 155 raise PatchApplicationFailed( |
143 p.filename, | 156 p, |
144 'File has a source filename specified but is not new') | 157 'File has a source filename specified but is not new') |
145 # Copy the file first. | 158 # Copy the file first. |
146 if os.path.isfile(filepath): | 159 if os.path.isfile(filepath): |
147 raise PatchApplicationFailed( | 160 raise PatchApplicationFailed( |
148 p.filename, 'File exist but was about to be overwriten') | 161 p, 'File exist but was about to be overwriten') |
149 shutil.copy2( | 162 shutil.copy2( |
150 os.path.join(self.project_path, p.source_filename), filepath) | 163 os.path.join(self.project_path, p.source_filename), filepath) |
151 if p.diff_hunks: | 164 if p.diff_hunks: |
152 stdout = subprocess2.check_output( | 165 stdout = subprocess2.check_output( |
153 ['patch', '-u', '--binary', '-p%s' % p.patchlevel], | 166 ['patch', '-u', '--binary', '-p%s' % p.patchlevel], |
154 stdin=p.get(False), | 167 stdin=p.get(False), |
155 stderr=subprocess2.STDOUT, | 168 stderr=subprocess2.STDOUT, |
156 cwd=self.project_path) | 169 cwd=self.project_path) |
157 elif p.is_new and not os.path.exists(filepath): | 170 elif p.is_new and not os.path.exists(filepath): |
158 # There is only a header. Just create the file. | 171 # There is only a header. Just create the file. |
159 open(filepath, 'w').close() | 172 open(filepath, 'w').close() |
160 for post in post_processors: | 173 for post in post_processors: |
161 post(self, p) | 174 post(self, p) |
162 except OSError, e: | 175 except OSError, e: |
163 raise PatchApplicationFailed(p.filename, '%s%s' % (stdout, e)) | 176 raise PatchApplicationFailed(p, '%s%s' % (stdout, e)) |
164 except subprocess.CalledProcessError, e: | 177 except subprocess.CalledProcessError, e: |
165 raise PatchApplicationFailed( | 178 raise PatchApplicationFailed( |
166 p.filename, '%s%s' % (stdout, getattr(e, 'stdout', None))) | 179 p, '%s%s' % (stdout, getattr(e, 'stdout', None))) |
167 | 180 |
168 def commit(self, commit_message, user): | 181 def commit(self, commit_message, user): |
169 """Stubbed out.""" | 182 """Stubbed out.""" |
170 raise NotImplementedError('RawCheckout can\'t commit') | 183 raise NotImplementedError('RawCheckout can\'t commit') |
171 | 184 |
172 | 185 |
173 class SvnConfig(object): | 186 class SvnConfig(object): |
174 """Parses a svn configuration file.""" | 187 """Parses a svn configuration file.""" |
175 def __init__(self, svn_config_dir=None): | 188 def __init__(self, svn_config_dir=None): |
176 super(SvnConfig, self).__init__() | 189 super(SvnConfig, self).__init__() |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 ['add', dir_to_create, '--force'], credentials=False) | 313 ['add', dir_to_create, '--force'], credentials=False) |
301 | 314 |
302 filepath = os.path.join(self.project_path, p.filename) | 315 filepath = os.path.join(self.project_path, p.filename) |
303 if p.is_binary: | 316 if p.is_binary: |
304 with open(filepath, 'wb') as f: | 317 with open(filepath, 'wb') as f: |
305 f.write(p.get()) | 318 f.write(p.get()) |
306 else: | 319 else: |
307 if p.source_filename: | 320 if p.source_filename: |
308 if not p.is_new: | 321 if not p.is_new: |
309 raise PatchApplicationFailed( | 322 raise PatchApplicationFailed( |
310 p.filename, | 323 p, |
311 'File has a source filename specified but is not new') | 324 'File has a source filename specified but is not new') |
312 # Copy the file first. | 325 # Copy the file first. |
313 if os.path.isfile(filepath): | 326 if os.path.isfile(filepath): |
314 raise PatchApplicationFailed( | 327 raise PatchApplicationFailed( |
315 p.filename, 'File exist but was about to be overwriten') | 328 p, 'File exist but was about to be overwriten') |
316 self._check_output_svn( | 329 self._check_output_svn( |
317 [ | 330 [ |
318 'copy', | 331 'copy', |
319 os.path.join(self.project_path, p.source_filename), | 332 os.path.join(self.project_path, p.source_filename), |
320 filepath | 333 filepath |
321 ]) | 334 ]) |
322 if p.diff_hunks: | 335 if p.diff_hunks: |
323 cmd = ['patch', '-p%s' % p.patchlevel, '--forward', '--force'] | 336 cmd = ['patch', '-p%s' % p.patchlevel, '--forward', '--force'] |
324 stdout += subprocess2.check_output( | 337 stdout += subprocess2.check_output( |
325 cmd, stdin=p.get(False), cwd=self.project_path) | 338 cmd, stdin=p.get(False), cwd=self.project_path) |
(...skipping 14 matching lines...) Expand all Loading... |
340 for value in values.split(';'): | 353 for value in values.split(';'): |
341 if '=' not in value: | 354 if '=' not in value: |
342 params = [value, '*'] | 355 params = [value, '*'] |
343 else: | 356 else: |
344 params = value.split('=', 1) | 357 params = value.split('=', 1) |
345 stdout += self._check_output_svn( | 358 stdout += self._check_output_svn( |
346 ['propset'] + params + [p.filename], credentials=False) | 359 ['propset'] + params + [p.filename], credentials=False) |
347 for post in post_processors: | 360 for post in post_processors: |
348 post(self, p) | 361 post(self, p) |
349 except OSError, e: | 362 except OSError, e: |
350 raise PatchApplicationFailed(p.filename, '%s%s' % (stdout, e)) | 363 raise PatchApplicationFailed(p, '%s%s' % (stdout, e)) |
351 except subprocess.CalledProcessError, e: | 364 except subprocess.CalledProcessError, e: |
352 raise PatchApplicationFailed( | 365 raise PatchApplicationFailed( |
353 p.filename, | 366 p, |
354 'While running %s;\n%s%s' % ( | 367 'While running %s;\n%s%s' % ( |
355 ' '.join(e.cmd), stdout, getattr(e, 'stdout', ''))) | 368 ' '.join(e.cmd), stdout, getattr(e, 'stdout', ''))) |
356 | 369 |
357 def commit(self, commit_message, user): | 370 def commit(self, commit_message, user): |
358 logging.info('Committing patch for %s' % user) | 371 logging.info('Committing patch for %s' % user) |
359 assert self.commit_user | 372 assert self.commit_user |
360 assert isinstance(commit_message, unicode) | 373 assert isinstance(commit_message, unicode) |
361 handle, commit_filename = tempfile.mkstemp(text=True) | 374 handle, commit_filename = tempfile.mkstemp(text=True) |
362 try: | 375 try: |
363 # Shouldn't assume default encoding is UTF-8. But really, if you are using | 376 # Shouldn't assume default encoding is UTF-8. But really, if you are using |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
496 # handled. | 509 # handled. |
497 if not prop[0] in ( | 510 if not prop[0] in ( |
498 'svn:eol-style', 'svn:executable', 'svn:mime-type'): | 511 'svn:eol-style', 'svn:executable', 'svn:mime-type'): |
499 raise patch.UnsupportedPatchFormat( | 512 raise patch.UnsupportedPatchFormat( |
500 p.filename, | 513 p.filename, |
501 'Cannot apply svn property %s to file %s.' % ( | 514 'Cannot apply svn property %s to file %s.' % ( |
502 prop[0], p.filename)) | 515 prop[0], p.filename)) |
503 for post in post_processors: | 516 for post in post_processors: |
504 post(self, p) | 517 post(self, p) |
505 except OSError, e: | 518 except OSError, e: |
506 raise PatchApplicationFailed(p.filename, '%s%s' % (stdout, e)) | 519 raise PatchApplicationFailed(p, '%s%s' % (stdout, e)) |
507 except subprocess.CalledProcessError, e: | 520 except subprocess.CalledProcessError, e: |
508 raise PatchApplicationFailed( | 521 raise PatchApplicationFailed( |
509 p.filename, '%s%s' % (stdout, getattr(e, 'stdout', None))) | 522 p, '%s%s' % (stdout, getattr(e, 'stdout', None))) |
510 # Once all the patches are processed and added to the index, commit the | 523 # Once all the patches are processed and added to the index, commit the |
511 # index. | 524 # index. |
512 self._check_call_git(['commit', '-m', 'Committed patch']) | 525 self._check_call_git(['commit', '-m', 'Committed patch']) |
513 # TODO(maruel): Weirdly enough they don't match, need to investigate. | 526 # TODO(maruel): Weirdly enough they don't match, need to investigate. |
514 #found_files = self._check_output_git( | 527 #found_files = self._check_output_git( |
515 # ['diff', 'master', '--name-only']).splitlines(False) | 528 # ['diff', 'master', '--name-only']).splitlines(False) |
516 #assert sorted(patches.filenames) == sorted(found_files), ( | 529 #assert sorted(patches.filenames) == sorted(found_files), ( |
517 # sorted(out), sorted(found_files)) | 530 # sorted(out), sorted(found_files)) |
518 | 531 |
519 def commit(self, commit_message, user): | 532 def commit(self, commit_message, user): |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
753 user, message)) | 766 user, message)) |
754 return 'FAKE' | 767 return 'FAKE' |
755 | 768 |
756 @property | 769 @property |
757 def project_name(self): | 770 def project_name(self): |
758 return self.checkout.project_name | 771 return self.checkout.project_name |
759 | 772 |
760 @property | 773 @property |
761 def project_path(self): | 774 def project_path(self): |
762 return self.checkout.project_path | 775 return self.checkout.project_path |
OLD | NEW |