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 |