| 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 posixpath |
| 10 import re | 10 import re |
| 11 import subprocess | 11 import subprocess |
| 12 | 12 |
| 13 import scm | 13 import scm |
| 14 import gclient_utils | 14 import gclient_utils |
| 15 | 15 |
| 16 | 16 |
| 17 class DiffFilterer(object): | 17 class DiffFilterer(object): |
| 18 """Simple class which tracks which file is being diffed and | 18 """Simple class which tracks which file is being diffed and |
| 19 replaces instances of its file name in the original and | 19 replaces instances of its file name in the original and |
| 20 working copy lines of the svn diff output.""" | 20 working copy lines of the svn/git diff output.""" |
| 21 index_string = "Index: " | 21 index_string = "Index: " |
| 22 original_prefix = "--- " | 22 original_prefix = "--- " |
| 23 working_prefix = "+++ " | 23 working_prefix = "+++ " |
| 24 | 24 |
| 25 def __init__(self, relpath): | 25 def __init__(self, relpath): |
| 26 # Note that we always use '/' as the path separator to be | 26 # Note that we always use '/' as the path separator to be |
| 27 # consistent with svn's cygwin-style output on Windows | 27 # consistent with svn's cygwin-style output on Windows |
| 28 self._relpath = relpath.replace("\\", "/") | 28 self._relpath = relpath.replace("\\", "/") |
| 29 self._current_file = "" | 29 self._current_file = "" |
| 30 self._replacement_file = "" | 30 self._replacement_file = "" |
| (...skipping 17 matching lines...) Expand all Loading... |
| 48 self.ReplaceAndPrint(line) | 48 self.ReplaceAndPrint(line) |
| 49 else: | 49 else: |
| 50 print line | 50 print line |
| 51 | 51 |
| 52 | 52 |
| 53 ### SCM abstraction layer | 53 ### SCM abstraction layer |
| 54 | 54 |
| 55 # Factory Method for SCM wrapper creation | 55 # Factory Method for SCM wrapper creation |
| 56 | 56 |
| 57 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'): |
| 58 # TODO(maruel): Deduce the SCM from the url. | |
| 59 scm_map = { | 58 scm_map = { |
| 60 'svn' : SVNWrapper, | 59 'svn' : SVNWrapper, |
| 61 'git' : GitWrapper, | 60 'git' : GitWrapper, |
| 62 } | 61 } |
| 63 | 62 |
| 64 orig_url = url | 63 orig_url = url |
| 65 | 64 |
| 66 if url: | 65 if url: |
| 67 url, _ = gclient_utils.SplitUrlRevision(url) | 66 url, _ = gclient_utils.SplitUrlRevision(url) |
| 68 if url.startswith('git:') or url.startswith('ssh:') or url.endswith('.git'): | 67 if url.startswith('git:') or url.startswith('ssh:') or url.endswith('.git'): |
| 69 scm_name = 'git' | 68 scm_name = 'git' |
| 70 | 69 |
| 71 if not scm_name in scm_map: | 70 if not scm_name in scm_map: |
| 72 raise gclient_utils.Error('Unsupported scm %s' % scm_name) | 71 raise gclient_utils.Error('Unsupported scm %s' % scm_name) |
| 73 return scm_map[scm_name](orig_url, root_dir, relpath, scm_name) | 72 return scm_map[scm_name](orig_url, root_dir, relpath, scm_name) |
| 74 | 73 |
| 75 | 74 |
| 76 # SCMWrapper base class | 75 # SCMWrapper base class |
| 77 | 76 |
| 78 class SCMWrapper(object): | 77 class SCMWrapper(object): |
| 79 """Add necessary glue between all the supported SCM. | 78 """Add necessary glue between all the supported SCM. |
| 80 | 79 |
| 81 This is the abstraction layer to bind to different SCM. Since currently only | 80 This is the abstraction layer to bind to different SCM. |
| 82 subversion is supported, a lot of subersionism remains. This can be sorted out | 81 """ |
| 83 once another SCM is supported.""" | |
| 84 def __init__(self, url=None, root_dir=None, relpath=None, | 82 def __init__(self, url=None, root_dir=None, relpath=None, |
| 85 scm_name='svn'): | 83 scm_name='svn'): |
| 86 self.scm_name = scm_name | 84 self.scm_name = scm_name |
| 87 self.url = url | 85 self.url = url |
| 88 self._root_dir = root_dir | 86 self._root_dir = root_dir |
| 89 if self._root_dir: | 87 if self._root_dir: |
| 90 self._root_dir = self._root_dir.replace('/', os.sep) | 88 self._root_dir = self._root_dir.replace('/', os.sep) |
| 91 self.relpath = relpath | 89 self.relpath = relpath |
| 92 if self.relpath: | 90 if self.relpath: |
| 93 self.relpath = self.relpath.replace('/', os.sep) | 91 self.relpath = self.relpath.replace('/', os.sep) |
| (...skipping 27 matching lines...) Expand all Loading... |
| 121 self._Run(['prune'], redirect_stdout=False) | 119 self._Run(['prune'], redirect_stdout=False) |
| 122 self._Run(['fsck'], redirect_stdout=False) | 120 self._Run(['fsck'], redirect_stdout=False) |
| 123 self._Run(['gc'], redirect_stdout=False) | 121 self._Run(['gc'], redirect_stdout=False) |
| 124 | 122 |
| 125 def diff(self, options, args, file_list): | 123 def diff(self, options, args, file_list): |
| 126 __pychecker__ = 'unusednames=args,file_list,options' | 124 __pychecker__ = 'unusednames=args,file_list,options' |
| 127 merge_base = self._Run(['merge-base', 'HEAD', 'origin']) | 125 merge_base = self._Run(['merge-base', 'HEAD', 'origin']) |
| 128 self._Run(['diff', merge_base], redirect_stdout=False) | 126 self._Run(['diff', merge_base], redirect_stdout=False) |
| 129 | 127 |
| 130 def export(self, options, args, file_list): | 128 def export(self, options, args, file_list): |
| 129 """Export a clean directory tree into the given path. |
| 130 |
| 131 Exports into the specified directory, creating the path if it does |
| 132 already exist. |
| 133 """ |
| 131 __pychecker__ = 'unusednames=file_list,options' | 134 __pychecker__ = 'unusednames=file_list,options' |
| 132 assert len(args) == 1 | 135 assert len(args) == 1 |
| 133 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) | 136 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) |
| 134 if not os.path.exists(export_path): | 137 if not os.path.exists(export_path): |
| 135 os.makedirs(export_path) | 138 os.makedirs(export_path) |
| 136 self._Run(['checkout-index', '-a', '--prefix=%s/' % export_path], | 139 self._Run(['checkout-index', '-a', '--prefix=%s/' % export_path], |
| 137 redirect_stdout=False) | 140 redirect_stdout=False) |
| 138 | 141 |
| 139 def pack(self, options, args, file_list): | 142 def pack(self, options, args, file_list): |
| 140 """Generates a patch file which can be applied to the root of the | 143 """Generates a patch file which can be applied to the root of the |
| 141 repository.""" | 144 repository. |
| 145 |
| 146 The patch file is generated from a diff of the merge base of HEAD and |
| 147 its upstream branch. |
| 148 """ |
| 142 __pychecker__ = 'unusednames=file_list,options' | 149 __pychecker__ = 'unusednames=file_list,options' |
| 143 path = os.path.join(self._root_dir, self.relpath) | 150 path = os.path.join(self._root_dir, self.relpath) |
| 144 merge_base = self._Run(['merge-base', 'HEAD', 'origin']) | 151 merge_base = self._Run(['merge-base', 'HEAD', 'origin']) |
| 145 command = ['diff', merge_base] | 152 command = ['diff', merge_base] |
| 146 filterer = DiffFilterer(self.relpath) | 153 filterer = DiffFilterer(self.relpath) |
| 147 self.RunAndFilterOutput(command, path, False, False, filterer.Filter) | 154 self.RunAndFilterOutput(command, path, False, False, filterer.Filter) |
| 148 | 155 |
| 149 def update(self, options, args, file_list): | 156 def update(self, options, args, file_list): |
| 150 """Runs git to update or transparently checkout the working copy. | 157 """Runs git to update or transparently checkout the working copy. |
| 151 | 158 |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 self.Run(command, os.path.join(self._root_dir, self.relpath)) | 318 self.Run(command, os.path.join(self._root_dir, self.relpath)) |
| 312 | 319 |
| 313 def diff(self, options, args, file_list): | 320 def diff(self, options, args, file_list): |
| 314 # NOTE: This function does not currently modify file_list. | 321 # NOTE: This function does not currently modify file_list. |
| 315 __pychecker__ = 'unusednames=file_list,options' | 322 __pychecker__ = 'unusednames=file_list,options' |
| 316 command = ['diff'] | 323 command = ['diff'] |
| 317 command.extend(args) | 324 command.extend(args) |
| 318 self.Run(command, os.path.join(self._root_dir, self.relpath)) | 325 self.Run(command, os.path.join(self._root_dir, self.relpath)) |
| 319 | 326 |
| 320 def export(self, options, args, file_list): | 327 def export(self, options, args, file_list): |
| 328 """Export a clean directory tree into the given path.""" |
| 321 __pychecker__ = 'unusednames=file_list,options' | 329 __pychecker__ = 'unusednames=file_list,options' |
| 322 assert len(args) == 1 | 330 assert len(args) == 1 |
| 323 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) | 331 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) |
| 324 try: | 332 try: |
| 325 os.makedirs(export_path) | 333 os.makedirs(export_path) |
| 326 except OSError: | 334 except OSError: |
| 327 pass | 335 pass |
| 328 assert os.path.exists(export_path) | 336 assert os.path.exists(export_path) |
| 329 command = ['export', '--force', '.'] | 337 command = ['export', '--force', '.'] |
| 330 command.append(export_path) | 338 command.append(export_path) |
| 331 self.Run(command, os.path.join(self._root_dir, self.relpath)) | 339 self.Run(command, os.path.join(self._root_dir, self.relpath)) |
| 332 | 340 |
| 333 def pack(self, options, args, file_list): | 341 def pack(self, options, args, file_list): |
| 334 """Generates a patch file which can be applied to the root of the | 342 """Generates a patch file which can be applied to the root of the |
| 335 repository.""" | 343 repository.""" |
| 336 __pychecker__ = 'unusednames=file_list,options' | 344 __pychecker__ = 'unusednames=file_list,options' |
| 337 path = os.path.join(self._root_dir, self.relpath) | 345 path = os.path.join(self._root_dir, self.relpath) |
| 338 command = ['diff'] | 346 command = ['diff'] |
| 339 command.extend(args) | 347 command.extend(args) |
| 340 | 348 |
| 341 filterer = DiffFilterer(self.relpath) | 349 filterer = DiffFilterer(self.relpath) |
| 342 self.RunAndFilterOutput(command, path, False, False, filterer.Filter) | 350 self.RunAndFilterOutput(command, path, False, False, filterer.Filter) |
| 343 | 351 |
| 344 def update(self, options, args, file_list): | 352 def update(self, options, args, file_list): |
| 345 """Runs SCM to update or transparently checkout the working copy. | 353 """Runs svn to update or transparently checkout the working copy. |
| 346 | 354 |
| 347 All updated files will be appended to file_list. | 355 All updated files will be appended to file_list. |
| 348 | 356 |
| 349 Raises: | 357 Raises: |
| 350 Error: if can't get URL for relative path. | 358 Error: if can't get URL for relative path. |
| 351 """ | 359 """ |
| 352 # Only update if git is not controlling the directory. | 360 # Only update if git is not controlling the directory. |
| 353 checkout_path = os.path.join(self._root_dir, self.relpath) | 361 checkout_path = os.path.join(self._root_dir, self.relpath) |
| 354 git_path = os.path.join(self._root_dir, self.relpath, '.git') | 362 git_path = os.path.join(self._root_dir, self.relpath, '.git') |
| 355 if os.path.exists(git_path): | 363 if os.path.exists(git_path): |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 command = ['status'] | 529 command = ['status'] |
| 522 command.extend(args) | 530 command.extend(args) |
| 523 if not os.path.isdir(path): | 531 if not os.path.isdir(path): |
| 524 # svn status won't work if the directory doesn't exist. | 532 # svn status won't work if the directory doesn't exist. |
| 525 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory " | 533 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory " |
| 526 "does not exist." | 534 "does not exist." |
| 527 % (' '.join(command), path)) | 535 % (' '.join(command), path)) |
| 528 # There's no file list to retrieve. | 536 # There's no file list to retrieve. |
| 529 else: | 537 else: |
| 530 self.RunAndGetFileList(options, command, path, file_list) | 538 self.RunAndGetFileList(options, command, path, file_list) |
| OLD | NEW |