Reapply 32057, 32058, 32059, 32062 and fixes problems introduced by these changes.

Noteworthy change is scm.SVN.GetFileProperty calls Capture instead of Run.

TEST=unit tests
BUG=none

Review URL: http://codereview.chromium.org/399009

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@32181 0039d316-1c4b-4281-b951-d872f2087c98
experimental/szager/collated-output
maruel@chromium.org 16 years ago
parent 26970fa907
commit 5aeb7dd54c

@ -19,10 +19,10 @@ import upload
import urllib2 import urllib2
# gcl now depends on gclient. # gcl now depends on gclient.
import gclient_scm from scm import SVN
import gclient_utils import gclient_utils
__version__ = '1.1.1' __version__ = '1.1.2'
CODEREVIEW_SETTINGS = { CODEREVIEW_SETTINGS = {
@ -46,43 +46,13 @@ MISSING_TEST_MSG = "Change contains new or modified methods, but no new tests!"
FILES_CACHE = {} FILES_CACHE = {}
### SVN Functions
def IsSVNMoved(filename):
"""Determine if a file has been added through svn mv"""
info = gclient_scm.CaptureSVNInfo(filename)
return (info.get('Copied From URL') and
info.get('Copied From Rev') and
info.get('Schedule') == 'add')
def GetSVNFileProperty(file, property_name):
"""Returns the value of an SVN property for the given file.
Args:
file: The file to check
property_name: The name of the SVN property, e.g. "svn:mime-type"
Returns:
The value of the property, which will be the empty string if the property
is not set on the file. If the file is not under version control, the
empty string is also returned.
"""
output = RunShell(["svn", "propget", property_name, file])
if (output.startswith("svn: ") and
output.endswith("is not under version control")):
return ""
else:
return output
def UnknownFiles(extra_args): def UnknownFiles(extra_args):
"""Runs svn status and prints unknown files. """Runs svn status and returns unknown files.
Any args in |extra_args| are passed to the tool to support giving alternate Any args in |extra_args| are passed to the tool to support giving alternate
code locations. code locations.
""" """
return [item[1] for item in gclient_scm.CaptureSVNStatus(extra_args) return [item[1] for item in SVN.CaptureStatus(extra_args)
if item[0][0] == '?'] if item[0][0] == '?']
@ -93,7 +63,7 @@ def GetRepositoryRoot():
""" """
global REPOSITORY_ROOT global REPOSITORY_ROOT
if not REPOSITORY_ROOT: if not REPOSITORY_ROOT:
infos = gclient_scm.CaptureSVNInfo(os.getcwd(), print_error=False) infos = SVN.CaptureInfo(os.getcwd(), print_error=False)
cur_dir_repo_root = infos.get("Repository Root") cur_dir_repo_root = infos.get("Repository Root")
if not cur_dir_repo_root: if not cur_dir_repo_root:
raise gclient_utils.Error("gcl run outside of repository") raise gclient_utils.Error("gcl run outside of repository")
@ -101,7 +71,7 @@ def GetRepositoryRoot():
REPOSITORY_ROOT = os.getcwd() REPOSITORY_ROOT = os.getcwd()
while True: while True:
parent = os.path.dirname(REPOSITORY_ROOT) parent = os.path.dirname(REPOSITORY_ROOT)
if (gclient_scm.CaptureSVNInfo(parent, print_error=False).get( if (SVN.CaptureInfo(parent, print_error=False).get(
"Repository Root") != cur_dir_repo_root): "Repository Root") != cur_dir_repo_root):
break break
REPOSITORY_ROOT = parent REPOSITORY_ROOT = parent
@ -146,7 +116,7 @@ def GetCachedFile(filename, max_age=60*60*24*3, use_root=False):
os.stat(cached_file).st_mtime > max_age): os.stat(cached_file).st_mtime > max_age):
local_dir = os.path.dirname(os.path.abspath(filename)) local_dir = os.path.dirname(os.path.abspath(filename))
local_base = os.path.basename(filename) local_base = os.path.basename(filename)
dir_info = gclient_scm.CaptureSVNInfo(".") dir_info = SVN.CaptureInfo(".")
repo_root = dir_info["Repository Root"] repo_root = dir_info["Repository Root"]
if use_root: if use_root:
url_path = repo_root url_path = repo_root
@ -158,7 +128,7 @@ def GetCachedFile(filename, max_age=60*60*24*3, use_root=False):
r = "" r = ""
if not use_root: if not use_root:
local_path = os.path.join(local_dir, local_base) local_path = os.path.join(local_dir, local_base)
r = gclient_scm.CaptureSVNStatus((local_path,)) r = SVN.CaptureStatus((local_path,))
rc = -1 rc = -1
if r: if r:
status = r[0][0] status = r[0][0]
@ -478,7 +448,7 @@ class ChangeInfo(object):
if update_status: if update_status:
for item in files: for item in files:
filename = os.path.join(local_root, item[1]) filename = os.path.join(local_root, item[1])
status_result = gclient_scm.CaptureSVNStatus(filename) status_result = SVN.CaptureStatus(filename)
if not status_result or not status_result[0][0]: if not status_result or not status_result[0][0]:
# File has been reverted. # File has been reverted.
save = True save = True
@ -562,7 +532,7 @@ def GetModifiedFiles():
files_in_cl[filename] = change_info.name files_in_cl[filename] = change_info.name
# Get all the modified files. # Get all the modified files.
status_result = gclient_scm.CaptureSVNStatus(None) status_result = SVN.CaptureStatus(None)
for line in status_result: for line in status_result:
status = line[0] status = line[0]
filename = line[1] filename = line[1]
@ -749,10 +719,10 @@ def GenerateDiff(files, root=None):
diff = [] diff = []
for filename in files: for filename in files:
# TODO(maruel): Use SVN.DiffItem().
# Use svn info output instead of os.path.isdir because the latter fails # Use svn info output instead of os.path.isdir because the latter fails
# when the file is deleted. # when the file is deleted.
if gclient_scm.CaptureSVNInfo(filename).get("Node Kind") in ("dir", if SVN.CaptureInfo(filename).get('Node Kind') == 'directory':
"directory"):
continue continue
# If the user specified a custom diff command in their svn config file, # If the user specified a custom diff command in their svn config file,
# then it'll be used when we do svn diff, which we don't want to happen # then it'll be used when we do svn diff, which we don't want to happen
@ -770,7 +740,7 @@ def GenerateDiff(files, root=None):
output = RunShell(["svn", "diff", "--config-dir", bogus_dir, filename]) output = RunShell(["svn", "diff", "--config-dir", bogus_dir, filename])
if output: if output:
diff.append(output) diff.append(output)
elif IsSVNMoved(filename): elif SVN.IsMoved(filename):
# svn diff on a mv/cp'd file outputs nothing. # svn diff on a mv/cp'd file outputs nothing.
# We put in an empty Index entry so upload.py knows about them. # We put in an empty Index entry so upload.py knows about them.
diff.append("\nIndex: %s\n" % filename) diff.append("\nIndex: %s\n" % filename)
@ -996,7 +966,7 @@ def Change(change_info, args):
silent = FilterFlag(args, "--silent") silent = FilterFlag(args, "--silent")
# Verify the user is running the change command from a read-write checkout. # Verify the user is running the change command from a read-write checkout.
svn_info = gclient_scm.CaptureSVNInfo('.') svn_info = SVN.CaptureInfo('.')
if not svn_info: if not svn_info:
ErrorExit("Current checkout is unversioned. Please retry with a versioned " ErrorExit("Current checkout is unversioned. Please retry with a versioned "
"directory.") "directory.")

@ -66,7 +66,7 @@ Hooks
""" """
__author__ = "darinf@gmail.com (Darin Fisher)" __author__ = "darinf@gmail.com (Darin Fisher)"
__version__ = "0.3.3" __version__ = "0.3.4"
import errno import errno
import logging import logging
@ -747,9 +747,9 @@ class GClient(object):
# Use entry and not entry_fixed there. # Use entry and not entry_fixed there.
if entry not in entries and os.path.exists(e_dir): if entry not in entries and os.path.exists(e_dir):
modified_files = False modified_files = False
if isinstance(prev_entries,list): if isinstance(prev_entries, list):
# old .gclient_entries format was list, now dict # old .gclient_entries format was list, now dict
modified_files = gclient_scm.CaptureSVNStatus(e_dir) modified_files = gclient_scm.scm.SVN.CaptureStatus(e_dir)
else: else:
file_list = [] file_list = []
scm = gclient_scm.CreateSCM(prev_entries[entry], self._root_dir, scm = gclient_scm.CreateSCM(prev_entries[entry], self._root_dir,
@ -830,7 +830,7 @@ class GClient(object):
(url, rev) = GetURLAndRev(name, solution["url"]) (url, rev) = GetURLAndRev(name, solution["url"])
entries[name] = "%s@%s" % (url, rev) entries[name] = "%s@%s" % (url, rev)
# TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset) # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset)
entries_deps_content[name] = gclient_scm.CaptureSVN( entries_deps_content[name] = gclient_scm.scm.SVN.Capture(
["cat", ["cat",
"%s/%s@%s" % (url, "%s/%s@%s" % (url,
self._options.deps_file, self._options.deps_file,

@ -1,16 +1,6 @@
# Copyright 2009 Google Inc. All Rights Reserved. # Copyright (c) 2009 The Chromium Authors. All rights reserved.
# # Use of this source code is governed by a BSD-style license that can be
# Licensed under the Apache License, Version 2.0 (the "License"); # found in the LICENSE file.
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Gclient-specific SCM-specific operations.""" """Gclient-specific SCM-specific operations."""
@ -18,19 +8,13 @@ import logging
import os import os
import re import re
import subprocess import subprocess
import sys
import xml.dom.minidom
import scm
import gclient_utils import gclient_utils
# TODO(maruel): Temporary.
from scm import CaptureGit, CaptureGitStatus, CaptureSVN
from scm import CaptureSVNHeadRevision, CaptureSVNInfo, CaptureSVNStatus
from scm import RunSVN, RunSVNAndFilterOutput, RunSVNAndGetFileList
### SCM abstraction layer ### SCM abstraction layer
# Factory Method for SCM wrapper creation # Factory Method for SCM wrapper creation
def CreateSCM(url=None, root_dir=None, relpath=None, scm_name='svn'): def CreateSCM(url=None, root_dir=None, relpath=None, scm_name='svn'):
@ -93,20 +77,20 @@ class SCMWrapper(object):
return getattr(self, command)(options, args, file_list) return getattr(self, command)(options, args, file_list)
class GitWrapper(SCMWrapper): class GitWrapper(SCMWrapper, scm.GIT):
"""Wrapper for Git""" """Wrapper for Git"""
def cleanup(self, options, args, file_list): def cleanup(self, options, args, file_list):
"""Cleanup working copy.""" """Cleanup working copy."""
__pychecker__ = 'unusednames=args,file_list,options' __pychecker__ = 'unusednames=args,file_list,options'
self._RunGit(['prune'], redirect_stdout=False) self._Run(['prune'], redirect_stdout=False)
self._RunGit(['fsck'], redirect_stdout=False) self._Run(['fsck'], redirect_stdout=False)
self._RunGit(['gc'], redirect_stdout=False) self._Run(['gc'], redirect_stdout=False)
def diff(self, options, args, file_list): def diff(self, options, args, file_list):
__pychecker__ = 'unusednames=args,file_list,options' __pychecker__ = 'unusednames=args,file_list,options'
merge_base = self._RunGit(['merge-base', 'HEAD', 'origin']) merge_base = self._Run(['merge-base', 'HEAD', 'origin'])
self._RunGit(['diff', merge_base], redirect_stdout=False) self._Run(['diff', merge_base], redirect_stdout=False)
def export(self, options, args, file_list): def export(self, options, args, file_list):
__pychecker__ = 'unusednames=file_list,options' __pychecker__ = 'unusednames=file_list,options'
@ -114,7 +98,7 @@ class GitWrapper(SCMWrapper):
export_path = os.path.abspath(os.path.join(args[0], self.relpath)) export_path = os.path.abspath(os.path.join(args[0], self.relpath))
if not os.path.exists(export_path): if not os.path.exists(export_path):
os.makedirs(export_path) os.makedirs(export_path)
self._RunGit(['checkout-index', '-a', '--prefix=%s/' % export_path], self._Run(['checkout-index', '-a', '--prefix=%s/' % export_path],
redirect_stdout=False) redirect_stdout=False)
def update(self, options, args, file_list): def update(self, options, args, file_list):
@ -142,21 +126,21 @@ class GitWrapper(SCMWrapper):
print("\n_____ %s%s" % (self.relpath, rev_str)) print("\n_____ %s%s" % (self.relpath, rev_str))
if not os.path.exists(self.checkout_path): if not os.path.exists(self.checkout_path):
self._RunGit(['clone', url, self.checkout_path], self._Run(['clone', url, self.checkout_path],
cwd=self._root_dir, redirect_stdout=False) cwd=self._root_dir, redirect_stdout=False)
if revision: if revision:
self._RunGit(['reset', '--hard', revision], redirect_stdout=False) self._Run(['reset', '--hard', revision], redirect_stdout=False)
files = self._RunGit(['ls-files']).split() files = self._Run(['ls-files']).split()
file_list.extend([os.path.join(self.checkout_path, f) for f in files]) file_list.extend([os.path.join(self.checkout_path, f) for f in files])
return return
self._RunGit(['remote', 'update'], redirect_stdout=False) self._Run(['remote', 'update'], redirect_stdout=False)
new_base = 'origin' new_base = 'origin'
if revision: if revision:
new_base = revision new_base = revision
files = self._RunGit(['diff', new_base, '--name-only']).split() files = self._Run(['diff', new_base, '--name-only']).split()
file_list.extend([os.path.join(self.checkout_path, f) for f in files]) file_list.extend([os.path.join(self.checkout_path, f) for f in files])
self._RunGit(['rebase', '-v', new_base], redirect_stdout=False) self._Run(['rebase', '-v', new_base], redirect_stdout=False)
print "Checked out revision %s." % self.revinfo(options, (), None) print "Checked out revision %s." % self.revinfo(options, (), None)
def revert(self, options, args, file_list): def revert(self, options, args, file_list):
@ -172,15 +156,15 @@ class GitWrapper(SCMWrapper):
print("\n_____ %s is missing, synching instead" % self.relpath) print("\n_____ %s is missing, synching instead" % self.relpath)
# Don't reuse the args. # Don't reuse the args.
return self.update(options, [], file_list) return self.update(options, [], file_list)
merge_base = self._RunGit(['merge-base', 'HEAD', 'origin']) merge_base = self._Run(['merge-base', 'HEAD', 'origin'])
files = self._RunGit(['diff', merge_base, '--name-only']).split() files = self._Run(['diff', merge_base, '--name-only']).split()
self._RunGit(['reset', '--hard', merge_base], redirect_stdout=False) self._Run(['reset', '--hard', merge_base], redirect_stdout=False)
file_list.extend([os.path.join(self.checkout_path, f) for f in files]) file_list.extend([os.path.join(self.checkout_path, f) for f in files])
def revinfo(self, options, args, file_list): def revinfo(self, options, args, file_list):
"""Display revision""" """Display revision"""
__pychecker__ = 'unusednames=args,file_list,options' __pychecker__ = 'unusednames=args,file_list,options'
return self._RunGit(['rev-parse', 'HEAD']) return self._Run(['rev-parse', 'HEAD'])
def runhooks(self, options, args, file_list): def runhooks(self, options, args, file_list):
self.status(options, args, file_list) self.status(options, args, file_list)
@ -192,29 +176,30 @@ class GitWrapper(SCMWrapper):
print('\n________ couldn\'t run status in %s:\nThe directory ' print('\n________ couldn\'t run status in %s:\nThe directory '
'does not exist.' % self.checkout_path) 'does not exist.' % self.checkout_path)
else: else:
merge_base = self._RunGit(['merge-base', 'HEAD', 'origin']) merge_base = self._Run(['merge-base', 'HEAD', 'origin'])
self._RunGit(['diff', '--name-status', merge_base], redirect_stdout=False) self._Run(['diff', '--name-status', merge_base], redirect_stdout=False)
files = self._RunGit(['diff', '--name-only', merge_base]).split() files = self._Run(['diff', '--name-only', merge_base]).split()
file_list.extend([os.path.join(self.checkout_path, f) for f in files]) file_list.extend([os.path.join(self.checkout_path, f) for f in files])
def _RunGit(self, args, cwd=None, checkrc=True, redirect_stdout=True): def _Run(self, args, cwd=None, checkrc=True, redirect_stdout=True):
# TODO(maruel): Merge with Capture?
stdout=None stdout=None
if redirect_stdout: if redirect_stdout:
stdout=subprocess.PIPE stdout=subprocess.PIPE
if cwd == None: if cwd == None:
cwd = self.checkout_path cwd = self.checkout_path
cmd = ['git'] cmd = [self.COMMAND]
cmd.extend(args) cmd.extend(args)
sp = subprocess.Popen(cmd, cwd=cwd, stdout=stdout) sp = subprocess.Popen(cmd, cwd=cwd, stdout=stdout)
if checkrc and sp.returncode: if checkrc and sp.returncode:
raise gclient_utils.Error('git command %s returned %d' % raise gclient_utils.Error('git command %s returned %d' %
(args[0], sp.returncode)) (args[0], sp.returncode))
output = sp.communicate()[0] output = sp.communicate()[0]
if output != None: if output is not None:
return output.strip() return output.strip()
class SVNWrapper(SCMWrapper): class SVNWrapper(SCMWrapper, scm.SVN):
""" Wrapper for SVN """ """ Wrapper for SVN """
def cleanup(self, options, args, file_list): def cleanup(self, options, args, file_list):
@ -222,14 +207,14 @@ class SVNWrapper(SCMWrapper):
__pychecker__ = 'unusednames=file_list,options' __pychecker__ = 'unusednames=file_list,options'
command = ['cleanup'] command = ['cleanup']
command.extend(args) command.extend(args)
RunSVN(command, os.path.join(self._root_dir, self.relpath)) self.Run(command, os.path.join(self._root_dir, self.relpath))
def diff(self, options, args, file_list): def diff(self, options, args, file_list):
# NOTE: This function does not currently modify file_list. # NOTE: This function does not currently modify file_list.
__pychecker__ = 'unusednames=file_list,options' __pychecker__ = 'unusednames=file_list,options'
command = ['diff'] command = ['diff']
command.extend(args) command.extend(args)
RunSVN(command, os.path.join(self._root_dir, self.relpath)) self.Run(command, os.path.join(self._root_dir, self.relpath))
def export(self, options, args, file_list): def export(self, options, args, file_list):
__pychecker__ = 'unusednames=file_list,options' __pychecker__ = 'unusednames=file_list,options'
@ -242,7 +227,7 @@ class SVNWrapper(SCMWrapper):
assert os.path.exists(export_path) assert os.path.exists(export_path)
command = ['export', '--force', '.'] command = ['export', '--force', '.']
command.append(export_path) command.append(export_path)
RunSVN(command, os.path.join(self._root_dir, self.relpath)) self.Run(command, os.path.join(self._root_dir, self.relpath))
def update(self, options, args, file_list): def update(self, options, args, file_list):
"""Runs SCM to update or transparently checkout the working copy. """Runs SCM to update or transparently checkout the working copy.
@ -279,11 +264,11 @@ class SVNWrapper(SCMWrapper):
command = ['checkout', url, checkout_path] command = ['checkout', url, checkout_path]
if revision: if revision:
command.extend(['--revision', str(revision)]) command.extend(['--revision', str(revision)])
RunSVNAndGetFileList(options, command, self._root_dir, file_list) self.RunAndGetFileList(options, command, self._root_dir, file_list)
return return
# Get the existing scm url and the revision number of the current checkout. # Get the existing scm url and the revision number of the current checkout.
from_info = CaptureSVNInfo(os.path.join(checkout_path, '.'), '.') from_info = self.CaptureInfo(os.path.join(checkout_path, '.'), '.')
if not from_info: if not from_info:
raise gclient_utils.Error("Can't update/checkout %r if an unversioned " raise gclient_utils.Error("Can't update/checkout %r if an unversioned "
"directory is present. Delete the directory " "directory is present. Delete the directory "
@ -293,12 +278,12 @@ class SVNWrapper(SCMWrapper):
if options.manually_grab_svn_rev: if options.manually_grab_svn_rev:
# Retrieve the current HEAD version because svn is slow at null updates. # Retrieve the current HEAD version because svn is slow at null updates.
if not revision: if not revision:
from_info_live = CaptureSVNInfo(from_info['URL'], '.') from_info_live = self.CaptureInfo(from_info['URL'], '.')
revision = str(from_info_live['Revision']) revision = str(from_info_live['Revision'])
rev_str = ' at %s' % revision rev_str = ' at %s' % revision
if from_info['URL'] != base_url: if from_info['URL'] != base_url:
to_info = CaptureSVNInfo(url, '.') to_info = self.CaptureInfo(url, '.')
if not to_info.get('Repository Root') or not to_info.get('UUID'): if not to_info.get('Repository Root') or not to_info.get('UUID'):
# The url is invalid or the server is not accessible, it's safer to bail # The url is invalid or the server is not accessible, it's safer to bail
# out right now. # out right now.
@ -320,12 +305,12 @@ class SVNWrapper(SCMWrapper):
from_info['Repository Root'], from_info['Repository Root'],
to_info['Repository Root'], to_info['Repository Root'],
self.relpath] self.relpath]
RunSVN(command, self._root_dir) self.Run(command, self._root_dir)
from_info['URL'] = from_info['URL'].replace( from_info['URL'] = from_info['URL'].replace(
from_info['Repository Root'], from_info['Repository Root'],
to_info['Repository Root']) to_info['Repository Root'])
else: else:
if CaptureSVNStatus(checkout_path): if self.CaptureStatus(checkout_path):
raise gclient_utils.Error("Can't switch the checkout to %s; UUID " raise gclient_utils.Error("Can't switch the checkout to %s; UUID "
"don't match and there is local changes " "don't match and there is local changes "
"in %s. Delete the directory and " "in %s. Delete the directory and "
@ -337,7 +322,7 @@ class SVNWrapper(SCMWrapper):
command = ['checkout', url, checkout_path] command = ['checkout', url, checkout_path]
if revision: if revision:
command.extend(['--revision', str(revision)]) command.extend(['--revision', str(revision)])
RunSVNAndGetFileList(options, command, self._root_dir, file_list) self.RunAndGetFileList(options, command, self._root_dir, file_list)
return return
@ -351,7 +336,7 @@ class SVNWrapper(SCMWrapper):
command = ["update", checkout_path] command = ["update", checkout_path]
if revision: if revision:
command.extend(['--revision', str(revision)]) command.extend(['--revision', str(revision)])
RunSVNAndGetFileList(options, command, self._root_dir, file_list) self.RunAndGetFileList(options, command, self._root_dir, file_list)
def revert(self, options, args, file_list): def revert(self, options, args, file_list):
"""Reverts local modifications. Subversion specific. """Reverts local modifications. Subversion specific.
@ -368,7 +353,7 @@ class SVNWrapper(SCMWrapper):
# Don't reuse the args. # Don't reuse the args.
return self.update(options, [], file_list) return self.update(options, [], file_list)
for file_status in CaptureSVNStatus(path): for file_status in self.CaptureStatus(path):
file_path = os.path.join(path, file_status[1]) file_path = os.path.join(path, file_status[1])
if file_status[0][0] == 'X': if file_status[0][0] == 'X':
# Ignore externals. # Ignore externals.
@ -403,7 +388,7 @@ class SVNWrapper(SCMWrapper):
try: try:
# svn revert is so broken we don't even use it. Using # svn revert is so broken we don't even use it. Using
# "svn up --revision BASE" achieve the same effect. # "svn up --revision BASE" achieve the same effect.
RunSVNAndGetFileList(options, ['update', '--revision', 'BASE'], path, self.RunAndGetFileList(options, ['update', '--revision', 'BASE'], path,
file_list) file_list)
except OSError, e: except OSError, e:
# Maybe the directory disapeared meanwhile. We don't want it to throw an # Maybe the directory disapeared meanwhile. We don't want it to throw an
@ -413,7 +398,7 @@ class SVNWrapper(SCMWrapper):
def revinfo(self, options, args, file_list): def revinfo(self, options, args, file_list):
"""Display revision""" """Display revision"""
__pychecker__ = 'unusednames=args,file_list,options' __pychecker__ = 'unusednames=args,file_list,options'
return CaptureSVNHeadRevision(self.url) return self.CaptureHeadRevision(self.url)
def runhooks(self, options, args, file_list): def runhooks(self, options, args, file_list):
self.status(options, args, file_list) self.status(options, args, file_list)
@ -430,7 +415,7 @@ class SVNWrapper(SCMWrapper):
% (' '.join(command), path)) % (' '.join(command), path))
# There's no file list to retrieve. # There's no file list to retrieve.
else: else:
RunSVNAndGetFileList(options, command, path, file_list) self.RunAndGetFileList(options, command, path, file_list)
def pack(self, options, args, file_list): def pack(self, options, args, file_list):
"""Generates a patch file which can be applied to the root of the """Generates a patch file which can be applied to the root of the
@ -475,4 +460,4 @@ class SVNWrapper(SCMWrapper):
print line print line
filterer = DiffFilterer(self.relpath) filterer = DiffFilterer(self.relpath)
RunSVNAndFilterOutput(command, path, False, False, filterer.Filter) self.RunAndFilterOutput(command, path, False, False, filterer.Filter)

@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
"""Generic utils."""
import errno import errno
import os import os
import re import re
@ -22,8 +24,6 @@ import time
import xml.dom.minidom import xml.dom.minidom
import xml.parsers.expat import xml.parsers.expat
## Generic utils
def SplitUrlRevision(url): def SplitUrlRevision(url):
"""Splits url and returns a two-tuple: url, rev""" """Splits url and returns a two-tuple: url, rev"""
@ -76,9 +76,9 @@ class PrintableObject(object):
return output return output
def FileRead(filename): def FileRead(filename, mode='rU'):
content = None content = None
f = open(filename, "rU") f = open(filename, mode)
try: try:
content = f.read() content = f.read()
finally: finally:
@ -86,8 +86,8 @@ def FileRead(filename):
return content return content
def FileWrite(filename, content): def FileWrite(filename, content, mode='w'):
f = open(filename, "w") f = open(filename, mode)
try: try:
f.write(content) f.write(content)
finally: finally:

@ -7,9 +7,8 @@ import re
import subprocess import subprocess
import sys import sys
# Imported from depot_tools.
import gclient_scm
import presubmit_support import presubmit_support
import scm
def Backquote(cmd, cwd=None): def Backquote(cmd, cwd=None):
"""Like running `cmd` in a shell script.""" """Like running `cmd` in a shell script."""
@ -35,7 +34,7 @@ class ChangeOptions:
raise Exception("Could not parse log message: %s" % log) raise Exception("Could not parse log message: %s" % log)
name = m.group(1) name = m.group(1)
description = m.group(2) description = m.group(2)
files = gclient_scm.CaptureGitStatus([root], upstream_branch) files = scm.GIT.CaptureStatus([root], upstream_branch)
issue = Backquote(['git', 'cl', 'status', '--field=id']) issue = Backquote(['git', 'cl', 'status', '--field=id'])
patchset = None patchset = None
self.change = presubmit_support.GitChange(name, description, root, files, self.change = presubmit_support.GitChange(name, description, root, files,

@ -6,7 +6,7 @@
"""Enables directory-specific presubmit checks to run at upload and/or commit. """Enables directory-specific presubmit checks to run at upload and/or commit.
""" """
__version__ = '1.3.3' __version__ = '1.3.4'
# TODO(joi) Add caching where appropriate/needed. The API is designed to allow # TODO(joi) Add caching where appropriate/needed. The API is designed to allow
# caching (between all different invocations of presubmit scripts for a given # caching (between all different invocations of presubmit scripts for a given
@ -35,11 +35,10 @@ import urllib2 # Exposed through the API.
import warnings import warnings
# Local imports. # Local imports.
# TODO(joi) Would be cleaner to factor out utils in gcl to separate module, but
# for now it would only be a couple of functions so hardly worth it.
import gcl import gcl
import gclient_scm import gclient_utils
import presubmit_canned_checks import presubmit_canned_checks
import scm
# Ask for feedback only once in program lifetime. # Ask for feedback only once in program lifetime.
@ -241,7 +240,7 @@ class InputApi(object):
Remember to check for the None case and show an appropriate error! Remember to check for the None case and show an appropriate error!
""" """
local_path = gclient_scm.CaptureSVNInfo(depot_path).get('Path') local_path = scm.SVN.CaptureInfo(depot_path).get('Path')
if local_path: if local_path:
return local_path return local_path
@ -254,7 +253,7 @@ class InputApi(object):
Returns: Returns:
The depot path (SVN URL) of the file if mapped, otherwise None. The depot path (SVN URL) of the file if mapped, otherwise None.
""" """
depot_path = gclient_scm.CaptureSVNInfo(local_path).get('URL') depot_path = scm.SVN.CaptureInfo(local_path).get('URL')
if depot_path: if depot_path:
return depot_path return depot_path
@ -354,7 +353,7 @@ class InputApi(object):
file_item = file_item.AbsoluteLocalPath() file_item = file_item.AbsoluteLocalPath()
if not file_item.startswith(self.change.RepositoryRoot()): if not file_item.startswith(self.change.RepositoryRoot()):
raise IOError('Access outside the repository root is denied.') raise IOError('Access outside the repository root is denied.')
return gcl.ReadFile(file_item, mode) return gclient_utils.FileRead(file_item, mode)
@staticmethod @staticmethod
def _RightHandSideLinesImpl(affected_files): def _RightHandSideLinesImpl(affected_files):
@ -432,7 +431,8 @@ class AffectedFile(object):
if self.IsDirectory(): if self.IsDirectory():
return [] return []
else: else:
return gcl.ReadFile(self.AbsoluteLocalPath()).splitlines() return gclient_utils.FileRead(self.AbsoluteLocalPath(),
'rU').splitlines()
def OldContents(self): def OldContents(self):
"""Returns an iterator over the lines in the old version of file. """Returns an iterator over the lines in the old version of file.
@ -464,7 +464,7 @@ class SvnAffectedFile(AffectedFile):
def ServerPath(self): def ServerPath(self):
if self._server_path is None: if self._server_path is None:
self._server_path = gclient_scm.CaptureSVNInfo( self._server_path = scm.SVN.CaptureInfo(
self.AbsoluteLocalPath()).get('URL', '') self.AbsoluteLocalPath()).get('URL', '')
return self._server_path return self._server_path
@ -476,13 +476,13 @@ class SvnAffectedFile(AffectedFile):
# querying subversion, especially on Windows. # querying subversion, especially on Windows.
self._is_directory = os.path.isdir(path) self._is_directory = os.path.isdir(path)
else: else:
self._is_directory = gclient_scm.CaptureSVNInfo( self._is_directory = scm.SVN.CaptureInfo(
path).get('Node Kind') in ('dir', 'directory') path).get('Node Kind') in ('dir', 'directory')
return self._is_directory return self._is_directory
def Property(self, property_name): def Property(self, property_name):
if not property_name in self._properties: if not property_name in self._properties:
self._properties[property_name] = gcl.GetSVNFileProperty( self._properties[property_name] = scm.SVN.GetFileProperty(
self.AbsoluteLocalPath(), property_name).rstrip() self.AbsoluteLocalPath(), property_name).rstrip()
return self._properties[property_name] return self._properties[property_name]
@ -494,7 +494,7 @@ class SvnAffectedFile(AffectedFile):
elif self.IsDirectory(): elif self.IsDirectory():
self._is_text_file = False self._is_text_file = False
else: else:
mime_type = gcl.GetSVNFileProperty(self.AbsoluteLocalPath(), mime_type = scm.SVN.GetFileProperty(self.AbsoluteLocalPath(),
'svn:mime-type') 'svn:mime-type')
self._is_text_file = (not mime_type or mime_type.startswith('text/')) self._is_text_file = (not mime_type or mime_type.startswith('text/'))
return self._is_text_file return self._is_text_file
@ -809,7 +809,7 @@ def DoGetTrySlaves(changed_files,
if verbose: if verbose:
output_stream.write("Running %s\n" % filename) output_stream.write("Running %s\n" % filename)
# Accept CRLF presubmit script. # Accept CRLF presubmit script.
presubmit_script = gcl.ReadFile(filename, 'rU') presubmit_script = gclient_utils.FileRead(filename, 'rU')
results += executer.ExecPresubmitScript(presubmit_script) results += executer.ExecPresubmitScript(presubmit_script)
slaves = list(set(results)) slaves = list(set(results))
@ -925,7 +925,7 @@ def DoPresubmitChecks(change,
if verbose: if verbose:
output_stream.write("Running %s\n" % filename) output_stream.write("Running %s\n" % filename)
# Accept CRLF presubmit script. # Accept CRLF presubmit script.
presubmit_script = gcl.ReadFile(filename, 'rU') presubmit_script = gclient_utils.FileRead(filename, 'rU')
results += executer.ExecPresubmitScript(presubmit_script, filename) results += executer.ExecPresubmitScript(presubmit_script, filename)
errors = [] errors = []
@ -1022,7 +1022,7 @@ def Main(argv):
options.files = ParseFiles(args, options.recursive) options.files = ParseFiles(args, options.recursive)
else: else:
# Grab modified files. # Grab modified files.
options.files = gclient_scm.CaptureGitStatus([options.root]) options.files = scm.GIT.CaptureStatus([options.root])
elif os.path.isdir(os.path.join(options.root, '.svn')): elif os.path.isdir(os.path.join(options.root, '.svn')):
change_class = SvnChange change_class = SvnChange
if not options.files: if not options.files:
@ -1030,7 +1030,7 @@ def Main(argv):
options.files = ParseFiles(args, options.recursive) options.files = ParseFiles(args, options.recursive)
else: else:
# Grab modified files. # Grab modified files.
options.files = gclient_scm.CaptureSVNStatus([options.root]) options.files = scm.SVN.CaptureStatus([options.root])
else: else:
# Doesn't seem under source control. # Doesn't seem under source control.
change_class = Change change_class = Change

@ -146,7 +146,7 @@ def Revert(revisions, force=False, commit=True, send_email=True, message=None,
print "" print ""
# Make sure these files are unmodified with svn status. # Make sure these files are unmodified with svn status.
status = gclient_scm.CaptureSVNStatus(files) status = gclient_scm.scm.SVN.CaptureStatus(files)
if status: if status:
if force: if force:
# TODO(maruel): Use the tool to correctly revert '?' files. # TODO(maruel): Use the tool to correctly revert '?' files.

151
scm.py

@ -2,25 +2,23 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
"""SCM-specific functions.""" """SCM-specific utility classes."""
import os import os
import re import re
import subprocess import subprocess
import sys import sys
import tempfile
import xml.dom.minidom import xml.dom.minidom
import gclient_utils import gclient_utils
SVN_COMMAND = "svn" class GIT(object):
GIT_COMMAND = "git" COMMAND = "git"
# ----------------------------------------------------------------------------- @staticmethod
# Git utils: def Capture(args, in_directory=None, print_error=True):
def CaptureGit(args, in_directory=None, print_error=True):
"""Runs git, capturing output sent to stdout as a string. """Runs git, capturing output sent to stdout as a string.
Args: Args:
@ -30,7 +28,7 @@ def CaptureGit(args, in_directory=None, print_error=True):
Returns: Returns:
The output sent to stdout as a string. The output sent to stdout as a string.
""" """
c = [GIT_COMMAND] c = [GIT.COMMAND]
c.extend(args) c.extend(args)
# *Sigh*: Windows needs shell=True, or else it won't search %PATH% for # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for
@ -47,7 +45,8 @@ def CaptureGit(args, in_directory=None, print_error=True):
stderr=stderr).communicate()[0] stderr=stderr).communicate()[0]
def CaptureGitStatus(files, upstream_branch='origin'): @staticmethod
def CaptureStatus(files, upstream_branch='origin'):
"""Returns git status. """Returns git status.
@files can be a string (one file) or a list of files. @files can be a string (one file) or a list of files.
@ -61,7 +60,7 @@ def CaptureGitStatus(files, upstream_branch='origin'):
else: else:
command.extend(files) command.extend(files)
status = CaptureGit(command).rstrip() status = GIT.Capture(command).rstrip()
results = [] results = []
if status: if status:
for statusline in status.split('\n'): for statusline in status.split('\n'):
@ -72,11 +71,11 @@ def CaptureGitStatus(files, upstream_branch='origin'):
return results return results
# ----------------------------------------------------------------------------- class SVN(object):
# SVN utils: COMMAND = "svn"
@staticmethod
def RunSVN(args, in_directory): def Run(args, in_directory):
"""Runs svn, sending output to stdout. """Runs svn, sending output to stdout.
Args: Args:
@ -86,13 +85,13 @@ def RunSVN(args, in_directory):
Raises: Raises:
Error: An error occurred while running the svn command. Error: An error occurred while running the svn command.
""" """
c = [SVN_COMMAND] c = [SVN.COMMAND]
c.extend(args) c.extend(args)
gclient_utils.SubprocessCall(c, in_directory) gclient_utils.SubprocessCall(c, in_directory)
@staticmethod
def CaptureSVN(args, in_directory=None, print_error=True): def Capture(args, in_directory=None, print_error=True):
"""Runs svn, capturing output sent to stdout as a string. """Runs svn, capturing output sent to stdout as a string.
Args: Args:
@ -102,7 +101,7 @@ def CaptureSVN(args, in_directory=None, print_error=True):
Returns: Returns:
The output sent to stdout as a string. The output sent to stdout as a string.
""" """
c = [SVN_COMMAND] c = [SVN.COMMAND]
c.extend(args) c.extend(args)
# *Sigh*: Windows needs shell=True, or else it won't search %PATH% for # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for
@ -118,15 +117,15 @@ def CaptureSVN(args, in_directory=None, print_error=True):
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=stderr).communicate()[0] stderr=stderr).communicate()[0]
@staticmethod
def RunSVNAndGetFileList(options, args, in_directory, file_list): def RunAndGetFileList(options, args, in_directory, file_list):
"""Runs svn checkout, update, or status, output to stdout. """Runs svn checkout, update, or status, output to stdout.
The first item in args must be either "checkout", "update", or "status". The first item in args must be either "checkout", "update", or "status".
svn's stdout is parsed to collect a list of files checked out or updated. svn's stdout is parsed to collect a list of files checked out or updated.
These files are appended to file_list. svn's stdout is also printed to These files are appended to file_list. svn's stdout is also printed to
sys.stdout as in RunSVN. sys.stdout as in Run.
Args: Args:
options: command line options to gclient options: command line options to gclient
@ -136,7 +135,7 @@ def RunSVNAndGetFileList(options, args, in_directory, file_list):
Raises: Raises:
Error: An error occurred while running the svn command. Error: An error occurred while running the svn command.
""" """
command = [SVN_COMMAND] command = [SVN.COMMAND]
command.extend(args) command.extend(args)
# svn update and svn checkout use the same pattern: the first three columns # svn update and svn checkout use the same pattern: the first three columns
@ -167,13 +166,14 @@ def RunSVNAndGetFileList(options, args, in_directory, file_list):
if match: if match:
file_list.append(match.group(1)) file_list.append(match.group(1))
RunSVNAndFilterOutput(args, SVN.RunAndFilterOutput(args,
in_directory, in_directory,
options.verbose, options.verbose,
True, True,
CaptureMatchingLines) CaptureMatchingLines)
def RunSVNAndFilterOutput(args, @staticmethod
def RunAndFilterOutput(args,
in_directory, in_directory,
print_messages, print_messages,
print_stdout, print_stdout,
@ -185,7 +185,7 @@ def RunSVNAndFilterOutput(args,
"status", or "diff". "status", or "diff".
svn's stdout is passed line-by-line to the given filter function. If svn's stdout is passed line-by-line to the given filter function. If
print_stdout is true, it is also printed to sys.stdout as in RunSVN. print_stdout is true, it is also printed to sys.stdout as in Run.
Args: Args:
args: A sequence of command line parameters to be passed to svn. args: A sequence of command line parameters to be passed to svn.
@ -200,7 +200,7 @@ def RunSVNAndFilterOutput(args,
Raises: Raises:
Error: An error occurred while running the svn command. Error: An error occurred while running the svn command.
""" """
command = [SVN_COMMAND] command = [SVN.COMMAND]
command.extend(args) command.extend(args)
gclient_utils.SubprocessCallAndFilter(command, gclient_utils.SubprocessCallAndFilter(command,
@ -209,7 +209,8 @@ def RunSVNAndFilterOutput(args,
print_stdout, print_stdout,
filter=filter) filter=filter)
def CaptureSVNInfo(relpath, in_directory=None, print_error=True): @staticmethod
def CaptureInfo(relpath, in_directory=None, print_error=True):
"""Returns a dictionary from the svn info output for the given file. """Returns a dictionary from the svn info output for the given file.
Args: Args:
@ -217,7 +218,7 @@ def CaptureSVNInfo(relpath, in_directory=None, print_error=True):
the directory given by in_directory. the directory given by in_directory.
in_directory: The directory where svn is to be run. in_directory: The directory where svn is to be run.
""" """
output = CaptureSVN(["info", "--xml", relpath], in_directory, print_error) output = SVN.Capture(["info", "--xml", relpath], in_directory, print_error)
dom = gclient_utils.ParseXML(output) dom = gclient_utils.ParseXML(output)
result = {} result = {}
if dom: if dom:
@ -237,29 +238,33 @@ def CaptureSVNInfo(relpath, in_directory=None, print_error=True):
result['Repository Root'] = C(GetNamedNodeText(dom, 'root'), str) result['Repository Root'] = C(GetNamedNodeText(dom, 'root'), str)
result['URL'] = C(GetNamedNodeText(dom, 'url'), str) result['URL'] = C(GetNamedNodeText(dom, 'url'), str)
result['UUID'] = C(GetNamedNodeText(dom, 'uuid'), str) result['UUID'] = C(GetNamedNodeText(dom, 'uuid'), str)
result['Revision'] = C(GetNodeNamedAttributeText(dom, 'entry', 'revision'), result['Revision'] = C(GetNodeNamedAttributeText(dom, 'entry',
'revision'),
int) int)
result['Node Kind'] = C(GetNodeNamedAttributeText(dom, 'entry', 'kind'), result['Node Kind'] = C(GetNodeNamedAttributeText(dom, 'entry', 'kind'),
str) str)
# Differs across versions.
if result['Node Kind'] == 'dir':
result['Node Kind'] = 'directory'
result['Schedule'] = C(GetNamedNodeText(dom, 'schedule'), str) result['Schedule'] = C(GetNamedNodeText(dom, 'schedule'), str)
result['Path'] = C(GetNodeNamedAttributeText(dom, 'entry', 'path'), str) result['Path'] = C(GetNodeNamedAttributeText(dom, 'entry', 'path'), str)
result['Copied From URL'] = C(GetNamedNodeText(dom, 'copy-from-url'), str) result['Copied From URL'] = C(GetNamedNodeText(dom, 'copy-from-url'), str)
result['Copied From Rev'] = C(GetNamedNodeText(dom, 'copy-from-rev'), str) result['Copied From Rev'] = C(GetNamedNodeText(dom, 'copy-from-rev'), str)
return result return result
@staticmethod
def CaptureSVNHeadRevision(url): def CaptureHeadRevision(url):
"""Get the head revision of a SVN repository. """Get the head revision of a SVN repository.
Returns: Returns:
Int head revision Int head revision
""" """
info = CaptureSVN(["info", "--xml", url], os.getcwd()) info = SVN.Capture(["info", "--xml", url], os.getcwd())
dom = xml.dom.minidom.parseString(info) dom = xml.dom.minidom.parseString(info)
return dom.getElementsByTagName('entry')[0].getAttribute('revision') return dom.getElementsByTagName('entry')[0].getAttribute('revision')
@staticmethod
def CaptureSVNStatus(files): def CaptureStatus(files):
"""Returns the svn 1.5 svn status emulated output. """Returns the svn 1.5 svn status emulated output.
@files can be a string (one file) or a list of files. @files can be a string (one file) or a list of files.
@ -291,11 +296,12 @@ def CaptureSVNStatus(files):
'replaced': 'R', 'replaced': 'R',
'unversioned': '?', 'unversioned': '?',
} }
dom = gclient_utils.ParseXML(CaptureSVN(command)) dom = gclient_utils.ParseXML(SVN.Capture(command))
results = [] results = []
if dom: if dom:
# /status/target/entry/(wc-status|commit|author|date) # /status/target/entry/(wc-status|commit|author|date)
for target in dom.getElementsByTagName('target'): for target in dom.getElementsByTagName('target'):
#base_path = target.getAttribute('path')
for entry in target.getElementsByTagName('entry'): for entry in target.getElementsByTagName('entry'):
file_path = entry.getAttribute('path') file_path = entry.getAttribute('path')
wc_status = entry.getElementsByTagName('wc-status') wc_status = entry.getElementsByTagName('wc-status')
@ -334,3 +340,76 @@ def CaptureSVNStatus(files):
item = (''.join(statuses), file_path) item = (''.join(statuses), file_path)
results.append(item) results.append(item)
return results return results
@staticmethod
def IsMoved(filename):
"""Determine if a file has been added through svn mv"""
info = SVN.CaptureInfo(filename)
return (info.get('Copied From URL') and
info.get('Copied From Rev') and
info.get('Schedule') == 'add')
@staticmethod
def GetFileProperty(file, property_name):
"""Returns the value of an SVN property for the given file.
Args:
file: The file to check
property_name: The name of the SVN property, e.g. "svn:mime-type"
Returns:
The value of the property, which will be the empty string if the property
is not set on the file. If the file is not under version control, the
empty string is also returned.
"""
output = SVN.Capture(["propget", property_name, file])
if (output.startswith("svn: ") and
output.endswith("is not under version control")):
return ""
else:
return output
@staticmethod
def DiffItem(filename):
"""Diff a single file"""
# Use svn info output instead of os.path.isdir because the latter fails
# when the file is deleted.
if SVN.CaptureInfo(filename).get("Node Kind") == "directory":
return None
# If the user specified a custom diff command in their svn config file,
# then it'll be used when we do svn diff, which we don't want to happen
# since we want the unified diff. Using --diff-cmd=diff doesn't always
# work, since they can have another diff executable in their path that
# gives different line endings. So we use a bogus temp directory as the
# config directory, which gets around these problems.
if sys.platform.startswith("win"):
parent_dir = tempfile.gettempdir()
else:
parent_dir = sys.path[0] # tempdir is not secure.
bogus_dir = os.path.join(parent_dir, "temp_svn_config")
if not os.path.exists(bogus_dir):
os.mkdir(bogus_dir)
# Grabs the diff data.
data = SVN.Capture(["diff", "--config-dir", bogus_dir, filename], None)
# We know the diff will be incorrectly formatted. Fix it.
if SVN.IsMoved(filename):
# The file is "new" in the patch sense. Generate a homebrew diff.
# We can't use ReadFile() since it's not using binary mode.
file_handle = open(filename, 'rb')
file_content = file_handle.read()
file_handle.close()
# Prepend '+' to every lines.
file_content = ['+' + i for i in file_content.splitlines(True)]
nb_lines = len(file_content)
# We need to use / since patch on unix will fail otherwise.
filename = filename.replace('\\', '/')
data = "Index: %s\n" % filename
data += ("============================================================="
"======\n")
# Note: Should we use /dev/null instead?
data += "--- %s\n" % filename
data += "+++ %s\n" % filename
data += "@@ -0,0 +1,%d @@\n" % nb_lines
data += ''.join(file_content)
return data

@ -16,7 +16,7 @@ class GclTestsBase(SuperMoxTestBase):
SuperMoxTestBase.setUp(self) SuperMoxTestBase.setUp(self)
self.fake_root_dir = self.RootDir() self.fake_root_dir = self.RootDir()
self.mox.StubOutWithMock(gcl, 'RunShell') self.mox.StubOutWithMock(gcl, 'RunShell')
self.mox.StubOutWithMock(gcl.gclient_scm, 'CaptureSVNInfo') self.mox.StubOutWithMock(gcl.SVN, 'CaptureInfo')
self.mox.StubOutWithMock(gcl, 'tempfile') self.mox.StubOutWithMock(gcl, 'tempfile')
self.mox.StubOutWithMock(gcl.upload, 'RealMain') self.mox.StubOutWithMock(gcl.upload, 'RealMain')
# These are not tested. # These are not tested.
@ -29,25 +29,21 @@ class GclUnittest(GclTestsBase):
def testMembersChanged(self): def testMembersChanged(self):
self.mox.ReplayAll() self.mox.ReplayAll()
members = [ members = [
'CODEREVIEW_SETTINGS', 'CODEREVIEW_SETTINGS_FILE', 'CODEREVIEW_SETTINGS', 'CODEREVIEW_SETTINGS_FILE', 'Change',
'Change', 'ChangeInfo', 'Changes', 'Commit', 'ChangeInfo', 'Changes', 'Commit', 'DEFAULT_LINT_IGNORE_REGEX',
'DEFAULT_LINT_IGNORE_REGEX', 'DEFAULT_LINT_REGEX', 'DEFAULT_LINT_REGEX', 'DeleteEmptyChangeLists', 'DoPresubmitChecks',
'DeleteEmptyChangeLists', 'DoPresubmitChecks',
'ErrorExit', 'FILES_CACHE', 'FilterFlag', 'GenerateChangeName', 'ErrorExit', 'FILES_CACHE', 'FilterFlag', 'GenerateChangeName',
'GenerateDiff', 'GenerateDiff', 'GetCLs', 'GetCacheDir', 'GetCachedFile',
'GetCacheDir', 'GetCachedFile', 'GetChangesDir', 'GetCLs', 'GetChangelistInfoFile', 'GetChangesDir', 'GetCodeReviewSetting',
'GetChangelistInfoFile', 'GetCodeReviewSetting', 'GetEditor', 'GetEditor', 'GetFilesNotInCL', 'GetInfoDir', 'GetIssueDescription',
'GetFilesNotInCL', 'GetInfoDir', 'GetIssueDescription', 'GetModifiedFiles', 'GetRepositoryRoot', 'Help', 'Lint',
'GetModifiedFiles', 'GetRepositoryRoot', 'LoadChangelistInfoForMultiple', 'MISSING_TEST_MSG', 'Opened',
'GetSVNFileProperty', 'Help', 'IsSVNMoved', 'OptionallyDoPresubmitChecks', 'PresubmitCL', 'REPOSITORY_ROOT',
'Lint', 'LoadChangelistInfoForMultiple', 'ReadFile', 'RunShell', 'RunShellWithReturnCode', 'SVN',
'MISSING_TEST_MSG', 'Opened', 'OptionallyDoPresubmitChecks', 'SendToRietveld', 'TryChange', 'UnknownFiles', 'UploadCL', 'Warn',
'PresubmitCL', 'ReadFile', 'REPOSITORY_ROOT', 'RunShell', 'WriteFile', 'gclient_utils', 'getpass', 'main', 'os', 'random', 're',
'RunShellWithReturnCode', 'SendToRietveld', 'TryChange', 'shutil', 'string', 'subprocess', 'sys', 'tempfile', 'upload',
'UnknownFiles', 'UploadCL', 'Warn', 'WriteFile', 'urllib2',
'gclient_scm', 'gclient_utils', 'getpass', 'main', 'os', 'random', 're',
'shutil', 'string', 'subprocess', 'sys', 'tempfile',
'upload', 'urllib2',
] ]
# If this test fails, you should add the relevant test. # If this test fails, you should add the relevant test.
self.compareMembers(gcl, members) self.compareMembers(gcl, members)
@ -70,8 +66,7 @@ class GclUnittest(GclTestsBase):
result = { result = {
"Repository Root": "" "Repository Root": ""
} }
gcl.gclient_scm.CaptureSVNInfo("/bleh/prout", print_error=False).AndReturn( gcl.SVN.CaptureInfo("/bleh/prout", print_error=False).AndReturn(result)
result)
self.mox.ReplayAll() self.mox.ReplayAll()
self.assertRaises(Exception, gcl.GetRepositoryRoot) self.assertRaises(Exception, gcl.GetRepositoryRoot)
@ -80,12 +75,10 @@ class GclUnittest(GclTestsBase):
root_path = gcl.os.path.join('bleh', 'prout', 'pouet') root_path = gcl.os.path.join('bleh', 'prout', 'pouet')
gcl.os.getcwd().AndReturn(root_path) gcl.os.getcwd().AndReturn(root_path)
result1 = { "Repository Root": "Some root" } result1 = { "Repository Root": "Some root" }
gcl.gclient_scm.CaptureSVNInfo(root_path, gcl.SVN.CaptureInfo(root_path, print_error=False).AndReturn(result1)
print_error=False).AndReturn(result1)
gcl.os.getcwd().AndReturn(root_path) gcl.os.getcwd().AndReturn(root_path)
results2 = { "Repository Root": "A different root" } results2 = { "Repository Root": "A different root" }
gcl.gclient_scm.CaptureSVNInfo( gcl.SVN.CaptureInfo(gcl.os.path.dirname(root_path),
gcl.os.path.dirname(root_path),
print_error=False).AndReturn(results2) print_error=False).AndReturn(results2)
self.mox.ReplayAll() self.mox.ReplayAll()
self.assertEquals(gcl.GetRepositoryRoot(), root_path) self.assertEquals(gcl.GetRepositoryRoot(), root_path)

@ -33,12 +33,12 @@ class BaseTestCase(GCBaseTestCase):
self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'FileWrite') self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'FileWrite')
self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'SubprocessCall') self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'SubprocessCall')
self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'RemoveDirectory') self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'RemoveDirectory')
self._CaptureSVNInfo = gclient_scm.CaptureSVNInfo self._CaptureSVNInfo = gclient_scm.scm.SVN.CaptureInfo
self.mox.StubOutWithMock(gclient_scm, 'CaptureSVN') self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'Capture')
self.mox.StubOutWithMock(gclient_scm, 'CaptureSVNInfo') self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'CaptureInfo')
self.mox.StubOutWithMock(gclient_scm, 'CaptureSVNStatus') self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'CaptureStatus')
self.mox.StubOutWithMock(gclient_scm, 'RunSVN') self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'Run')
self.mox.StubOutWithMock(gclient_scm, 'RunSVNAndGetFileList') self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'RunAndGetFileList')
self._scm_wrapper = gclient_scm.CreateSCM self._scm_wrapper = gclient_scm.CreateSCM
@ -64,9 +64,11 @@ class SVNWrapperTestCase(BaseTestCase):
def testDir(self): def testDir(self):
members = [ members = [
'FullUrlForRelativeUrl', 'RunCommand', 'cleanup', 'diff', 'export', 'COMMAND', 'Capture', 'CaptureHeadRevision', 'CaptureInfo',
'pack', 'relpath', 'revert', 'revinfo', 'runhooks', 'scm_name', 'status', 'CaptureStatus', 'DiffItem', 'FullUrlForRelativeUrl', 'GetFileProperty',
'update', 'url', 'IsMoved', 'Run', 'RunAndFilterOutput', 'RunAndGetFileList',
'RunCommand', 'cleanup', 'diff', 'export', 'pack', 'relpath', 'revert',
'revinfo', 'runhooks', 'scm_name', 'status', 'update', 'url',
] ]
# If you add a member, be sure to add the relevant test! # If you add a member, be sure to add the relevant test!
@ -113,7 +115,8 @@ class SVNWrapperTestCase(BaseTestCase):
# Checkout. # Checkout.
gclient_scm.os.path.exists(base_path).AndReturn(False) gclient_scm.os.path.exists(base_path).AndReturn(False)
files_list = self.mox.CreateMockAnything() files_list = self.mox.CreateMockAnything()
gclient_scm.RunSVNAndGetFileList(options, ['checkout', self.url, base_path], gclient_scm.scm.SVN.RunAndGetFileList(options,
['checkout', self.url, base_path],
self.root_dir, files_list) self.root_dir, files_list)
self.mox.ReplayAll() self.mox.ReplayAll()
@ -125,8 +128,9 @@ class SVNWrapperTestCase(BaseTestCase):
options = self.Options(verbose=True) options = self.Options(verbose=True)
base_path = gclient_scm.os.path.join(self.root_dir, self.relpath) base_path = gclient_scm.os.path.join(self.root_dir, self.relpath)
gclient_scm.os.path.isdir(base_path).AndReturn(True) gclient_scm.os.path.isdir(base_path).AndReturn(True)
gclient_scm.CaptureSVNStatus(base_path).AndReturn([]) gclient_scm.scm.SVN.CaptureStatus(base_path).AndReturn([])
gclient_scm.RunSVNAndGetFileList(options, ['update', '--revision', 'BASE'], gclient_scm.scm.SVN.RunAndGetFileList(options,
['update', '--revision', 'BASE'],
base_path, mox.IgnoreArg()) base_path, mox.IgnoreArg())
self.mox.ReplayAll() self.mox.ReplayAll()
@ -145,14 +149,15 @@ class SVNWrapperTestCase(BaseTestCase):
] ]
file_path1 = gclient_scm.os.path.join(base_path, 'a') file_path1 = gclient_scm.os.path.join(base_path, 'a')
file_path2 = gclient_scm.os.path.join(base_path, 'b') file_path2 = gclient_scm.os.path.join(base_path, 'b')
gclient_scm.CaptureSVNStatus(base_path).AndReturn(items) gclient_scm.scm.SVN.CaptureStatus(base_path).AndReturn(items)
gclient_scm.os.path.exists(file_path1).AndReturn(True) gclient_scm.os.path.exists(file_path1).AndReturn(True)
gclient_scm.os.path.isfile(file_path1).AndReturn(True) gclient_scm.os.path.isfile(file_path1).AndReturn(True)
gclient_scm.os.remove(file_path1) gclient_scm.os.remove(file_path1)
gclient_scm.os.path.exists(file_path2).AndReturn(True) gclient_scm.os.path.exists(file_path2).AndReturn(True)
gclient_scm.os.path.isfile(file_path2).AndReturn(True) gclient_scm.os.path.isfile(file_path2).AndReturn(True)
gclient_scm.os.remove(file_path2) gclient_scm.os.remove(file_path2)
gclient_scm.RunSVNAndGetFileList(options, ['update', '--revision', 'BASE'], gclient_scm.scm.SVN.RunAndGetFileList(options,
['update', '--revision', 'BASE'],
base_path, mox.IgnoreArg()) base_path, mox.IgnoreArg())
print(gclient_scm.os.path.join(base_path, 'a')) print(gclient_scm.os.path.join(base_path, 'a'))
print(gclient_scm.os.path.join(base_path, 'b')) print(gclient_scm.os.path.join(base_path, 'b'))
@ -170,7 +175,7 @@ class SVNWrapperTestCase(BaseTestCase):
items = [ items = [
('~ ', 'a'), ('~ ', 'a'),
] ]
gclient_scm.CaptureSVNStatus(base_path).AndReturn(items) gclient_scm.scm.SVN.CaptureStatus(base_path).AndReturn(items)
file_path = gclient_scm.os.path.join(base_path, 'a') file_path = gclient_scm.os.path.join(base_path, 'a')
print(file_path) print(file_path)
gclient_scm.os.path.exists(file_path).AndReturn(True) gclient_scm.os.path.exists(file_path).AndReturn(True)
@ -178,7 +183,8 @@ class SVNWrapperTestCase(BaseTestCase):
gclient_scm.os.path.isdir(file_path).AndReturn(True) gclient_scm.os.path.isdir(file_path).AndReturn(True)
gclient_scm.gclient_utils.RemoveDirectory(file_path) gclient_scm.gclient_utils.RemoveDirectory(file_path)
file_list1 = [] file_list1 = []
gclient_scm.RunSVNAndGetFileList(options, ['update', '--revision', 'BASE'], gclient_scm.scm.SVN.RunAndGetFileList(options,
['update', '--revision', 'BASE'],
base_path, mox.IgnoreArg()) base_path, mox.IgnoreArg())
self.mox.ReplayAll() self.mox.ReplayAll()
@ -191,7 +197,8 @@ class SVNWrapperTestCase(BaseTestCase):
options = self.Options(verbose=True) options = self.Options(verbose=True)
base_path = gclient_scm.os.path.join(self.root_dir, self.relpath) base_path = gclient_scm.os.path.join(self.root_dir, self.relpath)
gclient_scm.os.path.isdir(base_path).AndReturn(True) gclient_scm.os.path.isdir(base_path).AndReturn(True)
gclient_scm.RunSVNAndGetFileList(options, ['status'] + self.args, gclient_scm.scm.SVN.RunAndGetFileList(options,
['status'] + self.args,
base_path, []).AndReturn(None) base_path, []).AndReturn(None)
self.mox.ReplayAll() self.mox.ReplayAll()
@ -216,8 +223,9 @@ class SVNWrapperTestCase(BaseTestCase):
# Checkout. # Checkout.
gclient_scm.os.path.exists(base_path).AndReturn(False) gclient_scm.os.path.exists(base_path).AndReturn(False)
files_list = self.mox.CreateMockAnything() files_list = self.mox.CreateMockAnything()
gclient_scm.RunSVNAndGetFileList(options, ['checkout', self.url, gclient_scm.scm.SVN.RunAndGetFileList(options,
base_path], self.root_dir, files_list) ['checkout', self.url, base_path],
self.root_dir, files_list)
self.mox.ReplayAll() self.mox.ReplayAll()
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir, scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
relpath=self.relpath) relpath=self.relpath)
@ -238,15 +246,17 @@ class SVNWrapperTestCase(BaseTestCase):
).AndReturn(False) ).AndReturn(False)
# Checkout or update. # Checkout or update.
gclient_scm.os.path.exists(base_path).AndReturn(True) gclient_scm.os.path.exists(base_path).AndReturn(True)
gclient_scm.CaptureSVNInfo(gclient_scm.os.path.join(base_path, "."), '.' gclient_scm.scm.SVN.CaptureInfo(
gclient_scm.os.path.join(base_path, "."), '.'
).AndReturn(file_info) ).AndReturn(file_info)
# Cheat a bit here. # Cheat a bit here.
gclient_scm.CaptureSVNInfo(file_info['URL'], '.').AndReturn(file_info) gclient_scm.scm.SVN.CaptureInfo(file_info['URL'], '.').AndReturn(file_info)
additional_args = [] additional_args = []
if options.manually_grab_svn_rev: if options.manually_grab_svn_rev:
additional_args = ['--revision', str(file_info['Revision'])] additional_args = ['--revision', str(file_info['Revision'])]
files_list = [] files_list = []
gclient_scm.RunSVNAndGetFileList(options, gclient_scm.scm.SVN.RunAndGetFileList(
options,
['update', base_path] + additional_args, ['update', base_path] + additional_args,
self.root_dir, files_list) self.root_dir, files_list)
@ -356,9 +366,9 @@ from :3
def testDir(self): def testDir(self):
members = [ members = [
'FullUrlForRelativeUrl', 'RunCommand', 'cleanup', 'diff', 'export', 'COMMAND', 'Capture', 'CaptureStatus', 'FullUrlForRelativeUrl',
'relpath', 'revert', 'revinfo', 'runhooks', 'scm_name', 'status', 'RunCommand', 'cleanup', 'diff', 'export', 'relpath', 'revert',
'update', 'url', 'revinfo', 'runhooks', 'scm_name', 'status', 'update', 'url',
] ]
# If you add a member, be sure to add the relevant test! # If you add a member, be sure to add the relevant test!

@ -22,8 +22,6 @@ import __builtin__
import StringIO import StringIO
import gclient import gclient
# Temporary due to the "from scm import *" in gclient_scm.
import scm
from super_mox import mox, IsOneOf, SuperMoxTestBase from super_mox import mox, IsOneOf, SuperMoxTestBase
@ -50,16 +48,11 @@ class GClientBaseTestCase(BaseTestCase):
self.mox.StubOutWithMock(gclient.gclient_utils, 'SubprocessCall') self.mox.StubOutWithMock(gclient.gclient_utils, 'SubprocessCall')
self.mox.StubOutWithMock(gclient.gclient_utils, 'RemoveDirectory') self.mox.StubOutWithMock(gclient.gclient_utils, 'RemoveDirectory')
# Mock them to be sure nothing bad happens. # Mock them to be sure nothing bad happens.
self.mox.StubOutWithMock(gclient.gclient_scm, 'CaptureSVN') self.mox.StubOutWithMock(gclient.gclient_scm.scm.SVN, 'Capture')
self.mox.StubOutWithMock(gclient.gclient_scm, 'CaptureSVNInfo') self.mox.StubOutWithMock(gclient.gclient_scm.scm.SVN, 'CaptureInfo')
self.mox.StubOutWithMock(gclient.gclient_scm, 'CaptureSVNStatus') self.mox.StubOutWithMock(gclient.gclient_scm.scm.SVN, 'CaptureStatus')
self.mox.StubOutWithMock(gclient.gclient_scm, 'RunSVN') self.mox.StubOutWithMock(gclient.gclient_scm.scm.SVN, 'Run')
self.mox.StubOutWithMock(gclient.gclient_scm, 'RunSVNAndGetFileList') self.mox.StubOutWithMock(gclient.gclient_scm.scm.SVN, 'RunAndGetFileList')
self.mox.StubOutWithMock(scm, 'CaptureSVN')
self.mox.StubOutWithMock(scm, 'CaptureSVNInfo')
self.mox.StubOutWithMock(scm, 'CaptureSVNStatus')
self.mox.StubOutWithMock(scm, 'RunSVN')
self.mox.StubOutWithMock(scm, 'RunSVNAndGetFileList')
self._gclient_gclient = gclient.GClient self._gclient_gclient = gclient.GClient
gclient.GClient = self.mox.CreateMockAnything() gclient.GClient = self.mox.CreateMockAnything()
self._scm_wrapper = gclient.gclient_scm.CreateSCM self._scm_wrapper = gclient.gclient_scm.CreateSCM

@ -7,9 +7,9 @@
import StringIO import StringIO
# Local imports
import presubmit_support as presubmit import presubmit_support as presubmit
import presubmit_canned_checks # Shortcut.
from presubmit_support import presubmit_canned_checks
from super_mox import mox, SuperMoxTestBase from super_mox import mox, SuperMoxTestBase
@ -47,9 +47,11 @@ def GetPreferredTrySlaves():
presubmit.os.path.abspath = MockAbsPath presubmit.os.path.abspath = MockAbsPath
presubmit.os.getcwd = self.RootDir presubmit.os.getcwd = self.RootDir
presubmit.os.chdir = MockChdir presubmit.os.chdir = MockChdir
self.mox.StubOutWithMock(presubmit.gclient_scm, 'CaptureSVNInfo') self.mox.StubOutWithMock(presubmit.scm.SVN, 'CaptureInfo')
self.mox.StubOutWithMock(presubmit.gcl, 'GetSVNFileProperty') self.mox.StubOutWithMock(presubmit.scm.SVN, 'GetFileProperty')
# TODO(maruel): Err, small duplication of code here.
self.mox.StubOutWithMock(presubmit.gcl, 'ReadFile') self.mox.StubOutWithMock(presubmit.gcl, 'ReadFile')
self.mox.StubOutWithMock(presubmit.gclient_utils, 'FileRead')
class PresubmitUnittest(PresubmitTestsBase): class PresubmitUnittest(PresubmitTestsBase):
@ -63,9 +65,9 @@ class PresubmitUnittest(PresubmitTestsBase):
'NotImplementedException', 'OutputApi', 'ParseFiles', 'NotImplementedException', 'OutputApi', 'ParseFiles',
'PresubmitExecuter', 'PromptYesNo', 'ScanSubDirs', 'PresubmitExecuter', 'PromptYesNo', 'ScanSubDirs',
'SvnAffectedFile', 'SvnChange', 'cPickle', 'cStringIO', 'SvnAffectedFile', 'SvnChange', 'cPickle', 'cStringIO',
'exceptions', 'fnmatch', 'gcl', 'gclient_scm', 'glob', 'exceptions', 'fnmatch', 'gcl', 'gclient_utils', 'glob',
'logging', 'marshal', 'normpath', 'optparse', 'os', 'pickle', 'logging', 'marshal', 'normpath', 'optparse', 'os', 'pickle',
'presubmit_canned_checks', 'random', 're', 'subprocess', 'sys', 'presubmit_canned_checks', 'random', 're', 'scm', 'subprocess', 'sys',
'tempfile', 'time', 'traceback', 'types', 'unittest', 'urllib2', 'tempfile', 'time', 'traceback', 'types', 'unittest', 'urllib2',
'warnings', 'warnings',
] ]
@ -140,22 +142,22 @@ class PresubmitUnittest(PresubmitTestsBase):
presubmit.os.path.exists(notfound).AndReturn(True) presubmit.os.path.exists(notfound).AndReturn(True)
presubmit.os.path.isdir(notfound).AndReturn(False) presubmit.os.path.isdir(notfound).AndReturn(False)
presubmit.os.path.exists(flap).AndReturn(False) presubmit.os.path.exists(flap).AndReturn(False)
presubmit.gclient_scm.CaptureSVNInfo(flap presubmit.scm.SVN.CaptureInfo(flap
).AndReturn({'Node Kind': 'file'}) ).AndReturn({'Node Kind': 'file'})
presubmit.gcl.GetSVNFileProperty(blat, 'svn:mime-type').AndReturn(None) presubmit.scm.SVN.GetFileProperty(blat, 'svn:mime-type').AndReturn(None)
presubmit.gcl.GetSVNFileProperty( presubmit.scm.SVN.GetFileProperty(
binary, 'svn:mime-type').AndReturn('application/octet-stream') binary, 'svn:mime-type').AndReturn('application/octet-stream')
presubmit.gcl.GetSVNFileProperty( presubmit.scm.SVN.GetFileProperty(
notfound, 'svn:mime-type').AndReturn('') notfound, 'svn:mime-type').AndReturn('')
presubmit.gclient_scm.CaptureSVNInfo(blat).AndReturn( presubmit.scm.SVN.CaptureInfo(blat).AndReturn(
{'URL': 'svn:/foo/foo/blat.cc'}) {'URL': 'svn:/foo/foo/blat.cc'})
presubmit.gclient_scm.CaptureSVNInfo(binary).AndReturn( presubmit.scm.SVN.CaptureInfo(binary).AndReturn(
{'URL': 'svn:/foo/binary.dll'}) {'URL': 'svn:/foo/binary.dll'})
presubmit.gclient_scm.CaptureSVNInfo(notfound).AndReturn({}) presubmit.scm.SVN.CaptureInfo(notfound).AndReturn({})
presubmit.gclient_scm.CaptureSVNInfo(flap).AndReturn( presubmit.scm.SVN.CaptureInfo(flap).AndReturn(
{'URL': 'svn:/foo/boo/flap.h'}) {'URL': 'svn:/foo/boo/flap.h'})
presubmit.gcl.ReadFile(blat).AndReturn('boo!\nahh?') presubmit.gclient_utils.FileRead(blat, 'rU').AndReturn('boo!\nahh?')
presubmit.gcl.ReadFile(notfound).AndReturn('look!\nthere?') presubmit.gclient_utils.FileRead(notfound, 'rU').AndReturn('look!\nthere?')
self.mox.ReplayAll() self.mox.ReplayAll()
change = presubmit.SvnChange('mychange', '\n'.join(description_lines), change = presubmit.SvnChange('mychange', '\n'.join(description_lines),
@ -285,9 +287,9 @@ class PresubmitUnittest(PresubmitTestsBase):
root_path = join(self.fake_root_dir, 'PRESUBMIT.py') root_path = join(self.fake_root_dir, 'PRESUBMIT.py')
presubmit.os.path.isfile(root_path).AndReturn(True) presubmit.os.path.isfile(root_path).AndReturn(True)
presubmit.os.path.isfile(haspresubmit_path).AndReturn(True) presubmit.os.path.isfile(haspresubmit_path).AndReturn(True)
presubmit.gcl.ReadFile(root_path, presubmit.gclient_utils.FileRead(root_path,
'rU').AndReturn(self.presubmit_text) 'rU').AndReturn(self.presubmit_text)
presubmit.gcl.ReadFile(haspresubmit_path, presubmit.gclient_utils.FileRead(haspresubmit_path,
'rU').AndReturn(self.presubmit_text) 'rU').AndReturn(self.presubmit_text)
presubmit.random.randint(0, 4).AndReturn(1) presubmit.random.randint(0, 4).AndReturn(1)
self.mox.ReplayAll() self.mox.ReplayAll()
@ -313,9 +315,9 @@ class PresubmitUnittest(PresubmitTestsBase):
for i in range(2): for i in range(2):
presubmit.os.path.isfile(presubmit_path).AndReturn(True) presubmit.os.path.isfile(presubmit_path).AndReturn(True)
presubmit.os.path.isfile(haspresubmit_path).AndReturn(True) presubmit.os.path.isfile(haspresubmit_path).AndReturn(True)
presubmit.gcl.ReadFile(presubmit_path, 'rU' presubmit.gclient_utils.FileRead(presubmit_path, 'rU'
).AndReturn(self.presubmit_text) ).AndReturn(self.presubmit_text)
presubmit.gcl.ReadFile(haspresubmit_path, 'rU' presubmit.gclient_utils.FileRead(haspresubmit_path, 'rU'
).AndReturn(self.presubmit_text) ).AndReturn(self.presubmit_text)
presubmit.random.randint(0, 4).AndReturn(1) presubmit.random.randint(0, 4).AndReturn(1)
presubmit.random.randint(0, 4).AndReturn(1) presubmit.random.randint(0, 4).AndReturn(1)
@ -349,8 +351,9 @@ class PresubmitUnittest(PresubmitTestsBase):
'PRESUBMIT.py') 'PRESUBMIT.py')
presubmit.os.path.isfile(presubmit_path).AndReturn(True) presubmit.os.path.isfile(presubmit_path).AndReturn(True)
presubmit.os.path.isfile(haspresubmit_path).AndReturn(True) presubmit.os.path.isfile(haspresubmit_path).AndReturn(True)
presubmit.gcl.ReadFile(presubmit_path, 'rU').AndReturn(self.presubmit_text) presubmit.gclient_utils.FileRead(presubmit_path, 'rU'
presubmit.gcl.ReadFile(haspresubmit_path, 'rU').AndReturn( ).AndReturn(self.presubmit_text)
presubmit.gclient_utils.FileRead(haspresubmit_path, 'rU').AndReturn(
self.presubmit_text) self.presubmit_text)
presubmit.random.randint(0, 4).AndReturn(1) presubmit.random.randint(0, 4).AndReturn(1)
self.mox.ReplayAll() self.mox.ReplayAll()
@ -502,14 +505,14 @@ def CheckChangeOnCommit(input_api, output_api):
linux_presubmit = join(self.fake_root_dir, 'linux_only', 'PRESUBMIT.py') linux_presubmit = join(self.fake_root_dir, 'linux_only', 'PRESUBMIT.py')
presubmit.os.path.isfile(root_presubmit).AndReturn(True) presubmit.os.path.isfile(root_presubmit).AndReturn(True)
presubmit.gcl.ReadFile(root_presubmit, 'rU').AndReturn( presubmit.gclient_utils.FileRead(root_presubmit, 'rU').AndReturn(
self.presubmit_tryslave % '["win"]') self.presubmit_tryslave % '["win"]')
presubmit.os.path.isfile(root_presubmit).AndReturn(True) presubmit.os.path.isfile(root_presubmit).AndReturn(True)
presubmit.os.path.isfile(linux_presubmit).AndReturn(True) presubmit.os.path.isfile(linux_presubmit).AndReturn(True)
presubmit.gcl.ReadFile(root_presubmit, 'rU').AndReturn( presubmit.gclient_utils.FileRead(root_presubmit, 'rU').AndReturn(
self.presubmit_tryslave % '["win"]') self.presubmit_tryslave % '["win"]')
presubmit.gcl.ReadFile(linux_presubmit, 'rU').AndReturn( presubmit.gclient_utils.FileRead(linux_presubmit, 'rU').AndReturn(
self.presubmit_tryslave % '["linux"]') self.presubmit_tryslave % '["linux"]')
self.mox.ReplayAll() self.mox.ReplayAll()
@ -565,9 +568,9 @@ class InputApiUnittest(PresubmitTestsBase):
self.compareMembers(presubmit.InputApi(None, './.', False), members) self.compareMembers(presubmit.InputApi(None, './.', False), members)
def testDepotToLocalPath(self): def testDepotToLocalPath(self):
presubmit.gclient_scm.CaptureSVNInfo('svn://foo/smurf').AndReturn( presubmit.scm.SVN.CaptureInfo('svn://foo/smurf').AndReturn(
{'Path': 'prout'}) {'Path': 'prout'})
presubmit.gclient_scm.CaptureSVNInfo('svn:/foo/notfound/burp').AndReturn({}) presubmit.scm.SVN.CaptureInfo('svn:/foo/notfound/burp').AndReturn({})
self.mox.ReplayAll() self.mox.ReplayAll()
path = presubmit.InputApi(None, './p', False).DepotToLocalPath( path = presubmit.InputApi(None, './p', False).DepotToLocalPath(
@ -578,9 +581,9 @@ class InputApiUnittest(PresubmitTestsBase):
self.failUnless(path == None) self.failUnless(path == None)
def testLocalToDepotPath(self): def testLocalToDepotPath(self):
presubmit.gclient_scm.CaptureSVNInfo('smurf').AndReturn({'URL': presubmit.scm.SVN.CaptureInfo('smurf').AndReturn({'URL':
'svn://foo'}) 'svn://foo'})
presubmit.gclient_scm.CaptureSVNInfo('notfound-food').AndReturn({}) presubmit.scm.SVN.CaptureInfo('notfound-food').AndReturn({})
self.mox.ReplayAll() self.mox.ReplayAll()
path = presubmit.InputApi(None, './p', False).LocalToDepotPath('smurf') path = presubmit.InputApi(None, './p', False).LocalToDepotPath('smurf')
@ -631,18 +634,20 @@ class InputApiUnittest(PresubmitTestsBase):
presubmit.os.path.exists(notfound).AndReturn(False) presubmit.os.path.exists(notfound).AndReturn(False)
presubmit.os.path.exists(flap).AndReturn(True) presubmit.os.path.exists(flap).AndReturn(True)
presubmit.os.path.isdir(flap).AndReturn(False) presubmit.os.path.isdir(flap).AndReturn(False)
presubmit.gclient_scm.CaptureSVNInfo(beingdeleted).AndReturn({}) presubmit.scm.SVN.CaptureInfo(beingdeleted).AndReturn({})
presubmit.gclient_scm.CaptureSVNInfo(notfound).AndReturn({}) presubmit.scm.SVN.CaptureInfo(notfound).AndReturn({})
presubmit.gcl.GetSVNFileProperty(blat, 'svn:mime-type').AndReturn(None) presubmit.scm.SVN.GetFileProperty(blat, 'svn:mime-type').AndReturn(None)
presubmit.gcl.GetSVNFileProperty(readme, 'svn:mime-type').AndReturn(None) presubmit.scm.SVN.GetFileProperty(readme, 'svn:mime-type').AndReturn(None)
presubmit.gcl.GetSVNFileProperty(binary, 'svn:mime-type').AndReturn( presubmit.scm.SVN.GetFileProperty(binary, 'svn:mime-type').AndReturn(
'application/octet-stream') 'application/octet-stream')
presubmit.gcl.GetSVNFileProperty(weird, 'svn:mime-type').AndReturn(None) presubmit.scm.SVN.GetFileProperty(weird, 'svn:mime-type').AndReturn(None)
presubmit.gcl.GetSVNFileProperty(another, 'svn:mime-type').AndReturn(None) presubmit.scm.SVN.GetFileProperty(another, 'svn:mime-type').AndReturn(None)
presubmit.gcl.GetSVNFileProperty(third_party, 'svn:mime-type' presubmit.scm.SVN.GetFileProperty(third_party, 'svn:mime-type'
).AndReturn(None) ).AndReturn(None)
presubmit.gcl.ReadFile(blat).AndReturn('whatever\ncookie') presubmit.gclient_utils.FileRead(blat, 'rU'
presubmit.gcl.ReadFile(another).AndReturn('whatever\ncookie2') ).AndReturn('whatever\ncookie')
presubmit.gclient_utils.FileRead(another, 'rU'
).AndReturn('whatever\ncookie2')
self.mox.ReplayAll() self.mox.ReplayAll()
change = presubmit.SvnChange('mychange', '\n'.join(description_lines), change = presubmit.SvnChange('mychange', '\n'.join(description_lines),
@ -754,7 +759,7 @@ class InputApiUnittest(PresubmitTestsBase):
item = presubmit.os.path.join(self.fake_root_dir, item) item = presubmit.os.path.join(self.fake_root_dir, item)
presubmit.os.path.exists(item).AndReturn(True) presubmit.os.path.exists(item).AndReturn(True)
presubmit.os.path.isdir(item).AndReturn(False) presubmit.os.path.isdir(item).AndReturn(False)
presubmit.gcl.GetSVNFileProperty(item, 'svn:mime-type').AndReturn(None) presubmit.scm.SVN.GetFileProperty(item, 'svn:mime-type').AndReturn(None)
self.mox.ReplayAll() self.mox.ReplayAll()
change = presubmit.SvnChange('mychange', '', self.fake_root_dir, files, 0, change = presubmit.SvnChange('mychange', '', self.fake_root_dir, files, 0,
@ -776,7 +781,7 @@ class InputApiUnittest(PresubmitTestsBase):
item = presubmit.os.path.join(self.fake_root_dir, item) item = presubmit.os.path.join(self.fake_root_dir, item)
presubmit.os.path.exists(item).AndReturn(True) presubmit.os.path.exists(item).AndReturn(True)
presubmit.os.path.isdir(item).AndReturn(False) presubmit.os.path.isdir(item).AndReturn(False)
presubmit.gcl.GetSVNFileProperty(item, 'svn:mime-type').AndReturn(None) presubmit.scm.SVN.GetFileProperty(item, 'svn:mime-type').AndReturn(None)
self.mox.ReplayAll() self.mox.ReplayAll()
change = presubmit.SvnChange('mychange', '', self.fake_root_dir, files, 0, change = presubmit.SvnChange('mychange', '', self.fake_root_dir, files, 0,
@ -852,7 +857,7 @@ class InputApiUnittest(PresubmitTestsBase):
def testReadFileStringAccepted(self): def testReadFileStringAccepted(self):
path = presubmit.os.path.join(self.fake_root_dir, 'AA/boo') path = presubmit.os.path.join(self.fake_root_dir, 'AA/boo')
presubmit.gcl.ReadFile(path, 'x').AndReturn(None) presubmit.gclient_utils.FileRead(path, 'x').AndReturn(None)
self.mox.ReplayAll() self.mox.ReplayAll()
change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')], change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')],
@ -873,7 +878,8 @@ class InputApiUnittest(PresubmitTestsBase):
def testReadFileAffectedFileAccepted(self): def testReadFileAffectedFileAccepted(self):
file = presubmit.AffectedFile('AA/boo', 'M', self.fake_root_dir) file = presubmit.AffectedFile('AA/boo', 'M', self.fake_root_dir)
presubmit.gcl.ReadFile(file.AbsoluteLocalPath(), 'x').AndReturn(None) presubmit.gclient_utils.FileRead(file.AbsoluteLocalPath(), 'x'
).AndReturn(None)
self.mox.ReplayAll() self.mox.ReplayAll()
change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')], change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')],
@ -955,8 +961,8 @@ class AffectedFileUnittest(PresubmitTestsBase):
path = presubmit.os.path.join('foo', 'blat.cc') path = presubmit.os.path.join('foo', 'blat.cc')
presubmit.os.path.exists(path).AndReturn(True) presubmit.os.path.exists(path).AndReturn(True)
presubmit.os.path.isdir(path).AndReturn(False) presubmit.os.path.isdir(path).AndReturn(False)
presubmit.gcl.ReadFile(path).AndReturn('whatever\ncookie') presubmit.gclient_utils.FileRead(path, 'rU').AndReturn('whatever\ncookie')
presubmit.gclient_scm.CaptureSVNInfo(path).AndReturn( presubmit.scm.SVN.CaptureInfo(path).AndReturn(
{'URL': 'svn:/foo/foo/blat.cc'}) {'URL': 'svn:/foo/foo/blat.cc'})
self.mox.ReplayAll() self.mox.ReplayAll()
af = presubmit.SvnAffectedFile('foo/blat.cc', 'M') af = presubmit.SvnAffectedFile('foo/blat.cc', 'M')
@ -968,7 +974,7 @@ class AffectedFileUnittest(PresubmitTestsBase):
self.failUnless(af.ServerPath() == '') self.failUnless(af.ServerPath() == '')
def testProperty(self): def testProperty(self):
presubmit.gcl.GetSVNFileProperty('foo.cc', 'svn:secret-property' presubmit.scm.SVN.GetFileProperty('foo.cc', 'svn:secret-property'
).AndReturn('secret-property-value') ).AndReturn('secret-property-value')
self.mox.ReplayAll() self.mox.ReplayAll()
affected_file = presubmit.SvnAffectedFile('foo.cc', 'A') affected_file = presubmit.SvnAffectedFile('foo.cc', 'A')
@ -980,7 +986,7 @@ class AffectedFileUnittest(PresubmitTestsBase):
def testIsDirectoryNotExists(self): def testIsDirectoryNotExists(self):
presubmit.os.path.exists('foo.cc').AndReturn(False) presubmit.os.path.exists('foo.cc').AndReturn(False)
presubmit.gclient_scm.CaptureSVNInfo('foo.cc').AndReturn({}) presubmit.scm.SVN.CaptureInfo('foo.cc').AndReturn({})
self.mox.ReplayAll() self.mox.ReplayAll()
affected_file = presubmit.SvnAffectedFile('foo.cc', 'A') affected_file = presubmit.SvnAffectedFile('foo.cc', 'A')
# Verify cache coherency. # Verify cache coherency.
@ -1006,8 +1012,8 @@ class AffectedFileUnittest(PresubmitTestsBase):
presubmit.os.path.isdir(blat).AndReturn(False) presubmit.os.path.isdir(blat).AndReturn(False)
presubmit.os.path.exists(blob).AndReturn(True) presubmit.os.path.exists(blob).AndReturn(True)
presubmit.os.path.isdir(blob).AndReturn(False) presubmit.os.path.isdir(blob).AndReturn(False)
presubmit.gcl.GetSVNFileProperty(blat, 'svn:mime-type').AndReturn(None) presubmit.scm.SVN.GetFileProperty(blat, 'svn:mime-type').AndReturn(None)
presubmit.gcl.GetSVNFileProperty(blob, 'svn:mime-type' presubmit.scm.SVN.GetFileProperty(blob, 'svn:mime-type'
).AndReturn('application/octet-stream') ).AndReturn('application/octet-stream')
self.mox.ReplayAll() self.mox.ReplayAll()
@ -1153,9 +1159,9 @@ class CannedChecksUnittest(PresubmitTestsBase):
input_api1.AffectedSourceFiles(None).AndReturn(files1) input_api1.AffectedSourceFiles(None).AndReturn(files1)
else: else:
input_api1.AffectedFiles(include_deleted=False).AndReturn(files1) input_api1.AffectedFiles(include_deleted=False).AndReturn(files1)
presubmit.gcl.GetSVNFileProperty(presubmit.normpath('foo/bar.cc'), presubmit.scm.SVN.GetFileProperty(presubmit.normpath('foo/bar.cc'),
property).AndReturn(value1) property).AndReturn(value1)
presubmit.gcl.GetSVNFileProperty(presubmit.normpath('foo.cc'), presubmit.scm.SVN.GetFileProperty(presubmit.normpath('foo.cc'),
property).AndReturn(value1) property).AndReturn(value1)
change2 = presubmit.SvnChange('mychange', '', self.fake_root_dir, [], 0, 0) change2 = presubmit.SvnChange('mychange', '', self.fake_root_dir, [], 0, 0)
input_api2 = self.MockInputApi(change2, committing) input_api2 = self.MockInputApi(change2, committing)
@ -1168,9 +1174,9 @@ class CannedChecksUnittest(PresubmitTestsBase):
else: else:
input_api2.AffectedFiles(include_deleted=False).AndReturn(files2) input_api2.AffectedFiles(include_deleted=False).AndReturn(files2)
presubmit.gcl.GetSVNFileProperty(presubmit.normpath('foo/bar.cc'), presubmit.scm.SVN.GetFileProperty(presubmit.normpath('foo/bar.cc'),
property).AndReturn(value2) property).AndReturn(value2)
presubmit.gcl.GetSVNFileProperty(presubmit.normpath('foo.cc'), presubmit.scm.SVN.GetFileProperty(presubmit.normpath('foo.cc'),
property).AndReturn(value2) property).AndReturn(value2)
self.mox.ReplayAll() self.mox.ReplayAll()

@ -61,6 +61,7 @@ class RevertMainUnittest(RevertTestsBase):
class RevertRevertUnittest(RevertTestsBase): class RevertRevertUnittest(RevertTestsBase):
def setUp(self): def setUp(self):
RevertTestsBase.setUp(self) RevertTestsBase.setUp(self)
self.mox.StubOutWithMock(revert.gclient_scm.scm.SVN, 'CaptureStatus')
def testRevert(self): def testRevert(self):
revert.gcl.GetRepositoryRoot().AndReturn('foo') revert.gcl.GetRepositoryRoot().AndReturn('foo')
@ -73,7 +74,7 @@ class RevertRevertUnittest(RevertTestsBase):
}] }]
revert.CaptureSVNLog(['-r', '42', '-v']).AndReturn(entries) revert.CaptureSVNLog(['-r', '42', '-v']).AndReturn(entries)
revert.GetRepoBase().AndReturn('proto://fqdn/repo/') revert.GetRepoBase().AndReturn('proto://fqdn/repo/')
revert.gclient_scm.CaptureSVNStatus(['random_file']).AndReturn([]) revert.gclient_scm.scm.SVN.CaptureStatus(['random_file']).AndReturn([])
revert.gcl.RunShell(['svn', 'up', 'random_file']) revert.gcl.RunShell(['svn', 'up', 'random_file'])
revert.os.path.isdir('random_file').AndReturn(False) revert.os.path.isdir('random_file').AndReturn(False)
status = """--- Reverse-merging r42 into '.': status = """--- Reverse-merging r42 into '.':

@ -5,9 +5,12 @@
"""Unit tests for scm.py.""" """Unit tests for scm.py."""
import shutil
import tempfile
from gclient_test import BaseTestCase from gclient_test import BaseTestCase
import scm import scm
from super_mox import mox from super_mox import mox, SuperMoxBaseTestBase
class BaseSCMTestCase(BaseTestCase): class BaseSCMTestCase(BaseTestCase):
@ -21,17 +24,14 @@ class RootTestCase(BaseSCMTestCase):
def testMembersChanged(self): def testMembersChanged(self):
self.mox.ReplayAll() self.mox.ReplayAll()
members = [ members = [
'CaptureGit', 'CaptureGitStatus', 'GIT_COMMAND', 'GIT', 'SVN',
'CaptureSVN', 'CaptureSVNHeadRevision', 'CaptureSVNInfo', 'gclient_utils', 'os', 're', 'subprocess', 'sys', 'tempfile', 'xml',
'CaptureSVNStatus', 'RunSVN', 'RunSVNAndFilterOutput',
'RunSVNAndGetFileList', 'SVN_COMMAND',
'gclient_utils', 'os', 're', 'subprocess', 'sys', 'xml',
] ]
# If this test fails, you should add the relevant test. # If this test fails, you should add the relevant test.
self.compareMembers(scm, members) self.compareMembers(scm, members)
class GitWrapperTestCase(BaseSCMTestCase): class GitWrapperTestCase(SuperMoxBaseTestBase):
sample_git_import = """blob sample_git_import = """blob
mark :1 mark :1
data 6 data 6
@ -80,30 +80,44 @@ from :3
def CreateGitRepo(self, git_import, path): def CreateGitRepo(self, git_import, path):
try: try:
subprocess.Popen(['git', 'init'], stdout=subprocess.PIPE, scm.subprocess.Popen(['git', 'init'],
stderr=subprocess.STDOUT, cwd=path).communicate() stdout=scm.subprocess.PIPE,
except WindowsError: stderr=scm.subprocess.STDOUT,
cwd=path).communicate()
except OSError:
# git is not available, skip this test. # git is not available, skip this test.
return False return False
subprocess.Popen(['git', 'fast-import'], stdin=subprocess.PIPE, scm.subprocess.Popen(['git', 'fast-import'],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=scm.subprocess.PIPE,
stdout=scm.subprocess.PIPE,
stderr=scm.subprocess.STDOUT,
cwd=path).communicate(input=git_import) cwd=path).communicate(input=git_import)
subprocess.Popen(['git', 'checkout'], stdout=subprocess.PIPE, scm.subprocess.Popen(['git', 'checkout'],
stderr=subprocess.STDOUT, cwd=path).communicate() stdout=scm.subprocess.PIPE,
stderr=scm.subprocess.STDOUT,
cwd=path).communicate()
return True return True
def setUp(self): def setUp(self):
BaseSCMTestCase.setUp(self) SuperMoxBaseTestBase.setUp(self)
self.args = self.Args() self.args = self.Args()
self.url = 'git://foo' self.url = 'git://foo'
self.root_dir = tempfile.mkdtemp() self.root_dir = tempfile.mkdtemp()
self.relpath = '.' self.relpath = '.'
self.base_path = os.path.join(self.root_dir, self.relpath) self.base_path = scm.os.path.join(self.root_dir, self.relpath)
self.enabled = self.CreateGitRepo(self.sample_git_import, self.base_path) self.enabled = self.CreateGitRepo(self.sample_git_import, self.base_path)
def tearDown(self): def tearDown(self):
shutil.rmtree(self.root_dir) shutil.rmtree(self.root_dir)
gclient_test.BaseTestCase.tearDown(self) SuperMoxBaseTestBase.tearDown(self)
def testMembersChanged(self):
self.mox.ReplayAll()
members = [
'COMMAND', 'Capture', 'CaptureStatus',
]
# If this test fails, you should add the relevant test.
self.compareMembers(scm.GIT, members)
class SVNTestCase(BaseSCMTestCase): class SVNTestCase(BaseSCMTestCase):
@ -114,7 +128,17 @@ class SVNTestCase(BaseSCMTestCase):
self.url = self.Url() self.url = self.Url()
self.relpath = 'asf' self.relpath = 'asf'
def testGetSVNFileInfo(self): def testMembersChanged(self):
self.mox.ReplayAll()
members = [
'COMMAND', 'Capture', 'CaptureHeadRevision', 'CaptureInfo',
'CaptureStatus', 'DiffItem', 'GetFileProperty', 'IsMoved', 'Run',
'RunAndFilterOutput', 'RunAndGetFileList',
]
# If this test fails, you should add the relevant test.
self.compareMembers(scm.SVN, members)
def testGetFileInfo(self):
xml_text = r"""<?xml version="1.0"?> xml_text = r"""<?xml version="1.0"?>
<info> <info>
<entry kind="file" path="%s" revision="14628"> <entry kind="file" path="%s" revision="14628">
@ -130,8 +154,8 @@ class SVNTestCase(BaseSCMTestCase):
</entry> </entry>
</info> </info>
""" % self.url """ % self.url
self.mox.StubOutWithMock(scm, 'CaptureSVN') self.mox.StubOutWithMock(scm.SVN, 'Capture')
scm.CaptureSVN(['info', '--xml', self.url], '.', True).AndReturn(xml_text) scm.SVN.Capture(['info', '--xml', self.url], '.', True).AndReturn(xml_text)
expected = { expected = {
'URL': 'http://src.chromium.org/svn/trunk/src/chrome/app/d', 'URL': 'http://src.chromium.org/svn/trunk/src/chrome/app/d',
'UUID': None, 'UUID': None,
@ -145,10 +169,10 @@ class SVNTestCase(BaseSCMTestCase):
'Node Kind': 'file', 'Node Kind': 'file',
} }
self.mox.ReplayAll() self.mox.ReplayAll()
file_info = scm.CaptureSVNInfo(self.url, '.', True) file_info = scm.SVN.CaptureInfo(self.url, '.', True)
self.assertEquals(sorted(file_info.items()), sorted(expected.items())) self.assertEquals(sorted(file_info.items()), sorted(expected.items()))
def testCaptureSvnInfo(self): def testCaptureInfo(self):
xml_text = """<?xml version="1.0"?> xml_text = """<?xml version="1.0"?>
<info> <info>
<entry <entry
@ -172,10 +196,10 @@ class SVNTestCase(BaseSCMTestCase):
</entry> </entry>
</info> </info>
""" % (self.url, self.root_dir) """ % (self.url, self.root_dir)
self.mox.StubOutWithMock(scm, 'CaptureSVN') self.mox.StubOutWithMock(scm.SVN, 'Capture')
scm.CaptureSVN(['info', '--xml', self.url], '.', True).AndReturn(xml_text) scm.SVN.Capture(['info', '--xml', self.url], '.', True).AndReturn(xml_text)
self.mox.ReplayAll() self.mox.ReplayAll()
file_info = scm.CaptureSVNInfo(self.url, '.', True) file_info = scm.SVN.CaptureInfo(self.url, '.', True)
expected = { expected = {
'URL': self.url, 'URL': self.url,
'UUID': '7b9385f5-0452-0410-af26-ad4892b7a1fb', 'UUID': '7b9385f5-0452-0410-af26-ad4892b7a1fb',
@ -185,11 +209,11 @@ class SVNTestCase(BaseSCMTestCase):
'Copied From URL': None, 'Copied From URL': None,
'Copied From Rev': None, 'Copied From Rev': None,
'Path': '.', 'Path': '.',
'Node Kind': 'dir', 'Node Kind': 'directory',
} }
self.assertEqual(file_info, expected) self.assertEqual(file_info, expected)
def testCaptureSVNStatus(self): def testCaptureStatus(self):
text =r"""<?xml version="1.0"?> text =r"""<?xml version="1.0"?>
<status> <status>
<target path="."> <target path=".">
@ -236,7 +260,7 @@ class SVNTestCase(BaseSCMTestCase):
proc.communicate().AndReturn((text, 0)) proc.communicate().AndReturn((text, 0))
self.mox.ReplayAll() self.mox.ReplayAll()
info = scm.CaptureSVNStatus('.') info = scm.SVN.CaptureStatus('.')
expected = [ expected = [
('? ', 'unversionned_file.txt'), ('? ', 'unversionned_file.txt'),
('M ', 'build\\internal\\essential.vsprops'), ('M ', 'build\\internal\\essential.vsprops'),
@ -246,14 +270,14 @@ class SVNTestCase(BaseSCMTestCase):
] ]
self.assertEquals(sorted(info), sorted(expected)) self.assertEquals(sorted(info), sorted(expected))
def testRunSVN(self): def testRun(self):
param2 = 'bleh' param2 = 'bleh'
scm.gclient_utils.SubprocessCall(['svn', 'foo', 'bar'], scm.gclient_utils.SubprocessCall(['svn', 'foo', 'bar'],
param2).AndReturn(None) param2).AndReturn(None)
self.mox.ReplayAll() self.mox.ReplayAll()
scm.RunSVN(['foo', 'bar'], param2) scm.SVN.Run(['foo', 'bar'], param2)
def testCaptureSVNStatusEmpty(self): def testCaptureStatusEmpty(self):
text = r"""<?xml version="1.0"?> text = r"""<?xml version="1.0"?>
<status> <status>
<target <target
@ -268,7 +292,7 @@ class SVNTestCase(BaseSCMTestCase):
stdout=scm.subprocess.PIPE).AndReturn(proc) stdout=scm.subprocess.PIPE).AndReturn(proc)
proc.communicate().AndReturn((text, 0)) proc.communicate().AndReturn((text, 0))
self.mox.ReplayAll() self.mox.ReplayAll()
info = scm.CaptureSVNStatus(None) info = scm.SVN.CaptureStatus(None)
self.assertEquals(info, []) self.assertEquals(info, [])

@ -71,7 +71,7 @@ class SuperMoxBaseTestBase(mox.MoxTestBase):
if actual_members != expected_members: if actual_members != expected_members:
diff = ([i for i in actual_members if i not in expected_members] + diff = ([i for i in actual_members if i not in expected_members] +
[i for i in expected_members if i not in actual_members]) [i for i in expected_members if i not in actual_members])
print diff print>>sys.stderr, diff
self.assertEqual(actual_members, expected_members) self.assertEqual(actual_members, expected_members)
def UnMock(self, object, name): def UnMock(self, object, name):

@ -25,9 +25,9 @@ class TryChangeUnittest(TryChangeTestsBase):
'GetTryServerSettings', 'GuessVCS', 'GetTryServerSettings', 'GuessVCS',
'HELP_STRING', 'InvalidScript', 'NoTryServerAccess', 'PathDifference', 'HELP_STRING', 'InvalidScript', 'NoTryServerAccess', 'PathDifference',
'RunCommand', 'SCM', 'SVN', 'TryChange', 'USAGE', 'RunCommand', 'SCM', 'SVN', 'TryChange', 'USAGE',
'datetime', 'gcl', 'gclient_scm', 'getpass', 'logging', 'datetime', 'gcl', 'getpass', 'logging',
'optparse', 'os', 'presubmit_support', 'shutil', 'socket', 'subprocess', 'optparse', 'os', 'presubmit_support', 'scm', 'shutil', 'socket',
'sys', 'tempfile', 'upload', 'urllib', 'subprocess', 'sys', 'tempfile', 'upload', 'urllib',
] ]
# If this test fails, you should add the relevant test. # If this test fails, you should add the relevant test.
self.compareMembers(trychange, members) self.compareMembers(trychange, members)

@ -21,11 +21,11 @@ import tempfile
import urllib import urllib
import gcl import gcl
import gclient_scm import scm
import presubmit_support import presubmit_support
import upload import upload
__version__ = '1.1.1' __version__ = '1.1.2'
# Constants # Constants
@ -150,50 +150,8 @@ class SVN(SCM):
else: else:
os.chdir(root) os.chdir(root)
diff = [] # Directories will return None so filter them out.
for filename in files: diff = filter(None, [scm.SVN.DiffItem(f) for f in files])
# Use svn info output instead of os.path.isdir because the latter fails
# when the file is deleted.
if gclient_scm.CaptureSVNInfo(filename).get("Node Kind") in (
"dir", "directory"):
continue
# If the user specified a custom diff command in their svn config file,
# then it'll be used when we do svn diff, which we don't want to happen
# since we want the unified diff. Using --diff-cmd=diff doesn't always
# work, since they can have another diff executable in their path that
# gives different line endings. So we use a bogus temp directory as the
# config directory, which gets around these problems.
if sys.platform.startswith("win"):
parent_dir = tempfile.gettempdir()
else:
parent_dir = sys.path[0] # tempdir is not secure.
bogus_dir = os.path.join(parent_dir, "temp_svn_config")
if not os.path.exists(bogus_dir):
os.mkdir(bogus_dir)
# Grabs the diff data.
data = gcl.RunShell(["svn", "diff", "--config-dir", bogus_dir, filename])
# We know the diff will be incorrectly formatted. Fix it.
if gcl.IsSVNMoved(filename):
# The file is "new" in the patch sense. Generate a homebrew diff.
# We can't use ReadFile() since it's not using binary mode.
file_handle = open(filename, 'rb')
file_content = file_handle.read()
file_handle.close()
# Prepend '+' to every lines.
file_content = ['+' + i for i in file_content.splitlines(True)]
nb_lines = len(file_content)
# We need to use / since patch on unix will fail otherwise.
filename = filename.replace('\\', '/')
data = "Index: %s\n" % filename
data += ("============================================================="
"======\n")
# Note: Should we use /dev/null instead?
data += "--- %s\n" % filename
data += "+++ %s\n" % filename
data += "@@ -0,0 +1,%d @@\n" % nb_lines
data += ''.join(file_content)
diff.append(data)
os.chdir(previous_cwd) os.chdir(previous_cwd)
return "".join(diff) return "".join(diff)
@ -407,6 +365,7 @@ def GuessVCS(options):
Returns: Returns:
A SCM instance. Exits if the SCM can't be guessed. A SCM instance. Exits if the SCM can't be guessed.
""" """
__pychecker__ = 'no-returnvalues'
# Subversion has a .svn in all working directories. # Subversion has a .svn in all working directories.
if os.path.isdir('.svn'): if os.path.isdir('.svn'):
logging.info("Guessed VCS = Subversion") logging.info("Guessed VCS = Subversion")

Loading…
Cancel
Save