diff --git a/gcl.py b/gcl.py
index 1a9ce9d495..16afdd7c42 100755
--- a/gcl.py
+++ b/gcl.py
@@ -19,10 +19,10 @@ import upload
import urllib2
# gcl now depends on gclient.
-from scm import SVN
+import gclient_scm
import gclient_utils
-__version__ = '1.1.2'
+__version__ = '1.1.1'
CODEREVIEW_SETTINGS = {
@@ -46,13 +46,43 @@ MISSING_TEST_MSG = "Change contains new or modified methods, but no new tests!"
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):
"""Runs svn status and prints unknown files.
Any args in |extra_args| are passed to the tool to support giving alternate
code locations.
"""
- return [item[1] for item in SVN.CaptureStatus(extra_args)
+ return [item[1] for item in gclient_scm.CaptureSVNStatus(extra_args)
if item[0][0] == '?']
@@ -63,7 +93,7 @@ def GetRepositoryRoot():
"""
global REPOSITORY_ROOT
if not REPOSITORY_ROOT:
- infos = SVN.CaptureInfo(os.getcwd(), print_error=False)
+ infos = gclient_scm.CaptureSVNInfo(os.getcwd(), print_error=False)
cur_dir_repo_root = infos.get("Repository Root")
if not cur_dir_repo_root:
raise gclient_utils.Error("gcl run outside of repository")
@@ -71,7 +101,7 @@ def GetRepositoryRoot():
REPOSITORY_ROOT = os.getcwd()
while True:
parent = os.path.dirname(REPOSITORY_ROOT)
- if (SVN.CaptureInfo(parent, print_error=False).get(
+ if (gclient_scm.CaptureSVNInfo(parent, print_error=False).get(
"Repository Root") != cur_dir_repo_root):
break
REPOSITORY_ROOT = parent
@@ -116,7 +146,7 @@ def GetCachedFile(filename, max_age=60*60*24*3, use_root=False):
os.stat(cached_file).st_mtime > max_age):
local_dir = os.path.dirname(os.path.abspath(filename))
local_base = os.path.basename(filename)
- dir_info = SVN.CaptureInfo(".")
+ dir_info = gclient_scm.CaptureSVNInfo(".")
repo_root = dir_info["Repository Root"]
if use_root:
url_path = repo_root
@@ -128,7 +158,7 @@ def GetCachedFile(filename, max_age=60*60*24*3, use_root=False):
r = ""
if not use_root:
local_path = os.path.join(local_dir, local_base)
- r = SVN.CaptureStatus((local_path,))
+ r = gclient_scm.CaptureSVNStatus((local_path,))
rc = -1
if r:
status = r[0][0]
@@ -448,7 +478,7 @@ class ChangeInfo(object):
if update_status:
for item in files:
filename = os.path.join(local_root, item[1])
- status_result = SVN.CaptureStatus(filename)
+ status_result = gclient_scm.CaptureSVNStatus(filename)
if not status_result or not status_result[0][0]:
# File has been reverted.
save = True
@@ -532,7 +562,7 @@ def GetModifiedFiles():
files_in_cl[filename] = change_info.name
# Get all the modified files.
- status_result = SVN.CaptureStatus(None)
+ status_result = gclient_scm.CaptureSVNStatus(None)
for line in status_result:
status = line[0]
filename = line[1]
@@ -719,10 +749,10 @@ def GenerateDiff(files, root=None):
diff = []
for filename in files:
- # TODO(maruel): Use SVN.DiffItem().
# 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':
+ 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
@@ -740,7 +770,7 @@ def GenerateDiff(files, root=None):
output = RunShell(["svn", "diff", "--config-dir", bogus_dir, filename])
if output:
diff.append(output)
- elif SVN.IsMoved(filename):
+ elif IsSVNMoved(filename):
# svn diff on a mv/cp'd file outputs nothing.
# We put in an empty Index entry so upload.py knows about them.
diff.append("\nIndex: %s\n" % filename)
@@ -966,7 +996,7 @@ def Change(change_info, args):
silent = FilterFlag(args, "--silent")
# Verify the user is running the change command from a read-write checkout.
- svn_info = SVN.CaptureInfo('.')
+ svn_info = gclient_scm.CaptureSVNInfo('.')
if not svn_info:
ErrorExit("Current checkout is unversioned. Please retry with a versioned "
"directory.")
@@ -978,7 +1008,7 @@ def Change(change_info, args):
f.close()
else:
override_description = None
-
+
if change_info.issue:
try:
description = GetIssueDescription(change_info.issue)
diff --git a/gclient.py b/gclient.py
index 9edadc2c86..86d10f4340 100755
--- a/gclient.py
+++ b/gclient.py
@@ -66,7 +66,7 @@ Hooks
"""
__author__ = "darinf@gmail.com (Darin Fisher)"
-__version__ = "0.3.4"
+__version__ = "0.3.3"
import errno
import logging
@@ -747,9 +747,9 @@ class GClient(object):
# Use entry and not entry_fixed there.
if entry not in entries and os.path.exists(e_dir):
modified_files = False
- if isinstance(prev_entries, list):
+ if isinstance(prev_entries,list):
# old .gclient_entries format was list, now dict
- modified_files = gclient_scm.scm.SVN.CaptureStatus(e_dir)
+ modified_files = gclient_scm.CaptureSVNStatus(e_dir)
else:
file_list = []
scm = gclient_scm.CreateSCM(prev_entries[entry], self._root_dir,
@@ -830,7 +830,7 @@ class GClient(object):
(url, rev) = GetURLAndRev(name, solution["url"])
entries[name] = "%s@%s" % (url, rev)
# TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset)
- entries_deps_content[name] = gclient_scm.scm.SVN.Capture(
+ entries_deps_content[name] = gclient_scm.CaptureSVN(
["cat",
"%s/%s@%s" % (url,
self._options.deps_file,
diff --git a/gclient_scm.py b/gclient_scm.py
index e2a0017ca6..a9c537b9c2 100644
--- a/gclient_scm.py
+++ b/gclient_scm.py
@@ -1,6 +1,16 @@
-# Copyright (c) 2009 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
+# Copyright 2009 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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."""
@@ -8,13 +18,19 @@ import logging
import os
import re
import subprocess
+import sys
+import xml.dom.minidom
-import scm
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
+
# Factory Method for SCM wrapper creation
def CreateSCM(url=None, root_dir=None, relpath=None, scm_name='svn'):
@@ -77,20 +93,20 @@ class SCMWrapper(object):
return getattr(self, command)(options, args, file_list)
-class GitWrapper(SCMWrapper, scm.GIT):
+class GitWrapper(SCMWrapper):
"""Wrapper for Git"""
def cleanup(self, options, args, file_list):
"""Cleanup working copy."""
__pychecker__ = 'unusednames=args,file_list,options'
- self._Run(['prune'], redirect_stdout=False)
- self._Run(['fsck'], redirect_stdout=False)
- self._Run(['gc'], redirect_stdout=False)
+ self._RunGit(['prune'], redirect_stdout=False)
+ self._RunGit(['fsck'], redirect_stdout=False)
+ self._RunGit(['gc'], redirect_stdout=False)
def diff(self, options, args, file_list):
__pychecker__ = 'unusednames=args,file_list,options'
- merge_base = self._Run(['merge-base', 'HEAD', 'origin'])
- self._Run(['diff', merge_base], redirect_stdout=False)
+ merge_base = self._RunGit(['merge-base', 'HEAD', 'origin'])
+ self._RunGit(['diff', merge_base], redirect_stdout=False)
def export(self, options, args, file_list):
__pychecker__ = 'unusednames=file_list,options'
@@ -98,8 +114,8 @@ class GitWrapper(SCMWrapper, scm.GIT):
export_path = os.path.abspath(os.path.join(args[0], self.relpath))
if not os.path.exists(export_path):
os.makedirs(export_path)
- self._Run(['checkout-index', '-a', '--prefix=%s/' % export_path],
- redirect_stdout=False)
+ self._RunGit(['checkout-index', '-a', '--prefix=%s/' % export_path],
+ redirect_stdout=False)
def update(self, options, args, file_list):
"""Runs git to update or transparently checkout the working copy.
@@ -126,21 +142,21 @@ class GitWrapper(SCMWrapper, scm.GIT):
print("\n_____ %s%s" % (self.relpath, rev_str))
if not os.path.exists(self.checkout_path):
- self._Run(['clone', url, self.checkout_path],
- cwd=self._root_dir, redirect_stdout=False)
+ self._RunGit(['clone', url, self.checkout_path],
+ cwd=self._root_dir, redirect_stdout=False)
if revision:
- self._Run(['reset', '--hard', revision], redirect_stdout=False)
- files = self._Run(['ls-files']).split()
+ self._RunGit(['reset', '--hard', revision], redirect_stdout=False)
+ files = self._RunGit(['ls-files']).split()
file_list.extend([os.path.join(self.checkout_path, f) for f in files])
return
- self._Run(['remote', 'update'], redirect_stdout=False)
+ self._RunGit(['remote', 'update'], redirect_stdout=False)
new_base = 'origin'
if revision:
new_base = revision
- files = self._Run(['diff', new_base, '--name-only']).split()
+ files = self._RunGit(['diff', new_base, '--name-only']).split()
file_list.extend([os.path.join(self.checkout_path, f) for f in files])
- self._Run(['rebase', '-v', new_base], redirect_stdout=False)
+ self._RunGit(['rebase', '-v', new_base], redirect_stdout=False)
print "Checked out revision %s." % self.revinfo(options, (), None)
def revert(self, options, args, file_list):
@@ -156,15 +172,15 @@ class GitWrapper(SCMWrapper, scm.GIT):
print("\n_____ %s is missing, synching instead" % self.relpath)
# Don't reuse the args.
return self.update(options, [], file_list)
- merge_base = self._Run(['merge-base', 'HEAD', 'origin'])
- files = self._Run(['diff', merge_base, '--name-only']).split()
- self._Run(['reset', '--hard', merge_base], redirect_stdout=False)
+ merge_base = self._RunGit(['merge-base', 'HEAD', 'origin'])
+ files = self._RunGit(['diff', merge_base, '--name-only']).split()
+ self._RunGit(['reset', '--hard', merge_base], redirect_stdout=False)
file_list.extend([os.path.join(self.checkout_path, f) for f in files])
def revinfo(self, options, args, file_list):
"""Display revision"""
__pychecker__ = 'unusednames=args,file_list,options'
- return self._Run(['rev-parse', 'HEAD'])
+ return self._RunGit(['rev-parse', 'HEAD'])
def runhooks(self, options, args, file_list):
self.status(options, args, file_list)
@@ -176,30 +192,29 @@ class GitWrapper(SCMWrapper, scm.GIT):
print('\n________ couldn\'t run status in %s:\nThe directory '
'does not exist.' % self.checkout_path)
else:
- merge_base = self._Run(['merge-base', 'HEAD', 'origin'])
- self._Run(['diff', '--name-status', merge_base], redirect_stdout=False)
- files = self._Run(['diff', '--name-only', merge_base]).split()
+ merge_base = self._RunGit(['merge-base', 'HEAD', 'origin'])
+ self._RunGit(['diff', '--name-status', merge_base], redirect_stdout=False)
+ files = self._RunGit(['diff', '--name-only', merge_base]).split()
file_list.extend([os.path.join(self.checkout_path, f) for f in files])
- def _Run(self, args, cwd=None, checkrc=True, redirect_stdout=True):
- # TODO(maruel): Merge with Capture?
+ def _RunGit(self, args, cwd=None, checkrc=True, redirect_stdout=True):
stdout=None
if redirect_stdout:
stdout=subprocess.PIPE
if cwd == None:
cwd = self.checkout_path
- cmd = [self.COMMAND]
+ cmd = ['git']
cmd.extend(args)
sp = subprocess.Popen(cmd, cwd=cwd, stdout=stdout)
if checkrc and sp.returncode:
raise gclient_utils.Error('git command %s returned %d' %
(args[0], sp.returncode))
output = sp.communicate()[0]
- if output is not None:
+ if output != None:
return output.strip()
-class SVNWrapper(SCMWrapper, scm.SVN):
+class SVNWrapper(SCMWrapper):
""" Wrapper for SVN """
def cleanup(self, options, args, file_list):
@@ -207,14 +222,14 @@ class SVNWrapper(SCMWrapper, scm.SVN):
__pychecker__ = 'unusednames=file_list,options'
command = ['cleanup']
command.extend(args)
- self.Run(command, os.path.join(self._root_dir, self.relpath))
+ RunSVN(command, os.path.join(self._root_dir, self.relpath))
def diff(self, options, args, file_list):
# NOTE: This function does not currently modify file_list.
__pychecker__ = 'unusednames=file_list,options'
command = ['diff']
command.extend(args)
- self.Run(command, os.path.join(self._root_dir, self.relpath))
+ RunSVN(command, os.path.join(self._root_dir, self.relpath))
def export(self, options, args, file_list):
__pychecker__ = 'unusednames=file_list,options'
@@ -227,7 +242,7 @@ class SVNWrapper(SCMWrapper, scm.SVN):
assert os.path.exists(export_path)
command = ['export', '--force', '.']
command.append(export_path)
- self.Run(command, os.path.join(self._root_dir, self.relpath))
+ RunSVN(command, os.path.join(self._root_dir, self.relpath))
def update(self, options, args, file_list):
"""Runs SCM to update or transparently checkout the working copy.
@@ -264,11 +279,11 @@ class SVNWrapper(SCMWrapper, scm.SVN):
command = ['checkout', url, checkout_path]
if revision:
command.extend(['--revision', str(revision)])
- self.RunAndGetFileList(options, command, self._root_dir, file_list)
+ RunSVNAndGetFileList(options, command, self._root_dir, file_list)
return
# Get the existing scm url and the revision number of the current checkout.
- from_info = self.CaptureInfo(os.path.join(checkout_path, '.'), '.')
+ from_info = CaptureSVNInfo(os.path.join(checkout_path, '.'), '.')
if not from_info:
raise gclient_utils.Error("Can't update/checkout %r if an unversioned "
"directory is present. Delete the directory "
@@ -278,12 +293,12 @@ class SVNWrapper(SCMWrapper, scm.SVN):
if options.manually_grab_svn_rev:
# Retrieve the current HEAD version because svn is slow at null updates.
if not revision:
- from_info_live = self.CaptureInfo(from_info['URL'], '.')
+ from_info_live = CaptureSVNInfo(from_info['URL'], '.')
revision = str(from_info_live['Revision'])
rev_str = ' at %s' % revision
if from_info['URL'] != base_url:
- to_info = self.CaptureInfo(url, '.')
+ to_info = CaptureSVNInfo(url, '.')
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
# out right now.
@@ -305,12 +320,12 @@ class SVNWrapper(SCMWrapper, scm.SVN):
from_info['Repository Root'],
to_info['Repository Root'],
self.relpath]
- self.Run(command, self._root_dir)
+ RunSVN(command, self._root_dir)
from_info['URL'] = from_info['URL'].replace(
from_info['Repository Root'],
to_info['Repository Root'])
else:
- if self.CaptureStatus(checkout_path):
+ if CaptureSVNStatus(checkout_path):
raise gclient_utils.Error("Can't switch the checkout to %s; UUID "
"don't match and there is local changes "
"in %s. Delete the directory and "
@@ -322,7 +337,7 @@ class SVNWrapper(SCMWrapper, scm.SVN):
command = ['checkout', url, checkout_path]
if revision:
command.extend(['--revision', str(revision)])
- self.RunAndGetFileList(options, command, self._root_dir, file_list)
+ RunSVNAndGetFileList(options, command, self._root_dir, file_list)
return
@@ -336,7 +351,7 @@ class SVNWrapper(SCMWrapper, scm.SVN):
command = ["update", checkout_path]
if revision:
command.extend(['--revision', str(revision)])
- self.RunAndGetFileList(options, command, self._root_dir, file_list)
+ RunSVNAndGetFileList(options, command, self._root_dir, file_list)
def revert(self, options, args, file_list):
"""Reverts local modifications. Subversion specific.
@@ -353,7 +368,7 @@ class SVNWrapper(SCMWrapper, scm.SVN):
# Don't reuse the args.
return self.update(options, [], file_list)
- for file_status in self.CaptureStatus(path):
+ for file_status in CaptureSVNStatus(path):
file_path = os.path.join(path, file_status[1])
if file_status[0][0] == 'X':
# Ignore externals.
@@ -388,7 +403,7 @@ class SVNWrapper(SCMWrapper, scm.SVN):
try:
# svn revert is so broken we don't even use it. Using
# "svn up --revision BASE" achieve the same effect.
- self.RunAndGetFileList(options, ['update', '--revision', 'BASE'], path,
+ RunSVNAndGetFileList(options, ['update', '--revision', 'BASE'], path,
file_list)
except OSError, e:
# Maybe the directory disapeared meanwhile. We don't want it to throw an
@@ -398,7 +413,7 @@ class SVNWrapper(SCMWrapper, scm.SVN):
def revinfo(self, options, args, file_list):
"""Display revision"""
__pychecker__ = 'unusednames=args,file_list,options'
- return self.CaptureHeadRevision(self.url)
+ return CaptureSVNHeadRevision(self.url)
def runhooks(self, options, args, file_list):
self.status(options, args, file_list)
@@ -415,7 +430,7 @@ class SVNWrapper(SCMWrapper, scm.SVN):
% (' '.join(command), path))
# There's no file list to retrieve.
else:
- self.RunAndGetFileList(options, command, path, file_list)
+ RunSVNAndGetFileList(options, command, path, file_list)
def pack(self, options, args, file_list):
"""Generates a patch file which can be applied to the root of the
@@ -460,4 +475,4 @@ class SVNWrapper(SCMWrapper, scm.SVN):
print line
filterer = DiffFilterer(self.relpath)
- self.RunAndFilterOutput(command, path, False, False, filterer.Filter)
+ RunSVNAndFilterOutput(command, path, False, False, filterer.Filter)
diff --git a/gclient_utils.py b/gclient_utils.py
index 4a5989c0cd..9016270d4d 100644
--- a/gclient_utils.py
+++ b/gclient_utils.py
@@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""Generic utils."""
-
import errno
import os
import re
@@ -24,6 +22,8 @@ import time
import xml.dom.minidom
import xml.parsers.expat
+## Generic utils
+
def SplitUrlRevision(url):
"""Splits url and returns a two-tuple: url, rev"""
@@ -76,9 +76,9 @@ class PrintableObject(object):
return output
-def FileRead(filename, mode='rU'):
+def FileRead(filename):
content = None
- f = open(filename, mode)
+ f = open(filename, "rU")
try:
content = f.read()
finally:
@@ -86,8 +86,8 @@ def FileRead(filename, mode='rU'):
return content
-def FileWrite(filename, content, mode='w'):
- f = open(filename, mode)
+def FileWrite(filename, content):
+ f = open(filename, "w")
try:
f.write(content)
finally:
@@ -201,9 +201,9 @@ def SubprocessCallAndFilter(command,
only if we actually need to print something else as well, so you can
get the context of the output. If print_messages is false and print_stdout
is false, no output at all is generated.
-
- Also, if print_stdout is true, the command's stdout is also forwarded
- to stdout.
+
+ Also, if print_stdout is true, the command's stdout is also forwarded
+ to stdout.
If a filter function is specified, it is expected to take a single
string argument, and it will be called with each line of the
@@ -223,7 +223,7 @@ def SubprocessCallAndFilter(command,
# executable, but shell=True makes subprocess on Linux fail when it's called
# with a list because it only tries to execute the first item in the list.
kid = subprocess.Popen(command, bufsize=0, cwd=in_directory,
- shell=(sys.platform == 'win32'), stdout=subprocess.PIPE,
+ shell=(sys.platform == 'win32'), stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
# Also, we need to forward stdout to prevent weird re-ordering of output.
@@ -238,7 +238,7 @@ def SubprocessCallAndFilter(command,
if not print_messages:
print("\n________ running \'%s\' in \'%s\'"
% (' '.join(command), in_directory))
- print_messages = True
+ print_messages = True
sys.stdout.write(in_byte)
if in_byte != "\n":
in_line += in_byte
diff --git a/git_cl_hooks.py b/git_cl_hooks.py
index c63cbe268c..5203096f54 100644
--- a/git_cl_hooks.py
+++ b/git_cl_hooks.py
@@ -7,8 +7,9 @@ import re
import subprocess
import sys
+# Imported from depot_tools.
+import gclient_scm
import presubmit_support
-import scm
def Backquote(cmd, cwd=None):
"""Like running `cmd` in a shell script."""
@@ -34,7 +35,7 @@ class ChangeOptions:
raise Exception("Could not parse log message: %s" % log)
name = m.group(1)
description = m.group(2)
- files = scm.GIT.CaptureStatus([root], upstream_branch)
+ files = gclient_scm.CaptureGitStatus([root], upstream_branch)
issue = Backquote(['git', 'cl', 'status', '--field=id'])
patchset = None
self.change = presubmit_support.GitChange(name, description, root, files,
diff --git a/presubmit_support.py b/presubmit_support.py
index a68bdf0dd8..fabf7e946c 100755
--- a/presubmit_support.py
+++ b/presubmit_support.py
@@ -6,7 +6,7 @@
"""Enables directory-specific presubmit checks to run at upload and/or commit.
"""
-__version__ = '1.3.4'
+__version__ = '1.3.3'
# TODO(joi) Add caching where appropriate/needed. The API is designed to allow
# caching (between all different invocations of presubmit scripts for a given
@@ -35,10 +35,11 @@ import urllib2 # Exposed through the API.
import warnings
# 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 gclient_utils
+import gclient_scm
import presubmit_canned_checks
-import scm
# Ask for feedback only once in program lifetime.
@@ -240,7 +241,7 @@ class InputApi(object):
Remember to check for the None case and show an appropriate error!
"""
- local_path = scm.SVN.CaptureInfo(depot_path).get('Path')
+ local_path = gclient_scm.CaptureSVNInfo(depot_path).get('Path')
if local_path:
return local_path
@@ -253,7 +254,7 @@ class InputApi(object):
Returns:
The depot path (SVN URL) of the file if mapped, otherwise None.
"""
- depot_path = scm.SVN.CaptureInfo(local_path).get('URL')
+ depot_path = gclient_scm.CaptureSVNInfo(local_path).get('URL')
if depot_path:
return depot_path
@@ -353,7 +354,7 @@ class InputApi(object):
file_item = file_item.AbsoluteLocalPath()
if not file_item.startswith(self.change.RepositoryRoot()):
raise IOError('Access outside the repository root is denied.')
- return gclient_utils.FileRead(file_item, mode)
+ return gcl.ReadFile(file_item, mode)
@staticmethod
def _RightHandSideLinesImpl(affected_files):
@@ -431,8 +432,7 @@ class AffectedFile(object):
if self.IsDirectory():
return []
else:
- return gclient_utils.FileRead(self.AbsoluteLocalPath(),
- 'rU').splitlines()
+ return gcl.ReadFile(self.AbsoluteLocalPath()).splitlines()
def OldContents(self):
"""Returns an iterator over the lines in the old version of file.
@@ -464,7 +464,7 @@ class SvnAffectedFile(AffectedFile):
def ServerPath(self):
if self._server_path is None:
- self._server_path = scm.SVN.CaptureInfo(
+ self._server_path = gclient_scm.CaptureSVNInfo(
self.AbsoluteLocalPath()).get('URL', '')
return self._server_path
@@ -476,13 +476,13 @@ class SvnAffectedFile(AffectedFile):
# querying subversion, especially on Windows.
self._is_directory = os.path.isdir(path)
else:
- self._is_directory = scm.SVN.CaptureInfo(
+ self._is_directory = gclient_scm.CaptureSVNInfo(
path).get('Node Kind') in ('dir', 'directory')
return self._is_directory
def Property(self, property_name):
if not property_name in self._properties:
- self._properties[property_name] = scm.SVN.GetFileProperty(
+ self._properties[property_name] = gcl.GetSVNFileProperty(
self.AbsoluteLocalPath(), property_name).rstrip()
return self._properties[property_name]
@@ -494,8 +494,8 @@ class SvnAffectedFile(AffectedFile):
elif self.IsDirectory():
self._is_text_file = False
else:
- mime_type = scm.SVN.GetFileProperty(self.AbsoluteLocalPath(),
- 'svn:mime-type')
+ mime_type = gcl.GetSVNFileProperty(self.AbsoluteLocalPath(),
+ 'svn:mime-type')
self._is_text_file = (not mime_type or mime_type.startswith('text/'))
return self._is_text_file
@@ -809,7 +809,7 @@ def DoGetTrySlaves(changed_files,
if verbose:
output_stream.write("Running %s\n" % filename)
# Accept CRLF presubmit script.
- presubmit_script = gclient_utils.FileRead(filename, 'rU')
+ presubmit_script = gcl.ReadFile(filename, 'rU')
results += executer.ExecPresubmitScript(presubmit_script)
slaves = list(set(results))
@@ -925,7 +925,7 @@ def DoPresubmitChecks(change,
if verbose:
output_stream.write("Running %s\n" % filename)
# Accept CRLF presubmit script.
- presubmit_script = gclient_utils.FileRead(filename, 'rU')
+ presubmit_script = gcl.ReadFile(filename, 'rU')
results += executer.ExecPresubmitScript(presubmit_script, filename)
errors = []
@@ -1022,7 +1022,7 @@ def Main(argv):
options.files = ParseFiles(args, options.recursive)
else:
# Grab modified files.
- options.files = scm.GIT.CaptureStatus([options.root])
+ options.files = gclient_scm.CaptureGitStatus([options.root])
elif os.path.isdir(os.path.join(options.root, '.svn')):
change_class = SvnChange
if not options.files:
@@ -1030,7 +1030,7 @@ def Main(argv):
options.files = ParseFiles(args, options.recursive)
else:
# Grab modified files.
- options.files = scm.SVN.CaptureStatus([options.root])
+ options.files = gclient_scm.CaptureSVNStatus([options.root])
else:
# Doesn't seem under source control.
change_class = Change
diff --git a/revert.py b/revert.py
index dc56c1f9c3..71016654f0 100755
--- a/revert.py
+++ b/revert.py
@@ -146,7 +146,7 @@ def Revert(revisions, force=False, commit=True, send_email=True, message=None,
print ""
# Make sure these files are unmodified with svn status.
- status = gclient_scm.scm.SVN.CaptureStatus(files)
+ status = gclient_scm.CaptureSVNStatus(files)
if status:
if force:
# TODO(maruel): Use the tool to correctly revert '?' files.
diff --git a/scm.py b/scm.py
index 9c12ba8361..12848152ab 100644
--- a/scm.py
+++ b/scm.py
@@ -2,415 +2,335 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""SCM-specific utility classes."""
+"""SCM-specific functions."""
import os
import re
import subprocess
import sys
-import tempfile
import xml.dom.minidom
import gclient_utils
-class GIT(object):
- COMMAND = "git"
-
- @staticmethod
- def Capture(args, in_directory=None, print_error=True):
- """Runs git, capturing output sent to stdout as a string.
-
- Args:
- args: A sequence of command line parameters to be passed to git.
- in_directory: The directory where git is to be run.
-
- Returns:
- The output sent to stdout as a string.
- """
- c = [GIT.COMMAND]
- c.extend(args)
-
- # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for
- # the git.exe executable, but shell=True makes subprocess on Linux fail
- # when it's called with a list because it only tries to execute the
- # first string ("git").
- stderr = None
- if not print_error:
- stderr = subprocess.PIPE
- return subprocess.Popen(c,
- cwd=in_directory,
- shell=sys.platform.startswith('win'),
- stdout=subprocess.PIPE,
- stderr=stderr).communicate()[0]
-
-
- @staticmethod
- def CaptureStatus(files, upstream_branch='origin'):
- """Returns git status.
-
- @files can be a string (one file) or a list of files.
-
- Returns an array of (status, file) tuples."""
- command = ["diff", "--name-status", "-r", "%s.." % upstream_branch]
- if not files:
- pass
- elif isinstance(files, basestring):
- command.append(files)
- else:
- command.extend(files)
-
- status = GIT.Capture(command).rstrip()
- results = []
- if status:
- for statusline in status.split('\n'):
- m = re.match('^(\w)\t(.+)$', statusline)
- if not m:
- raise Exception("status currently unsupported: %s" % statusline)
- results.append(('%s ' % m.group(1), m.group(2)))
- return results
-
-
-class SVN(object):
- COMMAND = "svn"
-
- @staticmethod
- def Run(args, in_directory):
- """Runs svn, sending output to stdout.
-
- Args:
- args: A sequence of command line parameters to be passed to svn.
- in_directory: The directory where svn is to be run.
-
- Raises:
- Error: An error occurred while running the svn command.
- """
- c = [SVN.COMMAND]
- c.extend(args)
-
- gclient_utils.SubprocessCall(c, in_directory)
-
- @staticmethod
- def Capture(args, in_directory=None, print_error=True):
- """Runs svn, capturing output sent to stdout as a string.
-
- Args:
- args: A sequence of command line parameters to be passed to svn.
- in_directory: The directory where svn is to be run.
-
- Returns:
- The output sent to stdout as a string.
- """
- c = [SVN.COMMAND]
- c.extend(args)
-
- # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for
- # the svn.exe executable, but shell=True makes subprocess on Linux fail
- # when it's called with a list because it only tries to execute the
- # first string ("svn").
- stderr = None
- if not print_error:
- stderr = subprocess.PIPE
- return subprocess.Popen(c,
- cwd=in_directory,
- shell=(sys.platform == 'win32'),
- stdout=subprocess.PIPE,
- stderr=stderr).communicate()[0]
-
- @staticmethod
- def RunAndGetFileList(options, args, in_directory, file_list):
- """Runs svn checkout, update, or status, output to stdout.
-
- 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.
- These files are appended to file_list. svn's stdout is also printed to
- sys.stdout as in Run.
-
- Args:
- options: command line options to gclient
- args: A sequence of command line parameters to be passed to svn.
- in_directory: The directory where svn is to be run.
-
- Raises:
- Error: An error occurred while running the svn command.
- """
- command = [SVN.COMMAND]
- command.extend(args)
-
- # svn update and svn checkout use the same pattern: the first three columns
- # are for file status, property status, and lock status. This is followed
- # by two spaces, and then the path to the file.
- update_pattern = '^... (.*)$'
-
- # The first three columns of svn status are the same as for svn update and
- # svn checkout. The next three columns indicate addition-with-history,
- # switch, and remote lock status. This is followed by one space, and then
- # the path to the file.
- status_pattern = '^...... (.*)$'
-
- # args[0] must be a supported command. This will blow up if it's something
- # else, which is good. Note that the patterns are only effective when
- # these commands are used in their ordinary forms, the patterns are invalid
- # for "svn status --show-updates", for example.
- pattern = {
- 'checkout': update_pattern,
- 'status': status_pattern,
- 'update': update_pattern,
- }[args[0]]
-
- compiled_pattern = re.compile(pattern)
-
- def CaptureMatchingLines(line):
- match = compiled_pattern.search(line)
- if match:
- file_list.append(match.group(1))
-
- SVN.RunAndFilterOutput(args,
- in_directory,
- options.verbose,
- True,
- CaptureMatchingLines)
-
- @staticmethod
- def RunAndFilterOutput(args,
- in_directory,
- print_messages,
- print_stdout,
- filter):
- """Runs svn checkout, update, status, or diff, optionally outputting
- to stdout.
-
- The first item in args must be either "checkout", "update",
- "status", or "diff".
-
- 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 Run.
-
- Args:
- args: A sequence of command line parameters to be passed to svn.
- in_directory: The directory where svn is to be run.
- print_messages: Whether to print status messages to stdout about
- which Subversion commands are being run.
- print_stdout: Whether to forward Subversion's output to stdout.
- filter: A function taking one argument (a string) which will be
- passed each line (with the ending newline character removed) of
- Subversion's output for filtering.
-
- Raises:
- Error: An error occurred while running the svn command.
- """
- command = [SVN.COMMAND]
- command.extend(args)
-
- gclient_utils.SubprocessCallAndFilter(command,
- in_directory,
- print_messages,
- print_stdout,
- filter=filter)
-
- @staticmethod
- def CaptureInfo(relpath, in_directory=None, print_error=True):
- """Returns a dictionary from the svn info output for the given file.
-
- Args:
- relpath: The directory where the working copy resides relative to
- the directory given by in_directory.
- in_directory: The directory where svn is to be run.
- """
- output = SVN.Capture(["info", "--xml", relpath], in_directory, print_error)
- dom = gclient_utils.ParseXML(output)
- result = {}
- if dom:
- GetNamedNodeText = gclient_utils.GetNamedNodeText
- GetNodeNamedAttributeText = gclient_utils.GetNodeNamedAttributeText
- def C(item, f):
- if item is not None: return f(item)
- # /info/entry/
- # url
- # reposityory/(root|uuid)
- # wc-info/(schedule|depth)
- # commit/(author|date)
- # str() the results because they may be returned as Unicode, which
- # interferes with the higher layers matching up things in the deps
- # dictionary.
- # TODO(maruel): Fix at higher level instead (!)
- result['Repository Root'] = C(GetNamedNodeText(dom, 'root'), str)
- result['URL'] = C(GetNamedNodeText(dom, 'url'), str)
- result['UUID'] = C(GetNamedNodeText(dom, 'uuid'), str)
- result['Revision'] = C(GetNodeNamedAttributeText(dom, 'entry',
- 'revision'),
- int)
- result['Node Kind'] = C(GetNodeNamedAttributeText(dom, 'entry', 'kind'),
- str)
- # Differs across versions.
- if result['Node Kind'] == 'dir':
- result['Node Kind'] = 'directory'
- result['Schedule'] = C(GetNamedNodeText(dom, 'schedule'), str)
- result['Path'] = C(GetNodeNamedAttributeText(dom, 'entry', 'path'), str)
- result['Copied From URL'] = C(GetNamedNodeText(dom, 'copy-from-url'), str)
- result['Copied From Rev'] = C(GetNamedNodeText(dom, 'copy-from-rev'), str)
- return result
-
- @staticmethod
- def CaptureHeadRevision(url):
- """Get the head revision of a SVN repository.
-
- Returns:
- Int head revision
- """
- info = SVN.Capture(["info", "--xml", url], os.getcwd())
- dom = xml.dom.minidom.parseString(info)
- return dom.getElementsByTagName('entry')[0].getAttribute('revision')
-
- @staticmethod
- def CaptureStatus(files):
- """Returns the svn 1.5 svn status emulated output.
-
- @files can be a string (one file) or a list of files.
-
- Returns an array of (status, file) tuples."""
- command = ["status", "--xml"]
- if not files:
- pass
- elif isinstance(files, basestring):
- command.append(files)
- else:
- command.extend(files)
-
- status_letter = {
- None: ' ',
- '': ' ',
- 'added': 'A',
- 'conflicted': 'C',
- 'deleted': 'D',
- 'external': 'X',
- 'ignored': 'I',
- 'incomplete': '!',
- 'merged': 'G',
- 'missing': '!',
- 'modified': 'M',
- 'none': ' ',
- 'normal': ' ',
- 'obstructed': '~',
- 'replaced': 'R',
- 'unversioned': '?',
- }
- dom = gclient_utils.ParseXML(SVN.Capture(command))
- results = []
- if dom:
- # /status/target/entry/(wc-status|commit|author|date)
- for target in dom.getElementsByTagName('target'):
- #base_path = target.getAttribute('path')
- for entry in target.getElementsByTagName('entry'):
- file_path = entry.getAttribute('path')
- wc_status = entry.getElementsByTagName('wc-status')
- assert len(wc_status) == 1
- # Emulate svn 1.5 status ouput...
- statuses = [' '] * 7
- # Col 0
- xml_item_status = wc_status[0].getAttribute('item')
- if xml_item_status in status_letter:
- statuses[0] = status_letter[xml_item_status]
- else:
- raise Exception('Unknown item status "%s"; please implement me!' %
- xml_item_status)
- # Col 1
- xml_props_status = wc_status[0].getAttribute('props')
- if xml_props_status == 'modified':
- statuses[1] = 'M'
- elif xml_props_status == 'conflicted':
- statuses[1] = 'C'
- elif (not xml_props_status or xml_props_status == 'none' or
- xml_props_status == 'normal'):
- pass
- else:
- raise Exception('Unknown props status "%s"; please implement me!' %
- xml_props_status)
- # Col 2
- if wc_status[0].getAttribute('wc-locked') == 'true':
- statuses[2] = 'L'
- # Col 3
- if wc_status[0].getAttribute('copied') == 'true':
- statuses[3] = '+'
- # Col 4
- if wc_status[0].getAttribute('switched') == 'true':
- statuses[4] = 'S'
- # TODO(maruel): Col 5 and 6
- item = (''.join(statuses), file_path)
- results.append(item)
- 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.Run(["propget", property_name, file], None)
- if (output and
- 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
+SVN_COMMAND = "svn"
+GIT_COMMAND = "git"
+
+# -----------------------------------------------------------------------------
+# Git utils:
+
+
+def CaptureGit(args, in_directory=None, print_error=True):
+ """Runs git, capturing output sent to stdout as a string.
+
+ Args:
+ args: A sequence of command line parameters to be passed to git.
+ in_directory: The directory where git is to be run.
+
+ Returns:
+ The output sent to stdout as a string.
+ """
+ c = [GIT_COMMAND]
+ c.extend(args)
+
+ # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for
+ # the git.exe executable, but shell=True makes subprocess on Linux fail
+ # when it's called with a list because it only tries to execute the
+ # first string ("git").
+ stderr = None
+ if not print_error:
+ stderr = subprocess.PIPE
+ return subprocess.Popen(c,
+ cwd=in_directory,
+ shell=sys.platform.startswith('win'),
+ stdout=subprocess.PIPE,
+ stderr=stderr).communicate()[0]
+
+
+def CaptureGitStatus(files, upstream_branch='origin'):
+ """Returns git status.
+
+ @files can be a string (one file) or a list of files.
+
+ Returns an array of (status, file) tuples."""
+ command = ["diff", "--name-status", "-r", "%s.." % upstream_branch]
+ if not files:
+ pass
+ elif isinstance(files, basestring):
+ command.append(files)
+ else:
+ command.extend(files)
+
+ status = CaptureGit(command).rstrip()
+ results = []
+ if status:
+ for statusline in status.split('\n'):
+ m = re.match('^(\w)\t(.+)$', statusline)
+ if not m:
+ raise Exception("status currently unsupported: %s" % statusline)
+ results.append(('%s ' % m.group(1), m.group(2)))
+ return results
+
+
+# -----------------------------------------------------------------------------
+# SVN utils:
+
+
+def RunSVN(args, in_directory):
+ """Runs svn, sending output to stdout.
+
+ Args:
+ args: A sequence of command line parameters to be passed to svn.
+ in_directory: The directory where svn is to be run.
+
+ Raises:
+ Error: An error occurred while running the svn command.
+ """
+ c = [SVN_COMMAND]
+ c.extend(args)
+
+ gclient_utils.SubprocessCall(c, in_directory)
+
+
+def CaptureSVN(args, in_directory=None, print_error=True):
+ """Runs svn, capturing output sent to stdout as a string.
+
+ Args:
+ args: A sequence of command line parameters to be passed to svn.
+ in_directory: The directory where svn is to be run.
+
+ Returns:
+ The output sent to stdout as a string.
+ """
+ c = [SVN_COMMAND]
+ c.extend(args)
+
+ # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for
+ # the svn.exe executable, but shell=True makes subprocess on Linux fail
+ # when it's called with a list because it only tries to execute the
+ # first string ("svn").
+ stderr = None
+ if not print_error:
+ stderr = subprocess.PIPE
+ return subprocess.Popen(c,
+ cwd=in_directory,
+ shell=(sys.platform == 'win32'),
+ stdout=subprocess.PIPE,
+ stderr=stderr).communicate()[0]
+
+
+def RunSVNAndGetFileList(options, args, in_directory, file_list):
+ """Runs svn checkout, update, or status, output to stdout.
+
+ 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.
+ These files are appended to file_list. svn's stdout is also printed to
+ sys.stdout as in RunSVN.
+
+ Args:
+ options: command line options to gclient
+ args: A sequence of command line parameters to be passed to svn.
+ in_directory: The directory where svn is to be run.
+
+ Raises:
+ Error: An error occurred while running the svn command.
+ """
+ command = [SVN_COMMAND]
+ command.extend(args)
+
+ # svn update and svn checkout use the same pattern: the first three columns
+ # are for file status, property status, and lock status. This is followed
+ # by two spaces, and then the path to the file.
+ update_pattern = '^... (.*)$'
+
+ # The first three columns of svn status are the same as for svn update and
+ # svn checkout. The next three columns indicate addition-with-history,
+ # switch, and remote lock status. This is followed by one space, and then
+ # the path to the file.
+ status_pattern = '^...... (.*)$'
+
+ # args[0] must be a supported command. This will blow up if it's something
+ # else, which is good. Note that the patterns are only effective when
+ # these commands are used in their ordinary forms, the patterns are invalid
+ # for "svn status --show-updates", for example.
+ pattern = {
+ 'checkout': update_pattern,
+ 'status': status_pattern,
+ 'update': update_pattern,
+ }[args[0]]
+
+ compiled_pattern = re.compile(pattern)
+
+ def CaptureMatchingLines(line):
+ match = compiled_pattern.search(line)
+ if match:
+ file_list.append(match.group(1))
+
+ RunSVNAndFilterOutput(args,
+ in_directory,
+ options.verbose,
+ True,
+ CaptureMatchingLines)
+
+def RunSVNAndFilterOutput(args,
+ in_directory,
+ print_messages,
+ print_stdout,
+ filter):
+ """Runs svn checkout, update, status, or diff, optionally outputting
+ to stdout.
+
+ The first item in args must be either "checkout", "update",
+ "status", or "diff".
+
+ 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.
+
+ Args:
+ args: A sequence of command line parameters to be passed to svn.
+ in_directory: The directory where svn is to be run.
+ print_messages: Whether to print status messages to stdout about
+ which Subversion commands are being run.
+ print_stdout: Whether to forward Subversion's output to stdout.
+ filter: A function taking one argument (a string) which will be
+ passed each line (with the ending newline character removed) of
+ Subversion's output for filtering.
+
+ Raises:
+ Error: An error occurred while running the svn command.
+ """
+ command = [SVN_COMMAND]
+ command.extend(args)
+
+ gclient_utils.SubprocessCallAndFilter(command,
+ in_directory,
+ print_messages,
+ print_stdout,
+ filter=filter)
+
+def CaptureSVNInfo(relpath, in_directory=None, print_error=True):
+ """Returns a dictionary from the svn info output for the given file.
+
+ Args:
+ relpath: The directory where the working copy resides relative to
+ the directory given by in_directory.
+ in_directory: The directory where svn is to be run.
+ """
+ output = CaptureSVN(["info", "--xml", relpath], in_directory, print_error)
+ dom = gclient_utils.ParseXML(output)
+ result = {}
+ if dom:
+ GetNamedNodeText = gclient_utils.GetNamedNodeText
+ GetNodeNamedAttributeText = gclient_utils.GetNodeNamedAttributeText
+ def C(item, f):
+ if item is not None: return f(item)
+ # /info/entry/
+ # url
+ # reposityory/(root|uuid)
+ # wc-info/(schedule|depth)
+ # commit/(author|date)
+ # str() the results because they may be returned as Unicode, which
+ # interferes with the higher layers matching up things in the deps
+ # dictionary.
+ # TODO(maruel): Fix at higher level instead (!)
+ result['Repository Root'] = C(GetNamedNodeText(dom, 'root'), str)
+ result['URL'] = C(GetNamedNodeText(dom, 'url'), str)
+ result['UUID'] = C(GetNamedNodeText(dom, 'uuid'), str)
+ result['Revision'] = C(GetNodeNamedAttributeText(dom, 'entry', 'revision'),
+ int)
+ result['Node Kind'] = C(GetNodeNamedAttributeText(dom, 'entry', 'kind'),
+ str)
+ result['Schedule'] = C(GetNamedNodeText(dom, 'schedule'), str)
+ result['Path'] = C(GetNodeNamedAttributeText(dom, 'entry', 'path'), str)
+ result['Copied From URL'] = C(GetNamedNodeText(dom, 'copy-from-url'), str)
+ result['Copied From Rev'] = C(GetNamedNodeText(dom, 'copy-from-rev'), str)
+ return result
+
+
+def CaptureSVNHeadRevision(url):
+ """Get the head revision of a SVN repository.
+
+ Returns:
+ Int head revision
+ """
+ info = CaptureSVN(["info", "--xml", url], os.getcwd())
+ dom = xml.dom.minidom.parseString(info)
+ return dom.getElementsByTagName('entry')[0].getAttribute('revision')
+
+
+def CaptureSVNStatus(files):
+ """Returns the svn 1.5 svn status emulated output.
+
+ @files can be a string (one file) or a list of files.
+
+ Returns an array of (status, file) tuples."""
+ command = ["status", "--xml"]
+ if not files:
+ pass
+ elif isinstance(files, basestring):
+ command.append(files)
+ else:
+ command.extend(files)
+
+ status_letter = {
+ None: ' ',
+ '': ' ',
+ 'added': 'A',
+ 'conflicted': 'C',
+ 'deleted': 'D',
+ 'external': 'X',
+ 'ignored': 'I',
+ 'incomplete': '!',
+ 'merged': 'G',
+ 'missing': '!',
+ 'modified': 'M',
+ 'none': ' ',
+ 'normal': ' ',
+ 'obstructed': '~',
+ 'replaced': 'R',
+ 'unversioned': '?',
+ }
+ dom = gclient_utils.ParseXML(CaptureSVN(command))
+ results = []
+ if dom:
+ # /status/target/entry/(wc-status|commit|author|date)
+ for target in dom.getElementsByTagName('target'):
+ for entry in target.getElementsByTagName('entry'):
+ file_path = entry.getAttribute('path')
+ wc_status = entry.getElementsByTagName('wc-status')
+ assert len(wc_status) == 1
+ # Emulate svn 1.5 status ouput...
+ statuses = [' '] * 7
+ # Col 0
+ xml_item_status = wc_status[0].getAttribute('item')
+ if xml_item_status in status_letter:
+ statuses[0] = status_letter[xml_item_status]
+ else:
+ raise Exception('Unknown item status "%s"; please implement me!' %
+ xml_item_status)
+ # Col 1
+ xml_props_status = wc_status[0].getAttribute('props')
+ if xml_props_status == 'modified':
+ statuses[1] = 'M'
+ elif xml_props_status == 'conflicted':
+ statuses[1] = 'C'
+ elif (not xml_props_status or xml_props_status == 'none' or
+ xml_props_status == 'normal'):
+ pass
+ else:
+ raise Exception('Unknown props status "%s"; please implement me!' %
+ xml_props_status)
+ # Col 2
+ if wc_status[0].getAttribute('wc-locked') == 'true':
+ statuses[2] = 'L'
+ # Col 3
+ if wc_status[0].getAttribute('copied') == 'true':
+ statuses[3] = '+'
+ # Col 4
+ if wc_status[0].getAttribute('switched') == 'true':
+ statuses[4] = 'S'
+ # TODO(maruel): Col 5 and 6
+ item = (''.join(statuses), file_path)
+ results.append(item)
+ return results
diff --git a/tests/gcl_unittest.py b/tests/gcl_unittest.py
index a3c5524fa7..739840bb71 100755
--- a/tests/gcl_unittest.py
+++ b/tests/gcl_unittest.py
@@ -16,7 +16,7 @@ class GclTestsBase(SuperMoxTestBase):
SuperMoxTestBase.setUp(self)
self.fake_root_dir = self.RootDir()
self.mox.StubOutWithMock(gcl, 'RunShell')
- self.mox.StubOutWithMock(gcl.SVN, 'CaptureInfo')
+ self.mox.StubOutWithMock(gcl.gclient_scm, 'CaptureSVNInfo')
self.mox.StubOutWithMock(gcl, 'tempfile')
self.mox.StubOutWithMock(gcl.upload, 'RealMain')
# These are not tested.
@@ -29,21 +29,25 @@ class GclUnittest(GclTestsBase):
def testMembersChanged(self):
self.mox.ReplayAll()
members = [
- 'CODEREVIEW_SETTINGS', 'CODEREVIEW_SETTINGS_FILE', 'Change',
- 'ChangeInfo', 'Changes', 'Commit', 'DEFAULT_LINT_IGNORE_REGEX',
- 'DEFAULT_LINT_REGEX', 'DeleteEmptyChangeLists', 'DoPresubmitChecks',
- 'ErrorExit', 'FILES_CACHE', 'FilterFlag', 'GenerateChangeName',
- 'GenerateDiff', 'GetCLs', 'GetCacheDir', 'GetCachedFile',
- 'GetChangelistInfoFile', 'GetChangesDir', 'GetCodeReviewSetting',
- 'GetEditor', 'GetFilesNotInCL', 'GetInfoDir', 'GetIssueDescription',
- 'GetModifiedFiles', 'GetRepositoryRoot', 'Help', 'Lint',
- 'LoadChangelistInfoForMultiple', 'MISSING_TEST_MSG', 'Opened',
- 'OptionallyDoPresubmitChecks', 'PresubmitCL', 'REPOSITORY_ROOT',
- 'ReadFile', 'RunShell', 'RunShellWithReturnCode', 'SVN',
- 'SendToRietveld', 'TryChange', 'UnknownFiles', 'UploadCL', 'Warn',
- 'WriteFile', 'gclient_utils', 'getpass', 'main', 'os', 'random', 're',
- 'shutil', 'string', 'subprocess', 'sys', 'tempfile', 'upload',
- 'urllib2',
+ 'CODEREVIEW_SETTINGS', 'CODEREVIEW_SETTINGS_FILE',
+ 'Change', 'ChangeInfo', 'Changes', 'Commit',
+ 'DEFAULT_LINT_IGNORE_REGEX', 'DEFAULT_LINT_REGEX',
+ 'DeleteEmptyChangeLists', 'DoPresubmitChecks',
+ 'ErrorExit', 'FILES_CACHE', 'FilterFlag', 'GenerateChangeName',
+ 'GenerateDiff',
+ 'GetCacheDir', 'GetCachedFile', 'GetChangesDir', 'GetCLs',
+ 'GetChangelistInfoFile', 'GetCodeReviewSetting', 'GetEditor',
+ 'GetFilesNotInCL', 'GetInfoDir', 'GetIssueDescription',
+ 'GetModifiedFiles', 'GetRepositoryRoot',
+ 'GetSVNFileProperty', 'Help', 'IsSVNMoved',
+ 'Lint', 'LoadChangelistInfoForMultiple',
+ 'MISSING_TEST_MSG', 'Opened', 'OptionallyDoPresubmitChecks',
+ 'PresubmitCL', 'ReadFile', 'REPOSITORY_ROOT', 'RunShell',
+ 'RunShellWithReturnCode', 'SendToRietveld', 'TryChange',
+ 'UnknownFiles', 'UploadCL', 'Warn', 'WriteFile',
+ '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.
self.compareMembers(gcl, members)
@@ -66,7 +70,8 @@ class GclUnittest(GclTestsBase):
result = {
"Repository Root": ""
}
- gcl.SVN.CaptureInfo("/bleh/prout", print_error=False).AndReturn(result)
+ gcl.gclient_scm.CaptureSVNInfo("/bleh/prout", print_error=False).AndReturn(
+ result)
self.mox.ReplayAll()
self.assertRaises(Exception, gcl.GetRepositoryRoot)
@@ -75,11 +80,13 @@ class GclUnittest(GclTestsBase):
root_path = gcl.os.path.join('bleh', 'prout', 'pouet')
gcl.os.getcwd().AndReturn(root_path)
result1 = { "Repository Root": "Some root" }
- gcl.SVN.CaptureInfo(root_path, print_error=False).AndReturn(result1)
+ gcl.gclient_scm.CaptureSVNInfo(root_path,
+ print_error=False).AndReturn(result1)
gcl.os.getcwd().AndReturn(root_path)
results2 = { "Repository Root": "A different root" }
- gcl.SVN.CaptureInfo(gcl.os.path.dirname(root_path),
- print_error=False).AndReturn(results2)
+ gcl.gclient_scm.CaptureSVNInfo(
+ gcl.os.path.dirname(root_path),
+ print_error=False).AndReturn(results2)
self.mox.ReplayAll()
self.assertEquals(gcl.GetRepositoryRoot(), root_path)
diff --git a/tests/gclient_scm_test.py b/tests/gclient_scm_test.py
index e62711a975..11a2cd933c 100755
--- a/tests/gclient_scm_test.py
+++ b/tests/gclient_scm_test.py
@@ -33,12 +33,12 @@ class BaseTestCase(GCBaseTestCase):
self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'FileWrite')
self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'SubprocessCall')
self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'RemoveDirectory')
- self._CaptureSVNInfo = gclient_scm.scm.SVN.CaptureInfo
- self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'Capture')
- self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'CaptureInfo')
- self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'CaptureStatus')
- self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'Run')
- self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'RunAndGetFileList')
+ self._CaptureSVNInfo = gclient_scm.CaptureSVNInfo
+ self.mox.StubOutWithMock(gclient_scm, 'CaptureSVN')
+ self.mox.StubOutWithMock(gclient_scm, 'CaptureSVNInfo')
+ self.mox.StubOutWithMock(gclient_scm, 'CaptureSVNStatus')
+ self.mox.StubOutWithMock(gclient_scm, 'RunSVN')
+ self.mox.StubOutWithMock(gclient_scm, 'RunSVNAndGetFileList')
self._scm_wrapper = gclient_scm.CreateSCM
@@ -64,11 +64,9 @@ class SVNWrapperTestCase(BaseTestCase):
def testDir(self):
members = [
- 'COMMAND', 'Capture', 'CaptureHeadRevision', 'CaptureInfo',
- 'CaptureStatus', 'DiffItem', 'FullUrlForRelativeUrl', 'GetFileProperty',
- 'IsMoved', 'Run', 'RunAndFilterOutput', 'RunAndGetFileList',
- 'RunCommand', 'cleanup', 'diff', 'export', 'pack', 'relpath', 'revert',
- 'revinfo', 'runhooks', 'scm_name', 'status', 'update', 'url',
+ 'FullUrlForRelativeUrl', '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!
@@ -115,9 +113,8 @@ class SVNWrapperTestCase(BaseTestCase):
# Checkout.
gclient_scm.os.path.exists(base_path).AndReturn(False)
files_list = self.mox.CreateMockAnything()
- gclient_scm.scm.SVN.RunAndGetFileList(options,
- ['checkout', self.url, base_path],
- self.root_dir, files_list)
+ gclient_scm.RunSVNAndGetFileList(options, ['checkout', self.url, base_path],
+ self.root_dir, files_list)
self.mox.ReplayAll()
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
@@ -128,10 +125,9 @@ class SVNWrapperTestCase(BaseTestCase):
options = self.Options(verbose=True)
base_path = gclient_scm.os.path.join(self.root_dir, self.relpath)
gclient_scm.os.path.isdir(base_path).AndReturn(True)
- gclient_scm.scm.SVN.CaptureStatus(base_path).AndReturn([])
- gclient_scm.scm.SVN.RunAndGetFileList(options,
- ['update', '--revision', 'BASE'],
- base_path, mox.IgnoreArg())
+ gclient_scm.CaptureSVNStatus(base_path).AndReturn([])
+ gclient_scm.RunSVNAndGetFileList(options, ['update', '--revision', 'BASE'],
+ base_path, mox.IgnoreArg())
self.mox.ReplayAll()
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
@@ -149,16 +145,15 @@ class SVNWrapperTestCase(BaseTestCase):
]
file_path1 = gclient_scm.os.path.join(base_path, 'a')
file_path2 = gclient_scm.os.path.join(base_path, 'b')
- gclient_scm.scm.SVN.CaptureStatus(base_path).AndReturn(items)
+ gclient_scm.CaptureSVNStatus(base_path).AndReturn(items)
gclient_scm.os.path.exists(file_path1).AndReturn(True)
gclient_scm.os.path.isfile(file_path1).AndReturn(True)
gclient_scm.os.remove(file_path1)
gclient_scm.os.path.exists(file_path2).AndReturn(True)
gclient_scm.os.path.isfile(file_path2).AndReturn(True)
gclient_scm.os.remove(file_path2)
- gclient_scm.scm.SVN.RunAndGetFileList(options,
- ['update', '--revision', 'BASE'],
- base_path, mox.IgnoreArg())
+ gclient_scm.RunSVNAndGetFileList(options, ['update', '--revision', 'BASE'],
+ base_path, mox.IgnoreArg())
print(gclient_scm.os.path.join(base_path, 'a'))
print(gclient_scm.os.path.join(base_path, 'b'))
@@ -175,7 +170,7 @@ class SVNWrapperTestCase(BaseTestCase):
items = [
('~ ', 'a'),
]
- gclient_scm.scm.SVN.CaptureStatus(base_path).AndReturn(items)
+ gclient_scm.CaptureSVNStatus(base_path).AndReturn(items)
file_path = gclient_scm.os.path.join(base_path, 'a')
print(file_path)
gclient_scm.os.path.exists(file_path).AndReturn(True)
@@ -183,9 +178,8 @@ class SVNWrapperTestCase(BaseTestCase):
gclient_scm.os.path.isdir(file_path).AndReturn(True)
gclient_scm.gclient_utils.RemoveDirectory(file_path)
file_list1 = []
- gclient_scm.scm.SVN.RunAndGetFileList(options,
- ['update', '--revision', 'BASE'],
- base_path, mox.IgnoreArg())
+ gclient_scm.RunSVNAndGetFileList(options, ['update', '--revision', 'BASE'],
+ base_path, mox.IgnoreArg())
self.mox.ReplayAll()
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
@@ -197,9 +191,8 @@ class SVNWrapperTestCase(BaseTestCase):
options = self.Options(verbose=True)
base_path = gclient_scm.os.path.join(self.root_dir, self.relpath)
gclient_scm.os.path.isdir(base_path).AndReturn(True)
- gclient_scm.scm.SVN.RunAndGetFileList(options,
- ['status'] + self.args,
- base_path, []).AndReturn(None)
+ gclient_scm.RunSVNAndGetFileList(options, ['status'] + self.args,
+ base_path, []).AndReturn(None)
self.mox.ReplayAll()
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
@@ -223,9 +216,8 @@ class SVNWrapperTestCase(BaseTestCase):
# Checkout.
gclient_scm.os.path.exists(base_path).AndReturn(False)
files_list = self.mox.CreateMockAnything()
- gclient_scm.scm.SVN.RunAndGetFileList(options,
- ['checkout', self.url, base_path],
- self.root_dir, files_list)
+ gclient_scm.RunSVNAndGetFileList(options, ['checkout', self.url,
+ base_path], self.root_dir, files_list)
self.mox.ReplayAll()
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
relpath=self.relpath)
@@ -246,19 +238,17 @@ class SVNWrapperTestCase(BaseTestCase):
).AndReturn(False)
# Checkout or update.
gclient_scm.os.path.exists(base_path).AndReturn(True)
- gclient_scm.scm.SVN.CaptureInfo(
- gclient_scm.os.path.join(base_path, "."), '.'
- ).AndReturn(file_info)
+ gclient_scm.CaptureSVNInfo(gclient_scm.os.path.join(base_path, "."), '.'
+ ).AndReturn(file_info)
# Cheat a bit here.
- gclient_scm.scm.SVN.CaptureInfo(file_info['URL'], '.').AndReturn(file_info)
+ gclient_scm.CaptureSVNInfo(file_info['URL'], '.').AndReturn(file_info)
additional_args = []
if options.manually_grab_svn_rev:
additional_args = ['--revision', str(file_info['Revision'])]
files_list = []
- gclient_scm.scm.SVN.RunAndGetFileList(
- options,
- ['update', base_path] + additional_args,
- self.root_dir, files_list)
+ gclient_scm.RunSVNAndGetFileList(options,
+ ['update', base_path] + additional_args,
+ self.root_dir, files_list)
self.mox.ReplayAll()
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
@@ -366,9 +356,9 @@ from :3
def testDir(self):
members = [
- 'COMMAND', 'Capture', 'CaptureStatus', 'FullUrlForRelativeUrl',
- 'RunCommand', 'cleanup', 'diff', 'export', 'relpath', 'revert',
- 'revinfo', 'runhooks', 'scm_name', 'status', 'update', 'url',
+ 'FullUrlForRelativeUrl', 'RunCommand', 'cleanup', 'diff', 'export',
+ 'relpath', 'revert', 'revinfo', 'runhooks', 'scm_name', 'status',
+ 'update', 'url',
]
# If you add a member, be sure to add the relevant test!
diff --git a/tests/gclient_test.py b/tests/gclient_test.py
index e21c20ae7d..dc3dff4a5c 100755
--- a/tests/gclient_test.py
+++ b/tests/gclient_test.py
@@ -22,6 +22,8 @@ import __builtin__
import StringIO
import gclient
+# Temporary due to the "from scm import *" in gclient_scm.
+import scm
from super_mox import mox, IsOneOf, SuperMoxTestBase
@@ -48,11 +50,16 @@ class GClientBaseTestCase(BaseTestCase):
self.mox.StubOutWithMock(gclient.gclient_utils, 'SubprocessCall')
self.mox.StubOutWithMock(gclient.gclient_utils, 'RemoveDirectory')
# Mock them to be sure nothing bad happens.
- self.mox.StubOutWithMock(gclient.gclient_scm.scm.SVN, 'Capture')
- self.mox.StubOutWithMock(gclient.gclient_scm.scm.SVN, 'CaptureInfo')
- self.mox.StubOutWithMock(gclient.gclient_scm.scm.SVN, 'CaptureStatus')
- self.mox.StubOutWithMock(gclient.gclient_scm.scm.SVN, 'Run')
- self.mox.StubOutWithMock(gclient.gclient_scm.scm.SVN, 'RunAndGetFileList')
+ self.mox.StubOutWithMock(gclient.gclient_scm, 'CaptureSVN')
+ self.mox.StubOutWithMock(gclient.gclient_scm, 'CaptureSVNInfo')
+ self.mox.StubOutWithMock(gclient.gclient_scm, 'CaptureSVNStatus')
+ self.mox.StubOutWithMock(gclient.gclient_scm, 'RunSVN')
+ self.mox.StubOutWithMock(gclient.gclient_scm, 'RunSVNAndGetFileList')
+ 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
gclient.GClient = self.mox.CreateMockAnything()
self._scm_wrapper = gclient.gclient_scm.CreateSCM
diff --git a/tests/presubmit_unittest.py b/tests/presubmit_unittest.py
index b1fbbd4770..3149c9738d 100755
--- a/tests/presubmit_unittest.py
+++ b/tests/presubmit_unittest.py
@@ -7,9 +7,9 @@
import StringIO
+# Local imports
import presubmit_support as presubmit
-# Shortcut.
-from presubmit_support import presubmit_canned_checks
+import presubmit_canned_checks
from super_mox import mox, SuperMoxTestBase
@@ -47,11 +47,9 @@ def GetPreferredTrySlaves():
presubmit.os.path.abspath = MockAbsPath
presubmit.os.getcwd = self.RootDir
presubmit.os.chdir = MockChdir
- self.mox.StubOutWithMock(presubmit.scm.SVN, 'CaptureInfo')
- self.mox.StubOutWithMock(presubmit.scm.SVN, 'GetFileProperty')
- # TODO(maruel): Err, small duplication of code here.
+ self.mox.StubOutWithMock(presubmit.gclient_scm, 'CaptureSVNInfo')
+ self.mox.StubOutWithMock(presubmit.gcl, 'GetSVNFileProperty')
self.mox.StubOutWithMock(presubmit.gcl, 'ReadFile')
- self.mox.StubOutWithMock(presubmit.gclient_utils, 'FileRead')
class PresubmitUnittest(PresubmitTestsBase):
@@ -65,9 +63,9 @@ class PresubmitUnittest(PresubmitTestsBase):
'NotImplementedException', 'OutputApi', 'ParseFiles',
'PresubmitExecuter', 'PromptYesNo', 'ScanSubDirs',
'SvnAffectedFile', 'SvnChange', 'cPickle', 'cStringIO',
- 'exceptions', 'fnmatch', 'gcl', 'gclient_utils', 'glob',
+ 'exceptions', 'fnmatch', 'gcl', 'gclient_scm', 'glob',
'logging', 'marshal', 'normpath', 'optparse', 'os', 'pickle',
- 'presubmit_canned_checks', 'random', 're', 'scm', 'subprocess', 'sys',
+ 'presubmit_canned_checks', 'random', 're', 'subprocess', 'sys',
'tempfile', 'time', 'traceback', 'types', 'unittest', 'urllib2',
'warnings',
]
@@ -142,22 +140,22 @@ class PresubmitUnittest(PresubmitTestsBase):
presubmit.os.path.exists(notfound).AndReturn(True)
presubmit.os.path.isdir(notfound).AndReturn(False)
presubmit.os.path.exists(flap).AndReturn(False)
- presubmit.scm.SVN.CaptureInfo(flap
+ presubmit.gclient_scm.CaptureSVNInfo(flap
).AndReturn({'Node Kind': 'file'})
- presubmit.scm.SVN.GetFileProperty(blat, 'svn:mime-type').AndReturn(None)
- presubmit.scm.SVN.GetFileProperty(
+ presubmit.gcl.GetSVNFileProperty(blat, 'svn:mime-type').AndReturn(None)
+ presubmit.gcl.GetSVNFileProperty(
binary, 'svn:mime-type').AndReturn('application/octet-stream')
- presubmit.scm.SVN.GetFileProperty(
+ presubmit.gcl.GetSVNFileProperty(
notfound, 'svn:mime-type').AndReturn('')
- presubmit.scm.SVN.CaptureInfo(blat).AndReturn(
+ presubmit.gclient_scm.CaptureSVNInfo(blat).AndReturn(
{'URL': 'svn:/foo/foo/blat.cc'})
- presubmit.scm.SVN.CaptureInfo(binary).AndReturn(
+ presubmit.gclient_scm.CaptureSVNInfo(binary).AndReturn(
{'URL': 'svn:/foo/binary.dll'})
- presubmit.scm.SVN.CaptureInfo(notfound).AndReturn({})
- presubmit.scm.SVN.CaptureInfo(flap).AndReturn(
+ presubmit.gclient_scm.CaptureSVNInfo(notfound).AndReturn({})
+ presubmit.gclient_scm.CaptureSVNInfo(flap).AndReturn(
{'URL': 'svn:/foo/boo/flap.h'})
- presubmit.gclient_utils.FileRead(blat, 'rU').AndReturn('boo!\nahh?')
- presubmit.gclient_utils.FileRead(notfound, 'rU').AndReturn('look!\nthere?')
+ presubmit.gcl.ReadFile(blat).AndReturn('boo!\nahh?')
+ presubmit.gcl.ReadFile(notfound).AndReturn('look!\nthere?')
self.mox.ReplayAll()
change = presubmit.SvnChange('mychange', '\n'.join(description_lines),
@@ -287,10 +285,10 @@ class PresubmitUnittest(PresubmitTestsBase):
root_path = join(self.fake_root_dir, 'PRESUBMIT.py')
presubmit.os.path.isfile(root_path).AndReturn(True)
presubmit.os.path.isfile(haspresubmit_path).AndReturn(True)
- presubmit.gclient_utils.FileRead(root_path,
- 'rU').AndReturn(self.presubmit_text)
- presubmit.gclient_utils.FileRead(haspresubmit_path,
- 'rU').AndReturn(self.presubmit_text)
+ presubmit.gcl.ReadFile(root_path,
+ 'rU').AndReturn(self.presubmit_text)
+ presubmit.gcl.ReadFile(haspresubmit_path,
+ 'rU').AndReturn(self.presubmit_text)
presubmit.random.randint(0, 4).AndReturn(1)
self.mox.ReplayAll()
@@ -315,9 +313,9 @@ class PresubmitUnittest(PresubmitTestsBase):
for i in range(2):
presubmit.os.path.isfile(presubmit_path).AndReturn(True)
presubmit.os.path.isfile(haspresubmit_path).AndReturn(True)
- presubmit.gclient_utils.FileRead(presubmit_path, 'rU'
+ presubmit.gcl.ReadFile(presubmit_path, 'rU'
).AndReturn(self.presubmit_text)
- presubmit.gclient_utils.FileRead(haspresubmit_path, 'rU'
+ presubmit.gcl.ReadFile(haspresubmit_path, 'rU'
).AndReturn(self.presubmit_text)
presubmit.random.randint(0, 4).AndReturn(1)
presubmit.random.randint(0, 4).AndReturn(1)
@@ -351,9 +349,8 @@ class PresubmitUnittest(PresubmitTestsBase):
'PRESUBMIT.py')
presubmit.os.path.isfile(presubmit_path).AndReturn(True)
presubmit.os.path.isfile(haspresubmit_path).AndReturn(True)
- presubmit.gclient_utils.FileRead(presubmit_path, 'rU'
- ).AndReturn(self.presubmit_text)
- presubmit.gclient_utils.FileRead(haspresubmit_path, 'rU').AndReturn(
+ presubmit.gcl.ReadFile(presubmit_path, 'rU').AndReturn(self.presubmit_text)
+ presubmit.gcl.ReadFile(haspresubmit_path, 'rU').AndReturn(
self.presubmit_text)
presubmit.random.randint(0, 4).AndReturn(1)
self.mox.ReplayAll()
@@ -505,14 +502,14 @@ def CheckChangeOnCommit(input_api, output_api):
linux_presubmit = join(self.fake_root_dir, 'linux_only', 'PRESUBMIT.py')
presubmit.os.path.isfile(root_presubmit).AndReturn(True)
- presubmit.gclient_utils.FileRead(root_presubmit, 'rU').AndReturn(
+ presubmit.gcl.ReadFile(root_presubmit, 'rU').AndReturn(
self.presubmit_tryslave % '["win"]')
presubmit.os.path.isfile(root_presubmit).AndReturn(True)
presubmit.os.path.isfile(linux_presubmit).AndReturn(True)
- presubmit.gclient_utils.FileRead(root_presubmit, 'rU').AndReturn(
+ presubmit.gcl.ReadFile(root_presubmit, 'rU').AndReturn(
self.presubmit_tryslave % '["win"]')
- presubmit.gclient_utils.FileRead(linux_presubmit, 'rU').AndReturn(
+ presubmit.gcl.ReadFile(linux_presubmit, 'rU').AndReturn(
self.presubmit_tryslave % '["linux"]')
self.mox.ReplayAll()
@@ -568,9 +565,9 @@ class InputApiUnittest(PresubmitTestsBase):
self.compareMembers(presubmit.InputApi(None, './.', False), members)
def testDepotToLocalPath(self):
- presubmit.scm.SVN.CaptureInfo('svn://foo/smurf').AndReturn(
+ presubmit.gclient_scm.CaptureSVNInfo('svn://foo/smurf').AndReturn(
{'Path': 'prout'})
- presubmit.scm.SVN.CaptureInfo('svn:/foo/notfound/burp').AndReturn({})
+ presubmit.gclient_scm.CaptureSVNInfo('svn:/foo/notfound/burp').AndReturn({})
self.mox.ReplayAll()
path = presubmit.InputApi(None, './p', False).DepotToLocalPath(
@@ -581,9 +578,9 @@ class InputApiUnittest(PresubmitTestsBase):
self.failUnless(path == None)
def testLocalToDepotPath(self):
- presubmit.scm.SVN.CaptureInfo('smurf').AndReturn({'URL':
+ presubmit.gclient_scm.CaptureSVNInfo('smurf').AndReturn({'URL':
'svn://foo'})
- presubmit.scm.SVN.CaptureInfo('notfound-food').AndReturn({})
+ presubmit.gclient_scm.CaptureSVNInfo('notfound-food').AndReturn({})
self.mox.ReplayAll()
path = presubmit.InputApi(None, './p', False).LocalToDepotPath('smurf')
@@ -634,20 +631,18 @@ class InputApiUnittest(PresubmitTestsBase):
presubmit.os.path.exists(notfound).AndReturn(False)
presubmit.os.path.exists(flap).AndReturn(True)
presubmit.os.path.isdir(flap).AndReturn(False)
- presubmit.scm.SVN.CaptureInfo(beingdeleted).AndReturn({})
- presubmit.scm.SVN.CaptureInfo(notfound).AndReturn({})
- presubmit.scm.SVN.GetFileProperty(blat, 'svn:mime-type').AndReturn(None)
- presubmit.scm.SVN.GetFileProperty(readme, 'svn:mime-type').AndReturn(None)
- presubmit.scm.SVN.GetFileProperty(binary, 'svn:mime-type').AndReturn(
+ presubmit.gclient_scm.CaptureSVNInfo(beingdeleted).AndReturn({})
+ presubmit.gclient_scm.CaptureSVNInfo(notfound).AndReturn({})
+ presubmit.gcl.GetSVNFileProperty(blat, 'svn:mime-type').AndReturn(None)
+ presubmit.gcl.GetSVNFileProperty(readme, 'svn:mime-type').AndReturn(None)
+ presubmit.gcl.GetSVNFileProperty(binary, 'svn:mime-type').AndReturn(
'application/octet-stream')
- presubmit.scm.SVN.GetFileProperty(weird, 'svn:mime-type').AndReturn(None)
- presubmit.scm.SVN.GetFileProperty(another, 'svn:mime-type').AndReturn(None)
- presubmit.scm.SVN.GetFileProperty(third_party, 'svn:mime-type'
+ presubmit.gcl.GetSVNFileProperty(weird, 'svn:mime-type').AndReturn(None)
+ presubmit.gcl.GetSVNFileProperty(another, 'svn:mime-type').AndReturn(None)
+ presubmit.gcl.GetSVNFileProperty(third_party, 'svn:mime-type'
).AndReturn(None)
- presubmit.gclient_utils.FileRead(blat, 'rU'
- ).AndReturn('whatever\ncookie')
- presubmit.gclient_utils.FileRead(another, 'rU'
- ).AndReturn('whatever\ncookie2')
+ presubmit.gcl.ReadFile(blat).AndReturn('whatever\ncookie')
+ presubmit.gcl.ReadFile(another).AndReturn('whatever\ncookie2')
self.mox.ReplayAll()
change = presubmit.SvnChange('mychange', '\n'.join(description_lines),
@@ -759,7 +754,7 @@ class InputApiUnittest(PresubmitTestsBase):
item = presubmit.os.path.join(self.fake_root_dir, item)
presubmit.os.path.exists(item).AndReturn(True)
presubmit.os.path.isdir(item).AndReturn(False)
- presubmit.scm.SVN.GetFileProperty(item, 'svn:mime-type').AndReturn(None)
+ presubmit.gcl.GetSVNFileProperty(item, 'svn:mime-type').AndReturn(None)
self.mox.ReplayAll()
change = presubmit.SvnChange('mychange', '', self.fake_root_dir, files, 0,
@@ -781,7 +776,7 @@ class InputApiUnittest(PresubmitTestsBase):
item = presubmit.os.path.join(self.fake_root_dir, item)
presubmit.os.path.exists(item).AndReturn(True)
presubmit.os.path.isdir(item).AndReturn(False)
- presubmit.scm.SVN.GetFileProperty(item, 'svn:mime-type').AndReturn(None)
+ presubmit.gcl.GetSVNFileProperty(item, 'svn:mime-type').AndReturn(None)
self.mox.ReplayAll()
change = presubmit.SvnChange('mychange', '', self.fake_root_dir, files, 0,
@@ -857,7 +852,7 @@ class InputApiUnittest(PresubmitTestsBase):
def testReadFileStringAccepted(self):
path = presubmit.os.path.join(self.fake_root_dir, 'AA/boo')
- presubmit.gclient_utils.FileRead(path, 'x').AndReturn(None)
+ presubmit.gcl.ReadFile(path, 'x').AndReturn(None)
self.mox.ReplayAll()
change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')],
@@ -878,8 +873,7 @@ class InputApiUnittest(PresubmitTestsBase):
def testReadFileAffectedFileAccepted(self):
file = presubmit.AffectedFile('AA/boo', 'M', self.fake_root_dir)
- presubmit.gclient_utils.FileRead(file.AbsoluteLocalPath(), 'x'
- ).AndReturn(None)
+ presubmit.gcl.ReadFile(file.AbsoluteLocalPath(), 'x').AndReturn(None)
self.mox.ReplayAll()
change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')],
@@ -961,8 +955,8 @@ class AffectedFileUnittest(PresubmitTestsBase):
path = presubmit.os.path.join('foo', 'blat.cc')
presubmit.os.path.exists(path).AndReturn(True)
presubmit.os.path.isdir(path).AndReturn(False)
- presubmit.gclient_utils.FileRead(path, 'rU').AndReturn('whatever\ncookie')
- presubmit.scm.SVN.CaptureInfo(path).AndReturn(
+ presubmit.gcl.ReadFile(path).AndReturn('whatever\ncookie')
+ presubmit.gclient_scm.CaptureSVNInfo(path).AndReturn(
{'URL': 'svn:/foo/foo/blat.cc'})
self.mox.ReplayAll()
af = presubmit.SvnAffectedFile('foo/blat.cc', 'M')
@@ -974,7 +968,7 @@ class AffectedFileUnittest(PresubmitTestsBase):
self.failUnless(af.ServerPath() == '')
def testProperty(self):
- presubmit.scm.SVN.GetFileProperty('foo.cc', 'svn:secret-property'
+ presubmit.gcl.GetSVNFileProperty('foo.cc', 'svn:secret-property'
).AndReturn('secret-property-value')
self.mox.ReplayAll()
affected_file = presubmit.SvnAffectedFile('foo.cc', 'A')
@@ -986,7 +980,7 @@ class AffectedFileUnittest(PresubmitTestsBase):
def testIsDirectoryNotExists(self):
presubmit.os.path.exists('foo.cc').AndReturn(False)
- presubmit.scm.SVN.CaptureInfo('foo.cc').AndReturn({})
+ presubmit.gclient_scm.CaptureSVNInfo('foo.cc').AndReturn({})
self.mox.ReplayAll()
affected_file = presubmit.SvnAffectedFile('foo.cc', 'A')
# Verify cache coherency.
@@ -1012,8 +1006,8 @@ class AffectedFileUnittest(PresubmitTestsBase):
presubmit.os.path.isdir(blat).AndReturn(False)
presubmit.os.path.exists(blob).AndReturn(True)
presubmit.os.path.isdir(blob).AndReturn(False)
- presubmit.scm.SVN.GetFileProperty(blat, 'svn:mime-type').AndReturn(None)
- presubmit.scm.SVN.GetFileProperty(blob, 'svn:mime-type'
+ presubmit.gcl.GetSVNFileProperty(blat, 'svn:mime-type').AndReturn(None)
+ presubmit.gcl.GetSVNFileProperty(blob, 'svn:mime-type'
).AndReturn('application/octet-stream')
self.mox.ReplayAll()
@@ -1157,10 +1151,10 @@ class CannedChecksUnittest(PresubmitTestsBase):
input_api1.AffectedSourceFiles(None).AndReturn(files1)
else:
input_api1.AffectedFiles(include_deleted=False).AndReturn(files1)
- presubmit.scm.SVN.GetFileProperty(presubmit.normpath('foo/bar.cc'),
- property).AndReturn(value1)
- presubmit.scm.SVN.GetFileProperty(presubmit.normpath('foo.cc'),
- property).AndReturn(value1)
+ presubmit.gcl.GetSVNFileProperty(presubmit.normpath('foo/bar.cc'),
+ property).AndReturn(value1)
+ presubmit.gcl.GetSVNFileProperty(presubmit.normpath('foo.cc'),
+ property).AndReturn(value1)
change2 = presubmit.SvnChange('mychange', '', self.fake_root_dir, [], 0, 0)
input_api2 = self.MockInputApi(change2, committing)
files2 = [
@@ -1172,10 +1166,10 @@ class CannedChecksUnittest(PresubmitTestsBase):
else:
input_api2.AffectedFiles(include_deleted=False).AndReturn(files2)
- presubmit.scm.SVN.GetFileProperty(presubmit.normpath('foo/bar.cc'),
- property).AndReturn(value2)
- presubmit.scm.SVN.GetFileProperty(presubmit.normpath('foo.cc'),
- property).AndReturn(value2)
+ presubmit.gcl.GetSVNFileProperty(presubmit.normpath('foo/bar.cc'),
+ property).AndReturn(value2)
+ presubmit.gcl.GetSVNFileProperty(presubmit.normpath('foo.cc'),
+ property).AndReturn(value2)
self.mox.ReplayAll()
results1 = check(input_api1, presubmit.OutputApi, None)
diff --git a/tests/revert_unittest.py b/tests/revert_unittest.py
index 8e872e630b..9296d85861 100644
--- a/tests/revert_unittest.py
+++ b/tests/revert_unittest.py
@@ -61,7 +61,6 @@ class RevertMainUnittest(RevertTestsBase):
class RevertRevertUnittest(RevertTestsBase):
def setUp(self):
RevertTestsBase.setUp(self)
- self.mox.StubOutWithMock(revert.gclient_scm.scm.SVN, 'CaptureStatus')
def testRevert(self):
revert.gcl.GetRepositoryRoot().AndReturn('foo')
@@ -74,7 +73,7 @@ class RevertRevertUnittest(RevertTestsBase):
}]
revert.CaptureSVNLog(['-r', '42', '-v']).AndReturn(entries)
revert.GetRepoBase().AndReturn('proto://fqdn/repo/')
- revert.gclient_scm.scm.SVN.CaptureStatus(['random_file']).AndReturn([])
+ revert.gclient_scm.CaptureSVNStatus(['random_file']).AndReturn([])
revert.gcl.RunShell(['svn', 'up', 'random_file'])
revert.os.path.isdir('random_file').AndReturn(False)
status = """--- Reverse-merging r42 into '.':
diff --git a/tests/scm_unittest.py b/tests/scm_unittest.py
index 4dbb929653..68846d71e1 100755
--- a/tests/scm_unittest.py
+++ b/tests/scm_unittest.py
@@ -5,12 +5,9 @@
"""Unit tests for scm.py."""
-import shutil
-import tempfile
-
from gclient_test import BaseTestCase
import scm
-from super_mox import mox, SuperMoxBaseTestBase
+from super_mox import mox
class BaseSCMTestCase(BaseTestCase):
@@ -24,14 +21,17 @@ class RootTestCase(BaseSCMTestCase):
def testMembersChanged(self):
self.mox.ReplayAll()
members = [
- 'GIT', 'SVN',
- 'gclient_utils', 'os', 're', 'subprocess', 'sys', 'tempfile', 'xml',
+ 'CaptureGit', 'CaptureGitStatus', 'GIT_COMMAND',
+ 'CaptureSVN', 'CaptureSVNHeadRevision', 'CaptureSVNInfo',
+ 'CaptureSVNStatus', 'RunSVN', 'RunSVNAndFilterOutput',
+ 'RunSVNAndGetFileList', 'SVN_COMMAND',
+ 'gclient_utils', 'os', 're', 'subprocess', 'sys', 'xml',
]
# If this test fails, you should add the relevant test.
self.compareMembers(scm, members)
-class GitWrapperTestCase(SuperMoxBaseTestBase):
+class GitWrapperTestCase(BaseSCMTestCase):
sample_git_import = """blob
mark :1
data 6
@@ -80,44 +80,30 @@ from :3
def CreateGitRepo(self, git_import, path):
try:
- scm.subprocess.Popen(['git', 'init'],
- stdout=scm.subprocess.PIPE,
- stderr=scm.subprocess.STDOUT,
- cwd=path).communicate()
- except OSError:
+ subprocess.Popen(['git', 'init'], stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT, cwd=path).communicate()
+ except WindowsError:
# git is not available, skip this test.
return False
- scm.subprocess.Popen(['git', 'fast-import'],
- stdin=scm.subprocess.PIPE,
- stdout=scm.subprocess.PIPE,
- stderr=scm.subprocess.STDOUT,
- cwd=path).communicate(input=git_import)
- scm.subprocess.Popen(['git', 'checkout'],
- stdout=scm.subprocess.PIPE,
- stderr=scm.subprocess.STDOUT,
- cwd=path).communicate()
+ subprocess.Popen(['git', 'fast-import'], stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+ cwd=path).communicate(input=git_import)
+ subprocess.Popen(['git', 'checkout'], stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT, cwd=path).communicate()
return True
def setUp(self):
- SuperMoxBaseTestBase.setUp(self)
+ BaseSCMTestCase.setUp(self)
self.args = self.Args()
self.url = 'git://foo'
self.root_dir = tempfile.mkdtemp()
self.relpath = '.'
- self.base_path = scm.os.path.join(self.root_dir, self.relpath)
+ self.base_path = os.path.join(self.root_dir, self.relpath)
self.enabled = self.CreateGitRepo(self.sample_git_import, self.base_path)
def tearDown(self):
shutil.rmtree(self.root_dir)
- 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)
+ gclient_test.BaseTestCase.tearDown(self)
class SVNTestCase(BaseSCMTestCase):
@@ -128,17 +114,7 @@ class SVNTestCase(BaseSCMTestCase):
self.url = self.Url()
self.relpath = 'asf'
- 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):
+ def testGetSVNFileInfo(self):
xml_text = r"""
@@ -154,8 +130,8 @@ class SVNTestCase(BaseSCMTestCase):
""" % self.url
- self.mox.StubOutWithMock(scm.SVN, 'Capture')
- scm.SVN.Capture(['info', '--xml', self.url], '.', True).AndReturn(xml_text)
+ self.mox.StubOutWithMock(scm, 'CaptureSVN')
+ scm.CaptureSVN(['info', '--xml', self.url], '.', True).AndReturn(xml_text)
expected = {
'URL': 'http://src.chromium.org/svn/trunk/src/chrome/app/d',
'UUID': None,
@@ -169,10 +145,10 @@ class SVNTestCase(BaseSCMTestCase):
'Node Kind': 'file',
}
self.mox.ReplayAll()
- file_info = scm.SVN.CaptureInfo(self.url, '.', True)
+ file_info = scm.CaptureSVNInfo(self.url, '.', True)
self.assertEquals(sorted(file_info.items()), sorted(expected.items()))
- def testCaptureInfo(self):
+ def testCaptureSvnInfo(self):
xml_text = """
""" % (self.url, self.root_dir)
- self.mox.StubOutWithMock(scm.SVN, 'Capture')
- scm.SVN.Capture(['info', '--xml', self.url], '.', True).AndReturn(xml_text)
+ self.mox.StubOutWithMock(scm, 'CaptureSVN')
+ scm.CaptureSVN(['info', '--xml', self.url], '.', True).AndReturn(xml_text)
self.mox.ReplayAll()
- file_info = scm.SVN.CaptureInfo(self.url, '.', True)
+ file_info = scm.CaptureSVNInfo(self.url, '.', True)
expected = {
'URL': self.url,
'UUID': '7b9385f5-0452-0410-af26-ad4892b7a1fb',
@@ -209,11 +185,11 @@ class SVNTestCase(BaseSCMTestCase):
'Copied From URL': None,
'Copied From Rev': None,
'Path': '.',
- 'Node Kind': 'directory',
+ 'Node Kind': 'dir',
}
self.assertEqual(file_info, expected)
- def testCaptureStatus(self):
+ def testCaptureSVNStatus(self):
text =r"""
@@ -260,7 +236,7 @@ class SVNTestCase(BaseSCMTestCase):
proc.communicate().AndReturn((text, 0))
self.mox.ReplayAll()
- info = scm.SVN.CaptureStatus('.')
+ info = scm.CaptureSVNStatus('.')
expected = [
('? ', 'unversionned_file.txt'),
('M ', 'build\\internal\\essential.vsprops'),
@@ -270,14 +246,14 @@ class SVNTestCase(BaseSCMTestCase):
]
self.assertEquals(sorted(info), sorted(expected))
- def testRun(self):
+ def testRunSVN(self):
param2 = 'bleh'
scm.gclient_utils.SubprocessCall(['svn', 'foo', 'bar'],
param2).AndReturn(None)
self.mox.ReplayAll()
- scm.SVN.Run(['foo', 'bar'], param2)
+ scm.RunSVN(['foo', 'bar'], param2)
- def testCaptureStatusEmpty(self):
+ def testCaptureSVNStatusEmpty(self):
text = r"""
>sys.stderr, diff
+ print diff
self.assertEqual(actual_members, expected_members)
def UnMock(self, object, name):
diff --git a/tests/trychange_unittest.py b/tests/trychange_unittest.py
index 828d3ea4e8..24550dda31 100644
--- a/tests/trychange_unittest.py
+++ b/tests/trychange_unittest.py
@@ -25,9 +25,9 @@ class TryChangeUnittest(TryChangeTestsBase):
'GetTryServerSettings', 'GuessVCS',
'HELP_STRING', 'InvalidScript', 'NoTryServerAccess', 'PathDifference',
'RunCommand', 'SCM', 'SVN', 'TryChange', 'USAGE',
- 'datetime', 'gcl', 'getpass', 'logging',
- 'optparse', 'os', 'presubmit_support', 'scm', 'shutil', 'socket',
- 'subprocess', 'sys', 'tempfile', 'upload', 'urllib',
+ 'datetime', 'gcl', 'gclient_scm', 'getpass', 'logging',
+ 'optparse', 'os', 'presubmit_support', 'shutil', 'socket', 'subprocess',
+ 'sys', 'tempfile', 'upload', 'urllib',
]
# If this test fails, you should add the relevant test.
self.compareMembers(trychange, members)
diff --git a/trychange.py b/trychange.py
index 65e935a08a..cbe49f93f9 100755
--- a/trychange.py
+++ b/trychange.py
@@ -21,11 +21,11 @@ import tempfile
import urllib
import gcl
-import scm
+import gclient_scm
import presubmit_support
import upload
-__version__ = '1.1.2'
+__version__ = '1.1.1'
# Constants
@@ -150,8 +150,50 @@ class SVN(SCM):
else:
os.chdir(root)
- # Directories will return None so filter them out.
- diff = filter(None, [scm.SVN.DiffItem(f) for f in files])
+ diff = []
+ for filename 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)
return "".join(diff)
@@ -365,7 +407,6 @@ def GuessVCS(options):
Returns:
A SCM instance. Exits if the SCM can't be guessed.
"""
- __pychecker__ = 'no-returnvalues'
# Subversion has a .svn in all working directories.
if os.path.isdir('.svn'):
logging.info("Guessed VCS = Subversion")