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

Side by Side Diff: trychange.py

Issue 385007: Run pychecker over most scripts in depot_tools. Catched a few bugs. (Closed)
Patch Set: . Created 11 years, 1 month 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
« gclient.py ('K') | « 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/python 1 #!/usr/bin/python
2 # Copyright (c) 2009 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2009 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 """Client-side script to send a try job to the try server. It communicates to 5 """Client-side script to send a try job to the try server. It communicates to
6 the try server by either writting to a svn repository or by directly connecting 6 the try server by either writting to a svn repository or by directly connecting
7 to the server by HTTP. 7 to the server by HTTP.
8 """ 8 """
9 9
10 10
11 import datetime 11 import datetime
12 import getpass 12 import getpass
13 import logging 13 import logging
14 import optparse 14 import optparse
15 import os 15 import os
16 import shutil 16 import shutil
17 import socket 17 import socket
18 import subprocess 18 import subprocess
19 import sys 19 import sys
20 import tempfile 20 import tempfile
21 import traceback
22 import urllib 21 import urllib
23 22
24 import gcl 23 import gcl
25 import gclient
26 import gclient_scm 24 import gclient_scm
27 import presubmit_support 25 import presubmit_support
28 import upload 26 import upload
29 27
30 __version__ = '1.1.1' 28 __version__ = '1.1.1'
31 29
32 30
33 # Constants 31 # Constants
34 HELP_STRING = "Sorry, Tryserver is not available." 32 HELP_STRING = "Sorry, Tryserver is not available."
35 USAGE = r"""%prog [change_name] [options] 33 USAGE = r"""%prog [change_name] [options]
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 raise NoTryServerAccess(' '.join(command) + '\nOuput:\n' + output) 125 raise NoTryServerAccess(' '.join(command) + '\nOuput:\n' + output)
128 return output 126 return output
129 127
130 128
131 class SCM(object): 129 class SCM(object):
132 """Simplistic base class to implement one function: ProcessOptions.""" 130 """Simplistic base class to implement one function: ProcessOptions."""
133 def __init__(self, options): 131 def __init__(self, options):
134 self.options = options 132 self.options = options
135 133
136 def ProcessOptions(self): 134 def ProcessOptions(self):
137 raise Unimplemented 135 raise NotImplementedError
138 136
139 137
140 class SVN(SCM): 138 class SVN(SCM):
141 """Gathers the options and diff for a subversion checkout.""" 139 """Gathers the options and diff for a subversion checkout."""
142 def GenerateDiff(self, files, root): 140 def GenerateDiff(self, files, root):
143 """Returns a string containing the diff for the given file list. 141 """Returns a string containing the diff for the given file list.
144 142
145 The files in the list should either be absolute paths or relative to the 143 The files in the list should either be absolute paths or relative to the
146 given root. If no root directory is provided, the repository root will be 144 given root. If no root directory is provided, the repository root will be
147 used. 145 used.
148 """ 146 """
149 previous_cwd = os.getcwd() 147 previous_cwd = os.getcwd()
150 if root is None: 148 if root is None:
151 os.chdir(gcl.GetRepositoryRoot()) 149 os.chdir(gcl.GetRepositoryRoot())
152 else: 150 else:
153 os.chdir(root) 151 os.chdir(root)
154 152
155 diff = [] 153 diff = []
156 for file in files: 154 for filename in files:
157 # Use svn info output instead of os.path.isdir because the latter fails 155 # Use svn info output instead of os.path.isdir because the latter fails
158 # when the file is deleted. 156 # when the file is deleted.
159 if gclient_scm.CaptureSVNInfo(file).get("Node Kind") in ("dir", 157 if gclient_scm.CaptureSVNInfo(filename).get("Node Kind") in (
160 "directory"): 158 "dir", "directory"):
161 continue 159 continue
162 # If the user specified a custom diff command in their svn config file, 160 # If the user specified a custom diff command in their svn config file,
163 # then it'll be used when we do svn diff, which we don't want to happen 161 # then it'll be used when we do svn diff, which we don't want to happen
164 # since we want the unified diff. Using --diff-cmd=diff doesn't always 162 # since we want the unified diff. Using --diff-cmd=diff doesn't always
165 # work, since they can have another diff executable in their path that 163 # work, since they can have another diff executable in their path that
166 # gives different line endings. So we use a bogus temp directory as the 164 # gives different line endings. So we use a bogus temp directory as the
167 # config directory, which gets around these problems. 165 # config directory, which gets around these problems.
168 if sys.platform.startswith("win"): 166 if sys.platform.startswith("win"):
169 parent_dir = tempfile.gettempdir() 167 parent_dir = tempfile.gettempdir()
170 else: 168 else:
171 parent_dir = sys.path[0] # tempdir is not secure. 169 parent_dir = sys.path[0] # tempdir is not secure.
172 bogus_dir = os.path.join(parent_dir, "temp_svn_config") 170 bogus_dir = os.path.join(parent_dir, "temp_svn_config")
173 if not os.path.exists(bogus_dir): 171 if not os.path.exists(bogus_dir):
174 os.mkdir(bogus_dir) 172 os.mkdir(bogus_dir)
175 # Grabs the diff data. 173 # Grabs the diff data.
176 data = gcl.RunShell(["svn", "diff", "--config-dir", bogus_dir, file]) 174 data = gcl.RunShell(["svn", "diff", "--config-dir", bogus_dir, filename])
177 175
178 # We know the diff will be incorrectly formatted. Fix it. 176 # We know the diff will be incorrectly formatted. Fix it.
179 if gcl.IsSVNMoved(file): 177 if gcl.IsSVNMoved(filename):
180 # The file is "new" in the patch sense. Generate a homebrew diff. 178 # The file is "new" in the patch sense. Generate a homebrew diff.
181 # We can't use ReadFile() since it's not using binary mode. 179 # We can't use ReadFile() since it's not using binary mode.
182 file_handle = open(file, 'rb') 180 file_handle = open(filename, 'rb')
183 file_content = file_handle.read() 181 file_content = file_handle.read()
184 file_handle.close() 182 file_handle.close()
185 # Prepend '+' to every lines. 183 # Prepend '+' to every lines.
186 file_content = ['+' + i for i in file_content.splitlines(True)] 184 file_content = ['+' + i for i in file_content.splitlines(True)]
187 nb_lines = len(file_content) 185 nb_lines = len(file_content)
188 # We need to use / since patch on unix will fail otherwise. 186 # We need to use / since patch on unix will fail otherwise.
189 file = file.replace('\\', '/') 187 filename = filename.replace('\\', '/')
190 data = "Index: %s\n" % file 188 data = "Index: %s\n" % filename
191 data += ("=============================================================" 189 data += ("============================================================="
192 "======\n") 190 "======\n")
193 # Note: Should we use /dev/null instead? 191 # Note: Should we use /dev/null instead?
194 data += "--- %s\n" % file 192 data += "--- %s\n" % filename
195 data += "+++ %s\n" % file 193 data += "+++ %s\n" % filename
196 data += "@@ -0,0 +1,%d @@\n" % nb_lines 194 data += "@@ -0,0 +1,%d @@\n" % nb_lines
197 data += ''.join(file_content) 195 data += ''.join(file_content)
198 diff.append(data) 196 diff.append(data)
199 os.chdir(previous_cwd) 197 os.chdir(previous_cwd)
200 return "".join(diff) 198 return "".join(diff)
201 199
202 def GetFileNames(self): 200 def GetFileNames(self):
203 """Return the list of files in the diff.""" 201 """Return the list of files in the diff."""
204 return self.change_info.GetFileNames() 202 return self.change_info.GetFileNames()
205 203
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 # TODO: check for errors here? 246 # TODO: check for errors here?
249 root = upload.RunShell(['git', 'rev-parse', '--show-cdup']).strip() 247 root = upload.RunShell(['git', 'rev-parse', '--show-cdup']).strip()
250 return os.path.abspath(root) 248 return os.path.abspath(root)
251 249
252 def GetPatchName(self): 250 def GetPatchName(self):
253 """Construct a name for this patch.""" 251 """Construct a name for this patch."""
254 # TODO: perhaps include the hash of the current commit, to distinguish 252 # TODO: perhaps include the hash of the current commit, to distinguish
255 # patches? 253 # patches?
256 branch = upload.RunShell(['git', 'symbolic-ref', 'HEAD']).strip() 254 branch = upload.RunShell(['git', 'symbolic-ref', 'HEAD']).strip()
257 if not branch.startswith('refs/heads/'): 255 if not branch.startswith('refs/heads/'):
258 raise "Couldn't figure out branch name" 256 # TODO(maruel): Find a better type.
257 raise NoTryServerAccess("Couldn't figure out branch name")
259 branch = branch[len('refs/heads/'):] 258 branch = branch[len('refs/heads/'):]
260 return branch 259 return branch
261 260
262 def ProcessOptions(self): 261 def ProcessOptions(self):
263 if not self.options.diff: 262 if not self.options.diff:
264 self.options.diff = self.GenerateDiff() 263 self.options.diff = self.GenerateDiff()
265 if not self.options.name: 264 if not self.options.name:
266 self.options.name = self.GetPatchName() 265 self.options.name = self.GetPatchName()
267 if not self.options.email: 266 if not self.options.email:
268 self.options.email = self.GetEmail() 267 self.options.email = self.GetEmail()
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 try: 369 try:
371 RunCommand(['svn', 'ls', full_url]) 370 RunCommand(['svn', 'ls', full_url])
372 file_found = True 371 file_found = True
373 except NoTryServerAccess: 372 except NoTryServerAccess:
374 pass 373 pass
375 if file_found: 374 if file_found:
376 # The file already exists in the repo. Note that commiting a file is a 375 # The file already exists in the repo. Note that commiting a file is a
377 # no-op if the file's content (the diff) is not modified. This is why the 376 # no-op if the file's content (the diff) is not modified. This is why the
378 # file name contains the date and time. 377 # file name contains the date and time.
379 RunCommand(['svn', 'update', full_path]) 378 RunCommand(['svn', 'update', full_path])
380 file = open(full_path, 'wb') 379 f = open(full_path, 'wb')
381 file.write(options.diff) 380 f.write(options.diff)
382 file.close() 381 f.close()
383 else: 382 else:
384 # Add the file to the repo 383 # Add the file to the repo
385 file = open(full_path, 'wb') 384 f = open(full_path, 'wb')
386 file.write(options.diff) 385 f.write(options.diff)
387 file.close() 386 f.close()
388 RunCommand(["svn", "add", full_path]) 387 RunCommand(["svn", "add", full_path])
389 temp_file.write(description) 388 temp_file.write(description)
390 temp_file.flush() 389 temp_file.flush()
391 RunCommand(["svn", "commit", full_path, '--file', 390 RunCommand(["svn", "commit", full_path, '--file',
392 temp_file_name]) 391 temp_file_name])
393 finally: 392 finally:
394 temp_file.close() 393 temp_file.close()
395 shutil.rmtree(temp_dir, True) 394 shutil.rmtree(temp_dir, True)
396 395
397 396
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
565 options.diff = urllib.urlopen(options.url).read() 564 options.diff = urllib.urlopen(options.url).read()
566 elif options.diff: 565 elif options.diff:
567 options.diff = gcl.ReadFile(options.diff) 566 options.diff = gcl.ReadFile(options.diff)
568 # Process the VCS in any case at least to retrieve the email address. 567 # Process the VCS in any case at least to retrieve the email address.
569 try: 568 try:
570 options.scm = GuessVCS(options) 569 options.scm = GuessVCS(options)
571 options.scm.ProcessOptions() 570 options.scm.ProcessOptions()
572 except NoTryServerAccess, e: 571 except NoTryServerAccess, e:
573 # If we got the diff, we don't care. 572 # If we got the diff, we don't care.
574 if not options.diff: 573 if not options.diff:
574 # TODO(maruel): Raise what?
575 raise 575 raise
576 576
577 # Get try slaves from PRESUBMIT.py files if not specified. 577 # Get try slaves from PRESUBMIT.py files if not specified.
578 if not options.bot: 578 if not options.bot:
579 if options.url: 579 if options.url:
580 print('You need to specify which bots to use.') 580 print('You need to specify which bots to use.')
581 return 1 581 return 1
582 root_presubmit = gcl.GetCachedFile('PRESUBMIT.py', use_root=True) 582 root_presubmit = gcl.GetCachedFile('PRESUBMIT.py', use_root=True)
583 options.bot = presubmit_support.DoGetTrySlaves(options.scm.GetFileNames(), 583 options.bot = presubmit_support.DoGetTrySlaves(options.scm.GetFileNames(),
584 options.scm.GetLocalRoot(), 584 options.scm.GetLocalRoot(),
585 root_presubmit, 585 root_presubmit,
586 False, 586 False,
587 sys.stdout) 587 sys.stdout)
588 588
589 if options.name is None: 589 if options.name is None:
590 if options.issue: 590 if options.issue:
591 patch_name = 'Issue %s' % options.issue 591 options.name = 'Issue %s' % options.issue
592 else: 592 else:
593 options.name = 'Unnamed' 593 options.name = 'Unnamed'
594 print('Note: use --name NAME to change the try job name.') 594 print('Note: use --name NAME to change the try job name.')
595 if not options.email: 595 if not options.email:
596 print('Warning: TRYBOT_RESULTS_EMAIL_ADDRESS is not set. Try server ' 596 print('Warning: TRYBOT_RESULTS_EMAIL_ADDRESS is not set. Try server '
597 'results might\ngo to: %s@google.com.\n' % options.user) 597 'results might\ngo to: %s@google.com.\n' % options.user)
598 else: 598 else:
599 print('Results will be emailed to: ' + options.email) 599 print('Results will be emailed to: ' + options.email)
600 600
601 # Send the patch. 601 # Send the patch.
602 options.send_patch(options) 602 options.send_patch(options)
603 print 'Patch \'%s\' sent to try server: %s' % (options.name, 603 print 'Patch \'%s\' sent to try server: %s' % (options.name,
604 ', '.join(options.bot)) 604 ', '.join(options.bot))
605 except (InvalidScript, NoTryServerAccess), e: 605 except (InvalidScript, NoTryServerAccess), e:
606 if swallow_exception: 606 if swallow_exception:
607 return 1 607 return 1
608 print e 608 print e
609 return 1 609 return 1
610 return 0 610 return 0
611 611
612 612
613 if __name__ == "__main__": 613 if __name__ == "__main__":
614 sys.exit(TryChange(None, None, False)) 614 sys.exit(TryChange(None, None, False))
OLDNEW
« gclient.py ('K') | « tests/trychange_unittest.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698