| OLD | NEW |
| 1 # Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 # Copyright 2009 Google Inc. All Rights Reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # |
| 3 # found in the LICENSE file. | 3 # Licensed under the Apache License, Version 2.0 (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 |
| 6 # |
| 7 # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 # |
| 9 # Unless required by applicable law or agreed to in writing, software |
| 10 # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 # See the License for the specific language governing permissions and |
| 13 # limitations under the License. |
| 4 | 14 |
| 5 """Gclient-specific SCM-specific operations.""" | 15 """Gclient-specific SCM-specific operations.""" |
| 6 | 16 |
| 7 import logging | 17 import logging |
| 8 import os | 18 import os |
| 9 import re | 19 import re |
| 10 import subprocess | 20 import subprocess |
| 21 import sys |
| 22 import xml.dom.minidom |
| 11 | 23 |
| 12 import scm | |
| 13 import gclient_utils | 24 import gclient_utils |
| 25 # TODO(maruel): Temporary. |
| 26 from scm import CaptureGit, CaptureGitStatus, CaptureSVN |
| 27 from scm import CaptureSVNHeadRevision, CaptureSVNInfo, CaptureSVNStatus |
| 28 from scm import RunSVN, RunSVNAndFilterOutput, RunSVNAndGetFileList |
| 14 | 29 |
| 15 | 30 |
| 16 ### SCM abstraction layer | 31 ### SCM abstraction layer |
| 17 | 32 |
| 33 |
| 18 # Factory Method for SCM wrapper creation | 34 # Factory Method for SCM wrapper creation |
| 19 | 35 |
| 20 def CreateSCM(url=None, root_dir=None, relpath=None, scm_name='svn'): | 36 def CreateSCM(url=None, root_dir=None, relpath=None, scm_name='svn'): |
| 21 # TODO(maruel): Deduce the SCM from the url. | 37 # TODO(maruel): Deduce the SCM from the url. |
| 22 scm_map = { | 38 scm_map = { |
| 23 'svn' : SVNWrapper, | 39 'svn' : SVNWrapper, |
| 24 'git' : GitWrapper, | 40 'git' : GitWrapper, |
| 25 } | 41 } |
| 26 | 42 |
| 27 if url and (url.startswith('git:') or | 43 if url and (url.startswith('git:') or |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 if not command in commands: | 86 if not command in commands: |
| 71 raise gclient_utils.Error('Unknown command %s' % command) | 87 raise gclient_utils.Error('Unknown command %s' % command) |
| 72 | 88 |
| 73 if not command in dir(self): | 89 if not command in dir(self): |
| 74 raise gclient_utils.Error('Command %s not implemnted in %s wrapper' % ( | 90 raise gclient_utils.Error('Command %s not implemnted in %s wrapper' % ( |
| 75 command, self.scm_name)) | 91 command, self.scm_name)) |
| 76 | 92 |
| 77 return getattr(self, command)(options, args, file_list) | 93 return getattr(self, command)(options, args, file_list) |
| 78 | 94 |
| 79 | 95 |
| 80 class GitWrapper(SCMWrapper, scm.GIT): | 96 class GitWrapper(SCMWrapper): |
| 81 """Wrapper for Git""" | 97 """Wrapper for Git""" |
| 82 | 98 |
| 83 def cleanup(self, options, args, file_list): | 99 def cleanup(self, options, args, file_list): |
| 84 """Cleanup working copy.""" | 100 """Cleanup working copy.""" |
| 85 __pychecker__ = 'unusednames=args,file_list,options' | 101 __pychecker__ = 'unusednames=args,file_list,options' |
| 86 self._Run(['prune'], redirect_stdout=False) | 102 self._RunGit(['prune'], redirect_stdout=False) |
| 87 self._Run(['fsck'], redirect_stdout=False) | 103 self._RunGit(['fsck'], redirect_stdout=False) |
| 88 self._Run(['gc'], redirect_stdout=False) | 104 self._RunGit(['gc'], redirect_stdout=False) |
| 89 | 105 |
| 90 def diff(self, options, args, file_list): | 106 def diff(self, options, args, file_list): |
| 91 __pychecker__ = 'unusednames=args,file_list,options' | 107 __pychecker__ = 'unusednames=args,file_list,options' |
| 92 merge_base = self._Run(['merge-base', 'HEAD', 'origin']) | 108 merge_base = self._RunGit(['merge-base', 'HEAD', 'origin']) |
| 93 self._Run(['diff', merge_base], redirect_stdout=False) | 109 self._RunGit(['diff', merge_base], redirect_stdout=False) |
| 94 | 110 |
| 95 def export(self, options, args, file_list): | 111 def export(self, options, args, file_list): |
| 96 __pychecker__ = 'unusednames=file_list,options' | 112 __pychecker__ = 'unusednames=file_list,options' |
| 97 assert len(args) == 1 | 113 assert len(args) == 1 |
| 98 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) | 114 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) |
| 99 if not os.path.exists(export_path): | 115 if not os.path.exists(export_path): |
| 100 os.makedirs(export_path) | 116 os.makedirs(export_path) |
| 101 self._Run(['checkout-index', '-a', '--prefix=%s/' % export_path], | 117 self._RunGit(['checkout-index', '-a', '--prefix=%s/' % export_path], |
| 102 redirect_stdout=False) | 118 redirect_stdout=False) |
| 103 | 119 |
| 104 def update(self, options, args, file_list): | 120 def update(self, options, args, file_list): |
| 105 """Runs git to update or transparently checkout the working copy. | 121 """Runs git to update or transparently checkout the working copy. |
| 106 | 122 |
| 107 All updated files will be appended to file_list. | 123 All updated files will be appended to file_list. |
| 108 | 124 |
| 109 Raises: | 125 Raises: |
| 110 Error: if can't get URL for relative path. | 126 Error: if can't get URL for relative path. |
| 111 """ | 127 """ |
| 112 | 128 |
| 113 if args: | 129 if args: |
| 114 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args)) | 130 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args)) |
| 115 | 131 |
| 116 url, revision = gclient_utils.SplitUrlRevision(self.url) | 132 url, revision = gclient_utils.SplitUrlRevision(self.url) |
| 117 rev_str = "" | 133 rev_str = "" |
| 118 if options.revision: | 134 if options.revision: |
| 119 # Override the revision number. | 135 # Override the revision number. |
| 120 revision = str(options.revision) | 136 revision = str(options.revision) |
| 121 if revision: | 137 if revision: |
| 122 url = '%s@%s' % (url, revision) | 138 url = '%s@%s' % (url, revision) |
| 123 rev_str = ' at %s' % revision | 139 rev_str = ' at %s' % revision |
| 124 | 140 |
| 125 if options.verbose: | 141 if options.verbose: |
| 126 print("\n_____ %s%s" % (self.relpath, rev_str)) | 142 print("\n_____ %s%s" % (self.relpath, rev_str)) |
| 127 | 143 |
| 128 if not os.path.exists(self.checkout_path): | 144 if not os.path.exists(self.checkout_path): |
| 129 self._Run(['clone', url, self.checkout_path], | 145 self._RunGit(['clone', url, self.checkout_path], |
| 130 cwd=self._root_dir, redirect_stdout=False) | 146 cwd=self._root_dir, redirect_stdout=False) |
| 131 if revision: | 147 if revision: |
| 132 self._Run(['reset', '--hard', revision], redirect_stdout=False) | 148 self._RunGit(['reset', '--hard', revision], redirect_stdout=False) |
| 133 files = self._Run(['ls-files']).split() | 149 files = self._RunGit(['ls-files']).split() |
| 134 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 150 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
| 135 return | 151 return |
| 136 | 152 |
| 137 self._Run(['remote', 'update'], redirect_stdout=False) | 153 self._RunGit(['remote', 'update'], redirect_stdout=False) |
| 138 new_base = 'origin' | 154 new_base = 'origin' |
| 139 if revision: | 155 if revision: |
| 140 new_base = revision | 156 new_base = revision |
| 141 files = self._Run(['diff', new_base, '--name-only']).split() | 157 files = self._RunGit(['diff', new_base, '--name-only']).split() |
| 142 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 158 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
| 143 self._Run(['rebase', '-v', new_base], redirect_stdout=False) | 159 self._RunGit(['rebase', '-v', new_base], redirect_stdout=False) |
| 144 print "Checked out revision %s." % self.revinfo(options, (), None) | 160 print "Checked out revision %s." % self.revinfo(options, (), None) |
| 145 | 161 |
| 146 def revert(self, options, args, file_list): | 162 def revert(self, options, args, file_list): |
| 147 """Reverts local modifications. | 163 """Reverts local modifications. |
| 148 | 164 |
| 149 All reverted files will be appended to file_list. | 165 All reverted files will be appended to file_list. |
| 150 """ | 166 """ |
| 151 __pychecker__ = 'unusednames=args' | 167 __pychecker__ = 'unusednames=args' |
| 152 path = os.path.join(self._root_dir, self.relpath) | 168 path = os.path.join(self._root_dir, self.relpath) |
| 153 if not os.path.isdir(path): | 169 if not os.path.isdir(path): |
| 154 # revert won't work if the directory doesn't exist. It needs to | 170 # revert won't work if the directory doesn't exist. It needs to |
| 155 # checkout instead. | 171 # checkout instead. |
| 156 print("\n_____ %s is missing, synching instead" % self.relpath) | 172 print("\n_____ %s is missing, synching instead" % self.relpath) |
| 157 # Don't reuse the args. | 173 # Don't reuse the args. |
| 158 return self.update(options, [], file_list) | 174 return self.update(options, [], file_list) |
| 159 merge_base = self._Run(['merge-base', 'HEAD', 'origin']) | 175 merge_base = self._RunGit(['merge-base', 'HEAD', 'origin']) |
| 160 files = self._Run(['diff', merge_base, '--name-only']).split() | 176 files = self._RunGit(['diff', merge_base, '--name-only']).split() |
| 161 self._Run(['reset', '--hard', merge_base], redirect_stdout=False) | 177 self._RunGit(['reset', '--hard', merge_base], redirect_stdout=False) |
| 162 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 178 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
| 163 | 179 |
| 164 def revinfo(self, options, args, file_list): | 180 def revinfo(self, options, args, file_list): |
| 165 """Display revision""" | 181 """Display revision""" |
| 166 __pychecker__ = 'unusednames=args,file_list,options' | 182 __pychecker__ = 'unusednames=args,file_list,options' |
| 167 return self._Run(['rev-parse', 'HEAD']) | 183 return self._RunGit(['rev-parse', 'HEAD']) |
| 168 | 184 |
| 169 def runhooks(self, options, args, file_list): | 185 def runhooks(self, options, args, file_list): |
| 170 self.status(options, args, file_list) | 186 self.status(options, args, file_list) |
| 171 | 187 |
| 172 def status(self, options, args, file_list): | 188 def status(self, options, args, file_list): |
| 173 """Display status information.""" | 189 """Display status information.""" |
| 174 __pychecker__ = 'unusednames=args,options' | 190 __pychecker__ = 'unusednames=args,options' |
| 175 if not os.path.isdir(self.checkout_path): | 191 if not os.path.isdir(self.checkout_path): |
| 176 print('\n________ couldn\'t run status in %s:\nThe directory ' | 192 print('\n________ couldn\'t run status in %s:\nThe directory ' |
| 177 'does not exist.' % self.checkout_path) | 193 'does not exist.' % self.checkout_path) |
| 178 else: | 194 else: |
| 179 merge_base = self._Run(['merge-base', 'HEAD', 'origin']) | 195 merge_base = self._RunGit(['merge-base', 'HEAD', 'origin']) |
| 180 self._Run(['diff', '--name-status', merge_base], redirect_stdout=False) | 196 self._RunGit(['diff', '--name-status', merge_base], redirect_stdout=False) |
| 181 files = self._Run(['diff', '--name-only', merge_base]).split() | 197 files = self._RunGit(['diff', '--name-only', merge_base]).split() |
| 182 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 198 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
| 183 | 199 |
| 184 def _Run(self, args, cwd=None, checkrc=True, redirect_stdout=True): | 200 def _RunGit(self, args, cwd=None, checkrc=True, redirect_stdout=True): |
| 185 # TODO(maruel): Merge with Capture? | |
| 186 stdout=None | 201 stdout=None |
| 187 if redirect_stdout: | 202 if redirect_stdout: |
| 188 stdout=subprocess.PIPE | 203 stdout=subprocess.PIPE |
| 189 if cwd == None: | 204 if cwd == None: |
| 190 cwd = self.checkout_path | 205 cwd = self.checkout_path |
| 191 cmd = [self.COMMAND] | 206 cmd = ['git'] |
| 192 cmd.extend(args) | 207 cmd.extend(args) |
| 193 sp = subprocess.Popen(cmd, cwd=cwd, stdout=stdout) | 208 sp = subprocess.Popen(cmd, cwd=cwd, stdout=stdout) |
| 194 if checkrc and sp.returncode: | 209 if checkrc and sp.returncode: |
| 195 raise gclient_utils.Error('git command %s returned %d' % | 210 raise gclient_utils.Error('git command %s returned %d' % |
| 196 (args[0], sp.returncode)) | 211 (args[0], sp.returncode)) |
| 197 output = sp.communicate()[0] | 212 output = sp.communicate()[0] |
| 198 if output is not None: | 213 if output != None: |
| 199 return output.strip() | 214 return output.strip() |
| 200 | 215 |
| 201 | 216 |
| 202 class SVNWrapper(SCMWrapper, scm.SVN): | 217 class SVNWrapper(SCMWrapper): |
| 203 """ Wrapper for SVN """ | 218 """ Wrapper for SVN """ |
| 204 | 219 |
| 205 def cleanup(self, options, args, file_list): | 220 def cleanup(self, options, args, file_list): |
| 206 """Cleanup working copy.""" | 221 """Cleanup working copy.""" |
| 207 __pychecker__ = 'unusednames=file_list,options' | 222 __pychecker__ = 'unusednames=file_list,options' |
| 208 command = ['cleanup'] | 223 command = ['cleanup'] |
| 209 command.extend(args) | 224 command.extend(args) |
| 210 self.Run(command, os.path.join(self._root_dir, self.relpath)) | 225 RunSVN(command, os.path.join(self._root_dir, self.relpath)) |
| 211 | 226 |
| 212 def diff(self, options, args, file_list): | 227 def diff(self, options, args, file_list): |
| 213 # NOTE: This function does not currently modify file_list. | 228 # NOTE: This function does not currently modify file_list. |
| 214 __pychecker__ = 'unusednames=file_list,options' | 229 __pychecker__ = 'unusednames=file_list,options' |
| 215 command = ['diff'] | 230 command = ['diff'] |
| 216 command.extend(args) | 231 command.extend(args) |
| 217 self.Run(command, os.path.join(self._root_dir, self.relpath)) | 232 RunSVN(command, os.path.join(self._root_dir, self.relpath)) |
| 218 | 233 |
| 219 def export(self, options, args, file_list): | 234 def export(self, options, args, file_list): |
| 220 __pychecker__ = 'unusednames=file_list,options' | 235 __pychecker__ = 'unusednames=file_list,options' |
| 221 assert len(args) == 1 | 236 assert len(args) == 1 |
| 222 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) | 237 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) |
| 223 try: | 238 try: |
| 224 os.makedirs(export_path) | 239 os.makedirs(export_path) |
| 225 except OSError: | 240 except OSError: |
| 226 pass | 241 pass |
| 227 assert os.path.exists(export_path) | 242 assert os.path.exists(export_path) |
| 228 command = ['export', '--force', '.'] | 243 command = ['export', '--force', '.'] |
| 229 command.append(export_path) | 244 command.append(export_path) |
| 230 self.Run(command, os.path.join(self._root_dir, self.relpath)) | 245 RunSVN(command, os.path.join(self._root_dir, self.relpath)) |
| 231 | 246 |
| 232 def update(self, options, args, file_list): | 247 def update(self, options, args, file_list): |
| 233 """Runs SCM to update or transparently checkout the working copy. | 248 """Runs SCM to update or transparently checkout the working copy. |
| 234 | 249 |
| 235 All updated files will be appended to file_list. | 250 All updated files will be appended to file_list. |
| 236 | 251 |
| 237 Raises: | 252 Raises: |
| 238 Error: if can't get URL for relative path. | 253 Error: if can't get URL for relative path. |
| 239 """ | 254 """ |
| 240 # Only update if git is not controlling the directory. | 255 # Only update if git is not controlling the directory. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 257 if revision: | 272 if revision: |
| 258 forced_revision = True | 273 forced_revision = True |
| 259 url = '%s@%s' % (url, revision) | 274 url = '%s@%s' % (url, revision) |
| 260 rev_str = ' at %s' % revision | 275 rev_str = ' at %s' % revision |
| 261 | 276 |
| 262 if not os.path.exists(checkout_path): | 277 if not os.path.exists(checkout_path): |
| 263 # We need to checkout. | 278 # We need to checkout. |
| 264 command = ['checkout', url, checkout_path] | 279 command = ['checkout', url, checkout_path] |
| 265 if revision: | 280 if revision: |
| 266 command.extend(['--revision', str(revision)]) | 281 command.extend(['--revision', str(revision)]) |
| 267 self.RunAndGetFileList(options, command, self._root_dir, file_list) | 282 RunSVNAndGetFileList(options, command, self._root_dir, file_list) |
| 268 return | 283 return |
| 269 | 284 |
| 270 # Get the existing scm url and the revision number of the current checkout. | 285 # Get the existing scm url and the revision number of the current checkout. |
| 271 from_info = self.CaptureInfo(os.path.join(checkout_path, '.'), '.') | 286 from_info = CaptureSVNInfo(os.path.join(checkout_path, '.'), '.') |
| 272 if not from_info: | 287 if not from_info: |
| 273 raise gclient_utils.Error("Can't update/checkout %r if an unversioned " | 288 raise gclient_utils.Error("Can't update/checkout %r if an unversioned " |
| 274 "directory is present. Delete the directory " | 289 "directory is present. Delete the directory " |
| 275 "and try again." % | 290 "and try again." % |
| 276 checkout_path) | 291 checkout_path) |
| 277 | 292 |
| 278 if options.manually_grab_svn_rev: | 293 if options.manually_grab_svn_rev: |
| 279 # Retrieve the current HEAD version because svn is slow at null updates. | 294 # Retrieve the current HEAD version because svn is slow at null updates. |
| 280 if not revision: | 295 if not revision: |
| 281 from_info_live = self.CaptureInfo(from_info['URL'], '.') | 296 from_info_live = CaptureSVNInfo(from_info['URL'], '.') |
| 282 revision = str(from_info_live['Revision']) | 297 revision = str(from_info_live['Revision']) |
| 283 rev_str = ' at %s' % revision | 298 rev_str = ' at %s' % revision |
| 284 | 299 |
| 285 if from_info['URL'] != base_url: | 300 if from_info['URL'] != base_url: |
| 286 to_info = self.CaptureInfo(url, '.') | 301 to_info = CaptureSVNInfo(url, '.') |
| 287 if not to_info.get('Repository Root') or not to_info.get('UUID'): | 302 if not to_info.get('Repository Root') or not to_info.get('UUID'): |
| 288 # The url is invalid or the server is not accessible, it's safer to bail | 303 # The url is invalid or the server is not accessible, it's safer to bail |
| 289 # out right now. | 304 # out right now. |
| 290 raise gclient_utils.Error('This url is unreachable: %s' % url) | 305 raise gclient_utils.Error('This url is unreachable: %s' % url) |
| 291 can_switch = ((from_info['Repository Root'] != to_info['Repository Root']) | 306 can_switch = ((from_info['Repository Root'] != to_info['Repository Root']) |
| 292 and (from_info['UUID'] == to_info['UUID'])) | 307 and (from_info['UUID'] == to_info['UUID'])) |
| 293 if can_switch: | 308 if can_switch: |
| 294 print("\n_____ relocating %s to a new checkout" % self.relpath) | 309 print("\n_____ relocating %s to a new checkout" % self.relpath) |
| 295 # We have different roots, so check if we can switch --relocate. | 310 # We have different roots, so check if we can switch --relocate. |
| 296 # Subversion only permits this if the repository UUIDs match. | 311 # Subversion only permits this if the repository UUIDs match. |
| 297 # Perform the switch --relocate, then rewrite the from_url | 312 # Perform the switch --relocate, then rewrite the from_url |
| 298 # to reflect where we "are now." (This is the same way that | 313 # to reflect where we "are now." (This is the same way that |
| 299 # Subversion itself handles the metadata when switch --relocate | 314 # Subversion itself handles the metadata when switch --relocate |
| 300 # is used.) This makes the checks below for whether we | 315 # is used.) This makes the checks below for whether we |
| 301 # can update to a revision or have to switch to a different | 316 # can update to a revision or have to switch to a different |
| 302 # branch work as expected. | 317 # branch work as expected. |
| 303 # TODO(maruel): TEST ME ! | 318 # TODO(maruel): TEST ME ! |
| 304 command = ["switch", "--relocate", | 319 command = ["switch", "--relocate", |
| 305 from_info['Repository Root'], | 320 from_info['Repository Root'], |
| 306 to_info['Repository Root'], | 321 to_info['Repository Root'], |
| 307 self.relpath] | 322 self.relpath] |
| 308 self.Run(command, self._root_dir) | 323 RunSVN(command, self._root_dir) |
| 309 from_info['URL'] = from_info['URL'].replace( | 324 from_info['URL'] = from_info['URL'].replace( |
| 310 from_info['Repository Root'], | 325 from_info['Repository Root'], |
| 311 to_info['Repository Root']) | 326 to_info['Repository Root']) |
| 312 else: | 327 else: |
| 313 if self.CaptureStatus(checkout_path): | 328 if CaptureSVNStatus(checkout_path): |
| 314 raise gclient_utils.Error("Can't switch the checkout to %s; UUID " | 329 raise gclient_utils.Error("Can't switch the checkout to %s; UUID " |
| 315 "don't match and there is local changes " | 330 "don't match and there is local changes " |
| 316 "in %s. Delete the directory and " | 331 "in %s. Delete the directory and " |
| 317 "try again." % (url, checkout_path)) | 332 "try again." % (url, checkout_path)) |
| 318 # Ok delete it. | 333 # Ok delete it. |
| 319 print("\n_____ switching %s to a new checkout" % self.relpath) | 334 print("\n_____ switching %s to a new checkout" % self.relpath) |
| 320 gclient_utils.RemoveDirectory(checkout_path) | 335 gclient_utils.RemoveDirectory(checkout_path) |
| 321 # We need to checkout. | 336 # We need to checkout. |
| 322 command = ['checkout', url, checkout_path] | 337 command = ['checkout', url, checkout_path] |
| 323 if revision: | 338 if revision: |
| 324 command.extend(['--revision', str(revision)]) | 339 command.extend(['--revision', str(revision)]) |
| 325 self.RunAndGetFileList(options, command, self._root_dir, file_list) | 340 RunSVNAndGetFileList(options, command, self._root_dir, file_list) |
| 326 return | 341 return |
| 327 | 342 |
| 328 | 343 |
| 329 # If the provided url has a revision number that matches the revision | 344 # If the provided url has a revision number that matches the revision |
| 330 # number of the existing directory, then we don't need to bother updating. | 345 # number of the existing directory, then we don't need to bother updating. |
| 331 if not options.force and str(from_info['Revision']) == revision: | 346 if not options.force and str(from_info['Revision']) == revision: |
| 332 if options.verbose or not forced_revision: | 347 if options.verbose or not forced_revision: |
| 333 print("\n_____ %s%s" % (self.relpath, rev_str)) | 348 print("\n_____ %s%s" % (self.relpath, rev_str)) |
| 334 return | 349 return |
| 335 | 350 |
| 336 command = ["update", checkout_path] | 351 command = ["update", checkout_path] |
| 337 if revision: | 352 if revision: |
| 338 command.extend(['--revision', str(revision)]) | 353 command.extend(['--revision', str(revision)]) |
| 339 self.RunAndGetFileList(options, command, self._root_dir, file_list) | 354 RunSVNAndGetFileList(options, command, self._root_dir, file_list) |
| 340 | 355 |
| 341 def revert(self, options, args, file_list): | 356 def revert(self, options, args, file_list): |
| 342 """Reverts local modifications. Subversion specific. | 357 """Reverts local modifications. Subversion specific. |
| 343 | 358 |
| 344 All reverted files will be appended to file_list, even if Subversion | 359 All reverted files will be appended to file_list, even if Subversion |
| 345 doesn't know about them. | 360 doesn't know about them. |
| 346 """ | 361 """ |
| 347 __pychecker__ = 'unusednames=args' | 362 __pychecker__ = 'unusednames=args' |
| 348 path = os.path.join(self._root_dir, self.relpath) | 363 path = os.path.join(self._root_dir, self.relpath) |
| 349 if not os.path.isdir(path): | 364 if not os.path.isdir(path): |
| 350 # svn revert won't work if the directory doesn't exist. It needs to | 365 # svn revert won't work if the directory doesn't exist. It needs to |
| 351 # checkout instead. | 366 # checkout instead. |
| 352 print("\n_____ %s is missing, synching instead" % self.relpath) | 367 print("\n_____ %s is missing, synching instead" % self.relpath) |
| 353 # Don't reuse the args. | 368 # Don't reuse the args. |
| 354 return self.update(options, [], file_list) | 369 return self.update(options, [], file_list) |
| 355 | 370 |
| 356 for file_status in self.CaptureStatus(path): | 371 for file_status in CaptureSVNStatus(path): |
| 357 file_path = os.path.join(path, file_status[1]) | 372 file_path = os.path.join(path, file_status[1]) |
| 358 if file_status[0][0] == 'X': | 373 if file_status[0][0] == 'X': |
| 359 # Ignore externals. | 374 # Ignore externals. |
| 360 logging.info('Ignoring external %s' % file_path) | 375 logging.info('Ignoring external %s' % file_path) |
| 361 continue | 376 continue |
| 362 | 377 |
| 363 if logging.getLogger().isEnabledFor(logging.INFO): | 378 if logging.getLogger().isEnabledFor(logging.INFO): |
| 364 logging.info('%s%s' % (file[0], file[1])) | 379 logging.info('%s%s' % (file[0], file[1])) |
| 365 else: | 380 else: |
| 366 print(file_path) | 381 print(file_path) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 381 gclient_utils.RemoveDirectory(file_path) | 396 gclient_utils.RemoveDirectory(file_path) |
| 382 else: | 397 else: |
| 383 logging.error('no idea what is %s.\nYou just found a bug in gclient' | 398 logging.error('no idea what is %s.\nYou just found a bug in gclient' |
| 384 ', please ping maruel@chromium.org ASAP!' % file_path) | 399 ', please ping maruel@chromium.org ASAP!' % file_path) |
| 385 except EnvironmentError: | 400 except EnvironmentError: |
| 386 logging.error('Failed to remove %s.' % file_path) | 401 logging.error('Failed to remove %s.' % file_path) |
| 387 | 402 |
| 388 try: | 403 try: |
| 389 # svn revert is so broken we don't even use it. Using | 404 # svn revert is so broken we don't even use it. Using |
| 390 # "svn up --revision BASE" achieve the same effect. | 405 # "svn up --revision BASE" achieve the same effect. |
| 391 self.RunAndGetFileList(options, ['update', '--revision', 'BASE'], path, | 406 RunSVNAndGetFileList(options, ['update', '--revision', 'BASE'], path, |
| 392 file_list) | 407 file_list) |
| 393 except OSError, e: | 408 except OSError, e: |
| 394 # Maybe the directory disapeared meanwhile. We don't want it to throw an | 409 # Maybe the directory disapeared meanwhile. We don't want it to throw an |
| 395 # exception. | 410 # exception. |
| 396 logging.error('Failed to update:\n%s' % str(e)) | 411 logging.error('Failed to update:\n%s' % str(e)) |
| 397 | 412 |
| 398 def revinfo(self, options, args, file_list): | 413 def revinfo(self, options, args, file_list): |
| 399 """Display revision""" | 414 """Display revision""" |
| 400 __pychecker__ = 'unusednames=args,file_list,options' | 415 __pychecker__ = 'unusednames=args,file_list,options' |
| 401 return self.CaptureHeadRevision(self.url) | 416 return CaptureSVNHeadRevision(self.url) |
| 402 | 417 |
| 403 def runhooks(self, options, args, file_list): | 418 def runhooks(self, options, args, file_list): |
| 404 self.status(options, args, file_list) | 419 self.status(options, args, file_list) |
| 405 | 420 |
| 406 def status(self, options, args, file_list): | 421 def status(self, options, args, file_list): |
| 407 """Display status information.""" | 422 """Display status information.""" |
| 408 path = os.path.join(self._root_dir, self.relpath) | 423 path = os.path.join(self._root_dir, self.relpath) |
| 409 command = ['status'] | 424 command = ['status'] |
| 410 command.extend(args) | 425 command.extend(args) |
| 411 if not os.path.isdir(path): | 426 if not os.path.isdir(path): |
| 412 # svn status won't work if the directory doesn't exist. | 427 # svn status won't work if the directory doesn't exist. |
| 413 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory " | 428 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory " |
| 414 "does not exist." | 429 "does not exist." |
| 415 % (' '.join(command), path)) | 430 % (' '.join(command), path)) |
| 416 # There's no file list to retrieve. | 431 # There's no file list to retrieve. |
| 417 else: | 432 else: |
| 418 self.RunAndGetFileList(options, command, path, file_list) | 433 RunSVNAndGetFileList(options, command, path, file_list) |
| 419 | 434 |
| 420 def pack(self, options, args, file_list): | 435 def pack(self, options, args, file_list): |
| 421 """Generates a patch file which can be applied to the root of the | 436 """Generates a patch file which can be applied to the root of the |
| 422 repository.""" | 437 repository.""" |
| 423 __pychecker__ = 'unusednames=file_list,options' | 438 __pychecker__ = 'unusednames=file_list,options' |
| 424 path = os.path.join(self._root_dir, self.relpath) | 439 path = os.path.join(self._root_dir, self.relpath) |
| 425 command = ['diff'] | 440 command = ['diff'] |
| 426 command.extend(args) | 441 command.extend(args) |
| 427 # Simple class which tracks which file is being diffed and | 442 # Simple class which tracks which file is being diffed and |
| 428 # replaces instances of its file name in the original and | 443 # replaces instances of its file name in the original and |
| (...skipping 24 matching lines...) Expand all Loading... |
| 453 self.SetCurrentFile(line[len(self.index_string):]) | 468 self.SetCurrentFile(line[len(self.index_string):]) |
| 454 self.ReplaceAndPrint(line) | 469 self.ReplaceAndPrint(line) |
| 455 else: | 470 else: |
| 456 if (line.startswith(self.original_prefix) or | 471 if (line.startswith(self.original_prefix) or |
| 457 line.startswith(self.working_prefix)): | 472 line.startswith(self.working_prefix)): |
| 458 self.ReplaceAndPrint(line) | 473 self.ReplaceAndPrint(line) |
| 459 else: | 474 else: |
| 460 print line | 475 print line |
| 461 | 476 |
| 462 filterer = DiffFilterer(self.relpath) | 477 filterer = DiffFilterer(self.relpath) |
| 463 self.RunAndFilterOutput(command, path, False, False, filterer.Filter) | 478 RunSVNAndFilterOutput(command, path, False, False, filterer.Filter) |
| OLD | NEW |