| OLD | NEW |
| 1 # Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Gclient-specific SCM-specific operations.""" | 5 """Gclient-specific SCM-specific operations.""" |
| 6 | 6 |
| 7 import logging | 7 import logging |
| 8 import os | 8 import os |
| 9 import posixpath |
| 9 import re | 10 import re |
| 10 import subprocess | 11 import subprocess |
| 11 | 12 |
| 12 import scm | 13 import scm |
| 13 import gclient_utils | 14 import gclient_utils |
| 14 | 15 |
| 15 | 16 |
| 17 class DiffFilterer(object): |
| 18 """Simple class which tracks which file is being diffed and |
| 19 replaces instances of its file name in the original and |
| 20 working copy lines of the svn diff output.""" |
| 21 index_string = "Index: " |
| 22 original_prefix = "--- " |
| 23 working_prefix = "+++ " |
| 24 |
| 25 def __init__(self, relpath): |
| 26 # Note that we always use '/' as the path separator to be |
| 27 # consistent with svn's cygwin-style output on Windows |
| 28 self._relpath = relpath.replace("\\", "/") |
| 29 self._current_file = "" |
| 30 self._replacement_file = "" |
| 31 |
| 32 def SetCurrentFile(self, file): |
| 33 self._current_file = file |
| 34 # Note that we always use '/' as the path separator to be |
| 35 # consistent with svn's cygwin-style output on Windows |
| 36 self._replacement_file = posixpath.join(self._relpath, file) |
| 37 |
| 38 def ReplaceAndPrint(self, line): |
| 39 print(line.replace(self._current_file, self._replacement_file)) |
| 40 |
| 41 def Filter(self, line): |
| 42 if (line.startswith(self.index_string)): |
| 43 self.SetCurrentFile(line[len(self.index_string):]) |
| 44 self.ReplaceAndPrint(line) |
| 45 else: |
| 46 if (line.startswith(self.original_prefix) or |
| 47 line.startswith(self.working_prefix)): |
| 48 self.ReplaceAndPrint(line) |
| 49 else: |
| 50 print line |
| 51 |
| 52 |
| 16 ### SCM abstraction layer | 53 ### SCM abstraction layer |
| 17 | 54 |
| 18 # Factory Method for SCM wrapper creation | 55 # Factory Method for SCM wrapper creation |
| 19 | 56 |
| 20 def CreateSCM(url=None, root_dir=None, relpath=None, scm_name='svn'): | 57 def CreateSCM(url=None, root_dir=None, relpath=None, scm_name='svn'): |
| 21 # TODO(maruel): Deduce the SCM from the url. | 58 # TODO(maruel): Deduce the SCM from the url. |
| 22 scm_map = { | 59 scm_map = { |
| 23 'svn' : SVNWrapper, | 60 'svn' : SVNWrapper, |
| 24 'git' : GitWrapper, | 61 'git' : GitWrapper, |
| 25 } | 62 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 if file_list is None: | 99 if file_list is None: |
| 63 file_list = [] | 100 file_list = [] |
| 64 | 101 |
| 65 commands = ['cleanup', 'export', 'update', 'revert', 'revinfo', | 102 commands = ['cleanup', 'export', 'update', 'revert', 'revinfo', |
| 66 'status', 'diff', 'pack', 'runhooks'] | 103 'status', 'diff', 'pack', 'runhooks'] |
| 67 | 104 |
| 68 if not command in commands: | 105 if not command in commands: |
| 69 raise gclient_utils.Error('Unknown command %s' % command) | 106 raise gclient_utils.Error('Unknown command %s' % command) |
| 70 | 107 |
| 71 if not command in dir(self): | 108 if not command in dir(self): |
| 72 raise gclient_utils.Error('Command %s not implemnted in %s wrapper' % ( | 109 raise gclient_utils.Error('Command %s not implemented in %s wrapper' % ( |
| 73 command, self.scm_name)) | 110 command, self.scm_name)) |
| 74 | 111 |
| 75 return getattr(self, command)(options, args, file_list) | 112 return getattr(self, command)(options, args, file_list) |
| 76 | 113 |
| 77 | 114 |
| 78 class GitWrapper(SCMWrapper, scm.GIT): | 115 class GitWrapper(SCMWrapper, scm.GIT): |
| 79 """Wrapper for Git""" | 116 """Wrapper for Git""" |
| 80 | 117 |
| 81 def cleanup(self, options, args, file_list): | 118 def cleanup(self, options, args, file_list): |
| 82 """Cleanup working copy.""" | 119 """Cleanup working copy.""" |
| 83 __pychecker__ = 'unusednames=args,file_list,options' | 120 __pychecker__ = 'unusednames=args,file_list,options' |
| 84 self._Run(['prune'], redirect_stdout=False) | 121 self._Run(['prune'], redirect_stdout=False) |
| 85 self._Run(['fsck'], redirect_stdout=False) | 122 self._Run(['fsck'], redirect_stdout=False) |
| 86 self._Run(['gc'], redirect_stdout=False) | 123 self._Run(['gc'], redirect_stdout=False) |
| 87 | 124 |
| 88 def diff(self, options, args, file_list): | 125 def diff(self, options, args, file_list): |
| 89 __pychecker__ = 'unusednames=args,file_list,options' | 126 __pychecker__ = 'unusednames=args,file_list,options' |
| 90 merge_base = self._Run(['merge-base', 'HEAD', 'origin']) | 127 merge_base = self._Run(['merge-base', 'HEAD', 'origin']) |
| 91 self._Run(['diff', merge_base], redirect_stdout=False) | 128 self._Run(['diff', merge_base], redirect_stdout=False) |
| 92 | 129 |
| 93 def export(self, options, args, file_list): | 130 def export(self, options, args, file_list): |
| 94 __pychecker__ = 'unusednames=file_list,options' | 131 __pychecker__ = 'unusednames=file_list,options' |
| 95 assert len(args) == 1 | 132 assert len(args) == 1 |
| 96 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) | 133 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) |
| 97 if not os.path.exists(export_path): | 134 if not os.path.exists(export_path): |
| 98 os.makedirs(export_path) | 135 os.makedirs(export_path) |
| 99 self._Run(['checkout-index', '-a', '--prefix=%s/' % export_path], | 136 self._Run(['checkout-index', '-a', '--prefix=%s/' % export_path], |
| 100 redirect_stdout=False) | 137 redirect_stdout=False) |
| 101 | 138 |
| 139 def pack(self, options, args, file_list): |
| 140 """Generates a patch file which can be applied to the root of the |
| 141 repository.""" |
| 142 __pychecker__ = 'unusednames=file_list,options' |
| 143 path = os.path.join(self._root_dir, self.relpath) |
| 144 merge_base = self._Run(['merge-base', 'HEAD', 'origin']) |
| 145 command = ['diff', merge_base] |
| 146 filterer = DiffFilterer(self.relpath) |
| 147 self.RunAndFilterOutput(command, path, False, False, filterer.Filter) |
| 148 |
| 102 def update(self, options, args, file_list): | 149 def update(self, options, args, file_list): |
| 103 """Runs git to update or transparently checkout the working copy. | 150 """Runs git to update or transparently checkout the working copy. |
| 104 | 151 |
| 105 All updated files will be appended to file_list. | 152 All updated files will be appended to file_list. |
| 106 | 153 |
| 107 Raises: | 154 Raises: |
| 108 Error: if can't get URL for relative path. | 155 Error: if can't get URL for relative path. |
| 109 """ | 156 """ |
| 110 | 157 |
| 111 if args: | 158 if args: |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) | 318 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) |
| 272 try: | 319 try: |
| 273 os.makedirs(export_path) | 320 os.makedirs(export_path) |
| 274 except OSError: | 321 except OSError: |
| 275 pass | 322 pass |
| 276 assert os.path.exists(export_path) | 323 assert os.path.exists(export_path) |
| 277 command = ['export', '--force', '.'] | 324 command = ['export', '--force', '.'] |
| 278 command.append(export_path) | 325 command.append(export_path) |
| 279 self.Run(command, os.path.join(self._root_dir, self.relpath)) | 326 self.Run(command, os.path.join(self._root_dir, self.relpath)) |
| 280 | 327 |
| 328 def pack(self, options, args, file_list): |
| 329 """Generates a patch file which can be applied to the root of the |
| 330 repository.""" |
| 331 __pychecker__ = 'unusednames=file_list,options' |
| 332 path = os.path.join(self._root_dir, self.relpath) |
| 333 command = ['diff'] |
| 334 command.extend(args) |
| 335 |
| 336 filterer = DiffFilterer(self.relpath) |
| 337 self.RunAndFilterOutput(command, path, False, False, filterer.Filter) |
| 338 |
| 281 def update(self, options, args, file_list): | 339 def update(self, options, args, file_list): |
| 282 """Runs SCM to update or transparently checkout the working copy. | 340 """Runs SCM to update or transparently checkout the working copy. |
| 283 | 341 |
| 284 All updated files will be appended to file_list. | 342 All updated files will be appended to file_list. |
| 285 | 343 |
| 286 Raises: | 344 Raises: |
| 287 Error: if can't get URL for relative path. | 345 Error: if can't get URL for relative path. |
| 288 """ | 346 """ |
| 289 # Only update if git is not controlling the directory. | 347 # Only update if git is not controlling the directory. |
| 290 checkout_path = os.path.join(self._root_dir, self.relpath) | 348 checkout_path = os.path.join(self._root_dir, self.relpath) |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 command = ['status'] | 516 command = ['status'] |
| 459 command.extend(args) | 517 command.extend(args) |
| 460 if not os.path.isdir(path): | 518 if not os.path.isdir(path): |
| 461 # svn status won't work if the directory doesn't exist. | 519 # svn status won't work if the directory doesn't exist. |
| 462 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory " | 520 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory " |
| 463 "does not exist." | 521 "does not exist." |
| 464 % (' '.join(command), path)) | 522 % (' '.join(command), path)) |
| 465 # There's no file list to retrieve. | 523 # There's no file list to retrieve. |
| 466 else: | 524 else: |
| 467 self.RunAndGetFileList(options, command, path, file_list) | 525 self.RunAndGetFileList(options, command, path, file_list) |
| 468 | |
| 469 def pack(self, options, args, file_list): | |
| 470 """Generates a patch file which can be applied to the root of the | |
| 471 repository.""" | |
| 472 __pychecker__ = 'unusednames=file_list,options' | |
| 473 path = os.path.join(self._root_dir, self.relpath) | |
| 474 command = ['diff'] | |
| 475 command.extend(args) | |
| 476 # Simple class which tracks which file is being diffed and | |
| 477 # replaces instances of its file name in the original and | |
| 478 # working copy lines of the svn diff output. | |
| 479 class DiffFilterer(object): | |
| 480 index_string = "Index: " | |
| 481 original_prefix = "--- " | |
| 482 working_prefix = "+++ " | |
| 483 | |
| 484 def __init__(self, relpath): | |
| 485 # Note that we always use '/' as the path separator to be | |
| 486 # consistent with svn's cygwin-style output on Windows | |
| 487 self._relpath = relpath.replace("\\", "/") | |
| 488 self._current_file = "" | |
| 489 self._replacement_file = "" | |
| 490 | |
| 491 def SetCurrentFile(self, file): | |
| 492 self._current_file = file | |
| 493 # Note that we always use '/' as the path separator to be | |
| 494 # consistent with svn's cygwin-style output on Windows | |
| 495 self._replacement_file = self._relpath + '/' + file | |
| 496 | |
| 497 def ReplaceAndPrint(self, line): | |
| 498 print(line.replace(self._current_file, self._replacement_file)) | |
| 499 | |
| 500 def Filter(self, line): | |
| 501 if (line.startswith(self.index_string)): | |
| 502 self.SetCurrentFile(line[len(self.index_string):]) | |
| 503 self.ReplaceAndPrint(line) | |
| 504 else: | |
| 505 if (line.startswith(self.original_prefix) or | |
| 506 line.startswith(self.working_prefix)): | |
| 507 self.ReplaceAndPrint(line) | |
| 508 else: | |
| 509 print line | |
| 510 | |
| 511 filterer = DiffFilterer(self.relpath) | |
| 512 self.RunAndFilterOutput(command, path, False, False, filterer.Filter) | |
| OLD | NEW |