Chromium Code Reviews| 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 # Copy the file first. | |
| 143 if os.path.isfile(filepath): | |
| 144 raise PatchApplicationFailed( | |
| 145 p.filename, 'File exist but was about to be overwriten') | |
| 146 shutil.copy2( | |
| 147 os.path.join(self.project_path, p.source_filename), filepath) | |
|
Dirk Pranke
2011/09/28 23:39:27
I'm a bit confused by this. Won't the file usually
M-A Ruel
2011/09/29 14:15:58
Added a check to be explicit about the consistency
| |
| 140 if p.diff_hunks: | 148 if p.diff_hunks: |
| 141 stdout = subprocess2.check_output( | 149 stdout = subprocess2.check_output( |
| 142 ['patch', '-p%s' % p.patchlevel], | 150 ['patch', '-u', '--binary', '-p%s' % p.patchlevel], |
| 143 stdin=p.get(), | 151 stdin=p.get(False), |
| 144 stderr=subprocess2.STDOUT, | 152 stderr=subprocess2.STDOUT, |
| 145 cwd=self.project_path) | 153 cwd=self.project_path) |
| 146 elif p.is_new and not os.path.exists(filepath): | 154 elif p.is_new and not os.path.exists(filepath): |
| 147 # There is only a header. Just create the file. | 155 # There is only a header. Just create the file. |
| 148 open(filepath, 'w').close() | 156 open(filepath, 'w').close() |
| 149 for post in post_processors: | 157 for post in post_processors: |
| 150 post(self, p) | 158 post(self, p) |
| 151 except OSError, e: | 159 except OSError, e: |
| 152 raise PatchApplicationFailed(p.filename, '%s%s' % (stdout, e)) | 160 raise PatchApplicationFailed(p.filename, '%s%s' % (stdout, e)) |
| 153 except subprocess.CalledProcessError, e: | 161 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): | 294 for dir_to_create in reversed(dirs_to_create): |
| 287 os.mkdir(os.path.join(self.project_path, dir_to_create)) | 295 os.mkdir(os.path.join(self.project_path, dir_to_create)) |
| 288 stdout += self._check_output_svn( | 296 stdout += self._check_output_svn( |
| 289 ['add', dir_to_create, '--force'], credentials=False) | 297 ['add', dir_to_create, '--force'], credentials=False) |
| 290 | 298 |
| 291 filepath = os.path.join(self.project_path, p.filename) | 299 filepath = os.path.join(self.project_path, p.filename) |
| 292 if p.is_binary: | 300 if p.is_binary: |
| 293 with open(filepath, 'wb') as f: | 301 with open(filepath, 'wb') as f: |
| 294 f.write(p.get()) | 302 f.write(p.get()) |
| 295 else: | 303 else: |
| 304 if p.source_filename: | |
| 305 # Copy the file first. | |
| 306 if os.path.isfile(filepath): | |
| 307 raise PatchApplicationFailed( | |
| 308 p.filename, 'File exist but was about to be overwriten') | |
| 309 shutil.copy2( | |
| 310 os.path.join(self.project_path, p.source_filename), filepath) | |
|
Dirk Pranke
2011/09/28 23:39:27
same question.
| |
| 296 if p.diff_hunks: | 311 if p.diff_hunks: |
| 297 cmd = ['patch', '-p%s' % p.patchlevel, '--forward', '--force'] | 312 cmd = ['patch', '-p%s' % p.patchlevel, '--forward', '--force'] |
| 298 stdout += subprocess2.check_output( | 313 stdout += subprocess2.check_output( |
| 299 cmd, stdin=p.get(), cwd=self.project_path) | 314 cmd, stdin=p.get(False), cwd=self.project_path) |
| 300 elif p.is_new and not os.path.exists(filepath): | 315 elif p.is_new and not os.path.exists(filepath): |
| 301 # There is only a header. Just create the file if it doesn't | 316 # There is only a header. Just create the file if it doesn't |
| 302 # exist. | 317 # exist. |
| 303 open(filepath, 'w').close() | 318 open(filepath, 'w').close() |
| 304 if p.is_new: | 319 if p.is_new: |
| 305 stdout += self._check_output_svn( | 320 stdout += self._check_output_svn( |
| 306 ['add', p.filename, '--force'], credentials=False) | 321 ['add', p.filename, '--force'], credentials=False) |
| 307 for prop in p.svn_properties: | 322 for prop in p.svn_properties: |
| 308 stdout += self._check_output_svn( | 323 stdout += self._check_output_svn( |
| 309 ['propset', prop[0], prop[1], p.filename], credentials=False) | 324 ['propset', prop[0], prop[1], p.filename], credentials=False) |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 427 | 442 |
| 428 Ignores svn properties and raise an exception on unexpected ones. | 443 Ignores svn properties and raise an exception on unexpected ones. |
| 429 """ | 444 """ |
| 430 post_processors = post_processors or self.post_processors or [] | 445 post_processors = post_processors or self.post_processors or [] |
| 431 # It this throws, the checkout is corrupted. Maybe worth deleting it and | 446 # It this throws, the checkout is corrupted. Maybe worth deleting it and |
| 432 # trying again? | 447 # trying again? |
| 433 if self.remote_branch: | 448 if self.remote_branch: |
| 434 self._check_call_git( | 449 self._check_call_git( |
| 435 ['checkout', '-b', self.working_branch, | 450 ['checkout', '-b', self.working_branch, |
| 436 '%s/%s' % (self.remote, self.remote_branch), '--quiet']) | 451 '%s/%s' % (self.remote, self.remote_branch), '--quiet']) |
| 437 for p in patches: | 452 for index, p in enumerate(patches): |
| 438 try: | 453 try: |
| 439 stdout = '' | 454 stdout = '' |
| 440 if p.is_delete: | 455 if p.is_delete: |
| 441 stdout += self._check_output_git(['rm', p.filename]) | 456 if (not os.path.exists(p.filename) and |
| 457 any(p1.source_filename == p.filename for p1 in patches[0:index])): | |
| 458 # The file could already be deleted if a prior patch with file | |
| 459 # rename was already processed. To be sure, look at all the previous | |
| 460 # patches to see if they were a file rename. | |
| 461 pass | |
| 462 else: | |
| 463 stdout += self._check_output_git(['rm', p.filename]) | |
| 442 else: | 464 else: |
| 443 dirname = os.path.dirname(p.filename) | 465 dirname = os.path.dirname(p.filename) |
| 444 full_dir = os.path.join(self.project_path, dirname) | 466 full_dir = os.path.join(self.project_path, dirname) |
| 445 if dirname and not os.path.isdir(full_dir): | 467 if dirname and not os.path.isdir(full_dir): |
| 446 os.makedirs(full_dir) | 468 os.makedirs(full_dir) |
| 447 if p.is_binary: | 469 if p.is_binary: |
| 448 with open(os.path.join(self.project_path, p.filename), 'wb') as f: | 470 with open(os.path.join(self.project_path, p.filename), 'wb') as f: |
| 449 f.write(p.get()) | 471 f.write(p.get()) |
| 450 stdout += self._check_output_git(['add', p.filename]) | 472 stdout += self._check_output_git(['add', p.filename]) |
| 451 else: | 473 else: |
| 452 # No need to do anything special with p.is_new or if not | 474 # No need to do anything special with p.is_new or if not |
| 453 # p.diff_hunks. git apply manages all that already. | 475 # p.diff_hunks. git apply manages all that already. |
| 454 stdout += self._check_output_git( | 476 stdout += self._check_output_git( |
| 455 ['apply', '--index', '-p%s' % p.patchlevel], stdin=p.get()) | 477 ['apply', '--index', '-p%s' % p.patchlevel], stdin=p.get(True)) |
| 456 for prop in p.svn_properties: | 478 for prop in p.svn_properties: |
| 457 # Ignore some known auto-props flags through .subversion/config, | 479 # Ignore some known auto-props flags through .subversion/config, |
| 458 # bails out on the other ones. | 480 # bails out on the other ones. |
| 459 # TODO(maruel): Read ~/.subversion/config and detect the rules that | 481 # TODO(maruel): Read ~/.subversion/config and detect the rules that |
| 460 # applies here to figure out if the property will be correctly | 482 # applies here to figure out if the property will be correctly |
| 461 # handled. | 483 # handled. |
| 462 if not prop[0] in ('svn:eol-style', 'svn:executable'): | 484 if not prop[0] in ('svn:eol-style', 'svn:executable'): |
| 463 raise patch.UnsupportedPatchFormat( | 485 raise patch.UnsupportedPatchFormat( |
| 464 p.filename, | 486 p.filename, |
| 465 'Cannot apply svn property %s to file %s.' % ( | 487 'Cannot apply svn property %s to file %s.' % ( |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 717 user, message)) | 739 user, message)) |
| 718 return 'FAKE' | 740 return 'FAKE' |
| 719 | 741 |
| 720 @property | 742 @property |
| 721 def project_name(self): | 743 def project_name(self): |
| 722 return self.checkout.project_name | 744 return self.checkout.project_name |
| 723 | 745 |
| 724 @property | 746 @property |
| 725 def project_path(self): | 747 def project_path(self): |
| 726 return self.checkout.project_path | 748 return self.checkout.project_path |
| OLD | NEW |