Support for |change| argument to |GetPreferredTrySlaves()|, try 2.
Needed to make it so changes containing only *.mm are only sent to Mac trybots by default.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/8059009
git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@102930 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/gcl.py b/gcl.py
index 32286b2..72a83fd 100755
--- a/gcl.py
+++ b/gcl.py
@@ -961,11 +961,21 @@
if change_info.patchset:
trychange_args.extend(["--patchset", str(change_info.patchset)])
file_list = change_info.GetFileNames()
+ change = presubmit_support.SvnChange(change_info.name,
+ change_info.description,
+ change_info.GetLocalRoot(),
+ change_info.GetFiles(),
+ change_info.issue,
+ change_info.patchset,
+ None)
else:
file_list = []
+ change = None
+
trychange_args.extend(args)
return trychange.TryChange(
trychange_args,
+ change=change,
file_list=file_list,
swallow_exception=swallow_exception,
prog='gcl try',
diff --git a/git_cl.py b/git_cl.py
index cb33488..9946999 100755
--- a/git_cl.py
+++ b/git_cl.py
@@ -488,8 +488,7 @@
self.SetPatchset(0)
self.has_issue = False
- def RunHook(self, committing, upstream_branch, may_prompt, verbose, author):
- """Calls sys.exit() if the hook fails; returns a HookResults otherwise."""
+ def GetChange(self, upstream_branch, author):
root = RunCommand(['git', 'rev-parse', '--show-cdup']).strip() or '.'
absroot = os.path.abspath(root)
@@ -511,7 +510,7 @@
if not author:
author = RunGit(['config', 'user.email']).strip() or None
- change = presubmit_support.GitChange(
+ return presubmit_support.GitChange(
name,
description,
absroot,
@@ -520,6 +519,10 @@
patchset,
author)
+ def RunHook(self, committing, upstream_branch, may_prompt, verbose, author):
+ """Calls sys.exit() if the hook fails; returns a HookResults otherwise."""
+ change = self.GetChange(upstream_branch, author)
+
# Apply watchlists on upload.
if not committing:
watchlist = watchlists.Watchlists(change.RepositoryRoot())
diff --git a/git_try.py b/git_try.py
index 06aaa6e..27eafba 100755
--- a/git_try.py
+++ b/git_try.py
@@ -13,6 +13,7 @@
import subprocess2
import third_party.upload
import trychange
+import git_cl
def GetRietveldIssueNumber():
@@ -53,8 +54,10 @@
# Hack around a limitation in logging.
logging.getLogger().handlers = []
try:
+ cl = git_cl.Changelist()
+ change = cl.GetChange(cl.GetUpstreamBranch(), None)
sys.exit(trychange.TryChange(
- args, file_list=[], swallow_exception=False,
+ args, change, file_list=[], swallow_exception=False,
prog='git try',
extra_epilog='\n'
'git try will diff against your tracked branch and will '
diff --git a/presubmit_support.py b/presubmit_support.py
index 5ac38ac..85b3a3f 100755
--- a/presubmit_support.py
+++ b/presubmit_support.py
@@ -16,6 +16,7 @@
import cStringIO # Exposed through the API.
import fnmatch
import glob
+import inspect
import logging
import marshal # Exposed through the API.
import optparse
@@ -875,7 +876,7 @@
class GetTrySlavesExecuter(object):
@staticmethod
- def ExecPresubmitScript(script_text, presubmit_path, project):
+ def ExecPresubmitScript(script_text, presubmit_path, project, change):
"""Executes GetPreferredTrySlaves() from a single presubmit script.
Args:
@@ -894,10 +895,14 @@
function_name = 'GetPreferredTrySlaves'
if function_name in context:
- try:
- result = eval(function_name + '(' + repr(project) + ')', context)
- except TypeError:
- result = eval(function_name + '()', context)
+ get_preferred_try_slaves = context[function_name]
+ function_info = inspect.getargspec(get_preferred_try_slaves)
+ if len(function_info[0]) == 1:
+ result = get_preferred_try_slaves(project)
+ elif len(function_info[0]) == 2:
+ result = get_preferred_try_slaves(project, change)
+ else:
+ result = get_preferred_try_slaves()
if not isinstance(result, types.ListType):
raise PresubmitFailure(
'Presubmit functions must return a list, got a %s instead: %s' %
@@ -913,7 +918,8 @@
return result
-def DoGetTrySlaves(changed_files,
+def DoGetTrySlaves(change,
+ changed_files,
repository_root,
default_presubmit,
project,
@@ -942,7 +948,7 @@
output_stream.write("Running default presubmit script.\n")
fake_path = os.path.join(repository_root, 'PRESUBMIT.py')
results += executer.ExecPresubmitScript(
- default_presubmit, fake_path, project)
+ default_presubmit, fake_path, project, change)
for filename in presubmit_files:
filename = os.path.abspath(filename)
if verbose:
@@ -950,7 +956,7 @@
# Accept CRLF presubmit script.
presubmit_script = gclient_utils.FileRead(filename, 'rU')
results += executer.ExecPresubmitScript(
- presubmit_script, filename, project)
+ presubmit_script, filename, project, change)
slaves = list(set(results))
if slaves and verbose:
diff --git a/tests/presubmit_unittest.py b/tests/presubmit_unittest.py
index 466189e..055e8b6 100755
--- a/tests/presubmit_unittest.py
+++ b/tests/presubmit_unittest.py
@@ -153,7 +153,7 @@
'OutputApi', 'ParseFiles', 'PresubmitFailure',
'PresubmitExecuter', 'PresubmitOutput', 'ScanSubDirs',
'SvnAffectedFile', 'SvnChange', 'cPickle', 'cStringIO',
- 'fix_encoding', 'fnmatch', 'gclient_utils', 'glob', 'json',
+ 'fix_encoding', 'fnmatch', 'gclient_utils', 'glob', 'inspect', 'json',
'load_files',
'logging', 'marshal', 'normpath', 'optparse', 'os', 'owners', 'pickle',
'presubmit_canned_checks', 'random', 're', 'rietveld', 'scm',
@@ -669,11 +669,18 @@
def testGetTrySlavesExecuter(self):
self.mox.ReplayAll()
-
+ change = presubmit.Change(
+ 'foo',
+ 'Blah Blah\n\nSTORY=http://tracker.com/42\nBUG=boo\n',
+ self.fake_root_dir,
+ None,
+ 0,
+ 0,
+ None)
executer = presubmit.GetTrySlavesExecuter()
- self.assertEqual([], executer.ExecPresubmitScript('', '', ''))
- self.assertEqual(
- [], executer.ExecPresubmitScript('def foo():\n return\n', '', ''))
+ self.assertEqual([], executer.ExecPresubmitScript('', '', '', change))
+ self.assertEqual([],
+ executer.ExecPresubmitScript('def foo():\n return\n', '', '', change))
# bad results
starts_with_space_result = [' starts_with_space']
@@ -682,7 +689,7 @@
for result in starts_with_space_result, not_list_result1, not_list_result2:
self.assertRaises(presubmit.PresubmitFailure,
executer.ExecPresubmitScript,
- self.presubmit_tryslave % result, '', '')
+ self.presubmit_tryslave % result, '', '', change)
# good results
expected_result = ['1', '2', '3']
@@ -692,20 +699,31 @@
self.assertEqual(
result,
executer.ExecPresubmitScript(
- self.presubmit_tryslave % result, '', ''))
+ self.presubmit_tryslave % result, '', '', change))
def testGetTrySlavesExecuterWithProject(self):
self.mox.ReplayAll()
+ change = presubmit.Change(
+ 'foo',
+ 'Blah Blah\n\nSTORY=http://tracker.com/42\nBUG=boo\n',
+ self.fake_root_dir,
+ None,
+ 0,
+ 0,
+ None)
+
executer = presubmit.GetTrySlavesExecuter()
expected_result1 = ['1', '2']
expected_result2 = ['a', 'b', 'c']
script = self.presubmit_tryslave_project % (
repr('foo'), repr(expected_result1), repr(expected_result2))
self.assertEqual(
- expected_result1, executer.ExecPresubmitScript(script, '', 'foo'))
+ expected_result1, executer.ExecPresubmitScript(script, '', 'foo',
+ change))
self.assertEqual(
- expected_result2, executer.ExecPresubmitScript(script, '', 'bar'))
+ expected_result2, executer.ExecPresubmitScript(script, '', 'bar',
+ change))
def testDoGetTrySlaves(self):
join = presubmit.os.path.join
@@ -730,13 +748,18 @@
self.presubmit_tryslave % '["linux"]')
self.mox.ReplayAll()
+ change = presubmit.Change(
+ 'mychange', '', self.fake_root_dir, [], 0, 0, None)
+
output = StringIO.StringIO()
self.assertEqual(['win'],
- presubmit.DoGetTrySlaves([filename], self.fake_root_dir,
+ presubmit.DoGetTrySlaves(change, [filename],
+ self.fake_root_dir,
None, None, False, output))
output = StringIO.StringIO()
self.assertEqual(['win', 'linux'],
- presubmit.DoGetTrySlaves([filename, filename_linux],
+ presubmit.DoGetTrySlaves(change,
+ [filename, filename_linux],
self.fake_root_dir, None, None,
False, output))
diff --git a/tests/trychange_unittest.py b/tests/trychange_unittest.py
index 22c4e6a..f02c1bf 100755
--- a/tests/trychange_unittest.py
+++ b/tests/trychange_unittest.py
@@ -59,8 +59,8 @@
"""trychange.SVN tests."""
def testMembersChanged(self):
members = [
- 'AutomagicalSettings', 'GetCodeReviewSetting', 'ReadRootFile',
- 'GenerateDiff', 'GetFileNames',
+ 'AutomagicalSettings', 'CaptureStatus', 'GetCodeReviewSetting',
+ 'ReadRootFile', 'GenerateDiff', 'GetFileNames', 'files', 'file_tuples',
]
# If this test fails, you should add the relevant test.
self.compareMembers(trychange.SVN, members)
@@ -83,8 +83,8 @@
"""trychange.GIT tests."""
def testMembersChanged(self):
members = [
- 'AutomagicalSettings', 'GetCodeReviewSetting', 'ReadRootFile',
- 'GenerateDiff', 'GetFileNames',
+ 'AutomagicalSettings', 'CaptureStatus', 'GetCodeReviewSetting',
+ 'ReadRootFile', 'GenerateDiff', 'GetFileNames', 'files', 'file_tuples',
]
# If this test fails, you should add the relevant test.
self.compareMembers(trychange.GIT, members)
diff --git a/trychange.py b/trychange.py
index 9825b1e..26c9913 100755
--- a/trychange.py
+++ b/trychange.py
@@ -100,7 +100,12 @@
items.append(None)
self.diff_against = items[1]
self.options = options
- self.files = self.options.files
+ # Lazy-load file list from the SCM unless files were specified in options.
+ self._files = None
+ self._file_tuples = None
+ if self.options.files:
+ self._files = self.options.files
+ self._file_tuples = [('M', f) for f in self.files]
self.options.files = None
self.codereview_settings = None
self.codereview_settings_file = 'codereview.settings'
@@ -187,6 +192,38 @@
logging.warning('Didn\'t find %s' % filename)
return None
+ def _SetFileTuples(self, file_tuples):
+ excluded = ['!', '?', 'X', ' ', '~']
+ def Excluded(f):
+ if f[0][0] in excluded:
+ return True
+ for r in self.options.exclude:
+ if re.search(r, f[1]):
+ logging.info('Ignoring "%s"' % f[1])
+ return True
+ return False
+
+ self._file_tuples = [f for f in file_tuples if not Excluded(f)]
+ self._files = [f[1] for f in self._file_tuples]
+
+ def CaptureStatus(self):
+ """Returns the 'svn status' emulated output as an array of (status, file)
+ tuples."""
+ raise NotImplementedError(
+ "abstract method -- subclass %s must override" % self.__class__)
+
+ @property
+ def files(self):
+ if self._files is None:
+ self._SetFileTuples(self.CaptureStatus())
+ return self._files
+
+ @property
+ def file_tuples(self):
+ if self._file_tuples is None:
+ self._SetFileTuples(self.CaptureStatus())
+ return self._file_tuples
+
class SVN(SCM):
"""Gathers the options and diff for a subversion checkout."""
@@ -210,29 +247,19 @@
logging.debug('%s:\n%s' % (filename, data))
return data
+ def CaptureStatus(self):
+ previous_cwd = os.getcwd()
+ os.chdir(self.checkout_root)
+ result = scm.SVN.CaptureStatus(self.checkout_root)
+ os.chdir(previous_cwd)
+ return result
+
def GenerateDiff(self):
"""Returns a string containing the diff for the given file list.
The files in the list should either be absolute paths or relative to the
given root.
"""
- if not self.files:
- previous_cwd = os.getcwd()
- os.chdir(self.checkout_root)
-
- excluded = ['!', '?', 'X', ' ', '~']
- def Excluded(f):
- if f[0][0] in excluded:
- return True
- for r in self.options.exclude:
- if re.search(r, f[1]):
- logging.info('Ignoring "%s"' % f[1])
- return True
- return False
-
- self.files = [f[1] for f in scm.SVN.CaptureStatus(self.checkout_root)
- if not Excluded(f)]
- os.chdir(previous_cwd)
return scm.SVN.GenerateDiff(self.files, self.checkout_root, full_move=True,
revision=self.diff_against)
@@ -255,19 +282,10 @@
"(via the --track argument to \"git checkout -b ...\"")
logging.info("GIT(%s)" % self.checkout_root)
+ def CaptureStatus(self):
+ return scm.GIT.CaptureStatus(self.checkout_root, self.diff_against)
+
def GenerateDiff(self):
- if not self.files:
- self.files = scm.GIT.GetDifferentFiles(self.checkout_root,
- branch=self.diff_against)
-
- def NotExcluded(f):
- for r in self.options.exclude:
- if re.search(r, f):
- logging.info('Ignoring "%s"' % f)
- return False
- return True
-
- self.files = filter(NotExcluded, self.files)
return scm.GIT.GenerateDiff(self.checkout_root, files=self.files,
full_move=True,
branch=self.diff_against)
@@ -456,14 +474,17 @@
def GetMungedDiff(path_diff, diff):
# Munge paths to match svn.
+ changed_files = []
for i in range(len(diff)):
if diff[i].startswith('--- ') or diff[i].startswith('+++ '):
new_file = posixpath.join(path_diff, diff[i][4:]).replace('\\', '/')
+ changed_files.append(('M', new_file.split('\t')[0]))
diff[i] = diff[i][0:4] + new_file
- return diff
+ return (diff, changed_files)
def TryChange(argv,
+ change,
file_list,
swallow_exception,
prog=None,
@@ -646,6 +667,7 @@
options.rietveld_url = match.group(1)
try:
+ changed_files = None
# Always include os.getcwd() in the checkout settings.
checkouts = []
path = os.getcwd()
@@ -689,7 +711,8 @@
diff_url = ('%s/download/issue%d_%d.diff' %
(options.rietveld_url, options.issue, options.patchset))
diff = GetMungedDiff('', urllib.urlopen(diff_url).readlines())
- options.diff = ''.join(diff)
+ options.diff = ''.join(diff[0])
+ changed_files = diff[1]
else:
# Use this as the base.
root = checkouts[0].checkout_root
@@ -698,9 +721,21 @@
diff = checkout.GenerateDiff().splitlines(True)
path_diff = gclient_utils.PathDifference(root, checkout.checkout_root)
# Munge it.
- diffs.extend(GetMungedDiff(path_diff, diff))
+ diffs.extend(GetMungedDiff(path_diff, diff)[0])
options.diff = ''.join(diffs)
+ if not options.name:
+ if options.issue:
+ options.name = 'Issue %s' % options.issue
+ else:
+ options.name = 'Unnamed'
+ print('Note: use --name NAME to change the try job name.')
+
+ if not options.email:
+ parser.error('Using an anonymous checkout. Please use --email or set '
+ 'the TRYBOT_RESULTS_EMAIL_ADDRESS environment variable.')
+ print('Results will be emailed to: ' + options.email)
+
if not options.bot:
# Get try slaves from PRESUBMIT.py files if not specified.
# Even if the diff comes from options.url, use the local checkout for bot
@@ -708,7 +743,18 @@
try:
import presubmit_support
root_presubmit = checkouts[0].ReadRootFile('PRESUBMIT.py')
+ if not change:
+ if not changed_files:
+ changed_files = checkouts[0].file_tuples
+ change = presubmit_support.Change(options.name,
+ '',
+ checkouts[0].checkout_root,
+ changed_files,
+ options.issue,
+ options.patchset,
+ options.email)
options.bot = presubmit_support.DoGetTrySlaves(
+ change,
checkouts[0].GetFileNames(),
checkouts[0].checkout_root,
root_presubmit,
@@ -720,18 +766,6 @@
# If no bot is specified, either the default pool will be selected or the
# try server will refuse the job. Either case we don't need to interfere.
- if options.name is None:
- if options.issue:
- options.name = 'Issue %s' % options.issue
- else:
- options.name = 'Unnamed'
- print('Note: use --name NAME to change the try job name.')
- if not options.email:
- parser.error('Using an anonymous checkout. Please use --email or set '
- 'the TRYBOT_RESULTS_EMAIL_ADDRESS environment variable.')
- else:
- print('Results will be emailed to: ' + options.email)
-
# Prevent rietveld updates if we aren't running all the tests.
if options.testfilter is not None:
options.issue = None
@@ -767,4 +801,4 @@
if __name__ == "__main__":
fix_encoding.fix_encoding()
- sys.exit(TryChange(None, [], False))
+ sys.exit(TryChange(None, None, [], False))