| 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 |