Chromium Code Reviews

Side by Side Diff: trychange.py

Issue 7925014: Support for |change| argument to |GetPreferredTrySlaves()|. (Closed) Base URL: http://src.chromium.org/svn/trunk/tools/depot_tools/
Patch Set: '' Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | | Annotate | Revision Log
« no previous file with comments | « tests/trychange_unittest.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Client-side script to send a try job to the try server. It communicates to 6 """Client-side script to send a try job to the try server. It communicates to
7 the try server by either writting to a svn repository or by directly connecting 7 the try server by either writting to a svn repository or by directly connecting
8 to the server by HTTP. 8 to the server by HTTP.
9 """ 9 """
10 10
(...skipping 82 matching lines...)
93 93
94 class SCM(object): 94 class SCM(object):
95 """Simplistic base class to implement one function: ProcessOptions.""" 95 """Simplistic base class to implement one function: ProcessOptions."""
96 def __init__(self, options, path): 96 def __init__(self, options, path):
97 items = path.split('@') 97 items = path.split('@')
98 assert len(items) <= 2 98 assert len(items) <= 2
99 self.checkout_root = items[0] 99 self.checkout_root = items[0]
100 items.append(None) 100 items.append(None)
101 self.diff_against = items[1] 101 self.diff_against = items[1]
102 self.options = options 102 self.options = options
103 self.files = self.options.files 103 self._files = self.options.files
104 self._file_tuples = [('M', f) for f in self.files]
104 self.options.files = None 105 self.options.files = None
105 self.codereview_settings = None 106 self.codereview_settings = None
106 self.codereview_settings_file = 'codereview.settings' 107 self.codereview_settings_file = 'codereview.settings'
107 self.gclient_root = None 108 self.gclient_root = None
108 109
109 def GetFileNames(self): 110 def GetFileNames(self):
110 """Return the list of files in the diff.""" 111 """Return the list of files in the diff."""
111 return self.files 112 return self.files
112 113
113 def GetCodeReviewSetting(self, key): 114 def GetCodeReviewSetting(self, key):
(...skipping 66 matching lines...)
180 assert cur.startswith(root), (root, cur) 181 assert cur.startswith(root), (root, cur)
181 while cur.startswith(root): 182 while cur.startswith(root):
182 filepath = os.path.join(cur, filename) 183 filepath = os.path.join(cur, filename)
183 if os.path.isfile(filepath): 184 if os.path.isfile(filepath):
184 logging.info('Found %s at %s' % (filename, cur)) 185 logging.info('Found %s at %s' % (filename, cur))
185 return gclient_utils.FileRead(filepath) 186 return gclient_utils.FileRead(filepath)
186 cur = os.path.dirname(cur) 187 cur = os.path.dirname(cur)
187 logging.warning('Didn\'t find %s' % filename) 188 logging.warning('Didn\'t find %s' % filename)
188 return None 189 return None
189 190
191 def _SetFileTuples(self, file_tuples):
192 excluded = ['!', '?', 'X', ' ', '~']
193 def Excluded(f):
194 if f[0][0] in excluded:
195 return True
196 for r in self.options.exclude:
197 if re.search(r, f[1]):
198 logging.info('Ignoring "%s"' % f[1])
199 return True
200 return False
201
202 self._file_tuples = [f for f in file_tuples if not Excluded(f)]
203 self._files = [f[1] for f in self.file_tuples]
204
205 def CaptureStatus(self):
206 """Returns the 'svn status' emulated output as an array of (status, file) tu ples."""
M-A Ruel 2011/09/26 19:49:30 I guess you should switch of text editor. :)
207 raise NotImplementedError(
208 "abstract method -- subclass %s must override" % self.__class__)
209
210 @property
211 def files(self):
212 if not self._files:
213 self._SetFileTuples(self.CaptureStatus())
214 return self._files
215
216 @property
217 def file_tuples(self):
218 if not self._file_tuples:
219 self._SetFileTuples(self.CaptureStatus())
220 return self._file_tuples
221
190 222
191 class SVN(SCM): 223 class SVN(SCM):
192 """Gathers the options and diff for a subversion checkout.""" 224 """Gathers the options and diff for a subversion checkout."""
193 def __init__(self, *args, **kwargs): 225 def __init__(self, *args, **kwargs):
194 SCM.__init__(self, *args, **kwargs) 226 SCM.__init__(self, *args, **kwargs)
195 self.checkout_root = scm.SVN.GetCheckoutRoot(self.checkout_root) 227 self.checkout_root = scm.SVN.GetCheckoutRoot(self.checkout_root)
196 if not self.options.email: 228 if not self.options.email:
197 # Assumes the svn credential is an email address. 229 # Assumes the svn credential is an email address.
198 self.options.email = scm.SVN.GetEmail(self.checkout_root) 230 self.options.email = scm.SVN.GetEmail(self.checkout_root)
199 logging.info("SVN(%s)" % self.checkout_root) 231 logging.info("SVN(%s)" % self.checkout_root)
200 232
201 def ReadRootFile(self, filename): 233 def ReadRootFile(self, filename):
202 data = SCM.ReadRootFile(self, filename) 234 data = SCM.ReadRootFile(self, filename)
203 if data: 235 if data:
204 return data 236 return data
205 237
206 # Try to search on the subversion repository for the file. 238 # Try to search on the subversion repository for the file.
207 if not gcl: 239 if not gcl:
208 return None 240 return None
209 data = gcl.GetCachedFile(filename) 241 data = gcl.GetCachedFile(filename)
210 logging.debug('%s:\n%s' % (filename, data)) 242 logging.debug('%s:\n%s' % (filename, data))
211 return data 243 return data
212 244
245 def CaptureStatus(self):
246 previous_cwd = os.getcwd()
247 os.chdir(self.checkout_root)
248 result = scm.SVN.CaptureStatus(self.checkout_root)
249 os.chdir(previous_cwd)
250 return result
251
213 def GenerateDiff(self): 252 def GenerateDiff(self):
214 """Returns a string containing the diff for the given file list. 253 """Returns a string containing the diff for the given file list.
215 254
216 The files in the list should either be absolute paths or relative to the 255 The files in the list should either be absolute paths or relative to the
217 given root. 256 given root.
218 """ 257 """
219 if not self.files:
220 previous_cwd = os.getcwd()
221 os.chdir(self.checkout_root)
222
223 excluded = ['!', '?', 'X', ' ', '~']
224 def Excluded(f):
225 if f[0][0] in excluded:
226 return True
227 for r in self.options.exclude:
228 if re.search(r, f[1]):
229 logging.info('Ignoring "%s"' % f[1])
230 return True
231 return False
232
233 self.files = [f[1] for f in scm.SVN.CaptureStatus(self.checkout_root)
234 if not Excluded(f)]
235 os.chdir(previous_cwd)
236 return scm.SVN.GenerateDiff(self.files, self.checkout_root, full_move=True, 258 return scm.SVN.GenerateDiff(self.files, self.checkout_root, full_move=True,
237 revision=self.diff_against) 259 revision=self.diff_against)
238 260
239 261
240 class GIT(SCM): 262 class GIT(SCM):
241 """Gathers the options and diff for a git checkout.""" 263 """Gathers the options and diff for a git checkout."""
242 def __init__(self, *args, **kwargs): 264 def __init__(self, *args, **kwargs):
243 SCM.__init__(self, *args, **kwargs) 265 SCM.__init__(self, *args, **kwargs)
244 self.checkout_root = scm.GIT.GetCheckoutRoot(self.checkout_root) 266 self.checkout_root = scm.GIT.GetCheckoutRoot(self.checkout_root)
245 if not self.options.name: 267 if not self.options.name:
246 self.options.name = scm.GIT.GetPatchName(self.checkout_root) 268 self.options.name = scm.GIT.GetPatchName(self.checkout_root)
247 if not self.options.email: 269 if not self.options.email:
248 self.options.email = scm.GIT.GetEmail(self.checkout_root) 270 self.options.email = scm.GIT.GetEmail(self.checkout_root)
249 if not self.diff_against: 271 if not self.diff_against:
250 self.diff_against = scm.GIT.GetUpstreamBranch(self.checkout_root) 272 self.diff_against = scm.GIT.GetUpstreamBranch(self.checkout_root)
251 if not self.diff_against: 273 if not self.diff_against:
252 raise NoTryServerAccess( 274 raise NoTryServerAccess(
253 "Unable to determine default branch to diff against. " 275 "Unable to determine default branch to diff against. "
254 "Verify this branch is set up to track another" 276 "Verify this branch is set up to track another"
255 "(via the --track argument to \"git checkout -b ...\"") 277 "(via the --track argument to \"git checkout -b ...\"")
256 logging.info("GIT(%s)" % self.checkout_root) 278 logging.info("GIT(%s)" % self.checkout_root)
257 279
280 def CaptureStatus(self):
281 return scm.GIT.CaptureStatus(self.checkout_root, self.diff_against)
282
258 def GenerateDiff(self): 283 def GenerateDiff(self):
259 if not self.files:
260 self.files = scm.GIT.GetDifferentFiles(self.checkout_root,
261 branch=self.diff_against)
262
263 def NotExcluded(f):
264 for r in self.options.exclude:
265 if re.search(r, f):
266 logging.info('Ignoring "%s"' % f)
267 return False
268 return True
269
270 self.files = filter(NotExcluded, self.files)
271 return scm.GIT.GenerateDiff(self.checkout_root, files=self.files, 284 return scm.GIT.GenerateDiff(self.checkout_root, files=self.files,
272 full_move=True, 285 full_move=True,
273 branch=self.diff_against) 286 branch=self.diff_against)
274 287
275 288
276 def _ParseSendChangeOptions(options): 289 def _ParseSendChangeOptions(options):
277 """Parse common options passed to _SendChangeHTTP and _SendChangeSVN.""" 290 """Parse common options passed to _SendChangeHTTP and _SendChangeSVN."""
278 values = {} 291 values = {}
279 if options.email: 292 if options.email:
280 values['email'] = options.email 293 values['email'] = options.email
(...skipping 176 matching lines...)
457 def GetMungedDiff(path_diff, diff): 470 def GetMungedDiff(path_diff, diff):
458 # Munge paths to match svn. 471 # Munge paths to match svn.
459 for i in range(len(diff)): 472 for i in range(len(diff)):
460 if diff[i].startswith('--- ') or diff[i].startswith('+++ '): 473 if diff[i].startswith('--- ') or diff[i].startswith('+++ '):
461 new_file = posixpath.join(path_diff, diff[i][4:]).replace('\\', '/') 474 new_file = posixpath.join(path_diff, diff[i][4:]).replace('\\', '/')
462 diff[i] = diff[i][0:4] + new_file 475 diff[i] = diff[i][0:4] + new_file
463 return diff 476 return diff
464 477
465 478
466 def TryChange(argv, 479 def TryChange(argv,
480 change,
467 file_list, 481 file_list,
468 swallow_exception, 482 swallow_exception,
469 prog=None, 483 prog=None,
470 extra_epilog=None): 484 extra_epilog=None):
471 """ 485 """
472 Args: 486 Args:
473 argv: Arguments and options. 487 argv: Arguments and options.
474 file_list: Default value to pass to --file. 488 file_list: Default value to pass to --file.
475 swallow_exception: Whether we raise or swallow exceptions. 489 swallow_exception: Whether we raise or swallow exceptions.
476 """ 490 """
(...skipping 217 matching lines...)
694 # Use this as the base. 708 # Use this as the base.
695 root = checkouts[0].checkout_root 709 root = checkouts[0].checkout_root
696 diffs = [] 710 diffs = []
697 for checkout in checkouts: 711 for checkout in checkouts:
698 diff = checkout.GenerateDiff().splitlines(True) 712 diff = checkout.GenerateDiff().splitlines(True)
699 path_diff = gclient_utils.PathDifference(root, checkout.checkout_root) 713 path_diff = gclient_utils.PathDifference(root, checkout.checkout_root)
700 # Munge it. 714 # Munge it.
701 diffs.extend(GetMungedDiff(path_diff, diff)) 715 diffs.extend(GetMungedDiff(path_diff, diff))
702 options.diff = ''.join(diffs) 716 options.diff = ''.join(diffs)
703 717
718 if not options.name:
719 if options.issue:
720 options.name = 'Issue %s' % options.issue
721 else:
722 options.name = 'Unnamed'
723 print('Note: use --name NAME to change the try job name.')
724
725 if not options.email:
726 parser.error('Using an anonymous checkout. Please use --email or set '
727 'the TRYBOT_RESULTS_EMAIL_ADDRESS environment variable.')
728 print('Results will be emailed to: ' + options.email)
729
704 if not options.bot: 730 if not options.bot:
705 # Get try slaves from PRESUBMIT.py files if not specified. 731 # Get try slaves from PRESUBMIT.py files if not specified.
706 # Even if the diff comes from options.url, use the local checkout for bot 732 # Even if the diff comes from options.url, use the local checkout for bot
707 # selection. 733 # selection.
708 try: 734 try:
709 import presubmit_support 735 import presubmit_support
710 root_presubmit = checkouts[0].ReadRootFile('PRESUBMIT.py') 736 root_presubmit = checkouts[0].ReadRootFile('PRESUBMIT.py')
737 if change is None:
738 change = presubmit_support.Change(options.name,
739 '',
740 checkouts[0].checkout_root,
741 checkouts[0].file_tuples,
742 options.issue,
743 options.patchset,
744 options.email)
711 options.bot = presubmit_support.DoGetTrySlaves( 745 options.bot = presubmit_support.DoGetTrySlaves(
746 change,
712 checkouts[0].GetFileNames(), 747 checkouts[0].GetFileNames(),
713 checkouts[0].checkout_root, 748 checkouts[0].checkout_root,
714 root_presubmit, 749 root_presubmit,
715 options.project, 750 options.project,
716 False, 751 False,
717 sys.stdout) 752 sys.stdout)
718 except ImportError: 753 except ImportError:
719 pass 754 pass
720 # If no bot is specified, either the default pool will be selected or the 755 # If no bot is specified, either the default pool will be selected or the
721 # try server will refuse the job. Either case we don't need to interfere. 756 # try server will refuse the job. Either case we don't need to interfere.
722 757
723 if options.name is None:
724 if options.issue:
725 options.name = 'Issue %s' % options.issue
726 else:
727 options.name = 'Unnamed'
728 print('Note: use --name NAME to change the try job name.')
729 if not options.email:
730 parser.error('Using an anonymous checkout. Please use --email or set '
731 'the TRYBOT_RESULTS_EMAIL_ADDRESS environment variable.')
732 else:
733 print('Results will be emailed to: ' + options.email)
734
735 # Prevent rietveld updates if we aren't running all the tests. 758 # Prevent rietveld updates if we aren't running all the tests.
736 if options.testfilter is not None: 759 if options.testfilter is not None:
737 options.issue = None 760 options.issue = None
738 options.patchset = None 761 options.patchset = None
739 762
740 # Send the patch. 763 # Send the patch.
741 if options.send_patch: 764 if options.send_patch:
742 # If forced. 765 # If forced.
743 options.send_patch(options) 766 options.send_patch(options)
744 PrintSuccess(options) 767 PrintSuccess(options)
(...skipping 15 matching lines...)
760 print >> sys.stderr, e 783 print >> sys.stderr, e
761 return 1 784 return 1
762 except (gclient_utils.Error, subprocess2.CalledProcessError), e: 785 except (gclient_utils.Error, subprocess2.CalledProcessError), e:
763 print >> sys.stderr, e 786 print >> sys.stderr, e
764 return 1 787 return 1
765 return 0 788 return 0
766 789
767 790
768 if __name__ == "__main__": 791 if __name__ == "__main__":
769 fix_encoding.fix_encoding() 792 fix_encoding.fix_encoding()
770 sys.exit(TryChange(None, [], False)) 793 sys.exit(TryChange(None, None, [], False))
OLDNEW
« no previous file with comments | « tests/trychange_unittest.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine