OLD | NEW |
1 # coding=utf8 | 1 # coding=utf8 |
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 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 from __future__ import with_statement | 10 from __future__ import with_statement |
11 import ConfigParser | 11 import ConfigParser |
12 import fnmatch | 12 import fnmatch |
13 import logging | 13 import logging |
14 import os | 14 import os |
15 import re | 15 import re |
| 16 import shutil |
16 import subprocess | 17 import subprocess |
17 import sys | 18 import sys |
18 import tempfile | 19 import tempfile |
19 | 20 |
20 import patch | 21 import patch |
21 import scm | 22 import scm |
22 import subprocess2 | 23 import subprocess2 |
23 | 24 |
24 | 25 |
25 def get_code_review_setting(path, key, | 26 def get_code_review_setting(path, key, |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
130 dirname = os.path.dirname(p.filename) | 131 dirname = os.path.dirname(p.filename) |
131 full_dir = os.path.join(self.project_path, dirname) | 132 full_dir = os.path.join(self.project_path, dirname) |
132 if dirname and not os.path.isdir(full_dir): | 133 if dirname and not os.path.isdir(full_dir): |
133 os.makedirs(full_dir) | 134 os.makedirs(full_dir) |
134 | 135 |
135 filepath = os.path.join(self.project_path, p.filename) | 136 filepath = os.path.join(self.project_path, p.filename) |
136 if p.is_binary: | 137 if p.is_binary: |
137 with open(filepath, 'wb') as f: | 138 with open(filepath, 'wb') as f: |
138 f.write(p.get()) | 139 f.write(p.get()) |
139 else: | 140 else: |
| 141 if p.source_filename: |
| 142 if not p.is_new: |
| 143 raise PatchApplicationFailed( |
| 144 p.filename, |
| 145 'File has a source filename specified but is not new') |
| 146 # Copy the file first. |
| 147 if os.path.isfile(filepath): |
| 148 raise PatchApplicationFailed( |
| 149 p.filename, 'File exist but was about to be overwriten') |
| 150 shutil.copy2( |
| 151 os.path.join(self.project_path, p.source_filename), filepath) |
140 if p.diff_hunks: | 152 if p.diff_hunks: |
141 stdout = subprocess2.check_output( | 153 stdout = subprocess2.check_output( |
142 ['patch', '-p%s' % p.patchlevel], | 154 ['patch', '-u', '--binary', '-p%s' % p.patchlevel], |
143 stdin=p.get(), | 155 stdin=p.get(False), |
144 stderr=subprocess2.STDOUT, | 156 stderr=subprocess2.STDOUT, |
145 cwd=self.project_path) | 157 cwd=self.project_path) |
146 elif p.is_new and not os.path.exists(filepath): | 158 elif p.is_new and not os.path.exists(filepath): |
147 # There is only a header. Just create the file. | 159 # There is only a header. Just create the file. |
148 open(filepath, 'w').close() | 160 open(filepath, 'w').close() |
149 for post in post_processors: | 161 for post in post_processors: |
150 post(self, p) | 162 post(self, p) |
151 except OSError, e: | 163 except OSError, e: |
152 raise PatchApplicationFailed(p.filename, '%s%s' % (stdout, e)) | 164 raise PatchApplicationFailed(p.filename, '%s%s' % (stdout, e)) |
153 except subprocess.CalledProcessError, e: | 165 except subprocess.CalledProcessError, e: |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 for dir_to_create in reversed(dirs_to_create): | 298 for dir_to_create in reversed(dirs_to_create): |
287 os.mkdir(os.path.join(self.project_path, dir_to_create)) | 299 os.mkdir(os.path.join(self.project_path, dir_to_create)) |
288 stdout += self._check_output_svn( | 300 stdout += self._check_output_svn( |
289 ['add', dir_to_create, '--force'], credentials=False) | 301 ['add', dir_to_create, '--force'], credentials=False) |
290 | 302 |
291 filepath = os.path.join(self.project_path, p.filename) | 303 filepath = os.path.join(self.project_path, p.filename) |
292 if p.is_binary: | 304 if p.is_binary: |
293 with open(filepath, 'wb') as f: | 305 with open(filepath, 'wb') as f: |
294 f.write(p.get()) | 306 f.write(p.get()) |
295 else: | 307 else: |
| 308 if p.source_filename: |
| 309 if not p.is_new: |
| 310 raise PatchApplicationFailed( |
| 311 p.filename, |
| 312 'File has a source filename specified but is not new') |
| 313 # Copy the file first. |
| 314 if os.path.isfile(filepath): |
| 315 raise PatchApplicationFailed( |
| 316 p.filename, 'File exist but was about to be overwriten') |
| 317 shutil.copy2( |
| 318 os.path.join(self.project_path, p.source_filename), filepath) |
296 if p.diff_hunks: | 319 if p.diff_hunks: |
297 cmd = ['patch', '-p%s' % p.patchlevel, '--forward', '--force'] | 320 cmd = ['patch', '-p%s' % p.patchlevel, '--forward', '--force'] |
298 stdout += subprocess2.check_output( | 321 stdout += subprocess2.check_output( |
299 cmd, stdin=p.get(), cwd=self.project_path) | 322 cmd, stdin=p.get(False), cwd=self.project_path) |
300 elif p.is_new and not os.path.exists(filepath): | 323 elif p.is_new and not os.path.exists(filepath): |
301 # There is only a header. Just create the file if it doesn't | 324 # There is only a header. Just create the file if it doesn't |
302 # exist. | 325 # exist. |
303 open(filepath, 'w').close() | 326 open(filepath, 'w').close() |
304 if p.is_new: | 327 if p.is_new: |
305 stdout += self._check_output_svn( | 328 stdout += self._check_output_svn( |
306 ['add', p.filename, '--force'], credentials=False) | 329 ['add', p.filename, '--force'], credentials=False) |
307 for prop in p.svn_properties: | 330 for prop in p.svn_properties: |
308 stdout += self._check_output_svn( | 331 stdout += self._check_output_svn( |
309 ['propset', prop[0], prop[1], p.filename], credentials=False) | 332 ['propset', prop[0], prop[1], p.filename], credentials=False) |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
427 | 450 |
428 Ignores svn properties and raise an exception on unexpected ones. | 451 Ignores svn properties and raise an exception on unexpected ones. |
429 """ | 452 """ |
430 post_processors = post_processors or self.post_processors or [] | 453 post_processors = post_processors or self.post_processors or [] |
431 # It this throws, the checkout is corrupted. Maybe worth deleting it and | 454 # It this throws, the checkout is corrupted. Maybe worth deleting it and |
432 # trying again? | 455 # trying again? |
433 if self.remote_branch: | 456 if self.remote_branch: |
434 self._check_call_git( | 457 self._check_call_git( |
435 ['checkout', '-b', self.working_branch, | 458 ['checkout', '-b', self.working_branch, |
436 '%s/%s' % (self.remote, self.remote_branch), '--quiet']) | 459 '%s/%s' % (self.remote, self.remote_branch), '--quiet']) |
437 for p in patches: | 460 for index, p in enumerate(patches): |
438 try: | 461 try: |
439 stdout = '' | 462 stdout = '' |
440 if p.is_delete: | 463 if p.is_delete: |
441 stdout += self._check_output_git(['rm', p.filename]) | 464 if (not os.path.exists(p.filename) and |
| 465 any(p1.source_filename == p.filename for p1 in patches[0:index])): |
| 466 # The file could already be deleted if a prior patch with file |
| 467 # rename was already processed. To be sure, look at all the previous |
| 468 # patches to see if they were a file rename. |
| 469 pass |
| 470 else: |
| 471 stdout += self._check_output_git(['rm', p.filename]) |
442 else: | 472 else: |
443 dirname = os.path.dirname(p.filename) | 473 dirname = os.path.dirname(p.filename) |
444 full_dir = os.path.join(self.project_path, dirname) | 474 full_dir = os.path.join(self.project_path, dirname) |
445 if dirname and not os.path.isdir(full_dir): | 475 if dirname and not os.path.isdir(full_dir): |
446 os.makedirs(full_dir) | 476 os.makedirs(full_dir) |
447 if p.is_binary: | 477 if p.is_binary: |
448 with open(os.path.join(self.project_path, p.filename), 'wb') as f: | 478 with open(os.path.join(self.project_path, p.filename), 'wb') as f: |
449 f.write(p.get()) | 479 f.write(p.get()) |
450 stdout += self._check_output_git(['add', p.filename]) | 480 stdout += self._check_output_git(['add', p.filename]) |
451 else: | 481 else: |
452 # No need to do anything special with p.is_new or if not | 482 # No need to do anything special with p.is_new or if not |
453 # p.diff_hunks. git apply manages all that already. | 483 # p.diff_hunks. git apply manages all that already. |
454 stdout += self._check_output_git( | 484 stdout += self._check_output_git( |
455 ['apply', '--index', '-p%s' % p.patchlevel], stdin=p.get()) | 485 ['apply', '--index', '-p%s' % p.patchlevel], stdin=p.get(True)) |
456 for prop in p.svn_properties: | 486 for prop in p.svn_properties: |
457 # Ignore some known auto-props flags through .subversion/config, | 487 # Ignore some known auto-props flags through .subversion/config, |
458 # bails out on the other ones. | 488 # bails out on the other ones. |
459 # TODO(maruel): Read ~/.subversion/config and detect the rules that | 489 # TODO(maruel): Read ~/.subversion/config and detect the rules that |
460 # applies here to figure out if the property will be correctly | 490 # applies here to figure out if the property will be correctly |
461 # handled. | 491 # handled. |
462 if not prop[0] in ('svn:eol-style', 'svn:executable'): | 492 if not prop[0] in ('svn:eol-style', 'svn:executable'): |
463 raise patch.UnsupportedPatchFormat( | 493 raise patch.UnsupportedPatchFormat( |
464 p.filename, | 494 p.filename, |
465 'Cannot apply svn property %s to file %s.' % ( | 495 'Cannot apply svn property %s to file %s.' % ( |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 user, message)) | 747 user, message)) |
718 return 'FAKE' | 748 return 'FAKE' |
719 | 749 |
720 @property | 750 @property |
721 def project_name(self): | 751 def project_name(self): |
722 return self.checkout.project_name | 752 return self.checkout.project_name |
723 | 753 |
724 @property | 754 @property |
725 def project_path(self): | 755 def project_path(self): |
726 return self.checkout.project_path | 756 return self.checkout.project_path |
OLD | NEW |