| OLD | NEW |
| 1 # Copyright 2009 Google Inc. All Rights Reserved. | 1 # Copyright 2009 Google Inc. All Rights Reserved. |
| 2 # | 2 # |
| 3 # Licensed under the Apache License, Version 2.0 (the "License"); | 3 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 # you may not use this file except in compliance with the License. | 4 # you may not use this file except in compliance with the License. |
| 5 # You may obtain a copy of the License at | 5 # You may obtain a copy of the License at |
| 6 # | 6 # |
| 7 # http://www.apache.org/licenses/LICENSE-2.0 | 7 # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 # | 8 # |
| 9 # Unless required by applicable law or agreed to in writing, software | 9 # Unless required by applicable law or agreed to in writing, software |
| 10 # distributed under the License is distributed on an "AS IS" BASIS, | 10 # distributed under the License is distributed on an "AS IS" BASIS, |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 command, self.scm_name)) | 89 command, self.scm_name)) |
| 90 | 90 |
| 91 return getattr(self, command)(options, args, file_list) | 91 return getattr(self, command)(options, args, file_list) |
| 92 | 92 |
| 93 | 93 |
| 94 class GitWrapper(SCMWrapper): | 94 class GitWrapper(SCMWrapper): |
| 95 """Wrapper for Git""" | 95 """Wrapper for Git""" |
| 96 | 96 |
| 97 def cleanup(self, options, args, file_list): | 97 def cleanup(self, options, args, file_list): |
| 98 """Cleanup working copy.""" | 98 """Cleanup working copy.""" |
| 99 __pychecker__ = 'unusednames=args,file_list,options' |
| 99 self._RunGit(['prune'], redirect_stdout=False) | 100 self._RunGit(['prune'], redirect_stdout=False) |
| 100 self._RunGit(['fsck'], redirect_stdout=False) | 101 self._RunGit(['fsck'], redirect_stdout=False) |
| 101 self._RunGit(['gc'], redirect_stdout=False) | 102 self._RunGit(['gc'], redirect_stdout=False) |
| 102 | 103 |
| 103 def diff(self, options, args, file_list): | 104 def diff(self, options, args, file_list): |
| 104 # NOTE: This function does not currently modify file_list. | 105 __pychecker__ = 'unusednames=args,file_list,options' |
| 105 merge_base = self._RunGit(['merge-base', 'HEAD', 'origin']) | 106 merge_base = self._RunGit(['merge-base', 'HEAD', 'origin']) |
| 106 self._RunGit(['diff', merge_base], redirect_stdout=False) | 107 self._RunGit(['diff', merge_base], redirect_stdout=False) |
| 107 | 108 |
| 108 def export(self, options, args, file_list): | 109 def export(self, options, args, file_list): |
| 110 __pychecker__ = 'unusednames=file_list,options' |
| 109 assert len(args) == 1 | 111 assert len(args) == 1 |
| 110 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) | 112 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) |
| 111 if not os.path.exists(export_path): | 113 if not os.path.exists(export_path): |
| 112 os.makedirs(export_path) | 114 os.makedirs(export_path) |
| 113 self._RunGit(['checkout-index', '-a', '--prefix=%s/' % export_path], | 115 self._RunGit(['checkout-index', '-a', '--prefix=%s/' % export_path], |
| 114 redirect_stdout=False) | 116 redirect_stdout=False) |
| 115 | 117 |
| 116 def update(self, options, args, file_list): | 118 def update(self, options, args, file_list): |
| 117 """Runs git to update or transparently checkout the working copy. | 119 """Runs git to update or transparently checkout the working copy. |
| 118 | 120 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 files = self._RunGit(['diff', new_base, '--name-only']).split() | 162 files = self._RunGit(['diff', new_base, '--name-only']).split() |
| 161 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 163 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
| 162 self._RunGit(['rebase', '-v', new_base], redirect_stdout=False) | 164 self._RunGit(['rebase', '-v', new_base], redirect_stdout=False) |
| 163 print "Checked out revision %s." % self.revinfo(options, (), None) | 165 print "Checked out revision %s." % self.revinfo(options, (), None) |
| 164 | 166 |
| 165 def revert(self, options, args, file_list): | 167 def revert(self, options, args, file_list): |
| 166 """Reverts local modifications. | 168 """Reverts local modifications. |
| 167 | 169 |
| 168 All reverted files will be appended to file_list. | 170 All reverted files will be appended to file_list. |
| 169 """ | 171 """ |
| 172 __pychecker__ = 'unusednames=args' |
| 170 path = os.path.join(self._root_dir, self.relpath) | 173 path = os.path.join(self._root_dir, self.relpath) |
| 171 if not os.path.isdir(path): | 174 if not os.path.isdir(path): |
| 172 # revert won't work if the directory doesn't exist. It needs to | 175 # revert won't work if the directory doesn't exist. It needs to |
| 173 # checkout instead. | 176 # checkout instead. |
| 174 print("\n_____ %s is missing, synching instead" % self.relpath) | 177 print("\n_____ %s is missing, synching instead" % self.relpath) |
| 175 # Don't reuse the args. | 178 # Don't reuse the args. |
| 176 return self.update(options, [], file_list) | 179 return self.update(options, [], file_list) |
| 177 merge_base = self._RunGit(['merge-base', 'HEAD', 'origin']) | 180 merge_base = self._RunGit(['merge-base', 'HEAD', 'origin']) |
| 178 files = self._RunGit(['diff', merge_base, '--name-only']).split() | 181 files = self._RunGit(['diff', merge_base, '--name-only']).split() |
| 179 self._RunGit(['reset', '--hard', merge_base], redirect_stdout=False) | 182 self._RunGit(['reset', '--hard', merge_base], redirect_stdout=False) |
| 180 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 183 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
| 181 | 184 |
| 182 def revinfo(self, options, args, file_list): | 185 def revinfo(self, options, args, file_list): |
| 183 """Display revision""" | 186 """Display revision""" |
| 187 __pychecker__ = 'unusednames=args,file_list,options' |
| 184 return self._RunGit(['rev-parse', 'HEAD']) | 188 return self._RunGit(['rev-parse', 'HEAD']) |
| 185 | 189 |
| 186 def runhooks(self, options, args, file_list): | 190 def runhooks(self, options, args, file_list): |
| 187 self.status(options, args, file_list) | 191 self.status(options, args, file_list) |
| 188 | 192 |
| 189 def status(self, options, args, file_list): | 193 def status(self, options, args, file_list): |
| 190 """Display status information.""" | 194 """Display status information.""" |
| 195 __pychecker__ = 'unusednames=args,options' |
| 191 if not os.path.isdir(self.checkout_path): | 196 if not os.path.isdir(self.checkout_path): |
| 192 print('\n________ couldn\'t run status in %s:\nThe directory ' | 197 print('\n________ couldn\'t run status in %s:\nThe directory ' |
| 193 'does not exist.' % checkout_path) | 198 'does not exist.' % self.checkout_path) |
| 194 else: | 199 else: |
| 195 merge_base = self._RunGit(['merge-base', 'HEAD', 'origin']) | 200 merge_base = self._RunGit(['merge-base', 'HEAD', 'origin']) |
| 196 self._RunGit(['diff', '--name-status', merge_base], redirect_stdout=False) | 201 self._RunGit(['diff', '--name-status', merge_base], redirect_stdout=False) |
| 197 files = self._RunGit(['diff', '--name-only', merge_base]).split() | 202 files = self._RunGit(['diff', '--name-only', merge_base]).split() |
| 198 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 203 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
| 199 | 204 |
| 200 def _RunGit(self, args, cwd=None, checkrc=True, redirect_stdout=True): | 205 def _RunGit(self, args, cwd=None, checkrc=True, redirect_stdout=True): |
| 201 stdout=None | 206 stdout=None |
| 202 if redirect_stdout: | 207 if redirect_stdout: |
| 203 stdout=subprocess.PIPE | 208 stdout=subprocess.PIPE |
| 204 if cwd == None: | 209 if cwd == None: |
| 205 cwd = self.checkout_path | 210 cwd = self.checkout_path |
| 206 cmd = ['git'] | 211 cmd = ['git'] |
| 207 cmd.extend(args) | 212 cmd.extend(args) |
| 208 sp = subprocess.Popen(cmd, cwd=cwd, stdout=stdout) | 213 sp = subprocess.Popen(cmd, cwd=cwd, stdout=stdout) |
| 209 if checkrc and sp.returncode: | 214 if checkrc and sp.returncode: |
| 210 raise gclient_utils.Error('git command %s returned %d' % | 215 raise gclient_utils.Error('git command %s returned %d' % |
| 211 (args[0], sp.returncode)) | 216 (args[0], sp.returncode)) |
| 212 output = sp.communicate()[0] | 217 output = sp.communicate()[0] |
| 213 if output != None: | 218 if output != None: |
| 214 return output.strip() | 219 return output.strip() |
| 215 | 220 |
| 216 | 221 |
| 217 class SVNWrapper(SCMWrapper): | 222 class SVNWrapper(SCMWrapper): |
| 218 """ Wrapper for SVN """ | 223 """ Wrapper for SVN """ |
| 219 | 224 |
| 220 def cleanup(self, options, args, file_list): | 225 def cleanup(self, options, args, file_list): |
| 221 """Cleanup working copy.""" | 226 """Cleanup working copy.""" |
| 227 __pychecker__ = 'unusednames=file_list,options' |
| 222 command = ['cleanup'] | 228 command = ['cleanup'] |
| 223 command.extend(args) | 229 command.extend(args) |
| 224 RunSVN(command, os.path.join(self._root_dir, self.relpath)) | 230 RunSVN(command, os.path.join(self._root_dir, self.relpath)) |
| 225 | 231 |
| 226 def diff(self, options, args, file_list): | 232 def diff(self, options, args, file_list): |
| 227 # NOTE: This function does not currently modify file_list. | 233 # NOTE: This function does not currently modify file_list. |
| 234 __pychecker__ = 'unusednames=file_list,options' |
| 228 command = ['diff'] | 235 command = ['diff'] |
| 229 command.extend(args) | 236 command.extend(args) |
| 230 RunSVN(command, os.path.join(self._root_dir, self.relpath)) | 237 RunSVN(command, os.path.join(self._root_dir, self.relpath)) |
| 231 | 238 |
| 232 def export(self, options, args, file_list): | 239 def export(self, options, args, file_list): |
| 240 __pychecker__ = 'unusednames=file_list,options' |
| 233 assert len(args) == 1 | 241 assert len(args) == 1 |
| 234 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) | 242 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) |
| 235 try: | 243 try: |
| 236 os.makedirs(export_path) | 244 os.makedirs(export_path) |
| 237 except OSError: | 245 except OSError: |
| 238 pass | 246 pass |
| 239 assert os.path.exists(export_path) | 247 assert os.path.exists(export_path) |
| 240 command = ['export', '--force', '.'] | 248 command = ['export', '--force', '.'] |
| 241 command.append(export_path) | 249 command.append(export_path) |
| 242 RunSVN(command, os.path.join(self._root_dir, self.relpath)) | 250 RunSVN(command, os.path.join(self._root_dir, self.relpath)) |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 if revision: | 362 if revision: |
| 355 command.extend(['--revision', str(revision)]) | 363 command.extend(['--revision', str(revision)]) |
| 356 RunSVNAndGetFileList(options, command, self._root_dir, file_list) | 364 RunSVNAndGetFileList(options, command, self._root_dir, file_list) |
| 357 | 365 |
| 358 def revert(self, options, args, file_list): | 366 def revert(self, options, args, file_list): |
| 359 """Reverts local modifications. Subversion specific. | 367 """Reverts local modifications. Subversion specific. |
| 360 | 368 |
| 361 All reverted files will be appended to file_list, even if Subversion | 369 All reverted files will be appended to file_list, even if Subversion |
| 362 doesn't know about them. | 370 doesn't know about them. |
| 363 """ | 371 """ |
| 372 __pychecker__ = 'unusednames=args' |
| 364 path = os.path.join(self._root_dir, self.relpath) | 373 path = os.path.join(self._root_dir, self.relpath) |
| 365 if not os.path.isdir(path): | 374 if not os.path.isdir(path): |
| 366 # svn revert won't work if the directory doesn't exist. It needs to | 375 # svn revert won't work if the directory doesn't exist. It needs to |
| 367 # checkout instead. | 376 # checkout instead. |
| 368 print("\n_____ %s is missing, synching instead" % self.relpath) | 377 print("\n_____ %s is missing, synching instead" % self.relpath) |
| 369 # Don't reuse the args. | 378 # Don't reuse the args. |
| 370 return self.update(options, [], file_list) | 379 return self.update(options, [], file_list) |
| 371 | 380 |
| 372 for file in CaptureSVNStatus(path): | 381 for file_status in CaptureSVNStatus(path): |
| 373 file_path = os.path.join(path, file[1]) | 382 file_path = os.path.join(path, file_status[1]) |
| 374 if file[0][0] == 'X': | 383 if file_status[0][0] == 'X': |
| 375 # Ignore externals. | 384 # Ignore externals. |
| 376 logging.info('Ignoring external %s' % file_path) | 385 logging.info('Ignoring external %s' % file_path) |
| 377 continue | 386 continue |
| 378 | 387 |
| 379 if logging.getLogger().isEnabledFor(logging.INFO): | 388 if logging.getLogger().isEnabledFor(logging.INFO): |
| 380 logging.info('%s%s' % (file[0], file[1])) | 389 logging.info('%s%s' % (file[0], file[1])) |
| 381 else: | 390 else: |
| 382 print(file_path) | 391 print(file_path) |
| 383 if file[0].isspace(): | 392 if file_status[0].isspace(): |
| 384 logging.error('No idea what is the status of %s.\n' | 393 logging.error('No idea what is the status of %s.\n' |
| 385 'You just found a bug in gclient, please ping ' | 394 'You just found a bug in gclient, please ping ' |
| 386 'maruel@chromium.org ASAP!' % file_path) | 395 'maruel@chromium.org ASAP!' % file_path) |
| 387 # svn revert is really stupid. It fails on inconsistent line-endings, | 396 # svn revert is really stupid. It fails on inconsistent line-endings, |
| 388 # on switched directories, etc. So take no chance and delete everything! | 397 # on switched directories, etc. So take no chance and delete everything! |
| 389 try: | 398 try: |
| 390 if not os.path.exists(file_path): | 399 if not os.path.exists(file_path): |
| 391 pass | 400 pass |
| 392 elif os.path.isfile(file_path): | 401 elif os.path.isfile(file_path): |
| 393 logging.info('os.remove(%s)' % file_path) | 402 logging.info('os.remove(%s)' % file_path) |
| (...skipping 12 matching lines...) Expand all Loading... |
| 406 # "svn up --revision BASE" achieve the same effect. | 415 # "svn up --revision BASE" achieve the same effect. |
| 407 RunSVNAndGetFileList(options, ['update', '--revision', 'BASE'], path, | 416 RunSVNAndGetFileList(options, ['update', '--revision', 'BASE'], path, |
| 408 file_list) | 417 file_list) |
| 409 except OSError, e: | 418 except OSError, e: |
| 410 # Maybe the directory disapeared meanwhile. We don't want it to throw an | 419 # Maybe the directory disapeared meanwhile. We don't want it to throw an |
| 411 # exception. | 420 # exception. |
| 412 logging.error('Failed to update:\n%s' % str(e)) | 421 logging.error('Failed to update:\n%s' % str(e)) |
| 413 | 422 |
| 414 def revinfo(self, options, args, file_list): | 423 def revinfo(self, options, args, file_list): |
| 415 """Display revision""" | 424 """Display revision""" |
| 425 __pychecker__ = 'unusednames=args,file_list,options' |
| 416 return CaptureSVNHeadRevision(self.url) | 426 return CaptureSVNHeadRevision(self.url) |
| 417 | 427 |
| 418 def runhooks(self, options, args, file_list): | 428 def runhooks(self, options, args, file_list): |
| 419 self.status(options, args, file_list) | 429 self.status(options, args, file_list) |
| 420 | 430 |
| 421 def status(self, options, args, file_list): | 431 def status(self, options, args, file_list): |
| 422 """Display status information.""" | 432 """Display status information.""" |
| 423 path = os.path.join(self._root_dir, self.relpath) | 433 path = os.path.join(self._root_dir, self.relpath) |
| 424 command = ['status'] | 434 command = ['status'] |
| 425 command.extend(args) | 435 command.extend(args) |
| 426 if not os.path.isdir(path): | 436 if not os.path.isdir(path): |
| 427 # svn status won't work if the directory doesn't exist. | 437 # svn status won't work if the directory doesn't exist. |
| 428 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory " | 438 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory " |
| 429 "does not exist." | 439 "does not exist." |
| 430 % (' '.join(command), path)) | 440 % (' '.join(command), path)) |
| 431 # There's no file list to retrieve. | 441 # There's no file list to retrieve. |
| 432 else: | 442 else: |
| 433 RunSVNAndGetFileList(options, command, path, file_list) | 443 RunSVNAndGetFileList(options, command, path, file_list) |
| 434 | 444 |
| 435 def pack(self, options, args, file_list): | 445 def pack(self, options, args, file_list): |
| 436 """Generates a patch file which can be applied to the root of the | 446 """Generates a patch file which can be applied to the root of the |
| 437 repository.""" | 447 repository.""" |
| 448 __pychecker__ = 'unusednames=file_list,options' |
| 438 path = os.path.join(self._root_dir, self.relpath) | 449 path = os.path.join(self._root_dir, self.relpath) |
| 439 command = ['diff'] | 450 command = ['diff'] |
| 440 command.extend(args) | 451 command.extend(args) |
| 441 # Simple class which tracks which file is being diffed and | 452 # Simple class which tracks which file is being diffed and |
| 442 # replaces instances of its file name in the original and | 453 # replaces instances of its file name in the original and |
| 443 # working copy lines of the svn diff output. | 454 # working copy lines of the svn diff output. |
| 444 class DiffFilterer(object): | 455 class DiffFilterer(object): |
| 445 index_string = "Index: " | 456 index_string = "Index: " |
| 446 original_prefix = "--- " | 457 original_prefix = "--- " |
| 447 working_prefix = "+++ " | 458 working_prefix = "+++ " |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 750 'normal': ' ', | 761 'normal': ' ', |
| 751 'obstructed': '~', | 762 'obstructed': '~', |
| 752 'replaced': 'R', | 763 'replaced': 'R', |
| 753 'unversioned': '?', | 764 'unversioned': '?', |
| 754 } | 765 } |
| 755 dom = gclient_utils.ParseXML(CaptureSVN(command)) | 766 dom = gclient_utils.ParseXML(CaptureSVN(command)) |
| 756 results = [] | 767 results = [] |
| 757 if dom: | 768 if dom: |
| 758 # /status/target/entry/(wc-status|commit|author|date) | 769 # /status/target/entry/(wc-status|commit|author|date) |
| 759 for target in dom.getElementsByTagName('target'): | 770 for target in dom.getElementsByTagName('target'): |
| 760 base_path = target.getAttribute('path') | |
| 761 for entry in target.getElementsByTagName('entry'): | 771 for entry in target.getElementsByTagName('entry'): |
| 762 file = entry.getAttribute('path') | 772 file_path = entry.getAttribute('path') |
| 763 wc_status = entry.getElementsByTagName('wc-status') | 773 wc_status = entry.getElementsByTagName('wc-status') |
| 764 assert len(wc_status) == 1 | 774 assert len(wc_status) == 1 |
| 765 # Emulate svn 1.5 status ouput... | 775 # Emulate svn 1.5 status ouput... |
| 766 statuses = [' ' for i in range(7)] | 776 statuses = [' '] * 7 |
| 767 # Col 0 | 777 # Col 0 |
| 768 xml_item_status = wc_status[0].getAttribute('item') | 778 xml_item_status = wc_status[0].getAttribute('item') |
| 769 if xml_item_status in status_letter: | 779 if xml_item_status in status_letter: |
| 770 statuses[0] = status_letter[xml_item_status] | 780 statuses[0] = status_letter[xml_item_status] |
| 771 else: | 781 else: |
| 772 raise Exception('Unknown item status "%s"; please implement me!' % | 782 raise Exception('Unknown item status "%s"; please implement me!' % |
| 773 xml_item_status) | 783 xml_item_status) |
| 774 # Col 1 | 784 # Col 1 |
| 775 xml_props_status = wc_status[0].getAttribute('props') | 785 xml_props_status = wc_status[0].getAttribute('props') |
| 776 if xml_props_status == 'modified': | 786 if xml_props_status == 'modified': |
| 777 statuses[1] = 'M' | 787 statuses[1] = 'M' |
| 778 elif xml_props_status == 'conflicted': | 788 elif xml_props_status == 'conflicted': |
| 779 statuses[1] = 'C' | 789 statuses[1] = 'C' |
| 780 elif (not xml_props_status or xml_props_status == 'none' or | 790 elif (not xml_props_status or xml_props_status == 'none' or |
| 781 xml_props_status == 'normal'): | 791 xml_props_status == 'normal'): |
| 782 pass | 792 pass |
| 783 else: | 793 else: |
| 784 raise Exception('Unknown props status "%s"; please implement me!' % | 794 raise Exception('Unknown props status "%s"; please implement me!' % |
| 785 xml_props_status) | 795 xml_props_status) |
| 786 # Col 2 | 796 # Col 2 |
| 787 if wc_status[0].getAttribute('wc-locked') == 'true': | 797 if wc_status[0].getAttribute('wc-locked') == 'true': |
| 788 statuses[2] = 'L' | 798 statuses[2] = 'L' |
| 789 # Col 3 | 799 # Col 3 |
| 790 if wc_status[0].getAttribute('copied') == 'true': | 800 if wc_status[0].getAttribute('copied') == 'true': |
| 791 statuses[3] = '+' | 801 statuses[3] = '+' |
| 792 # Col 4 | 802 # Col 4 |
| 793 if wc_status[0].getAttribute('switched') == 'true': | 803 if wc_status[0].getAttribute('switched') == 'true': |
| 794 statuses[4] = 'S' | 804 statuses[4] = 'S' |
| 795 # TODO(maruel): Col 5 and 6 | 805 # TODO(maruel): Col 5 and 6 |
| 796 item = (''.join(statuses), file) | 806 item = (''.join(statuses), file_path) |
| 797 results.append(item) | 807 results.append(item) |
| 798 return results | 808 return results |
| OLD | NEW |