Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: gclient_scm.py

Issue 874002: Stop SVNWrapper and GitWrapper from inheriting from scm.SVN and scm.GIT. (Closed)
Patch Set: Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« gclient.py ('K') | « gclient.py ('k') | scm.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 if not command in commands: 103 if not command in commands:
104 raise gclient_utils.Error('Unknown command %s' % command) 104 raise gclient_utils.Error('Unknown command %s' % command)
105 105
106 if not command in dir(self): 106 if not command in dir(self):
107 raise gclient_utils.Error('Command %s not implemented in %s wrapper' % ( 107 raise gclient_utils.Error('Command %s not implemented in %s wrapper' % (
108 command, self.scm_name)) 108 command, self.scm_name))
109 109
110 return getattr(self, command)(options, args, file_list) 110 return getattr(self, command)(options, args, file_list)
111 111
112 112
113 class GitWrapper(SCMWrapper, scm.GIT): 113 class GitWrapper(SCMWrapper):
114 """Wrapper for Git""" 114 """Wrapper for Git"""
115 115
116 def cleanup(self, options, args, file_list): 116 def cleanup(self, options, args, file_list):
117 """'Cleanup' the repo. 117 """'Cleanup' the repo.
118 118
119 There's no real git equivalent for the svn cleanup command, do a no-op. 119 There's no real git equivalent for the svn cleanup command, do a no-op.
120 """ 120 """
121 __pychecker__ = 'unusednames=options,args,file_list' 121 __pychecker__ = 'unusednames=options,args,file_list'
122 122
123 def diff(self, options, args, file_list): 123 def diff(self, options, args, file_list):
(...skipping 15 matching lines...) Expand all
139 self._Run(['checkout-index', '-a', '--prefix=%s/' % export_path], 139 self._Run(['checkout-index', '-a', '--prefix=%s/' % export_path],
140 redirect_stdout=False) 140 redirect_stdout=False)
141 141
142 def pack(self, options, args, file_list): 142 def pack(self, options, args, file_list):
143 """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
144 repository. 144 repository.
145 145
146 The patch file is generated from a diff of the merge base of HEAD and 146 The patch file is generated from a diff of the merge base of HEAD and
147 its upstream branch. 147 its upstream branch.
148 """ 148 """
149 __pychecker__ = 'unusednames=options,file_list' 149 __pychecker__ = 'unusednames=options,args,file_list'
150 path = os.path.join(self._root_dir, self.relpath) 150 path = os.path.join(self._root_dir, self.relpath)
151 merge_base = self._Run(['merge-base', 'HEAD', 'origin']) 151 merge_base = self._Run(['merge-base', 'HEAD', 'origin'])
152 command = ['diff', merge_base] 152 command = ['diff', merge_base]
153 filterer = DiffFilterer(self.relpath) 153 filterer = DiffFilterer(self.relpath)
154 self.RunAndFilterOutput(command, path, False, False, filterer.Filter) 154 scm.GIT.RunAndFilterOutput(command, path, False, False, filterer.Filter)
155 155
156 def update(self, options, args, file_list): 156 def update(self, options, args, file_list):
157 """Runs git to update or transparently checkout the working copy. 157 """Runs git to update or transparently checkout the working copy.
158 158
159 All updated files will be appended to file_list. 159 All updated files will be appended to file_list.
160 160
161 Raises: 161 Raises:
162 Error: if can't get URL for relative path. 162 Error: if can't get URL for relative path.
163 """ 163 """
164 164
(...skipping 24 matching lines...) Expand all
189 if revision.startswith('refs/heads/'): 189 if revision.startswith('refs/heads/'):
190 rev_type = "branch" 190 rev_type = "branch"
191 elif revision.startswith('origin/'): 191 elif revision.startswith('origin/'):
192 # For compatability with old naming, translate 'origin' to 'refs/heads' 192 # For compatability with old naming, translate 'origin' to 'refs/heads'
193 revision = revision.replace('origin/', 'refs/heads/') 193 revision = revision.replace('origin/', 'refs/heads/')
194 rev_type = "branch" 194 rev_type = "branch"
195 else: 195 else:
196 # hash is also a tag, only make a distinction at checkout 196 # hash is also a tag, only make a distinction at checkout
197 rev_type = "hash" 197 rev_type = "hash"
198 198
199
200 if not os.path.exists(self.checkout_path): 199 if not os.path.exists(self.checkout_path):
201 self._Clone(rev_type, revision, url, options.verbose) 200 self._Clone(rev_type, revision, url, options.verbose)
202 files = self._Run(['ls-files']).split() 201 files = self._Run(['ls-files']).split()
203 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) 202 file_list.extend([os.path.join(self.checkout_path, f) for f in files])
204 if not verbose: 203 if not verbose:
205 # Make the output a little prettier. It's nice to have some whitespace 204 # Make the output a little prettier. It's nice to have some whitespace
206 # between projects when cloning. 205 # between projects when cloning.
207 print "" 206 print ""
208 return 207 return
209 208
(...skipping 24 matching lines...) Expand all
234 # - rebase those changes on top of the hash 233 # - rebase those changes on top of the hash
235 # 3) current branch based on a remote with or without changes, no switch 234 # 3) current branch based on a remote with or without changes, no switch
236 # - see if we can FF, if not, prompt the user for rebase, merge, or stop 235 # - see if we can FF, if not, prompt the user for rebase, merge, or stop
237 # 4) current branch based on a remote, switches to a new remote 236 # 4) current branch based on a remote, switches to a new remote
238 # - exit 237 # - exit
239 238
240 # GetUpstream returns something like 'refs/remotes/origin/master' for a 239 # GetUpstream returns something like 'refs/remotes/origin/master' for a
241 # tracking branch 240 # tracking branch
242 # or 'master' if not a tracking branch (it's based on a specific rev/hash) 241 # or 'master' if not a tracking branch (it's based on a specific rev/hash)
243 # or it returns None if it couldn't find an upstream 242 # or it returns None if it couldn't find an upstream
244 upstream_branch = self.GetUpstream(self.checkout_path) 243 upstream_branch = scm.GIT.GetUpstream(self.checkout_path)
245 if not upstream_branch or not upstream_branch.startswith('refs/remotes'): 244 if not upstream_branch or not upstream_branch.startswith('refs/remotes'):
246 current_type = "hash" 245 current_type = "hash"
247 logging.debug("Current branch is based off a specific rev and is not " 246 logging.debug("Current branch is based off a specific rev and is not "
248 "tracking an upstream.") 247 "tracking an upstream.")
249 elif upstream_branch.startswith('refs/remotes'): 248 elif upstream_branch.startswith('refs/remotes'):
250 current_type = "branch" 249 current_type = "branch"
251 else: 250 else:
252 raise gclient_utils.Error('Invalid Upstream') 251 raise gclient_utils.Error('Invalid Upstream')
253 252
254 # Update the remotes first so we have all the refs. 253 # Update the remotes first so we have all the refs.
255 for i in range(3): 254 for _ in range(3):
256 try: 255 try:
257 remote_output, remote_err = self.Capture( 256 remote_output, remote_err = scm.GIT.Capture(
258 ['remote'] + verbose + ['update'], 257 ['remote'] + verbose + ['update'],
259 self.checkout_path, 258 self.checkout_path,
260 print_error=False) 259 print_error=False)
261 break 260 break
262 except gclient_utils.CheckCallError, e: 261 except gclient_utils.CheckCallError, e:
263 # Hackish but at that point, git is known to work so just checking for 262 # Hackish but at that point, git is known to work so just checking for
264 # 502 in stderr should be fine. 263 # 502 in stderr should be fine.
265 if '502' in e.stderr: 264 if '502' in e.stderr:
266 print str(e) 265 print str(e)
267 print "Retrying..." 266 print "Retrying..."
268 continue 267 continue
269 raise e 268 raise e
270 269
271 if verbose: 270 if verbose:
272 print remote_output.strip() 271 print remote_output.strip()
273 # git remote update prints to stderr when used with --verbose 272 # git remote update prints to stderr when used with --verbose
274 print remote_err.strip() 273 print remote_err.strip()
275 274
276 # This is a big hammer, debatable if it should even be here... 275 # This is a big hammer, debatable if it should even be here...
277 if options.force or options.reset: 276 if options.force or options.reset:
278 self._Run(['reset', '--hard', 'HEAD'], redirect_stdout=False) 277 self._Run(['reset', '--hard', 'HEAD'], redirect_stdout=False)
279 278
280 if current_type is 'hash': 279 if current_type == 'hash':
281 # case 1 280 # case 1
282 if self.IsGitSvn(self.checkout_path) and upstream_branch is not None: 281 if scm.GIT.IsGitSvn(self.checkout_path) and upstream_branch is not None:
283 # Our git-svn branch (upstream_branch) is our upstream 282 # Our git-svn branch (upstream_branch) is our upstream
284 self._AttemptRebase(upstream_branch, files, verbose=options.verbose, 283 self._AttemptRebase(upstream_branch, files, verbose=options.verbose,
285 newbase=revision, printed_path=printed_path) 284 newbase=revision, printed_path=printed_path)
286 printed_path = True 285 printed_path = True
287 else: 286 else:
288 # Can't find a merge-base since we don't know our upstream. That makes 287 # Can't find a merge-base since we don't know our upstream. That makes
289 # this command VERY likely to produce a rebase failure. For now we 288 # this command VERY likely to produce a rebase failure. For now we
290 # assume origin is our upstream since that's what the old behavior was. 289 # assume origin is our upstream since that's what the old behavior was.
291 upstream_branch = 'origin' 290 upstream_branch = 'origin'
292 if options.revision: 291 if options.revision:
293 upstream_branch = revision 292 upstream_branch = revision
294 self._AttemptRebase(upstream_branch, files=files, 293 self._AttemptRebase(upstream_branch, files=files,
295 verbose=options.verbose, printed_path=printed_path) 294 verbose=options.verbose, printed_path=printed_path)
296 printed_path = True 295 printed_path = True
297 elif rev_type is 'hash': 296 elif rev_type == 'hash':
298 # case 2 297 # case 2
299 self._AttemptRebase(upstream_branch, files, verbose=options.verbose, 298 self._AttemptRebase(upstream_branch, files, verbose=options.verbose,
300 newbase=revision, printed_path=printed_path) 299 newbase=revision, printed_path=printed_path)
301 printed_path = True 300 printed_path = True
302 elif revision.replace('heads', 'remotes/origin') != upstream_branch: 301 elif revision.replace('heads', 'remotes/origin') != upstream_branch:
303 # case 4 302 # case 4
304 new_base = revision.replace('heads', 'remotes/origin') 303 new_base = revision.replace('heads', 'remotes/origin')
305 if not printed_path: 304 if not printed_path:
306 print("\n_____ %s%s" % (self.relpath, rev_str)) 305 print("\n_____ %s%s" % (self.relpath, rev_str))
307 switch_error = ("Switching upstream branch from %s to %s\n" 306 switch_error = ("Switching upstream branch from %s to %s\n"
308 % (upstream_branch, new_base) + 307 % (upstream_branch, new_base) +
309 "Please merge or rebase manually:\n" + 308 "Please merge or rebase manually:\n" +
310 "cd %s; git rebase %s\n" % (self.checkout_path, new_base) + 309 "cd %s; git rebase %s\n" % (self.checkout_path, new_base) +
311 "OR git checkout -b <some new branch> %s" % new_base) 310 "OR git checkout -b <some new branch> %s" % new_base)
312 raise gclient_utils.Error(switch_error) 311 raise gclient_utils.Error(switch_error)
313 else: 312 else:
314 # case 3 - the default case 313 # case 3 - the default case
315 files = self._Run(['diff', upstream_branch, '--name-only']).split() 314 files = self._Run(['diff', upstream_branch, '--name-only']).split()
316 if verbose: 315 if verbose:
317 print "Trying fast-forward merge to branch : %s" % upstream_branch 316 print "Trying fast-forward merge to branch : %s" % upstream_branch
318 try: 317 try:
319 merge_output, merge_err = self.Capture(['merge', '--ff-only', 318 merge_output, merge_err = scm.GIT.Capture(['merge', '--ff-only',
320 upstream_branch], 319 upstream_branch],
321 self.checkout_path, 320 self.checkout_path,
322 print_error=False) 321 print_error=False)
323 except gclient_utils.CheckCallError, e: 322 except gclient_utils.CheckCallError, e:
324 if re.match('fatal: Not possible to fast-forward, aborting.', e.stderr): 323 if re.match('fatal: Not possible to fast-forward, aborting.', e.stderr):
325 if not printed_path: 324 if not printed_path:
326 print("\n_____ %s%s" % (self.relpath, rev_str)) 325 print("\n_____ %s%s" % (self.relpath, rev_str))
327 printed_path = True 326 printed_path = True
328 while True: 327 while True:
329 try: 328 try:
330 action = str(raw_input("Cannot fast-forward merge, attempt to " 329 action = str(raw_input("Cannot fast-forward merge, attempt to "
331 "rebase? (y)es / (q)uit / (s)kip : ")) 330 "rebase? (y)es / (q)uit / (s)kip : "))
332 except ValueError: 331 except ValueError:
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 if not verbose: 439 if not verbose:
441 # git clone doesn't seem to insert a newline properly before printing 440 # git clone doesn't seem to insert a newline properly before printing
442 # to stdout 441 # to stdout
443 print "" 442 print ""
444 443
445 clone_cmd = ['clone'] 444 clone_cmd = ['clone']
446 if verbose: 445 if verbose:
447 clone_cmd.append('--verbose') 446 clone_cmd.append('--verbose')
448 clone_cmd.extend([url, self.checkout_path]) 447 clone_cmd.extend([url, self.checkout_path])
449 448
450 for i in range(3): 449 for _ in range(3):
451 try: 450 try:
452 self._Run(clone_cmd, cwd=self._root_dir, redirect_stdout=False) 451 self._Run(clone_cmd, cwd=self._root_dir, redirect_stdout=False)
453 break 452 break
454 except gclient_utils.Error, e: 453 except gclient_utils.Error, e:
455 # TODO(maruel): Hackish, should be fixed by moving _Run() to 454 # TODO(maruel): Hackish, should be fixed by moving _Run() to
456 # CheckCall(). 455 # CheckCall().
457 # Too bad we don't have access to the actual output. 456 # Too bad we don't have access to the actual output.
458 # We should check for "transfer closed with NNN bytes remaining to 457 # We should check for "transfer closed with NNN bytes remaining to
459 # read". In the meantime, just make sure .git exists. 458 # read". In the meantime, just make sure .git exists.
460 if (e.args[0] == 'git command clone returned 128' and 459 if (e.args[0] == 'git command clone returned 128' and
461 os.path.exists(os.path.join(self.checkout_path, '.git'))): 460 os.path.exists(os.path.join(self.checkout_path, '.git'))):
462 print str(e) 461 print str(e)
463 print "Retrying..." 462 print "Retrying..."
464 continue 463 continue
465 raise e 464 raise e
466 465
467 if rev_type is "branch": 466 if rev_type == "branch":
468 short_rev = revision.replace('refs/heads/', '') 467 short_rev = revision.replace('refs/heads/', '')
469 new_branch = revision.replace('heads', 'remotes/origin') 468 new_branch = revision.replace('heads', 'remotes/origin')
470 elif revision.startswith('refs/tags/'): 469 elif revision.startswith('refs/tags/'):
471 short_rev = revision.replace('refs/tags/', '') 470 short_rev = revision.replace('refs/tags/', '')
472 new_branch = revision 471 new_branch = revision
473 else: 472 else:
474 # revision is a specific sha1 hash 473 # revision is a specific sha1 hash
475 short_rev = revision 474 short_rev = revision
476 new_branch = revision 475 new_branch = revision
477 476
(...skipping 21 matching lines...) Expand all
499 rebase_cmd = ['rebase'] 498 rebase_cmd = ['rebase']
500 if verbose: 499 if verbose:
501 rebase_cmd.append('--verbose') 500 rebase_cmd.append('--verbose')
502 if newbase: 501 if newbase:
503 rebase_cmd.extend(['--onto', newbase]) 502 rebase_cmd.extend(['--onto', newbase])
504 rebase_cmd.append(upstream) 503 rebase_cmd.append(upstream)
505 if branch: 504 if branch:
506 rebase_cmd.append(branch) 505 rebase_cmd.append(branch)
507 506
508 try: 507 try:
509 rebase_output, rebase_err = self.Capture(rebase_cmd, self.checkout_path, 508 rebase_output, rebase_err = scm.GIT.Capture(rebase_cmd,
510 print_error=False) 509 self.checkout_path,
510 print_error=False)
511 except gclient_utils.CheckCallError, e: 511 except gclient_utils.CheckCallError, e:
512 if re.match(r'cannot rebase: you have unstaged changes', e.stderr) or \ 512 if re.match(r'cannot rebase: you have unstaged changes', e.stderr) or \
513 re.match(r'cannot rebase: your index contains uncommitted changes', 513 re.match(r'cannot rebase: your index contains uncommitted changes',
514 e.stderr): 514 e.stderr):
515 while True: 515 while True:
516 rebase_action = str(raw_input("Cannot rebase because of unstaged " 516 rebase_action = str(raw_input("Cannot rebase because of unstaged "
517 "changes.\n'git reset --hard HEAD' ?\n" 517 "changes.\n'git reset --hard HEAD' ?\n"
518 "WARNING: destroys any uncommitted " 518 "WARNING: destroys any uncommitted "
519 "work in your current branch!" 519 "work in your current branch!"
520 " (y)es / (q)uit / (s)how : ")) 520 " (y)es / (q)uit / (s)how : "))
521 if re.match(r'yes|y', rebase_action, re.I): 521 if re.match(r'yes|y', rebase_action, re.I):
522 self._Run(['reset', '--hard', 'HEAD'], redirect_stdout=False) 522 self._Run(['reset', '--hard', 'HEAD'], redirect_stdout=False)
523 # Should this be recursive? 523 # Should this be recursive?
524 rebase_output, rebase_err = self.Capture(rebase_cmd, 524 rebase_output, rebase_err = scm.GIT.Capture(rebase_cmd,
525 self.checkout_path) 525 self.checkout_path)
526 break 526 break
527 elif re.match(r'quit|q', rebase_action, re.I): 527 elif re.match(r'quit|q', rebase_action, re.I):
528 raise gclient_utils.Error("Please merge or rebase manually\n" 528 raise gclient_utils.Error("Please merge or rebase manually\n"
529 "cd %s && git " % self.checkout_path 529 "cd %s && git " % self.checkout_path
530 + "%s" % ' '.join(rebase_cmd)) 530 + "%s" % ' '.join(rebase_cmd))
531 elif re.match(r'show|s', rebase_action, re.I): 531 elif re.match(r'show|s', rebase_action, re.I):
532 print "\n%s" % e.stderr.strip() 532 print "\n%s" % e.stderr.strip()
533 continue 533 continue
534 else: 534 else:
535 gclient_utils.Error("Input not recognized") 535 gclient_utils.Error("Input not recognized")
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
571 571
572 def _Run(self, args, cwd=None, redirect_stdout=True): 572 def _Run(self, args, cwd=None, redirect_stdout=True):
573 # TODO(maruel): Merge with Capture or better gclient_utils.CheckCall(). 573 # TODO(maruel): Merge with Capture or better gclient_utils.CheckCall().
574 if cwd is None: 574 if cwd is None:
575 cwd = self.checkout_path 575 cwd = self.checkout_path
576 stdout = None 576 stdout = None
577 if redirect_stdout: 577 if redirect_stdout:
578 stdout = subprocess.PIPE 578 stdout = subprocess.PIPE
579 if cwd == None: 579 if cwd == None:
580 cwd = self.checkout_path 580 cwd = self.checkout_path
581 cmd = [self.COMMAND] 581 cmd = [scm.GIT.COMMAND]
582 cmd.extend(args) 582 cmd.extend(args)
583 logging.debug(cmd) 583 logging.debug(cmd)
584 try: 584 try:
585 sp = subprocess.Popen(cmd, cwd=cwd, stdout=stdout) 585 sp = subprocess.Popen(cmd, cwd=cwd, stdout=stdout)
586 output = sp.communicate()[0] 586 output = sp.communicate()[0]
587 except OSError: 587 except OSError:
588 raise gclient_utils.Error("git command '%s' failed to run." % 588 raise gclient_utils.Error("git command '%s' failed to run." %
589 ' '.join(cmd) + "\nCheck that you have git installed.") 589 ' '.join(cmd) + "\nCheck that you have git installed.")
590 if sp.returncode: 590 if sp.returncode:
591 raise gclient_utils.Error('git command %s returned %d' % 591 raise gclient_utils.Error('git command %s returned %d' %
592 (args[0], sp.returncode)) 592 (args[0], sp.returncode))
593 if output is not None: 593 if output is not None:
594 return output.strip() 594 return output.strip()
595 595
596 596
597 class SVNWrapper(SCMWrapper, scm.SVN): 597 class SVNWrapper(SCMWrapper):
598 """ Wrapper for SVN """ 598 """ Wrapper for SVN """
599 599
600 def cleanup(self, options, args, file_list): 600 def cleanup(self, options, args, file_list):
601 """Cleanup working copy.""" 601 """Cleanup working copy."""
602 __pychecker__ = 'unusednames=file_list,options' 602 __pychecker__ = 'unusednames=file_list,options'
603 command = ['cleanup'] 603 command = ['cleanup']
604 command.extend(args) 604 command.extend(args)
605 self.Run(command, os.path.join(self._root_dir, self.relpath)) 605 scm.SVN.Run(command, os.path.join(self._root_dir, self.relpath))
606 606
607 def diff(self, options, args, file_list): 607 def diff(self, options, args, file_list):
608 # NOTE: This function does not currently modify file_list. 608 # NOTE: This function does not currently modify file_list.
609 __pychecker__ = 'unusednames=file_list,options' 609 __pychecker__ = 'unusednames=file_list,options'
610 command = ['diff'] 610 command = ['diff']
611 command.extend(args) 611 command.extend(args)
612 self.Run(command, os.path.join(self._root_dir, self.relpath)) 612 scm.SVN.Run(command, os.path.join(self._root_dir, self.relpath))
613 613
614 def export(self, options, args, file_list): 614 def export(self, options, args, file_list):
615 """Export a clean directory tree into the given path.""" 615 """Export a clean directory tree into the given path."""
616 __pychecker__ = 'unusednames=file_list,options' 616 __pychecker__ = 'unusednames=file_list,options'
617 assert len(args) == 1 617 assert len(args) == 1
618 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) 618 export_path = os.path.abspath(os.path.join(args[0], self.relpath))
619 try: 619 try:
620 os.makedirs(export_path) 620 os.makedirs(export_path)
621 except OSError: 621 except OSError:
622 pass 622 pass
623 assert os.path.exists(export_path) 623 assert os.path.exists(export_path)
624 command = ['export', '--force', '.'] 624 command = ['export', '--force', '.']
625 command.append(export_path) 625 command.append(export_path)
626 self.Run(command, os.path.join(self._root_dir, self.relpath)) 626 scm.SVN.Run(command, os.path.join(self._root_dir, self.relpath))
627 627
628 def pack(self, options, args, file_list): 628 def pack(self, options, args, file_list):
629 """Generates a patch file which can be applied to the root of the 629 """Generates a patch file which can be applied to the root of the
630 repository.""" 630 repository."""
631 __pychecker__ = 'unusednames=file_list,options' 631 __pychecker__ = 'unusednames=file_list,options'
632 path = os.path.join(self._root_dir, self.relpath) 632 path = os.path.join(self._root_dir, self.relpath)
633 command = ['diff'] 633 command = ['diff']
634 command.extend(args) 634 command.extend(args)
635 635
636 filterer = DiffFilterer(self.relpath) 636 filterer = DiffFilterer(self.relpath)
637 self.RunAndFilterOutput(command, path, False, False, filterer.Filter) 637 scm.SVN.RunAndFilterOutput(command, path, False, False, filterer.Filter)
638 638
639 def update(self, options, args, file_list): 639 def update(self, options, args, file_list):
640 """Runs svn to update or transparently checkout the working copy. 640 """Runs svn to update or transparently checkout the working copy.
641 641
642 All updated files will be appended to file_list. 642 All updated files will be appended to file_list.
643 643
644 Raises: 644 Raises:
645 Error: if can't get URL for relative path. 645 Error: if can't get URL for relative path.
646 """ 646 """
647 # Only update if git is not controlling the directory. 647 # Only update if git is not controlling the directory.
(...skipping 16 matching lines...) Expand all
664 if revision: 664 if revision:
665 forced_revision = True 665 forced_revision = True
666 url = '%s@%s' % (url, revision) 666 url = '%s@%s' % (url, revision)
667 rev_str = ' at %s' % revision 667 rev_str = ' at %s' % revision
668 668
669 if not os.path.exists(checkout_path): 669 if not os.path.exists(checkout_path):
670 # We need to checkout. 670 # We need to checkout.
671 command = ['checkout', url, checkout_path] 671 command = ['checkout', url, checkout_path]
672 if revision: 672 if revision:
673 command.extend(['--revision', str(revision)]) 673 command.extend(['--revision', str(revision)])
674 self.RunAndGetFileList(options, command, self._root_dir, file_list) 674 scm.SVN.RunAndGetFileList(options, command, self._root_dir, file_list)
675 return 675 return
676 676
677 # Get the existing scm url and the revision number of the current checkout. 677 # Get the existing scm url and the revision number of the current checkout.
678 from_info = self.CaptureInfo(os.path.join(checkout_path, '.'), '.') 678 from_info = scm.SVN.CaptureInfo(os.path.join(checkout_path, '.'), '.')
679 if not from_info: 679 if not from_info:
680 raise gclient_utils.Error("Can't update/checkout %r if an unversioned " 680 raise gclient_utils.Error("Can't update/checkout %r if an unversioned "
681 "directory is present. Delete the directory " 681 "directory is present. Delete the directory "
682 "and try again." % 682 "and try again." %
683 checkout_path) 683 checkout_path)
684 684
685 if options.manually_grab_svn_rev: 685 if options.manually_grab_svn_rev:
686 # Retrieve the current HEAD version because svn is slow at null updates. 686 # Retrieve the current HEAD version because svn is slow at null updates.
687 if not revision: 687 if not revision:
688 from_info_live = self.CaptureInfo(from_info['URL'], '.') 688 from_info_live = scm.SVN.CaptureInfo(from_info['URL'], '.')
689 revision = str(from_info_live['Revision']) 689 revision = str(from_info_live['Revision'])
690 rev_str = ' at %s' % revision 690 rev_str = ' at %s' % revision
691 691
692 if from_info['URL'] != base_url: 692 if from_info['URL'] != base_url:
693 to_info = self.CaptureInfo(url, '.') 693 to_info = scm.SVN.CaptureInfo(url, '.')
694 if not to_info.get('Repository Root') or not to_info.get('UUID'): 694 if not to_info.get('Repository Root') or not to_info.get('UUID'):
695 # The url is invalid or the server is not accessible, it's safer to bail 695 # The url is invalid or the server is not accessible, it's safer to bail
696 # out right now. 696 # out right now.
697 raise gclient_utils.Error('This url is unreachable: %s' % url) 697 raise gclient_utils.Error('This url is unreachable: %s' % url)
698 can_switch = ((from_info['Repository Root'] != to_info['Repository Root']) 698 can_switch = ((from_info['Repository Root'] != to_info['Repository Root'])
699 and (from_info['UUID'] == to_info['UUID'])) 699 and (from_info['UUID'] == to_info['UUID']))
700 if can_switch: 700 if can_switch:
701 print("\n_____ relocating %s to a new checkout" % self.relpath) 701 print("\n_____ relocating %s to a new checkout" % self.relpath)
702 # We have different roots, so check if we can switch --relocate. 702 # We have different roots, so check if we can switch --relocate.
703 # Subversion only permits this if the repository UUIDs match. 703 # Subversion only permits this if the repository UUIDs match.
704 # Perform the switch --relocate, then rewrite the from_url 704 # Perform the switch --relocate, then rewrite the from_url
705 # to reflect where we "are now." (This is the same way that 705 # to reflect where we "are now." (This is the same way that
706 # Subversion itself handles the metadata when switch --relocate 706 # Subversion itself handles the metadata when switch --relocate
707 # is used.) This makes the checks below for whether we 707 # is used.) This makes the checks below for whether we
708 # can update to a revision or have to switch to a different 708 # can update to a revision or have to switch to a different
709 # branch work as expected. 709 # branch work as expected.
710 # TODO(maruel): TEST ME ! 710 # TODO(maruel): TEST ME !
711 command = ["switch", "--relocate", 711 command = ["switch", "--relocate",
712 from_info['Repository Root'], 712 from_info['Repository Root'],
713 to_info['Repository Root'], 713 to_info['Repository Root'],
714 self.relpath] 714 self.relpath]
715 self.Run(command, self._root_dir) 715 scm.SVN.Run(command, self._root_dir)
716 from_info['URL'] = from_info['URL'].replace( 716 from_info['URL'] = from_info['URL'].replace(
717 from_info['Repository Root'], 717 from_info['Repository Root'],
718 to_info['Repository Root']) 718 to_info['Repository Root'])
719 else: 719 else:
720 if self.CaptureStatus(checkout_path): 720 if scm.SVN.CaptureStatus(checkout_path):
721 raise gclient_utils.Error("Can't switch the checkout to %s; UUID " 721 raise gclient_utils.Error("Can't switch the checkout to %s; UUID "
722 "don't match and there is local changes " 722 "don't match and there is local changes "
723 "in %s. Delete the directory and " 723 "in %s. Delete the directory and "
724 "try again." % (url, checkout_path)) 724 "try again." % (url, checkout_path))
725 # Ok delete it. 725 # Ok delete it.
726 print("\n_____ switching %s to a new checkout" % self.relpath) 726 print("\n_____ switching %s to a new checkout" % self.relpath)
727 gclient_utils.RemoveDirectory(checkout_path) 727 gclient_utils.RemoveDirectory(checkout_path)
728 # We need to checkout. 728 # We need to checkout.
729 command = ['checkout', url, checkout_path] 729 command = ['checkout', url, checkout_path]
730 if revision: 730 if revision:
731 command.extend(['--revision', str(revision)]) 731 command.extend(['--revision', str(revision)])
732 self.RunAndGetFileList(options, command, self._root_dir, file_list) 732 scm.SVN.RunAndGetFileList(options, command, self._root_dir, file_list)
733 return 733 return
734 734
735 735
736 # If the provided url has a revision number that matches the revision 736 # If the provided url has a revision number that matches the revision
737 # number of the existing directory, then we don't need to bother updating. 737 # number of the existing directory, then we don't need to bother updating.
738 if not options.force and str(from_info['Revision']) == revision: 738 if not options.force and str(from_info['Revision']) == revision:
739 if options.verbose or not forced_revision: 739 if options.verbose or not forced_revision:
740 print("\n_____ %s%s" % (self.relpath, rev_str)) 740 print("\n_____ %s%s" % (self.relpath, rev_str))
741 return 741 return
742 742
743 command = ["update", checkout_path] 743 command = ["update", checkout_path]
744 if revision: 744 if revision:
745 command.extend(['--revision', str(revision)]) 745 command.extend(['--revision', str(revision)])
746 self.RunAndGetFileList(options, command, self._root_dir, file_list) 746 scm.SVN.RunAndGetFileList(options, command, self._root_dir, file_list)
747 747
748 def revert(self, options, args, file_list): 748 def revert(self, options, args, file_list):
749 """Reverts local modifications. Subversion specific. 749 """Reverts local modifications. Subversion specific.
750 750
751 All reverted files will be appended to file_list, even if Subversion 751 All reverted files will be appended to file_list, even if Subversion
752 doesn't know about them. 752 doesn't know about them.
753 """ 753 """
754 __pychecker__ = 'unusednames=args' 754 __pychecker__ = 'unusednames=args'
755 path = os.path.join(self._root_dir, self.relpath) 755 path = os.path.join(self._root_dir, self.relpath)
756 if not os.path.isdir(path): 756 if not os.path.isdir(path):
757 # svn revert won't work if the directory doesn't exist. It needs to 757 # svn revert won't work if the directory doesn't exist. It needs to
758 # checkout instead. 758 # checkout instead.
759 print("\n_____ %s is missing, synching instead" % self.relpath) 759 print("\n_____ %s is missing, synching instead" % self.relpath)
760 # Don't reuse the args. 760 # Don't reuse the args.
761 return self.update(options, [], file_list) 761 return self.update(options, [], file_list)
762 762
763 for file_status in self.CaptureStatus(path): 763 for file_status in scm.SVN.CaptureStatus(path):
764 file_path = os.path.join(path, file_status[1]) 764 file_path = os.path.join(path, file_status[1])
765 if file_status[0][0] == 'X': 765 if file_status[0][0] == 'X':
766 # Ignore externals. 766 # Ignore externals.
767 logging.info('Ignoring external %s' % file_path) 767 logging.info('Ignoring external %s' % file_path)
768 continue 768 continue
769 769
770 if logging.getLogger().isEnabledFor(logging.INFO): 770 if logging.getLogger().isEnabledFor(logging.INFO):
771 logging.info('%s%s' % (file[0], file[1])) 771 logging.info('%s%s' % (file[0], file[1]))
772 else: 772 else:
773 print(file_path) 773 print(file_path)
(...skipping 14 matching lines...) Expand all
788 gclient_utils.RemoveDirectory(file_path) 788 gclient_utils.RemoveDirectory(file_path)
789 else: 789 else:
790 logging.error('no idea what is %s.\nYou just found a bug in gclient' 790 logging.error('no idea what is %s.\nYou just found a bug in gclient'
791 ', please ping maruel@chromium.org ASAP!' % file_path) 791 ', please ping maruel@chromium.org ASAP!' % file_path)
792 except EnvironmentError: 792 except EnvironmentError:
793 logging.error('Failed to remove %s.' % file_path) 793 logging.error('Failed to remove %s.' % file_path)
794 794
795 try: 795 try:
796 # svn revert is so broken we don't even use it. Using 796 # svn revert is so broken we don't even use it. Using
797 # "svn up --revision BASE" achieve the same effect. 797 # "svn up --revision BASE" achieve the same effect.
798 self.RunAndGetFileList(options, ['update', '--revision', 'BASE'], path, 798 scm.SVN.RunAndGetFileList(options, ['update', '--revision', 'BASE'], path,
799 file_list) 799 file_list)
800 except OSError, e: 800 except OSError, e:
801 # Maybe the directory disapeared meanwhile. We don't want it to throw an 801 # Maybe the directory disapeared meanwhile. We don't want it to throw an
802 # exception. 802 # exception.
803 logging.error('Failed to update:\n%s' % str(e)) 803 logging.error('Failed to update:\n%s' % str(e))
804 804
805 def revinfo(self, options, args, file_list): 805 def revinfo(self, options, args, file_list):
806 """Display revision""" 806 """Display revision"""
807 __pychecker__ = 'unusednames=args,file_list,options' 807 __pychecker__ = 'unusednames=args,file_list,options'
808 return self.CaptureHeadRevision(self.url) 808 return scm.SVN.CaptureHeadRevision(self.url)
809 809
810 def runhooks(self, options, args, file_list): 810 def runhooks(self, options, args, file_list):
811 self.status(options, args, file_list) 811 self.status(options, args, file_list)
812 812
813 def status(self, options, args, file_list): 813 def status(self, options, args, file_list):
814 """Display status information.""" 814 """Display status information."""
815 path = os.path.join(self._root_dir, self.relpath) 815 path = os.path.join(self._root_dir, self.relpath)
816 command = ['status'] 816 command = ['status']
817 command.extend(args) 817 command.extend(args)
818 if not os.path.isdir(path): 818 if not os.path.isdir(path):
819 # svn status won't work if the directory doesn't exist. 819 # svn status won't work if the directory doesn't exist.
820 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory " 820 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory "
821 "does not exist." 821 "does not exist."
822 % (' '.join(command), path)) 822 % (' '.join(command), path))
823 # There's no file list to retrieve. 823 # There's no file list to retrieve.
824 else: 824 else:
825 self.RunAndGetFileList(options, command, path, file_list) 825 scm.SVN.RunAndGetFileList(options, command, path, file_list)
826 826
827 def FullUrlForRelativeUrl(self, url): 827 def FullUrlForRelativeUrl(self, url):
828 # Find the forth '/' and strip from there. A bit hackish. 828 # Find the forth '/' and strip from there. A bit hackish.
829 return '/'.join(self.url.split('/')[:4]) + url 829 return '/'.join(self.url.split('/')[:4]) + url
OLDNEW
« gclient.py ('K') | « gclient.py ('k') | scm.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698