Commit 3a292688 authored by maruel@chromium.org's avatar maruel@chromium.org

Redo of r56893 with fix to support python 2.5.

Original Description:

Remove code duplication and improve style.

Create a Popen function to reduce code duplication.
Use RemoveDirectory where relevant.
Make drover slightly more posix friendly.

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@57083 0039d316-1c4b-4281-b951-d872f2087c98
parent dd218e59
...@@ -8,10 +8,11 @@ import os ...@@ -8,10 +8,11 @@ import os
import re import re
import subprocess import subprocess
import sys import sys
import webbrowser
import breakpad import breakpad
import gclient_utils
USAGE = """ USAGE = """
WARNING: Please use this tool in an empty directory WARNING: Please use this tool in an empty directory
(or at least one that you don't mind clobbering.) (or at least one that you don't mind clobbering.)
...@@ -46,31 +47,6 @@ files_info_ = None ...@@ -46,31 +47,6 @@ files_info_ = None
delete_map_ = None delete_map_ = None
file_pattern_ = r"[ ]+([MADUC])[ ]+/((?:trunk|branches/.*?)/src(.*)/(.*))" file_pattern_ = r"[ ]+([MADUC])[ ]+/((?:trunk|branches/.*?)/src(.*)/(.*))"
def deltree(root):
"""Removes a given directory"""
if (not os.path.exists(root)):
return
if sys.platform == 'win32':
os.system('rmdir /S /Q ' + root.replace('/','\\'))
else:
for name in os.listdir(root):
path = os.path.join(root, name)
if os.path.isdir(path):
deltree(path)
else:
os.unlink(path)
os.rmdir(root)
def clobberDir(dirname):
"""Removes a given directory"""
if (os.path.exists(dirname)):
print dir + " directory found, deleting"
# The following line was removed due to access controls in Windows
# which make os.unlink(path) calls impossible.
#TODO(laforge) : Is this correct?
deltree(dirname)
def runGcl(subcommand): def runGcl(subcommand):
gcl_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gcl") gcl_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gcl")
...@@ -87,11 +63,9 @@ def gclUpload(revision, author): ...@@ -87,11 +63,9 @@ def gclUpload(revision, author):
return runGcl(command) return runGcl(command)
def getSVNInfo(url, revision): def getSVNInfo(url, revision):
command = 'svn info ' + url + "@"+str(revision) svn_info = gclient_utils.Popen(['svn', 'info', '%s@%s' % (url, revision)],
svn_info = subprocess.Popen(command, stdout=subprocess.PIPE,
shell=True, stderr=subprocess.PIPE).stdout.readlines()
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).stdout.readlines()
info = {} info = {}
for line in svn_info: for line in svn_info:
match = re.search(r"(.*?):(.*)", line) match = re.search(r"(.*?):(.*)", line)
...@@ -101,11 +75,9 @@ def getSVNInfo(url, revision): ...@@ -101,11 +75,9 @@ def getSVNInfo(url, revision):
return info return info
def isSVNDirty(): def isSVNDirty():
command = 'svn status' svn_status = gclient_utils.Popen(['svn', 'status'],
svn_status = subprocess.Popen(command, stdout=subprocess.PIPE,
shell=True, stderr=subprocess.PIPE).stdout.readlines()
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).stdout.readlines()
for line in svn_status: for line in svn_status:
match = re.search(r"^[^X?]", line) match = re.search(r"^[^X?]", line)
if match: if match:
...@@ -145,22 +117,18 @@ def inCheckoutRoot(path): ...@@ -145,22 +117,18 @@ def inCheckoutRoot(path):
def getRevisionLog(url, revision): def getRevisionLog(url, revision):
"""Takes an svn url and gets the associated revision.""" """Takes an svn url and gets the associated revision."""
command = 'svn log ' + url + " -r"+str(revision) svn_log = gclient_utils.Popen(['svn', 'log', url, '-r', str(revision)],
svn_log = subprocess.Popen(command, stdout=subprocess.PIPE,
shell=True, stderr=subprocess.PIPE).stdout.readlines()
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).stdout.readlines()
# Don't include the header lines and the trailing "---..." line and eliminate # Don't include the header lines and the trailing "---..." line and eliminate
# any '\r's. # any '\r's.
return ''.join([l.replace('\r','') for l in svn_log[3:-1]]) return ''.join([l.replace('\r','') for l in svn_log[3:-1]])
def getSVNVersionInfo(): def getSVNVersionInfo():
"""Extract version information from SVN""" """Extract version information from SVN"""
command = 'svn --version' svn_info = gclient_utils.Popen(['svn', '--version'],
svn_info = subprocess.Popen(command, stdout=subprocess.PIPE,
shell=True, stderr=subprocess.PIPE).stdout.readlines()
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).stdout.readlines()
info = {} info = {}
for line in svn_info: for line in svn_info:
match = re.search(r"svn, version ((\d+)\.(\d+)\.(\d+)) \(r(\d+)\)", line) match = re.search(r"svn, version ((\d+)\.(\d+)\.(\d+)) \(r(\d+)\)", line)
...@@ -304,16 +272,14 @@ def revertRevision(url, revision): ...@@ -304,16 +272,14 @@ def revertRevision(url, revision):
os.system(command) os.system(command)
def getFileInfo(url, revision): def getFileInfo(url, revision):
global files_info_, file_pattern_ global files_info_
if (files_info_ != None): if (files_info_ != None):
return files_info_ return files_info_
command = 'svn log ' + url + " -r " + str(revision) + " -v" svn_log = gclient_utils.Popen(['svn', 'log', url, '-r', str(revision), '-v'],
svn_log = subprocess.Popen(command, stdout=subprocess.PIPE,
shell=True, stderr=subprocess.PIPE).stdout.readlines()
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).stdout.readlines()
info = [] info = []
for line in svn_log: for line in svn_log:
...@@ -470,7 +436,7 @@ def drover(options, args): ...@@ -470,7 +436,7 @@ def drover(options, args):
if not (options.revertbot or SKIP_CHECK_WORKING or if not (options.revertbot or SKIP_CHECK_WORKING or
prompt("Working directory: '%s' already exists, clobber?" % working)): prompt("Working directory: '%s' already exists, clobber?" % working)):
return 0 return 0
deltree(working) gclient_utils.RemoveDirectory(working)
if not options.local: if not options.local:
os.makedirs(working) os.makedirs(working)
......
...@@ -208,14 +208,8 @@ def ErrorExit(msg): ...@@ -208,14 +208,8 @@ def ErrorExit(msg):
def RunShellWithReturnCode(command, print_output=False): def RunShellWithReturnCode(command, print_output=False):
"""Executes a command and returns the output and the return code.""" """Executes a command and returns the output and the return code."""
# Use a shell for subcommands on Windows to get a PATH search, and because svn p = gclient_utils.Popen(command, stdout=subprocess.PIPE,
# may be a batch file. stderr=subprocess.STDOUT, universal_newlines=True)
use_shell = sys.platform.startswith("win")
env = os.environ.copy()
env['LANGUAGE'] = 'en'
p = subprocess.Popen(command, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, shell=use_shell, env=env,
universal_newlines=True)
if print_output: if print_output:
output_array = [] output_array = []
while True: while True:
......
...@@ -653,7 +653,7 @@ class GitWrapper(SCMWrapper): ...@@ -653,7 +653,7 @@ class GitWrapper(SCMWrapper):
cmd.extend(args) cmd.extend(args)
logging.debug(cmd) logging.debug(cmd)
try: try:
sp = subprocess.Popen(cmd, cwd=cwd, stdout=stdout) sp = gclient_utils.Popen(cmd, cwd=cwd, stdout=stdout)
output = sp.communicate()[0] output = sp.communicate()[0]
except OSError: except OSError:
raise gclient_utils.Error("git command '%s' failed to run." % raise gclient_utils.Error("git command '%s' failed to run." %
......
...@@ -23,7 +23,6 @@ import subprocess ...@@ -23,7 +23,6 @@ import subprocess
import sys import sys
import threading import threading
import time import time
import threading
import xml.dom.minidom import xml.dom.minidom
import xml.parsers.expat import xml.parsers.expat
...@@ -39,8 +38,31 @@ class CheckCallError(OSError): ...@@ -39,8 +38,31 @@ class CheckCallError(OSError):
self.stderr = stderr self.stderr = stderr
def Popen(*args, **kwargs):
"""Calls subprocess.Popen() with hacks to work around certain behaviors.
Ensure English outpout for svn and make it work reliably on Windows.
"""
copied = False
if not 'env' in kwargs:
copied = True
kwargs = kwargs.copy()
# It's easier to parse the stdout if it is always in English.
kwargs['env'] = os.environ.copy()
kwargs['env']['LANGUAGE'] = 'en'
if not 'shell' in kwargs:
if not copied:
kwargs = kwargs.copy()
# *Sigh*: Windows needs shell=True, or else it won't search %PATH% for the
# 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.
kwargs['shell'] = (sys.platform=='win32')
return subprocess.Popen(*args, **kwargs)
def CheckCall(command, cwd=None, print_error=True): def CheckCall(command, cwd=None, print_error=True):
"""Like subprocess.check_call() but returns stdout. """Similar subprocess.check_call() but redirects stdout and
returns (stdout, stderr).
Works on python 2.4 Works on python 2.4
""" """
...@@ -49,13 +71,7 @@ def CheckCall(command, cwd=None, print_error=True): ...@@ -49,13 +71,7 @@ def CheckCall(command, cwd=None, print_error=True):
stderr = None stderr = None
if not print_error: if not print_error:
stderr = subprocess.PIPE stderr = subprocess.PIPE
env = os.environ.copy() process = Popen(command, cwd=cwd, stdout=subprocess.PIPE, stderr=stderr)
env['LANGUAGE'] = 'en'
process = subprocess.Popen(command, cwd=cwd,
shell=sys.platform.startswith('win'),
stdout=subprocess.PIPE,
stderr=stderr,
env=env)
std_out, std_err = process.communicate() std_out, std_err = process.communicate()
except OSError, e: except OSError, e:
raise CheckCallError(command, cwd, e.errno, None) raise CheckCallError(command, cwd, e.errno, None)
...@@ -275,15 +291,9 @@ def SubprocessCallAndFilter(command, ...@@ -275,15 +291,9 @@ def SubprocessCallAndFilter(command,
if print_messages: if print_messages:
print('\n________ running \'%s\' in \'%s\'' print('\n________ running \'%s\' in \'%s\''
% (' '.join(command), in_directory)) % (' '.join(command), in_directory))
env = os.environ.copy()
env['LANGUAGE'] = 'en'
# *Sigh*: Windows needs shell=True, or else it won't search %PATH% for the kid = Popen(command, bufsize=0, cwd=in_directory,
# executable, but shell=True makes subprocess on Linux fail when it's called stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# 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,
stderr=subprocess.STDOUT, env=env)
# Do a flush of sys.stdout before we begin reading from the subprocess's # Do a flush of sys.stdout before we begin reading from the subprocess's
# stdout. # stdout.
...@@ -327,7 +337,7 @@ def SubprocessCallAndFilter(command, ...@@ -327,7 +337,7 @@ def SubprocessCallAndFilter(command,
msg = 'failed to run command: %s' % ' '.join(command) msg = 'failed to run command: %s' % ' '.join(command)
if fail_status != None: if fail_status != None:
print >>sys.stderr, msg print >> sys.stderr, msg
sys.exit(fail_status) sys.exit(fail_status)
raise Error(msg) raise Error(msg)
...@@ -337,10 +347,10 @@ def FindGclientRoot(from_dir, filename='.gclient'): ...@@ -337,10 +347,10 @@ def FindGclientRoot(from_dir, filename='.gclient'):
"""Tries to find the gclient root.""" """Tries to find the gclient root."""
path = os.path.realpath(from_dir) path = os.path.realpath(from_dir)
while not os.path.exists(os.path.join(path, filename)): while not os.path.exists(os.path.join(path, filename)):
next = os.path.split(path) split_path = os.path.split(path)
if not next[1]: if not split_path[1]:
return None return None
path = next[0] path = split_path[0]
logging.info('Found gclient root at ' + path) logging.info('Found gclient root at ' + path)
return path return path
......
...@@ -215,7 +215,7 @@ class GIT(object): ...@@ -215,7 +215,7 @@ class GIT(object):
# pipe at a time. # pipe at a time.
# The -100 is an arbitrary limit so we don't search forever. # The -100 is an arbitrary limit so we don't search forever.
cmd = ['git', 'log', '-100', '--pretty=medium'] cmd = ['git', 'log', '-100', '--pretty=medium']
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, cwd=cwd) proc = gclient_utils.Popen(cmd, stdout=subprocess.PIPE, cwd=cwd)
for line in proc.stdout: for line in proc.stdout:
match = git_svn_re.match(line) match = git_svn_re.match(line)
if match: if match:
...@@ -371,19 +371,11 @@ class SVN(object): ...@@ -371,19 +371,11 @@ class SVN(object):
""" """
c = [SVN.COMMAND] c = [SVN.COMMAND]
c.extend(args) c.extend(args)
# *Sigh*: Windows needs shell=True, or else it won't search %PATH% for
# 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 stderr = None
if not print_error: if not print_error:
stderr = subprocess.PIPE stderr = subprocess.PIPE
return subprocess.Popen(c, return gclient_utils.Popen(c, cwd=in_directory, stdout=subprocess.PIPE,
cwd=in_directory, stderr=stderr).communicate()[0]
shell=(sys.platform == 'win32'),
stdout=subprocess.PIPE,
stderr=stderr).communicate()[0]
@staticmethod @staticmethod
def RunAndGetFileList(verbose, args, in_directory, file_list): def RunAndGetFileList(verbose, args, in_directory, file_list):
......
...@@ -24,7 +24,7 @@ class GclientUtilsUnittest(GclientUtilBase): ...@@ -24,7 +24,7 @@ class GclientUtilsUnittest(GclientUtilBase):
'CheckCall', 'CheckCallError', 'Error', 'ExecutionQueue', 'FileRead', 'CheckCall', 'CheckCallError', 'Error', 'ExecutionQueue', 'FileRead',
'FileWrite', 'FindFileUpwards', 'FindGclientRoot', 'FileWrite', 'FindFileUpwards', 'FindGclientRoot',
'GetGClientRootAndEntries', 'GetNamedNodeText', 'GetGClientRootAndEntries', 'GetNamedNodeText',
'GetNodeNamedAttributeText', 'PathDifference', 'ParseXML', 'GetNodeNamedAttributeText', 'PathDifference', 'ParseXML', 'Popen',
'PrintableObject', 'RemoveDirectory', 'SplitUrlRevision', 'PrintableObject', 'RemoveDirectory', 'SplitUrlRevision',
'SubprocessCall', 'SubprocessCallAndFilter', 'SyntaxErrorToError', 'SubprocessCall', 'SubprocessCallAndFilter', 'SyntaxErrorToError',
'WorkItem', 'WorkItem',
......
...@@ -28,6 +28,7 @@ class BaseTestCase(SuperMoxTestBase): ...@@ -28,6 +28,7 @@ class BaseTestCase(SuperMoxTestBase):
class BaseSCMTestCase(BaseTestCase): class BaseSCMTestCase(BaseTestCase):
def setUp(self): def setUp(self):
BaseTestCase.setUp(self) BaseTestCase.setUp(self)
self.mox.StubOutWithMock(scm.gclient_utils, 'Popen')
self.mox.StubOutWithMock(scm.gclient_utils, 'SubprocessCall') self.mox.StubOutWithMock(scm.gclient_utils, 'SubprocessCall')
self.mox.StubOutWithMock(scm.gclient_utils, 'SubprocessCallAndFilter') self.mox.StubOutWithMock(scm.gclient_utils, 'SubprocessCallAndFilter')
...@@ -295,11 +296,10 @@ class SVNTestCase(BaseSCMTestCase): ...@@ -295,11 +296,10 @@ class SVNTestCase(BaseSCMTestCase):
</status> </status>
""" """
proc = self.mox.CreateMockAnything() proc = self.mox.CreateMockAnything()
scm.subprocess.Popen(['svn', 'status', '--xml', '.'], scm.gclient_utils.Popen(['svn', 'status', '--xml', '.'],
cwd=None, cwd=None,
shell=scm.sys.platform.startswith('win'), stderr=None,
stderr=None, stdout=scm.subprocess.PIPE).AndReturn(proc)
stdout=scm.subprocess.PIPE).AndReturn(proc)
proc.communicate().AndReturn((text, 0)) proc.communicate().AndReturn((text, 0))
self.mox.ReplayAll() self.mox.ReplayAll()
...@@ -328,11 +328,10 @@ class SVNTestCase(BaseSCMTestCase): ...@@ -328,11 +328,10 @@ class SVNTestCase(BaseSCMTestCase):
</target> </target>
</status>""" </status>"""
proc = self.mox.CreateMockAnything() proc = self.mox.CreateMockAnything()
scm.subprocess.Popen(['svn', 'status', '--xml'], scm.gclient_utils.Popen(['svn', 'status', '--xml'],
cwd=None, cwd=None,
shell=scm.sys.platform.startswith('win'), stderr=None,
stderr=None, stdout=scm.subprocess.PIPE).AndReturn(proc)
stdout=scm.subprocess.PIPE).AndReturn(proc)
proc.communicate().AndReturn((text, 0)) proc.communicate().AndReturn((text, 0))
self.mox.ReplayAll() self.mox.ReplayAll()
info = scm.SVN.CaptureStatus(None) info = scm.SVN.CaptureStatus(None)
......
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