Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(275)

Side by Side Diff: trychange.py

Issue 8059009: Support for |change| argument to |GetPreferredTrySlaves()|, try 2. (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. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | 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...) Expand 10 before | Expand all | Expand 10 after
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 # Lazy-load file list from the SCM unless files were specified in options.
104 self._files = None
105 self._file_tuples = None
106 if self.options.files:
107 self._files = self.options.files
108 self._file_tuples = [('M', f) for f in self.files]
104 self.options.files = None 109 self.options.files = None
105 self.codereview_settings = None 110 self.codereview_settings = None
106 self.codereview_settings_file = 'codereview.settings' 111 self.codereview_settings_file = 'codereview.settings'
107 self.gclient_root = None 112 self.gclient_root = None
108 113
109 def GetFileNames(self): 114 def GetFileNames(self):
110 """Return the list of files in the diff.""" 115 """Return the list of files in the diff."""
111 return self.files 116 return self.files
112 117
113 def GetCodeReviewSetting(self, key): 118 def GetCodeReviewSetting(self, key):
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 assert cur.startswith(root), (root, cur) 185 assert cur.startswith(root), (root, cur)
181 while cur.startswith(root): 186 while cur.startswith(root):
182 filepath = os.path.join(cur, filename) 187 filepath = os.path.join(cur, filename)
183 if os.path.isfile(filepath): 188 if os.path.isfile(filepath):
184 logging.info('Found %s at %s' % (filename, cur)) 189 logging.info('Found %s at %s' % (filename, cur))
185 return gclient_utils.FileRead(filepath) 190 return gclient_utils.FileRead(filepath)
186 cur = os.path.dirname(cur) 191 cur = os.path.dirname(cur)
187 logging.warning('Didn\'t find %s' % filename) 192 logging.warning('Didn\'t find %s' % filename)
188 return None 193 return None
189 194
195 def _SetFileTuples(self, file_tuples):
196 excluded = ['!', '?', 'X', ' ', '~']
197 def Excluded(f):
198 if f[0][0] in excluded:
199 return True
200 for r in self.options.exclude:
201 if re.search(r, f[1]):
202 logging.info('Ignoring "%s"' % f[1])
203 return True
204 return False
205
206 self._file_tuples = [f for f in file_tuples if not Excluded(f)]
207 self._files = [f[1] for f in self._file_tuples]
208
209 def CaptureStatus(self):
210 """Returns the 'svn status' emulated output as an array of (status, file)
211 tuples."""
212 raise NotImplementedError(
213 "abstract method -- subclass %s must override" % self.__class__)
214
215 @property
216 def files(self):
217 if self._files is None:
218 self._SetFileTuples(self.CaptureStatus())
219 return self._files
220
221 @property
222 def file_tuples(self):
223 if self._file_tuples is None:
224 self._SetFileTuples(self.CaptureStatus())
225 return self._file_tuples
226
190 227
191 class SVN(SCM): 228 class SVN(SCM):
192 """Gathers the options and diff for a subversion checkout.""" 229 """Gathers the options and diff for a subversion checkout."""
193 def __init__(self, *args, **kwargs): 230 def __init__(self, *args, **kwargs):
194 SCM.__init__(self, *args, **kwargs) 231 SCM.__init__(self, *args, **kwargs)
195 self.checkout_root = scm.SVN.GetCheckoutRoot(self.checkout_root) 232 self.checkout_root = scm.SVN.GetCheckoutRoot(self.checkout_root)
196 if not self.options.email: 233 if not self.options.email:
197 # Assumes the svn credential is an email address. 234 # Assumes the svn credential is an email address.
198 self.options.email = scm.SVN.GetEmail(self.checkout_root) 235 self.options.email = scm.SVN.GetEmail(self.checkout_root)
199 logging.info("SVN(%s)" % self.checkout_root) 236 logging.info("SVN(%s)" % self.checkout_root)
200 237
201 def ReadRootFile(self, filename): 238 def ReadRootFile(self, filename):
202 data = SCM.ReadRootFile(self, filename) 239 data = SCM.ReadRootFile(self, filename)
203 if data: 240 if data:
204 return data 241 return data
205 242
206 # Try to search on the subversion repository for the file. 243 # Try to search on the subversion repository for the file.
207 if not gcl: 244 if not gcl:
208 return None 245 return None
209 data = gcl.GetCachedFile(filename) 246 data = gcl.GetCachedFile(filename)
210 logging.debug('%s:\n%s' % (filename, data)) 247 logging.debug('%s:\n%s' % (filename, data))
211 return data 248 return data
212 249
250 def CaptureStatus(self):
251 previous_cwd = os.getcwd()
252 os.chdir(self.checkout_root)
253 result = scm.SVN.CaptureStatus(self.checkout_root)
254 os.chdir(previous_cwd)
255 return result
256
213 def GenerateDiff(self): 257 def GenerateDiff(self):
214 """Returns a string containing the diff for the given file list. 258 """Returns a string containing the diff for the given file list.
215 259
216 The files in the list should either be absolute paths or relative to the 260 The files in the list should either be absolute paths or relative to the
217 given root. 261 given root.
218 """ 262 """
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, 263 return scm.SVN.GenerateDiff(self.files, self.checkout_root, full_move=True,
237 revision=self.diff_against) 264 revision=self.diff_against)
238 265
239 266
240 class GIT(SCM): 267 class GIT(SCM):
241 """Gathers the options and diff for a git checkout.""" 268 """Gathers the options and diff for a git checkout."""
242 def __init__(self, *args, **kwargs): 269 def __init__(self, *args, **kwargs):
243 SCM.__init__(self, *args, **kwargs) 270 SCM.__init__(self, *args, **kwargs)
244 self.checkout_root = scm.GIT.GetCheckoutRoot(self.checkout_root) 271 self.checkout_root = scm.GIT.GetCheckoutRoot(self.checkout_root)
245 if not self.options.name: 272 if not self.options.name:
246 self.options.name = scm.GIT.GetPatchName(self.checkout_root) 273 self.options.name = scm.GIT.GetPatchName(self.checkout_root)
247 if not self.options.email: 274 if not self.options.email:
248 self.options.email = scm.GIT.GetEmail(self.checkout_root) 275 self.options.email = scm.GIT.GetEmail(self.checkout_root)
249 if not self.diff_against: 276 if not self.diff_against:
250 self.diff_against = scm.GIT.GetUpstreamBranch(self.checkout_root) 277 self.diff_against = scm.GIT.GetUpstreamBranch(self.checkout_root)
251 if not self.diff_against: 278 if not self.diff_against:
252 raise NoTryServerAccess( 279 raise NoTryServerAccess(
253 "Unable to determine default branch to diff against. " 280 "Unable to determine default branch to diff against. "
254 "Verify this branch is set up to track another" 281 "Verify this branch is set up to track another"
255 "(via the --track argument to \"git checkout -b ...\"") 282 "(via the --track argument to \"git checkout -b ...\"")
256 logging.info("GIT(%s)" % self.checkout_root) 283 logging.info("GIT(%s)" % self.checkout_root)
257 284
285 def CaptureStatus(self):
286 return scm.GIT.CaptureStatus(self.checkout_root, self.diff_against)
287
258 def GenerateDiff(self): 288 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, 289 return scm.GIT.GenerateDiff(self.checkout_root, files=self.files,
272 full_move=True, 290 full_move=True,
273 branch=self.diff_against) 291 branch=self.diff_against)
274 292
275 293
276 def _ParseSendChangeOptions(options): 294 def _ParseSendChangeOptions(options):
277 """Parse common options passed to _SendChangeHTTP and _SendChangeSVN.""" 295 """Parse common options passed to _SendChangeHTTP and _SendChangeSVN."""
278 values = {} 296 values = {}
279 if options.email: 297 if options.email:
280 values['email'] = options.email 298 values['email'] = options.email
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 # ENOENT == 2 = they don't have git installed. 467 # ENOENT == 2 = they don't have git installed.
450 # 128 = git error code when not in a repo. 468 # 128 = git error code when not in a repo.
451 logging.warning('Unexpected error code: %s' % e.returncode) 469 logging.warning('Unexpected error code: %s' % e.returncode)
452 raise 470 raise
453 raise NoTryServerAccess("Could not guess version control system. " 471 raise NoTryServerAccess("Could not guess version control system. "
454 "Are you in a working copy directory?") 472 "Are you in a working copy directory?")
455 473
456 474
457 def GetMungedDiff(path_diff, diff): 475 def GetMungedDiff(path_diff, diff):
458 # Munge paths to match svn. 476 # Munge paths to match svn.
477 changed_files = []
459 for i in range(len(diff)): 478 for i in range(len(diff)):
460 if diff[i].startswith('--- ') or diff[i].startswith('+++ '): 479 if diff[i].startswith('--- ') or diff[i].startswith('+++ '):
461 new_file = posixpath.join(path_diff, diff[i][4:]).replace('\\', '/') 480 new_file = posixpath.join(path_diff, diff[i][4:]).replace('\\', '/')
481 changed_files.append(('M', new_file.split('\t')[0]))
462 diff[i] = diff[i][0:4] + new_file 482 diff[i] = diff[i][0:4] + new_file
463 return diff 483 return (diff, changed_files)
464 484
465 485
466 def TryChange(argv, 486 def TryChange(argv,
487 change,
467 file_list, 488 file_list,
M-A Ruel 2011/09/30 15:38:44 I just realized this was an error. TryChange shoul
468 swallow_exception, 489 swallow_exception,
469 prog=None, 490 prog=None,
470 extra_epilog=None): 491 extra_epilog=None):
471 """ 492 """
472 Args: 493 Args:
473 argv: Arguments and options. 494 argv: Arguments and options.
474 file_list: Default value to pass to --file. 495 file_list: Default value to pass to --file.
475 swallow_exception: Whether we raise or swallow exceptions. 496 swallow_exception: Whether we raise or swallow exceptions.
476 """ 497 """
477 # Parse argv 498 # Parse argv
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
639 if not '://' in options.rietveld_url: 660 if not '://' in options.rietveld_url:
640 options.rietveld_url = 'http://' + options.rietveld_url 661 options.rietveld_url = 'http://' + options.rietveld_url
641 match = re.match(r'^(.*)/(\d+)/?$', options.rietveld_url) 662 match = re.match(r'^(.*)/(\d+)/?$', options.rietveld_url)
642 if match: 663 if match:
643 if options.issue or options.patchset: 664 if options.issue or options.patchset:
644 parser.error('Cannot use both --issue and use a review number url') 665 parser.error('Cannot use both --issue and use a review number url')
645 options.issue = int(match.group(2)) 666 options.issue = int(match.group(2))
646 options.rietveld_url = match.group(1) 667 options.rietveld_url = match.group(1)
647 668
648 try: 669 try:
670 changed_files = None
649 # Always include os.getcwd() in the checkout settings. 671 # Always include os.getcwd() in the checkout settings.
650 checkouts = [] 672 checkouts = []
651 path = os.getcwd() 673 path = os.getcwd()
652 if options.upstream_branch: 674 if options.upstream_branch:
653 path += '@' + options.upstream_branch 675 path += '@' + options.upstream_branch
654 checkouts.append(GuessVCS(options, path)) 676 checkouts.append(GuessVCS(options, path))
655 checkouts[0].AutomagicalSettings() 677 checkouts[0].AutomagicalSettings()
656 for item in options.sub_rep: 678 for item in options.sub_rep:
657 checkout = GuessVCS(options, os.path.join(checkouts[0].checkout_root, 679 checkout = GuessVCS(options, os.path.join(checkouts[0].checkout_root,
658 item)) 680 item))
(...skipping 23 matching lines...) Expand all
682 # When patchset is specified, it's because it's done by gcl/git-try. 704 # When patchset is specified, it's because it's done by gcl/git-try.
683 if json is None: 705 if json is None:
684 parser.error('json or simplejson library is missing, please install.') 706 parser.error('json or simplejson library is missing, please install.')
685 api_url = '%s/api/%d' % (options.rietveld_url, options.issue) 707 api_url = '%s/api/%d' % (options.rietveld_url, options.issue)
686 logging.debug(api_url) 708 logging.debug(api_url)
687 contents = json.loads(urllib.urlopen(api_url).read()) 709 contents = json.loads(urllib.urlopen(api_url).read())
688 options.patchset = contents['patchsets'][-1] 710 options.patchset = contents['patchsets'][-1]
689 diff_url = ('%s/download/issue%d_%d.diff' % 711 diff_url = ('%s/download/issue%d_%d.diff' %
690 (options.rietveld_url, options.issue, options.patchset)) 712 (options.rietveld_url, options.issue, options.patchset))
691 diff = GetMungedDiff('', urllib.urlopen(diff_url).readlines()) 713 diff = GetMungedDiff('', urllib.urlopen(diff_url).readlines())
692 options.diff = ''.join(diff) 714 options.diff = ''.join(diff[0])
715 changed_files = diff[1]
693 else: 716 else:
694 # Use this as the base. 717 # Use this as the base.
695 root = checkouts[0].checkout_root 718 root = checkouts[0].checkout_root
696 diffs = [] 719 diffs = []
697 for checkout in checkouts: 720 for checkout in checkouts:
698 diff = checkout.GenerateDiff().splitlines(True) 721 diff = checkout.GenerateDiff().splitlines(True)
699 path_diff = gclient_utils.PathDifference(root, checkout.checkout_root) 722 path_diff = gclient_utils.PathDifference(root, checkout.checkout_root)
700 # Munge it. 723 # Munge it.
701 diffs.extend(GetMungedDiff(path_diff, diff)) 724 diffs.extend(GetMungedDiff(path_diff, diff)[0])
702 options.diff = ''.join(diffs) 725 options.diff = ''.join(diffs)
703 726
727 if not options.name:
728 if options.issue:
729 options.name = 'Issue %s' % options.issue
730 else:
731 options.name = 'Unnamed'
732 print('Note: use --name NAME to change the try job name.')
733
734 if not options.email:
735 parser.error('Using an anonymous checkout. Please use --email or set '
736 'the TRYBOT_RESULTS_EMAIL_ADDRESS environment variable.')
737 print('Results will be emailed to: ' + options.email)
738
704 if not options.bot: 739 if not options.bot:
705 # Get try slaves from PRESUBMIT.py files if not specified. 740 # 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 741 # Even if the diff comes from options.url, use the local checkout for bot
707 # selection. 742 # selection.
708 try: 743 try:
709 import presubmit_support 744 import presubmit_support
710 root_presubmit = checkouts[0].ReadRootFile('PRESUBMIT.py') 745 root_presubmit = checkouts[0].ReadRootFile('PRESUBMIT.py')
746 if not change:
747 if not changed_files:
748 changed_files = checkouts[0].file_tuples
749 change = presubmit_support.Change(options.name,
750 '',
751 checkouts[0].checkout_root,
752 changed_files,
753 options.issue,
754 options.patchset,
755 options.email)
711 options.bot = presubmit_support.DoGetTrySlaves( 756 options.bot = presubmit_support.DoGetTrySlaves(
757 change,
712 checkouts[0].GetFileNames(), 758 checkouts[0].GetFileNames(),
713 checkouts[0].checkout_root, 759 checkouts[0].checkout_root,
714 root_presubmit, 760 root_presubmit,
715 options.project, 761 options.project,
716 False, 762 False,
717 sys.stdout) 763 sys.stdout)
718 except ImportError: 764 except ImportError:
719 pass 765 pass
720 # If no bot is specified, either the default pool will be selected or the 766 # 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. 767 # try server will refuse the job. Either case we don't need to interfere.
722 768
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. 769 # Prevent rietveld updates if we aren't running all the tests.
736 if options.testfilter is not None: 770 if options.testfilter is not None:
737 options.issue = None 771 options.issue = None
738 options.patchset = None 772 options.patchset = None
739 773
740 # Send the patch. 774 # Send the patch.
741 if options.send_patch: 775 if options.send_patch:
742 # If forced. 776 # If forced.
743 options.send_patch(options) 777 options.send_patch(options)
744 PrintSuccess(options) 778 PrintSuccess(options)
(...skipping 15 matching lines...) Expand all
760 print >> sys.stderr, e 794 print >> sys.stderr, e
761 return 1 795 return 1
762 except (gclient_utils.Error, subprocess2.CalledProcessError), e: 796 except (gclient_utils.Error, subprocess2.CalledProcessError), e:
763 print >> sys.stderr, e 797 print >> sys.stderr, e
764 return 1 798 return 1
765 return 0 799 return 0
766 800
767 801
768 if __name__ == "__main__": 802 if __name__ == "__main__":
769 fix_encoding.fix_encoding() 803 fix_encoding.fix_encoding()
770 sys.exit(TryChange(None, [], False)) 804 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
This is Rietveld 408576698