Commit 4810a966 authored by maruel@chromium.org's avatar maruel@chromium.org

Deprecate gcl.GetSVNStatus() for gclient.CaptureSVNStatus() and fix some...

Deprecate gcl.GetSVNStatus() for gclient.CaptureSVNStatus() and fix some status information that was lost.
This was breaking gclient revert on unversioned files.

TEST=ran "for %a in (tests\*test.py) do python %a" and all tests succeeded.
Review URL: http://codereview.chromium.org/115264

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@15894 0039d316-1c4b-4281-b951-d872f2087c98
parent 46a94109
...@@ -76,78 +76,14 @@ def GetSVNFileProperty(file, property_name): ...@@ -76,78 +76,14 @@ def GetSVNFileProperty(file, property_name):
return output return output
def GetSVNStatus(file):
"""Returns the svn 1.5 svn status emulated output.
@file can be a string (one file) or a list of files."""
command = ["svn", "status", "--xml"]
if file is None:
pass
elif isinstance(file, basestring):
command.append(file)
else:
command.extend(file)
status_letter = {
'': ' ',
'added': 'A',
'conflicted': 'C',
'deleted': 'D',
'ignored': 'I',
'missing': '!',
'modified': 'M',
'normal': ' ',
'replaced': 'R',
'unversioned': '?',
# TODO(maruel): Find the corresponding strings for X, ~
}
output = RunShell(command)
dom = gclient.ParseXML(output)
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 = entry.getAttribute('path')
wc_status = entry.getElementsByTagName('wc-status')
assert len(wc_status) == 1
# Emulate svn 1.5 status ouput...
statuses = [' ' for i in range(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 3
if wc_status[0].getAttribute('copied') == 'true':
statuses[3] = '+'
item = (''.join(statuses), file)
results.append(item)
return results
def UnknownFiles(extra_args): def UnknownFiles(extra_args):
"""Runs svn status and prints unknown files. """Runs svn status and prints 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 GetSVNStatus(extra_args) if item[0][0] == '?'] return [item[1] for item in gclient.CaptureSVNStatus(extra_args)
if item[0][0] == '?']
def GetRepositoryRoot(): def GetRepositoryRoot():
...@@ -488,7 +424,7 @@ def LoadChangelistInfo(changename, fail_on_not_found=True, ...@@ -488,7 +424,7 @@ def LoadChangelistInfo(changename, fail_on_not_found=True,
if update_status: if update_status:
for file in files: for file in files:
filename = os.path.join(GetRepositoryRoot(), file[1]) filename = os.path.join(GetRepositoryRoot(), file[1])
status_result = GetSVNStatus(filename) status_result = gclient.CaptureSVNStatus(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
...@@ -547,7 +483,7 @@ def GetModifiedFiles(): ...@@ -547,7 +483,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 = GetSVNStatus(None) status_result = gclient.CaptureSVNStatus(None)
for line in status_result: for line in status_result:
status = line[0] status = line[0]
filename = line[1] filename = line[1]
......
...@@ -612,30 +612,39 @@ def CaptureSVNHeadRevision(url): ...@@ -612,30 +612,39 @@ def CaptureSVNHeadRevision(url):
return int(dom.getElementsByTagName('entry')[0].getAttribute('revision')) return int(dom.getElementsByTagName('entry')[0].getAttribute('revision'))
class FileStatus: def CaptureSVNStatus(files):
def __init__(self, path, text_status, props, lock, history): """Returns the svn 1.5 svn status emulated output.
self.path = path
self.text_status = text_status
self.props = props
self.lock = lock
self.history = history
def __str__(self): @files can be a string (one file) or a list of files.
# Emulate svn status 1.5 output.
return (self.text_status + self.props + self.lock + self.history + ' ' +
self.path)
def CaptureSVNStatus(path):
"""Runs 'svn status' on an existing path.
Args:
path: The directory to run svn status.
Returns: Returns an array of (status, file) tuples."""
An array of FileStatus corresponding to the emulated output of 'svn status' command = ["status", "--xml"]
version 1.5.""" if not files:
dom = ParseXML(CaptureSVN(["status", "--xml"], path)) 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 = ParseXML(CaptureSVN(command))
results = [] results = []
if dom: if dom:
# /status/target/entry/(wc-status|commit|author|date) # /status/target/entry/(wc-status|commit|author|date)
...@@ -649,18 +658,8 @@ def CaptureSVNStatus(path): ...@@ -649,18 +658,8 @@ def CaptureSVNStatus(path):
statuses = [' ' for i in range(7)] statuses = [' ' for i in range(7)]
# Col 0 # Col 0
xml_item_status = wc_status[0].getAttribute('item') xml_item_status = wc_status[0].getAttribute('item')
if xml_item_status == 'unversioned': if xml_item_status in status_letter:
statuses[0] = '?' statuses[0] = status_letter[xml_item_status]
elif xml_item_status == 'modified':
statuses[0] = 'M'
elif xml_item_status == 'added':
statuses[0] = 'A'
elif xml_item_status == 'conflicted':
statuses[0] = 'C'
elif xml_item_status in ('incomplete', 'missing'):
statuses[0] = '!'
elif not xml_item_status:
pass
else: else:
raise Exception('Unknown item status "%s"; please implement me!' % raise Exception('Unknown item status "%s"; please implement me!' %
xml_item_status) xml_item_status)
...@@ -682,8 +681,7 @@ def CaptureSVNStatus(path): ...@@ -682,8 +681,7 @@ def CaptureSVNStatus(path):
# Col 3 # Col 3
if wc_status[0].getAttribute('copied') == 'true': if wc_status[0].getAttribute('copied') == 'true':
statuses[3] = '+' statuses[3] = '+'
item = FileStatus(file, statuses[0], statuses[1], statuses[2], item = (''.join(statuses), file)
statuses[3])
results.append(item) results.append(item)
return results return results
...@@ -856,10 +854,10 @@ class SCMWrapper(object): ...@@ -856,10 +854,10 @@ class SCMWrapper(object):
# Batch the command. # Batch the command.
files_to_revert = [] files_to_revert = []
for file in files: for file in files:
file_path = os.path.join(path, file.path) file_path = os.path.join(path, file[1])
print(file_path) print(file_path)
# Unversioned file or unexpected unversioned file. # Unversioned file or unexpected unversioned file.
if file.text_status in ('?', '~'): if file[0][0] in ('?', '~'):
# Remove extraneous file. Also remove unexpected unversioned # Remove extraneous file. Also remove unexpected unversioned
# directories. svn won't touch them but we want to delete these. # directories. svn won't touch them but we want to delete these.
file_list.append(file_path) file_list.append(file_path)
...@@ -868,10 +866,10 @@ class SCMWrapper(object): ...@@ -868,10 +866,10 @@ class SCMWrapper(object):
except EnvironmentError: except EnvironmentError:
RemoveDirectory(file_path) RemoveDirectory(file_path)
if file.text_status != '?': if file[0][0] != '?':
# For any other status, svn revert will work. # For any other status, svn revert will work.
file_list.append(file_path) file_list.append(file_path)
files_to_revert.append(file.path) files_to_revert.append(file[1])
# Revert them all at once. # Revert them all at once.
if files_to_revert: if files_to_revert:
......
...@@ -48,7 +48,7 @@ class GclUnittest(GclTestsBase): ...@@ -48,7 +48,7 @@ class GclUnittest(GclTestsBase):
'ErrorExit', 'GenerateChangeName', 'GenerateDiff', 'GetCLs', 'ErrorExit', 'GenerateChangeName', 'GenerateDiff', 'GetCLs',
'GetChangelistInfoFile', 'GetCodeReviewSetting', 'GetEditor', 'GetChangelistInfoFile', 'GetCodeReviewSetting', 'GetEditor',
'GetFilesNotInCL', 'GetInfoDir', 'GetIssueDescription', 'GetFilesNotInCL', 'GetInfoDir', 'GetIssueDescription',
'GetModifiedFiles', 'GetRepositoryRoot', 'GetSVNStatus', 'GetModifiedFiles', 'GetRepositoryRoot',
'GetSVNFileProperty', 'Help', 'IGNORE_PATHS', 'IsSVNMoved', 'IsTreeOpen', 'GetSVNFileProperty', 'Help', 'IGNORE_PATHS', 'IsSVNMoved', 'IsTreeOpen',
'Lint', 'LoadChangelistInfo', 'LoadChangelistInfoForMultiple', 'Lint', 'LoadChangelistInfo', 'LoadChangelistInfoForMultiple',
'MISSING_TEST_MSG', 'Opened', 'PresubmitCL', 'ReadFile', 'MISSING_TEST_MSG', 'Opened', 'PresubmitCL', 'ReadFile',
...@@ -62,70 +62,6 @@ class GclUnittest(GclTestsBase): ...@@ -62,70 +62,6 @@ class GclUnittest(GclTestsBase):
# 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)
def testGetSVNStatus(self):
def RunShellMock(command):
return r"""<?xml version="1.0"?>
<status>
<target path=".">
<entry path="unversionned_file.txt">
<wc-status props="none" item="unversioned"></wc-status>
</entry>
<entry path="build\internal\essential.vsprops">
<wc-status props="normal" item="modified" revision="14628">
<commit revision="13818">
<author>ajwong@chromium.org</author>
<date>2009-04-16T00:42:06.872358Z</date>
</commit>
</wc-status>
</entry>
<entry path="chrome\app\d">
<wc-status props="none" copied="true" tree-conflicted="true" item="added">
</wc-status>
</entry>
<entry path="chrome\app\DEPS">
<wc-status props="modified" item="modified" revision="14628">
<commit revision="1279">
<author>brettw@google.com</author>
<date>2008-08-23T17:16:42.090152Z</date>
</commit>
</wc-status>
</entry>
<entry path="scripts\master\factory\gclient_factory.py">
<wc-status props="normal" item="conflicted" revision="14725">
<commit revision="14633">
<author>nsylvain@chromium.org</author>
<date>2009-04-27T19:37:17.977400Z</date>
</commit>
</wc-status>
</entry>
</target>
</status>
"""
# GclTestsBase.tearDown will restore the original.
gcl.RunShell = RunShellMock
info = gcl.GetSVNStatus('.')
expected = [
('? ', 'unversionned_file.txt'),
('M ', 'build\\internal\\essential.vsprops'),
('A + ', 'chrome\\app\\d'),
('MM ', 'chrome\\app\\DEPS'),
('C ', 'scripts\\master\\factory\\gclient_factory.py'),
]
self.assertEquals(sorted(info), sorted(expected))
def testGetSVNStatusEmpty(self):
def RunShellMock(command):
return r"""<?xml version="1.0"?>
<status>
<target
path="perf">
</target>
</status>
"""
# GclTestsBase.tearDown will restore the original.
gcl.RunShell = RunShellMock
info = gcl.GetSVNStatus(None)
self.assertEquals(info, [])
def testHelp(self): def testHelp(self):
old_stdout = sys.stdout old_stdout = sys.stdout
......
...@@ -1159,8 +1159,8 @@ class SCMWrapperTestCase(GClientBaseTestCase): ...@@ -1159,8 +1159,8 @@ class SCMWrapperTestCase(GClientBaseTestCase):
gclient.os.path.isdir = self.mox.CreateMockAnything() gclient.os.path.isdir = self.mox.CreateMockAnything()
gclient.os.path.isdir(base_path).AndReturn(True) gclient.os.path.isdir(base_path).AndReturn(True)
items = [ items = [
gclient.FileStatus('a', 'M', ' ', ' ', ' '), ('M ', 'a'),
gclient.FileStatus('b', 'A', ' ', ' ', ' '), ('A ', 'b'),
] ]
gclient.CaptureSVNStatus(base_path).AndReturn(items) gclient.CaptureSVNStatus(base_path).AndReturn(items)
...@@ -1387,6 +1387,73 @@ class SubprocessCallAndCaptureTestCase(BaseTestCase): ...@@ -1387,6 +1387,73 @@ class SubprocessCallAndCaptureTestCase(BaseTestCase):
self.assertEquals(capture_list, ['cc', 'dd']) self.assertEquals(capture_list, ['cc', 'dd'])
self.mox.VerifyAll() self.mox.VerifyAll()
def testCaptureSVNStatus(self):
x = self
def CaptureSVNMock(command):
x.assertEquals(['status', '--xml', '.'], command)
return r"""<?xml version="1.0"?>
<status>
<target path=".">
<entry path="unversionned_file.txt">
<wc-status props="none" item="unversioned"></wc-status>
</entry>
<entry path="build\internal\essential.vsprops">
<wc-status props="normal" item="modified" revision="14628">
<commit revision="13818">
<author>ajwong@chromium.org</author>
<date>2009-04-16T00:42:06.872358Z</date>
</commit>
</wc-status>
</entry>
<entry path="chrome\app\d">
<wc-status props="none" copied="true" tree-conflicted="true" item="added">
</wc-status>
</entry>
<entry path="chrome\app\DEPS">
<wc-status props="modified" item="modified" revision="14628">
<commit revision="1279">
<author>brettw@google.com</author>
<date>2008-08-23T17:16:42.090152Z</date>
</commit>
</wc-status>
</entry>
<entry path="scripts\master\factory\gclient_factory.py">
<wc-status props="normal" item="conflicted" revision="14725">
<commit revision="14633">
<author>nsylvain@chromium.org</author>
<date>2009-04-27T19:37:17.977400Z</date>
</commit>
</wc-status>
</entry>
</target>
</status>
"""
gclient.CaptureSVN = CaptureSVNMock
info = gclient.CaptureSVNStatus('.')
expected = [
('? ', 'unversionned_file.txt'),
('M ', 'build\\internal\\essential.vsprops'),
('A + ', 'chrome\\app\\d'),
('MM ', 'chrome\\app\\DEPS'),
('C ', 'scripts\\master\\factory\\gclient_factory.py'),
]
self.assertEquals(sorted(info), sorted(expected))
def testCaptureSVNStatusEmpty(self):
x = self
def CaptureSVNMock(command):
x.assertEquals(['status', '--xml'], command)
return r"""<?xml version="1.0"?>
<status>
<target
path="perf">
</target>
</status>
"""
gclient.CaptureSVN = CaptureSVNMock
info = gclient.CaptureSVNStatus(None)
self.assertEquals(info, [])
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment