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

Side by Side Diff: gclient_scm.py

Issue 3420014: Remove cruft from having to do bookeeping of options.stdout. (Closed)
Patch Set: Created 10 years, 3 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
« no previous file with comments | « gclient.py ('k') | gclient_utils.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) 2010 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2010 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 sys 11 import sys
12 import time 12 import time
13 13
14 import scm 14 import scm
15 import gclient_utils 15 import gclient_utils
16 16
17 17
18 class DiffFilterer(object): 18 class DiffFilterer(object):
19 """Simple class which tracks which file is being diffed and 19 """Simple class which tracks which file is being diffed and
20 replaces instances of its file name in the original and 20 replaces instances of its file name in the original and
21 working copy lines of the svn/git diff output.""" 21 working copy lines of the svn/git diff output."""
22 index_string = "Index: " 22 index_string = "Index: "
23 original_prefix = "--- " 23 original_prefix = "--- "
24 working_prefix = "+++ " 24 working_prefix = "+++ "
25 25
26 def __init__(self, relpath, stdout): 26 def __init__(self, relpath):
27 # Note that we always use '/' as the path separator to be 27 # Note that we always use '/' as the path separator to be
28 # consistent with svn's cygwin-style output on Windows 28 # consistent with svn's cygwin-style output on Windows
29 self._relpath = relpath.replace("\\", "/") 29 self._relpath = relpath.replace("\\", "/")
30 self._current_file = "" 30 self._current_file = ""
31 self._replacement_file = "" 31 self._replacement_file = ""
32 self._stdout = stdout
33 32
34 def SetCurrentFile(self, current_file): 33 def SetCurrentFile(self, current_file):
35 self._current_file = current_file 34 self._current_file = current_file
36 # Note that we always use '/' as the path separator to be 35 # Note that we always use '/' as the path separator to be
37 # consistent with svn's cygwin-style output on Windows 36 # consistent with svn's cygwin-style output on Windows
38 self._replacement_file = posixpath.join(self._relpath, current_file) 37 self._replacement_file = posixpath.join(self._relpath, current_file)
39 38
40 def _Replace(self, line): 39 def _Replace(self, line):
41 return line.replace(self._current_file, self._replacement_file) 40 return line.replace(self._current_file, self._replacement_file)
42 41
43 def Filter(self, line): 42 def Filter(self, line):
44 if (line.startswith(self.index_string)): 43 if (line.startswith(self.index_string)):
45 self.SetCurrentFile(line[len(self.index_string):]) 44 self.SetCurrentFile(line[len(self.index_string):])
46 line = self._Replace(line) 45 line = self._Replace(line)
47 else: 46 else:
48 if (line.startswith(self.original_prefix) or 47 if (line.startswith(self.original_prefix) or
49 line.startswith(self.working_prefix)): 48 line.startswith(self.working_prefix)):
50 line = self._Replace(line) 49 line = self._Replace(line)
51 self._stdout.write(line + '\n') 50 print(line)
52 51
53 52
54 ### SCM abstraction layer 53 ### SCM abstraction layer
55 54
56 # Factory Method for SCM wrapper creation 55 # Factory Method for SCM wrapper creation
57 56
58 def GetScmName(url): 57 def GetScmName(url):
59 if url: 58 if url:
60 url, _ = gclient_utils.SplitUrlRevision(url) 59 url, _ = gclient_utils.SplitUrlRevision(url)
61 if (url.startswith('git://') or url.startswith('ssh://') or 60 if (url.startswith('git://') or url.startswith('ssh://') or
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 """Generates a patch file which can be applied to the root of the 145 """Generates a patch file which can be applied to the root of the
147 repository. 146 repository.
148 147
149 The patch file is generated from a diff of the merge base of HEAD and 148 The patch file is generated from a diff of the merge base of HEAD and
150 its upstream branch. 149 its upstream branch.
151 """ 150 """
152 merge_base = self._Capture(['merge-base', 'HEAD', 'origin']) 151 merge_base = self._Capture(['merge-base', 'HEAD', 'origin'])
153 gclient_utils.CheckCallAndFilter( 152 gclient_utils.CheckCallAndFilter(
154 ['git', 'diff', merge_base], 153 ['git', 'diff', merge_base],
155 cwd=self.checkout_path, 154 cwd=self.checkout_path,
156 filter_fn=DiffFilterer(self.relpath, options.stdout).Filter, 155 filter_fn=DiffFilterer(self.relpath).Filter)
157 stdout=options.stdout)
158 156
159 def update(self, options, args, file_list): 157 def update(self, options, args, file_list):
160 """Runs git to update or transparently checkout the working copy. 158 """Runs git to update or transparently checkout the working copy.
161 159
162 All updated files will be appended to file_list. 160 All updated files will be appended to file_list.
163 161
164 Raises: 162 Raises:
165 Error: if can't get URL for relative path. 163 Error: if can't get URL for relative path.
166 """ 164 """
167 if args: 165 if args:
(...skipping 10 matching lines...) Expand all
178 revision = str(options.revision) 176 revision = str(options.revision)
179 if not revision: 177 if not revision:
180 revision = default_rev 178 revision = default_rev
181 179
182 rev_str = ' at %s' % revision 180 rev_str = ' at %s' % revision
183 files = [] 181 files = []
184 182
185 printed_path = False 183 printed_path = False
186 verbose = [] 184 verbose = []
187 if options.verbose: 185 if options.verbose:
188 options.stdout.write("\n_____ %s%s\n" % (self.relpath, rev_str)) 186 print('\n_____ %s%s' % (self.relpath, rev_str))
189 verbose = ['--verbose'] 187 verbose = ['--verbose']
190 printed_path = True 188 printed_path = True
191 189
192 if revision.startswith('refs/heads/'): 190 if revision.startswith('refs/heads/'):
193 rev_type = "branch" 191 rev_type = "branch"
194 elif revision.startswith('origin/'): 192 elif revision.startswith('origin/'):
195 # For compatability with old naming, translate 'origin' to 'refs/heads' 193 # For compatability with old naming, translate 'origin' to 'refs/heads'
196 revision = revision.replace('origin/', 'refs/heads/') 194 revision = revision.replace('origin/', 'refs/heads/')
197 rev_type = "branch" 195 rev_type = "branch"
198 else: 196 else:
199 # hash is also a tag, only make a distinction at checkout 197 # hash is also a tag, only make a distinction at checkout
200 rev_type = "hash" 198 rev_type = "hash"
201 199
202 if not os.path.exists(self.checkout_path): 200 if not os.path.exists(self.checkout_path):
203 self._Clone(revision, url, options) 201 self._Clone(revision, url, options)
204 files = self._Capture(['ls-files']).split() 202 files = self._Capture(['ls-files']).split()
205 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])
206 if not verbose: 204 if not verbose:
207 # Make the output a little prettier. It's nice to have some whitespace 205 # Make the output a little prettier. It's nice to have some whitespace
208 # between projects when cloning. 206 # between projects when cloning.
209 options.stdout.write('\n') 207 print('')
210 return 208 return
211 209
212 if not os.path.exists(os.path.join(self.checkout_path, '.git')): 210 if not os.path.exists(os.path.join(self.checkout_path, '.git')):
213 raise gclient_utils.Error('\n____ %s%s\n' 211 raise gclient_utils.Error('\n____ %s%s\n'
214 '\tPath is not a git repo. No .git dir.\n' 212 '\tPath is not a git repo. No .git dir.\n'
215 '\tTo resolve:\n' 213 '\tTo resolve:\n'
216 '\t\trm -rf %s\n' 214 '\t\trm -rf %s\n'
217 '\tAnd run gclient sync again\n' 215 '\tAnd run gclient sync again\n'
218 % (self.relpath, rev_str, self.relpath)) 216 % (self.relpath, rev_str, self.relpath))
219 217
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 for _ in range(10): 257 for _ in range(10):
260 try: 258 try:
261 remote_output = scm.GIT.Capture( 259 remote_output = scm.GIT.Capture(
262 ['remote'] + verbose + ['update'], 260 ['remote'] + verbose + ['update'],
263 cwd=self.checkout_path) 261 cwd=self.checkout_path)
264 break 262 break
265 except gclient_utils.CheckCallError, e: 263 except gclient_utils.CheckCallError, e:
266 # Hackish but at that point, git is known to work so just checking for 264 # Hackish but at that point, git is known to work so just checking for
267 # 502 in stderr should be fine. 265 # 502 in stderr should be fine.
268 if '502' in e.stderr: 266 if '502' in e.stderr:
269 options.stdout.write(str(e) + '\n') 267 print(str(e))
270 options.stdout.write('Sleeping %.1f seconds and retrying...\n' % 268 print('Sleeping %.1f seconds and retrying...' % backoff_time)
271 backoff_time)
272 time.sleep(backoff_time) 269 time.sleep(backoff_time)
273 backoff_time *= 1.3 270 backoff_time *= 1.3
274 continue 271 continue
275 raise 272 raise
276 273
277 if verbose: 274 if verbose:
278 options.stdout.write(remote_output) 275 print(remote_output.strip())
279 276
280 # This is a big hammer, debatable if it should even be here... 277 # This is a big hammer, debatable if it should even be here...
281 if options.force or options.reset: 278 if options.force or options.reset:
282 self._Run(['reset', '--hard', 'HEAD'], options) 279 self._Run(['reset', '--hard', 'HEAD'], options)
283 280
284 if current_type == 'detached': 281 if current_type == 'detached':
285 # case 0 282 # case 0
286 self._CheckClean(rev_str) 283 self._CheckClean(rev_str)
287 self._CheckDetachedHead(rev_str, options) 284 self._CheckDetachedHead(rev_str, options)
288 self._Capture(['checkout', '--quiet', '%s^0' % revision]) 285 self._Capture(['checkout', '--quiet', '%s^0' % revision])
289 if not printed_path: 286 if not printed_path:
290 options.stdout.write('\n_____ %s%s\n' % (self.relpath, rev_str)) 287 print('\n_____ %s%s' % (self.relpath, rev_str))
291 elif current_type == 'hash': 288 elif current_type == 'hash':
292 # case 1 289 # case 1
293 if scm.GIT.IsGitSvn(self.checkout_path) and upstream_branch is not None: 290 if scm.GIT.IsGitSvn(self.checkout_path) and upstream_branch is not None:
294 # Our git-svn branch (upstream_branch) is our upstream 291 # Our git-svn branch (upstream_branch) is our upstream
295 self._AttemptRebase(upstream_branch, files, options, 292 self._AttemptRebase(upstream_branch, files, options,
296 newbase=revision, printed_path=printed_path) 293 newbase=revision, printed_path=printed_path)
297 printed_path = True 294 printed_path = True
298 else: 295 else:
299 # Can't find a merge-base since we don't know our upstream. That makes 296 # Can't find a merge-base since we don't know our upstream. That makes
300 # this command VERY likely to produce a rebase failure. For now we 297 # this command VERY likely to produce a rebase failure. For now we
301 # assume origin is our upstream since that's what the old behavior was. 298 # assume origin is our upstream since that's what the old behavior was.
302 upstream_branch = 'origin' 299 upstream_branch = 'origin'
303 if options.revision or deps_revision: 300 if options.revision or deps_revision:
304 upstream_branch = revision 301 upstream_branch = revision
305 self._AttemptRebase(upstream_branch, files, options, 302 self._AttemptRebase(upstream_branch, files, options,
306 printed_path=printed_path) 303 printed_path=printed_path)
307 printed_path = True 304 printed_path = True
308 elif rev_type == 'hash': 305 elif rev_type == 'hash':
309 # case 2 306 # case 2
310 self._AttemptRebase(upstream_branch, files, options, 307 self._AttemptRebase(upstream_branch, files, options,
311 newbase=revision, printed_path=printed_path) 308 newbase=revision, printed_path=printed_path)
312 printed_path = True 309 printed_path = True
313 elif revision.replace('heads', 'remotes/origin') != upstream_branch: 310 elif revision.replace('heads', 'remotes/origin') != upstream_branch:
314 # case 4 311 # case 4
315 new_base = revision.replace('heads', 'remotes/origin') 312 new_base = revision.replace('heads', 'remotes/origin')
316 if not printed_path: 313 if not printed_path:
317 options.stdout.write('\n_____ %s%s\n' % (self.relpath, rev_str)) 314 print('\n_____ %s%s' % (self.relpath, rev_str))
318 switch_error = ("Switching upstream branch from %s to %s\n" 315 switch_error = ("Switching upstream branch from %s to %s\n"
319 % (upstream_branch, new_base) + 316 % (upstream_branch, new_base) +
320 "Please merge or rebase manually:\n" + 317 "Please merge or rebase manually:\n" +
321 "cd %s; git rebase %s\n" % (self.checkout_path, new_base) + 318 "cd %s; git rebase %s\n" % (self.checkout_path, new_base) +
322 "OR git checkout -b <some new branch> %s" % new_base) 319 "OR git checkout -b <some new branch> %s" % new_base)
323 raise gclient_utils.Error(switch_error) 320 raise gclient_utils.Error(switch_error)
324 else: 321 else:
325 # case 3 - the default case 322 # case 3 - the default case
326 files = self._Capture(['diff', upstream_branch, '--name-only']).split() 323 files = self._Capture(['diff', upstream_branch, '--name-only']).split()
327 if verbose: 324 if verbose:
328 options.stdout.write('Trying fast-forward merge to branch : %s\n' % 325 print('Trying fast-forward merge to branch : %s' % upstream_branch)
329 upstream_branch)
330 try: 326 try:
331 merge_output = scm.GIT.Capture(['merge', '--ff-only', upstream_branch], 327 merge_output = scm.GIT.Capture(['merge', '--ff-only', upstream_branch],
332 cwd=self.checkout_path) 328 cwd=self.checkout_path)
333 except gclient_utils.CheckCallError, e: 329 except gclient_utils.CheckCallError, e:
334 if re.match('fatal: Not possible to fast-forward, aborting.', e.stderr): 330 if re.match('fatal: Not possible to fast-forward, aborting.', e.stderr):
335 if not printed_path: 331 if not printed_path:
336 options.stdout.write('\n_____ %s%s\n' % (self.relpath, rev_str)) 332 print('\n_____ %s%s' % (self.relpath, rev_str))
337 printed_path = True 333 printed_path = True
338 while True: 334 while True:
339 try: 335 try:
340 # TODO(maruel): That can't work with --jobs. 336 # TODO(maruel): That can't work with --jobs.
341 action = str(raw_input("Cannot fast-forward merge, attempt to " 337 action = str(raw_input("Cannot fast-forward merge, attempt to "
342 "rebase? (y)es / (q)uit / (s)kip : ")) 338 "rebase? (y)es / (q)uit / (s)kip : "))
343 except ValueError: 339 except ValueError:
344 gclient_utils.Error('Invalid Character') 340 gclient_utils.Error('Invalid Character')
345 continue 341 continue
346 if re.match(r'yes|y', action, re.I): 342 if re.match(r'yes|y', action, re.I):
347 self._AttemptRebase(upstream_branch, files, options, 343 self._AttemptRebase(upstream_branch, files, options,
348 printed_path=printed_path) 344 printed_path=printed_path)
349 printed_path = True 345 printed_path = True
350 break 346 break
351 elif re.match(r'quit|q', action, re.I): 347 elif re.match(r'quit|q', action, re.I):
352 raise gclient_utils.Error("Can't fast-forward, please merge or " 348 raise gclient_utils.Error("Can't fast-forward, please merge or "
353 "rebase manually.\n" 349 "rebase manually.\n"
354 "cd %s && git " % self.checkout_path 350 "cd %s && git " % self.checkout_path
355 + "rebase %s" % upstream_branch) 351 + "rebase %s" % upstream_branch)
356 elif re.match(r'skip|s', action, re.I): 352 elif re.match(r'skip|s', action, re.I):
357 options.stdout.write('Skipping %s\n' % self.relpath) 353 print('Skipping %s' % self.relpath)
358 return 354 return
359 else: 355 else:
360 options.stdout.write('Input not recognized\n') 356 print('Input not recognized')
361 elif re.match("error: Your local changes to '.*' would be " 357 elif re.match("error: Your local changes to '.*' would be "
362 "overwritten by merge. Aborting.\nPlease, commit your " 358 "overwritten by merge. Aborting.\nPlease, commit your "
363 "changes or stash them before you can merge.\n", 359 "changes or stash them before you can merge.\n",
364 e.stderr): 360 e.stderr):
365 if not printed_path: 361 if not printed_path:
366 options.stdout.write('\n_____ %s%s\n' % (self.relpath, rev_str)) 362 print('\n_____ %s%s' % (self.relpath, rev_str))
367 printed_path = True 363 printed_path = True
368 raise gclient_utils.Error(e.stderr) 364 raise gclient_utils.Error(e.stderr)
369 else: 365 else:
370 # Some other problem happened with the merge 366 # Some other problem happened with the merge
371 logging.error("Error during fast-forward merge in %s!" % self.relpath) 367 logging.error("Error during fast-forward merge in %s!" % self.relpath)
372 options.stdout.write(e.stderr + '\n') 368 print(e.stderr)
373 raise 369 raise
374 else: 370 else:
375 # Fast-forward merge was successful 371 # Fast-forward merge was successful
376 if not re.match('Already up-to-date.', merge_output) or verbose: 372 if not re.match('Already up-to-date.', merge_output) or verbose:
377 if not printed_path: 373 if not printed_path:
378 options.stdout.write('\n_____ %s%s\n' % (self.relpath, rev_str)) 374 print('\n_____ %s%s' % (self.relpath, rev_str))
379 printed_path = True 375 printed_path = True
380 options.stdout.write(merge_output) 376 print(merge_output.strip())
381 if not verbose: 377 if not verbose:
382 # Make the output a little prettier. It's nice to have some 378 # Make the output a little prettier. It's nice to have some
383 # whitespace between projects when syncing. 379 # whitespace between projects when syncing.
384 options.stdout.write('\n') 380 print('')
385 381
386 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) 382 file_list.extend([os.path.join(self.checkout_path, f) for f in files])
387 383
388 # If the rebase generated a conflict, abort and ask user to fix 384 # If the rebase generated a conflict, abort and ask user to fix
389 if self._IsRebasing(): 385 if self._IsRebasing():
390 raise gclient_utils.Error('\n____ %s%s\n' 386 raise gclient_utils.Error('\n____ %s%s\n'
391 '\nConflict while rebasing this branch.\n' 387 '\nConflict while rebasing this branch.\n'
392 'Fix the conflict and run gclient again.\n' 388 'Fix the conflict and run gclient again.\n'
393 'See man git-rebase for details.\n' 389 'See man git-rebase for details.\n'
394 % (self.relpath, rev_str)) 390 % (self.relpath, rev_str))
395 391
396 if verbose: 392 if verbose:
397 options.stdout.write('Checked out revision %s\n' % 393 print('Checked out revision %s' % self.revinfo(options, (), None))
398 self.revinfo(options, (), None))
399 394
400 def revert(self, options, args, file_list): 395 def revert(self, options, args, file_list):
401 """Reverts local modifications. 396 """Reverts local modifications.
402 397
403 All reverted files will be appended to file_list. 398 All reverted files will be appended to file_list.
404 """ 399 """
405 if not os.path.isdir(self.checkout_path): 400 if not os.path.isdir(self.checkout_path):
406 # revert won't work if the directory doesn't exist. It needs to 401 # revert won't work if the directory doesn't exist. It needs to
407 # checkout instead. 402 # checkout instead.
408 options.stdout.write('\n_____ %s is missing, synching instead\n' % 403 print('\n_____ %s is missing, synching instead' % self.relpath)
409 self.relpath)
410 # Don't reuse the args. 404 # Don't reuse the args.
411 return self.update(options, [], file_list) 405 return self.update(options, [], file_list)
412 406
413 default_rev = "refs/heads/master" 407 default_rev = "refs/heads/master"
414 _, deps_revision = gclient_utils.SplitUrlRevision(self.url) 408 _, deps_revision = gclient_utils.SplitUrlRevision(self.url)
415 if not deps_revision: 409 if not deps_revision:
416 deps_revision = default_rev 410 deps_revision = default_rev
417 if deps_revision.startswith('refs/heads/'): 411 if deps_revision.startswith('refs/heads/'):
418 deps_revision = deps_revision.replace('refs/heads/', 'origin/') 412 deps_revision = deps_revision.replace('refs/heads/', 'origin/')
419 413
420 files = self._Capture(['diff', deps_revision, '--name-only']).split() 414 files = self._Capture(['diff', deps_revision, '--name-only']).split()
421 self._Run(['reset', '--hard', deps_revision], options) 415 self._Run(['reset', '--hard', deps_revision], options)
422 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) 416 file_list.extend([os.path.join(self.checkout_path, f) for f in files])
423 417
424 def revinfo(self, options, args, file_list): 418 def revinfo(self, options, args, file_list):
425 """Returns revision""" 419 """Returns revision"""
426 return self._Capture(['rev-parse', 'HEAD']) 420 return self._Capture(['rev-parse', 'HEAD'])
427 421
428 def runhooks(self, options, args, file_list): 422 def runhooks(self, options, args, file_list):
429 self.status(options, args, file_list) 423 self.status(options, args, file_list)
430 424
431 def status(self, options, args, file_list): 425 def status(self, options, args, file_list):
432 """Display status information.""" 426 """Display status information."""
433 if not os.path.isdir(self.checkout_path): 427 if not os.path.isdir(self.checkout_path):
434 options.stdout.write( 428 print(('\n________ couldn\'t run status in %s:\n'
435 ('\n________ couldn\'t run status in %s:\nThe directory ' 429 'The directory does not exist.') % self.checkout_path)
436 'does not exist.\n') % self.checkout_path)
437 else: 430 else:
438 merge_base = self._Capture(['merge-base', 'HEAD', 'origin']) 431 merge_base = self._Capture(['merge-base', 'HEAD', 'origin'])
439 self._Run(['diff', '--name-status', merge_base], options) 432 self._Run(['diff', '--name-status', merge_base], options)
440 files = self._Capture(['diff', '--name-only', merge_base]).split() 433 files = self._Capture(['diff', '--name-only', merge_base]).split()
441 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) 434 file_list.extend([os.path.join(self.checkout_path, f) for f in files])
442 435
443 def FullUrlForRelativeUrl(self, url): 436 def FullUrlForRelativeUrl(self, url):
444 # Strip from last '/' 437 # Strip from last '/'
445 # Equivalent to unix basename 438 # Equivalent to unix basename
446 base_url = self.url 439 base_url = self.url
447 return base_url[:base_url.rfind('/')] + url 440 return base_url[:base_url.rfind('/')] + url
448 441
449 def _Clone(self, revision, url, options): 442 def _Clone(self, revision, url, options):
450 """Clone a git repository from the given URL. 443 """Clone a git repository from the given URL.
451 444
452 Once we've cloned the repo, we checkout a working branch if the specified 445 Once we've cloned the repo, we checkout a working branch if the specified
453 revision is a branch head. If it is a tag or a specific commit, then we 446 revision is a branch head. If it is a tag or a specific commit, then we
454 leave HEAD detached as it makes future updates simpler -- in this case the 447 leave HEAD detached as it makes future updates simpler -- in this case the
455 user should first create a new branch or switch to an existing branch before 448 user should first create a new branch or switch to an existing branch before
456 making changes in the repo.""" 449 making changes in the repo."""
457 if not options.verbose: 450 if not options.verbose:
458 # git clone doesn't seem to insert a newline properly before printing 451 # git clone doesn't seem to insert a newline properly before printing
459 # to stdout 452 # to stdout
460 options.stdout.write('\n') 453 print('')
461 454
462 clone_cmd = ['clone'] 455 clone_cmd = ['clone']
463 if revision.startswith('refs/heads/'): 456 if revision.startswith('refs/heads/'):
464 clone_cmd.extend(['-b', revision.replace('refs/heads/', '')]) 457 clone_cmd.extend(['-b', revision.replace('refs/heads/', '')])
465 detach_head = False 458 detach_head = False
466 else: 459 else:
467 clone_cmd.append('--no-checkout') 460 clone_cmd.append('--no-checkout')
468 detach_head = True 461 detach_head = True
469 if options.verbose: 462 if options.verbose:
470 clone_cmd.append('--verbose') 463 clone_cmd.append('--verbose')
471 clone_cmd.extend([url, self.checkout_path]) 464 clone_cmd.extend([url, self.checkout_path])
472 465
473 for _ in range(3): 466 for _ in range(3):
474 try: 467 try:
475 self._Run(clone_cmd, options, cwd=self._root_dir) 468 self._Run(clone_cmd, options, cwd=self._root_dir)
476 break 469 break
477 except gclient_utils.Error, e: 470 except gclient_utils.Error, e:
478 # TODO(maruel): Hackish, should be fixed by moving _Run() to 471 # TODO(maruel): Hackish, should be fixed by moving _Run() to
479 # CheckCall(). 472 # CheckCall().
480 # Too bad we don't have access to the actual output. 473 # Too bad we don't have access to the actual output.
481 # We should check for "transfer closed with NNN bytes remaining to 474 # We should check for "transfer closed with NNN bytes remaining to
482 # read". In the meantime, just make sure .git exists. 475 # read". In the meantime, just make sure .git exists.
483 if (e.args[0] == 'git command clone returned 128' and 476 if (e.args[0] == 'git command clone returned 128' and
484 os.path.exists(os.path.join(self.checkout_path, '.git'))): 477 os.path.exists(os.path.join(self.checkout_path, '.git'))):
485 options.stdout.write(str(e) + '\n') 478 print(str(e))
486 options.stdout.write('Retrying...\n') 479 print('Retrying...')
487 continue 480 continue
488 raise e 481 raise e
489 482
490 if detach_head: 483 if detach_head:
491 # Squelch git's very verbose detached HEAD warning and use our own 484 # Squelch git's very verbose detached HEAD warning and use our own
492 self._Capture(['checkout', '--quiet', '%s^0' % revision]) 485 self._Capture(['checkout', '--quiet', '%s^0' % revision])
493 options.stdout.write( 486 print(
494 ('Checked out %s to a detached HEAD. Before making any commits\n' 487 ('Checked out %s to a detached HEAD. Before making any commits\n'
495 'in this repo, you should use \'git checkout <branch>\' to switch to\n' 488 'in this repo, you should use \'git checkout <branch>\' to switch to\n'
496 'an existing branch or use \'git checkout origin -b <branch>\' to\n' 489 'an existing branch or use \'git checkout origin -b <branch>\' to\n'
497 'create a new branch for your work.') % revision) 490 'create a new branch for your work.') % revision)
498 491
499 def _AttemptRebase(self, upstream, files, options, newbase=None, 492 def _AttemptRebase(self, upstream, files, options, newbase=None,
500 branch=None, printed_path=False): 493 branch=None, printed_path=False):
501 """Attempt to rebase onto either upstream or, if specified, newbase.""" 494 """Attempt to rebase onto either upstream or, if specified, newbase."""
502 files.extend(self._Capture(['diff', upstream, '--name-only']).split()) 495 files.extend(self._Capture(['diff', upstream, '--name-only']).split())
503 revision = upstream 496 revision = upstream
504 if newbase: 497 if newbase:
505 revision = newbase 498 revision = newbase
506 if not printed_path: 499 if not printed_path:
507 options.stdout.write('\n_____ %s : Attempting rebase onto %s...\n' % ( 500 print('\n_____ %s : Attempting rebase onto %s...' % (
508 self.relpath, revision)) 501 self.relpath, revision))
509 printed_path = True 502 printed_path = True
510 else: 503 else:
511 options.stdout.write('Attempting rebase onto %s...\n' % revision) 504 print('Attempting rebase onto %s...' % revision)
512 505
513 # Build the rebase command here using the args 506 # Build the rebase command here using the args
514 # git rebase [options] [--onto <newbase>] <upstream> [<branch>] 507 # git rebase [options] [--onto <newbase>] <upstream> [<branch>]
515 rebase_cmd = ['rebase'] 508 rebase_cmd = ['rebase']
516 if options.verbose: 509 if options.verbose:
517 rebase_cmd.append('--verbose') 510 rebase_cmd.append('--verbose')
518 if newbase: 511 if newbase:
519 rebase_cmd.extend(['--onto', newbase]) 512 rebase_cmd.extend(['--onto', newbase])
520 rebase_cmd.append(upstream) 513 rebase_cmd.append(upstream)
521 if branch: 514 if branch:
(...skipping 14 matching lines...) Expand all
536 if re.match(r'yes|y', rebase_action, re.I): 529 if re.match(r'yes|y', rebase_action, re.I):
537 self._Run(['reset', '--hard', 'HEAD'], options) 530 self._Run(['reset', '--hard', 'HEAD'], options)
538 # Should this be recursive? 531 # Should this be recursive?
539 rebase_output = scm.GIT.Capture(rebase_cmd, cwd=self.checkout_path) 532 rebase_output = scm.GIT.Capture(rebase_cmd, cwd=self.checkout_path)
540 break 533 break
541 elif re.match(r'quit|q', rebase_action, re.I): 534 elif re.match(r'quit|q', rebase_action, re.I):
542 raise gclient_utils.Error("Please merge or rebase manually\n" 535 raise gclient_utils.Error("Please merge or rebase manually\n"
543 "cd %s && git " % self.checkout_path 536 "cd %s && git " % self.checkout_path
544 + "%s" % ' '.join(rebase_cmd)) 537 + "%s" % ' '.join(rebase_cmd))
545 elif re.match(r'show|s', rebase_action, re.I): 538 elif re.match(r'show|s', rebase_action, re.I):
546 options.stdout.write('\n%s\n' % e.stderr.strip()) 539 print('\n%s' % e.stderr.strip())
547 continue 540 continue
548 else: 541 else:
549 gclient_utils.Error("Input not recognized") 542 gclient_utils.Error("Input not recognized")
550 continue 543 continue
551 elif re.search(r'^CONFLICT', e.stdout, re.M): 544 elif re.search(r'^CONFLICT', e.stdout, re.M):
552 raise gclient_utils.Error("Conflict while rebasing this branch.\n" 545 raise gclient_utils.Error("Conflict while rebasing this branch.\n"
553 "Fix the conflict and run gclient again.\n" 546 "Fix the conflict and run gclient again.\n"
554 "See 'man git-rebase' for details.\n") 547 "See 'man git-rebase' for details.\n")
555 else: 548 else:
556 options.stdout.write(e.stdout.strip() + '\n') 549 print(e.stdout.strip())
557 options.stdout.write('Rebase produced error output:\n%s\n' % 550 print('Rebase produced error output:\n%s' % e.stderr.strip())
558 e.stderr.strip())
559 raise gclient_utils.Error("Unrecognized error, please merge or rebase " 551 raise gclient_utils.Error("Unrecognized error, please merge or rebase "
560 "manually.\ncd %s && git " % 552 "manually.\ncd %s && git " %
561 self.checkout_path 553 self.checkout_path
562 + "%s" % ' '.join(rebase_cmd)) 554 + "%s" % ' '.join(rebase_cmd))
563 555
564 options.stdout.write(rebase_output) 556 print(rebase_output.strip())
565 if not options.verbose: 557 if not options.verbose:
566 # Make the output a little prettier. It's nice to have some 558 # Make the output a little prettier. It's nice to have some
567 # whitespace between projects when syncing. 559 # whitespace between projects when syncing.
568 options.stdout.write('\n') 560 print('')
569 561
570 @staticmethod 562 @staticmethod
571 def _CheckMinVersion(min_version): 563 def _CheckMinVersion(min_version):
572 (ok, current_version) = scm.GIT.AssertVersion(min_version) 564 (ok, current_version) = scm.GIT.AssertVersion(min_version)
573 if not ok: 565 if not ok:
574 raise gclient_utils.Error('git version %s < minimum required %s' % 566 raise gclient_utils.Error('git version %s < minimum required %s' %
575 (current_version, min_version)) 567 (current_version, min_version))
576 568
577 def _IsRebasing(self): 569 def _IsRebasing(self):
578 # Check for any of REBASE-i/REBASE-m/REBASE/AM. Unfortunately git doesn't 570 # Check for any of REBASE-i/REBASE-m/REBASE/AM. Unfortunately git doesn't
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
617 raise gclient_utils.Error('\n____ %s%s\n' 609 raise gclient_utils.Error('\n____ %s%s\n'
618 '\tAlready in a conflict, i.e. (no branch).\n' 610 '\tAlready in a conflict, i.e. (no branch).\n'
619 '\tFix the conflict and run gclient again.\n' 611 '\tFix the conflict and run gclient again.\n'
620 '\tOr to abort run:\n\t\tgit-rebase --abort\n' 612 '\tOr to abort run:\n\t\tgit-rebase --abort\n'
621 '\tSee man git-rebase for details.\n' 613 '\tSee man git-rebase for details.\n'
622 % (self.relpath, rev_str)) 614 % (self.relpath, rev_str))
623 # Let's just save off the commit so we can proceed. 615 # Let's just save off the commit so we can proceed.
624 name = ('saved-by-gclient-' + 616 name = ('saved-by-gclient-' +
625 self._Capture(['rev-parse', '--short', 'HEAD'])) 617 self._Capture(['rev-parse', '--short', 'HEAD']))
626 self._Capture(['branch', name]) 618 self._Capture(['branch', name])
627 options.stdout.write( 619 print('\n_____ found an unreferenced commit and saved it as \'%s\'' %
628 '\n_____ found an unreferenced commit and saved it as \'%s\'\n' %
629 name) 620 name)
630 621
631 def _GetCurrentBranch(self): 622 def _GetCurrentBranch(self):
632 # Returns name of current branch or None for detached HEAD 623 # Returns name of current branch or None for detached HEAD
633 branch = self._Capture(['rev-parse', '--abbrev-ref=strict', 'HEAD']) 624 branch = self._Capture(['rev-parse', '--abbrev-ref=strict', 'HEAD'])
634 if branch == 'HEAD': 625 if branch == 'HEAD':
635 return None 626 return None
636 return branch 627 return branch
637 628
638 def _Capture(self, args): 629 def _Capture(self, args):
639 return gclient_utils.CheckCall( 630 return gclient_utils.CheckCall(
640 ['git'] + args, cwd=self.checkout_path, print_error=False)[0].strip() 631 ['git'] + args, cwd=self.checkout_path, print_error=False)[0].strip()
641 632
642 def _Run(self, args, options, **kwargs): 633 def _Run(self, args, options, **kwargs):
643 kwargs.setdefault('cwd', self.checkout_path) 634 kwargs.setdefault('cwd', self.checkout_path)
644 gclient_utils.CheckCallAndFilterAndHeader(['git'] + args, 635 gclient_utils.CheckCallAndFilterAndHeader(['git'] + args,
645 always=options.verbose, stdout=options.stdout, **kwargs) 636 always=options.verbose, **kwargs)
646 637
647 638
648 class SVNWrapper(SCMWrapper): 639 class SVNWrapper(SCMWrapper):
649 """ Wrapper for SVN """ 640 """ Wrapper for SVN """
650 641
651 def cleanup(self, options, args, file_list): 642 def cleanup(self, options, args, file_list):
652 """Cleanup working copy.""" 643 """Cleanup working copy."""
653 self._Run(['cleanup'] + args, options) 644 self._Run(['cleanup'] + args, options)
654 645
655 def diff(self, options, args, file_list): 646 def diff(self, options, args, file_list):
(...skipping 17 matching lines...) Expand all
673 def pack(self, options, args, file_list): 664 def pack(self, options, args, file_list):
674 """Generates a patch file which can be applied to the root of the 665 """Generates a patch file which can be applied to the root of the
675 repository.""" 666 repository."""
676 if not os.path.isdir(self.checkout_path): 667 if not os.path.isdir(self.checkout_path):
677 raise gclient_utils.Error('Directory %s is not present.' % 668 raise gclient_utils.Error('Directory %s is not present.' %
678 self.checkout_path) 669 self.checkout_path)
679 gclient_utils.CheckCallAndFilter( 670 gclient_utils.CheckCallAndFilter(
680 ['svn', 'diff', '-x', '--ignore-eol-style'] + args, 671 ['svn', 'diff', '-x', '--ignore-eol-style'] + args,
681 cwd=self.checkout_path, 672 cwd=self.checkout_path,
682 print_stdout=False, 673 print_stdout=False,
683 filter_fn=DiffFilterer(self.relpath, options.stdout).Filter, 674 filter_fn=DiffFilterer(self.relpath).Filter)
684 stdout=options.stdout)
685 675
686 def update(self, options, args, file_list): 676 def update(self, options, args, file_list):
687 """Runs svn to update or transparently checkout the working copy. 677 """Runs svn to update or transparently checkout the working copy.
688 678
689 All updated files will be appended to file_list. 679 All updated files will be appended to file_list.
690 680
691 Raises: 681 Raises:
692 Error: if can't get URL for relative path. 682 Error: if can't get URL for relative path.
693 """ 683 """
694 # Only update if git is not controlling the directory. 684 # Only update if git is not controlling the directory.
695 git_path = os.path.join(self.checkout_path, '.git') 685 git_path = os.path.join(self.checkout_path, '.git')
696 if os.path.exists(git_path): 686 if os.path.exists(git_path):
697 options.stdout.write('________ found .git directory; skipping %s\n' % 687 print('________ found .git directory; skipping %s' % self.relpath)
698 self.relpath)
699 return 688 return
700 689
701 if args: 690 if args:
702 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args)) 691 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args))
703 692
704 # revision is the revision to match. It is None if no revision is specified, 693 # revision is the revision to match. It is None if no revision is specified,
705 # i.e. the 'deps ain't pinned'. 694 # i.e. the 'deps ain't pinned'.
706 url, revision = gclient_utils.SplitUrlRevision(self.url) 695 url, revision = gclient_utils.SplitUrlRevision(self.url)
707 # Keep the original unpinned url for reference in case the repo is switched. 696 # Keep the original unpinned url for reference in case the repo is switched.
708 base_url = url 697 base_url = url
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 # The repository url changed, need to switch. 739 # The repository url changed, need to switch.
751 try: 740 try:
752 to_info = scm.SVN.CaptureInfo(url) 741 to_info = scm.SVN.CaptureInfo(url)
753 except gclient_utils.Error: 742 except gclient_utils.Error:
754 # The url is invalid or the server is not accessible, it's safer to bail 743 # The url is invalid or the server is not accessible, it's safer to bail
755 # out right now. 744 # out right now.
756 raise gclient_utils.Error('This url is unreachable: %s' % url) 745 raise gclient_utils.Error('This url is unreachable: %s' % url)
757 can_switch = ((from_info['Repository Root'] != to_info['Repository Root']) 746 can_switch = ((from_info['Repository Root'] != to_info['Repository Root'])
758 and (from_info['UUID'] == to_info['UUID'])) 747 and (from_info['UUID'] == to_info['UUID']))
759 if can_switch: 748 if can_switch:
760 options.stdout.write('\n_____ relocating %s to a new checkout\n' % 749 print('\n_____ relocating %s to a new checkout' % self.relpath)
761 self.relpath)
762 # We have different roots, so check if we can switch --relocate. 750 # We have different roots, so check if we can switch --relocate.
763 # Subversion only permits this if the repository UUIDs match. 751 # Subversion only permits this if the repository UUIDs match.
764 # Perform the switch --relocate, then rewrite the from_url 752 # Perform the switch --relocate, then rewrite the from_url
765 # to reflect where we "are now." (This is the same way that 753 # to reflect where we "are now." (This is the same way that
766 # Subversion itself handles the metadata when switch --relocate 754 # Subversion itself handles the metadata when switch --relocate
767 # is used.) This makes the checks below for whether we 755 # is used.) This makes the checks below for whether we
768 # can update to a revision or have to switch to a different 756 # can update to a revision or have to switch to a different
769 # branch work as expected. 757 # branch work as expected.
770 # TODO(maruel): TEST ME ! 758 # TODO(maruel): TEST ME !
771 command = ['switch', '--relocate', 759 command = ['switch', '--relocate',
772 from_info['Repository Root'], 760 from_info['Repository Root'],
773 to_info['Repository Root'], 761 to_info['Repository Root'],
774 self.relpath] 762 self.relpath]
775 self._Run(command, options, cwd=self._root_dir) 763 self._Run(command, options, cwd=self._root_dir)
776 from_info['URL'] = from_info['URL'].replace( 764 from_info['URL'] = from_info['URL'].replace(
777 from_info['Repository Root'], 765 from_info['Repository Root'],
778 to_info['Repository Root']) 766 to_info['Repository Root'])
779 else: 767 else:
780 if not options.force and not options.reset: 768 if not options.force and not options.reset:
781 # Look for local modifications but ignore unversioned files. 769 # Look for local modifications but ignore unversioned files.
782 for status in scm.SVN.CaptureStatus(self.checkout_path): 770 for status in scm.SVN.CaptureStatus(self.checkout_path):
783 if status[0] != '?': 771 if status[0] != '?':
784 raise gclient_utils.Error( 772 raise gclient_utils.Error(
785 ('Can\'t switch the checkout to %s; UUID don\'t match and ' 773 ('Can\'t switch the checkout to %s; UUID don\'t match and '
786 'there is local changes in %s. Delete the directory and ' 774 'there is local changes in %s. Delete the directory and '
787 'try again.') % (url, self.checkout_path)) 775 'try again.') % (url, self.checkout_path))
788 # Ok delete it. 776 # Ok delete it.
789 options.stdout.write('\n_____ switching %s to a new checkout\n' % 777 print('\n_____ switching %s to a new checkout' % self.relpath)
790 self.relpath)
791 gclient_utils.RemoveDirectory(self.checkout_path) 778 gclient_utils.RemoveDirectory(self.checkout_path)
792 # We need to checkout. 779 # We need to checkout.
793 command = ['checkout', url, self.checkout_path] 780 command = ['checkout', url, self.checkout_path]
794 command = self._AddAdditionalUpdateFlags(command, options, revision) 781 command = self._AddAdditionalUpdateFlags(command, options, revision)
795 self._RunAndGetFileList(command, options, file_list, self._root_dir) 782 self._RunAndGetFileList(command, options, file_list, self._root_dir)
796 return 783 return
797 784
798 # If the provided url has a revision number that matches the revision 785 # If the provided url has a revision number that matches the revision
799 # number of the existing directory, then we don't need to bother updating. 786 # number of the existing directory, then we don't need to bother updating.
800 if not options.force and str(from_info['Revision']) == revision: 787 if not options.force and str(from_info['Revision']) == revision:
801 if options.verbose or not forced_revision: 788 if options.verbose or not forced_revision:
802 options.stdout.write('\n_____ %s%s\n' % (self.relpath, rev_str)) 789 print('\n_____ %s%s' % (self.relpath, rev_str))
803 return 790 return
804 791
805 command = ['update', self.checkout_path] 792 command = ['update', self.checkout_path]
806 command = self._AddAdditionalUpdateFlags(command, options, revision) 793 command = self._AddAdditionalUpdateFlags(command, options, revision)
807 self._RunAndGetFileList(command, options, file_list, self._root_dir) 794 self._RunAndGetFileList(command, options, file_list, self._root_dir)
808 795
809 def updatesingle(self, options, args, file_list): 796 def updatesingle(self, options, args, file_list):
810 filename = args.pop() 797 filename = args.pop()
811 if scm.SVN.AssertVersion("1.5")[0]: 798 if scm.SVN.AssertVersion("1.5")[0]:
812 if not os.path.exists(os.path.join(self.checkout_path, '.svn')): 799 if not os.path.exists(os.path.join(self.checkout_path, '.svn')):
(...skipping 23 matching lines...) Expand all
836 823
837 def revert(self, options, args, file_list): 824 def revert(self, options, args, file_list):
838 """Reverts local modifications. Subversion specific. 825 """Reverts local modifications. Subversion specific.
839 826
840 All reverted files will be appended to file_list, even if Subversion 827 All reverted files will be appended to file_list, even if Subversion
841 doesn't know about them. 828 doesn't know about them.
842 """ 829 """
843 if not os.path.isdir(self.checkout_path): 830 if not os.path.isdir(self.checkout_path):
844 # svn revert won't work if the directory doesn't exist. It needs to 831 # svn revert won't work if the directory doesn't exist. It needs to
845 # checkout instead. 832 # checkout instead.
846 options.stdout.write('\n_____ %s is missing, synching instead\n' % 833 print('\n_____ %s is missing, synching instead' % self.relpath)
847 self.relpath)
848 # Don't reuse the args. 834 # Don't reuse the args.
849 return self.update(options, [], file_list) 835 return self.update(options, [], file_list)
850 836
851 # Do a flush of sys.stdout every 10 secs or so otherwise it may never be
852 # flushed fast enough for buildbot.
853 last_flushed_at = time.time()
854 sys.stdout.flush()
855
856 for file_status in scm.SVN.CaptureStatus(self.checkout_path): 837 for file_status in scm.SVN.CaptureStatus(self.checkout_path):
857 file_path = os.path.join(self.checkout_path, file_status[1]) 838 file_path = os.path.join(self.checkout_path, file_status[1])
858 if file_status[0][0] == 'X': 839 if file_status[0][0] == 'X':
859 # Ignore externals. 840 # Ignore externals.
860 logging.info('Ignoring external %s' % file_path) 841 logging.info('Ignoring external %s' % file_path)
861 continue 842 continue
862 843
863 if logging.getLogger().isEnabledFor(logging.INFO): 844 if logging.getLogger().isEnabledFor(logging.INFO):
864 logging.info('%s%s' % (file[0], file[1])) 845 logging.info('%s%s' % (file[0], file[1]))
865 else: 846 else:
866 options.stdout.write(file_path + '\n') 847 print(file_path)
867 # Flush at least 10 seconds between line writes. We wait at least 10
868 # seconds to avoid overloading the reader that called us with output,
869 # which can slow busy readers down.
870 if (time.time() - last_flushed_at) > 10:
871 last_flushed_at = time.time()
872 sys.stdout.flush()
873 848
874 if file_status[0].isspace(): 849 if file_status[0].isspace():
875 logging.error('No idea what is the status of %s.\n' 850 logging.error('No idea what is the status of %s.\n'
876 'You just found a bug in gclient, please ping ' 851 'You just found a bug in gclient, please ping '
877 'maruel@chromium.org ASAP!' % file_path) 852 'maruel@chromium.org ASAP!' % file_path)
878 # svn revert is really stupid. It fails on inconsistent line-endings, 853 # svn revert is really stupid. It fails on inconsistent line-endings,
879 # on switched directories, etc. So take no chance and delete everything! 854 # on switched directories, etc. So take no chance and delete everything!
880 try: 855 try:
881 if not os.path.exists(file_path): 856 if not os.path.exists(file_path):
882 pass 857 pass
(...skipping 27 matching lines...) Expand all
910 return None 885 return None
911 886
912 def runhooks(self, options, args, file_list): 887 def runhooks(self, options, args, file_list):
913 self.status(options, args, file_list) 888 self.status(options, args, file_list)
914 889
915 def status(self, options, args, file_list): 890 def status(self, options, args, file_list):
916 """Display status information.""" 891 """Display status information."""
917 command = ['status'] + args 892 command = ['status'] + args
918 if not os.path.isdir(self.checkout_path): 893 if not os.path.isdir(self.checkout_path):
919 # svn status won't work if the directory doesn't exist. 894 # svn status won't work if the directory doesn't exist.
920 options.stdout.write( 895 print(('\n________ couldn\'t run \'%s\' in \'%s\':\n'
921 ('\n________ couldn\'t run \'%s\' in \'%s\':\nThe directory ' 896 'The directory does not exist.') %
922 'does not exist.') % (' '.join(command), self.checkout_path)) 897 (' '.join(command), self.checkout_path))
923 # There's no file list to retrieve. 898 # There's no file list to retrieve.
924 else: 899 else:
925 self._RunAndGetFileList(command, options, file_list) 900 self._RunAndGetFileList(command, options, file_list)
926 901
927 def FullUrlForRelativeUrl(self, url): 902 def FullUrlForRelativeUrl(self, url):
928 # Find the forth '/' and strip from there. A bit hackish. 903 # Find the forth '/' and strip from there. A bit hackish.
929 return '/'.join(self.url.split('/')[:4]) + url 904 return '/'.join(self.url.split('/')[:4]) + url
930 905
931 def _Run(self, args, options, **kwargs): 906 def _Run(self, args, options, **kwargs):
932 """Runs a commands that goes to stdout.""" 907 """Runs a commands that goes to stdout."""
933 kwargs.setdefault('cwd', self.checkout_path) 908 kwargs.setdefault('cwd', self.checkout_path)
934 gclient_utils.CheckCallAndFilterAndHeader(['svn'] + args, 909 gclient_utils.CheckCallAndFilterAndHeader(['svn'] + args,
935 always=options.verbose, stdout=options.stdout, **kwargs) 910 always=options.verbose, **kwargs)
936 911
937 def _RunAndGetFileList(self, args, options, file_list, cwd=None): 912 def _RunAndGetFileList(self, args, options, file_list, cwd=None):
938 """Runs a commands that goes to stdout and grabs the file listed.""" 913 """Runs a commands that goes to stdout and grabs the file listed."""
939 cwd = cwd or self.checkout_path 914 cwd = cwd or self.checkout_path
940 scm.SVN.RunAndGetFileList(options.verbose, args, cwd=cwd, 915 scm.SVN.RunAndGetFileList(options.verbose, args, cwd=cwd,
941 file_list=file_list, stdout=options.stdout) 916 file_list=file_list)
942 917
943 @staticmethod 918 @staticmethod
944 def _AddAdditionalUpdateFlags(command, options, revision): 919 def _AddAdditionalUpdateFlags(command, options, revision):
945 """Add additional flags to command depending on what options are set. 920 """Add additional flags to command depending on what options are set.
946 command should be a list of strings that represents an svn command. 921 command should be a list of strings that represents an svn command.
947 922
948 This method returns a new list to be used as a command.""" 923 This method returns a new list to be used as a command."""
949 new_command = command[:] 924 new_command = command[:]
950 if revision: 925 if revision:
951 new_command.extend(['--revision', str(revision).strip()]) 926 new_command.extend(['--revision', str(revision).strip()])
952 # --force was added to 'svn update' in svn 1.5. 927 # --force was added to 'svn update' in svn 1.5.
953 if ((options.force or options.manually_grab_svn_rev) and 928 if ((options.force or options.manually_grab_svn_rev) and
954 scm.SVN.AssertVersion("1.5")[0]): 929 scm.SVN.AssertVersion("1.5")[0]):
955 new_command.append('--force') 930 new_command.append('--force')
956 return new_command 931 return new_command
OLDNEW
« no previous file with comments | « gclient.py ('k') | gclient_utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698