OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2006-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 # | 5 # |
6 # Wrapper script around Rietveld's upload.py that groups files into | 6 # Wrapper script around Rietveld's upload.py that groups files into |
7 # changelists. | 7 # changelists. |
8 | 8 |
9 import getpass | 9 import getpass |
10 import os | 10 import os |
11 import random | 11 import random |
12 import re | 12 import re |
13 import shutil | 13 import shutil |
14 import string | 14 import string |
15 import subprocess | 15 import subprocess |
16 import sys | 16 import sys |
17 import tempfile | 17 import tempfile |
18 import upload | 18 import upload |
19 import urllib2 | 19 import urllib2 |
20 import xml.dom.minidom | |
21 | 20 |
22 # gcl now depends on gclient. | 21 # gcl now depends on gclient. |
23 import gclient_scm | 22 import gclient_scm |
24 import gclient_utils | 23 import gclient_utils |
25 | 24 |
26 __version__ = '1.1.1' | 25 __version__ = '1.1.1' |
27 | 26 |
28 | 27 |
29 CODEREVIEW_SETTINGS = { | 28 CODEREVIEW_SETTINGS = { |
30 # Default values. | 29 # Default values. |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 url_path = repo_root | 152 url_path = repo_root |
154 else: | 153 else: |
155 url_path = dir_info["URL"] | 154 url_path = dir_info["URL"] |
156 content = "" | 155 content = "" |
157 while True: | 156 while True: |
158 # First, look for a locally modified version of the file. | 157 # First, look for a locally modified version of the file. |
159 local_path = os.path.join(local_dir, local_base) | 158 local_path = os.path.join(local_dir, local_base) |
160 r = gclient_scm.CaptureSVNStatus((local_path,)) | 159 r = gclient_scm.CaptureSVNStatus((local_path,)) |
161 rc = -1 | 160 rc = -1 |
162 if r: | 161 if r: |
163 (status, file) = r[0] | 162 status = r[0][0] |
164 rc = 0 | 163 rc = 0 |
165 if not rc and status[0] in ('A','M'): | 164 if not rc and status[0] in ('A','M'): |
166 content = ReadFile(local_path) | 165 content = ReadFile(local_path) |
167 rc = 0 | 166 rc = 0 |
168 else: | 167 else: |
169 # Then look in the repository. | 168 # Then look in the repository. |
170 svn_path = url_path + "/" + filename | 169 svn_path = url_path + "/" + filename |
171 content, rc = RunShellWithReturnCode(["svn", "cat", svn_path]) | 170 content, rc = RunShellWithReturnCode(["svn", "cat", svn_path]) |
172 | 171 |
173 if not rc: | 172 if not rc: |
174 # Exit the loop if the file was found. Override content. | 173 # Exit the loop if the file was found. Override content. |
175 break | 174 break |
176 # Make sure to mark settings as empty if not found. | 175 # Make sure to mark settings as empty if not found. |
177 content = "" | 176 content = "" |
178 if url_path == repo_root: | 177 if url_path == repo_root: |
179 # Reached the root. Abandoning search. | 178 # Reached the root. Abandoning search. |
180 break | 179 break |
181 # Go up one level to try again. | 180 # Go up one level to try again. |
182 url_path = os.path.dirname(url_path) | 181 url_path = os.path.dirname(url_path) |
183 local_dir = os.path.dirname(local_dir) | 182 local_dir = os.path.dirname(local_dir) |
184 # Write a cached version even if there isn't a file, so we don't try to | 183 # Write a cached version even if there isn't a file, so we don't try to |
185 # fetch it each time. | 184 # fetch it each time. |
186 WriteFile(cached_file, content) | 185 WriteFile(cached_file, content) |
187 else: | 186 else: |
188 content = ReadFile(cached_settings_file) | 187 content = ReadFile(cached_file) |
189 # Keep the content cached in memory. | 188 # Keep the content cached in memory. |
190 FILES_CACHE[filename] = content | 189 FILES_CACHE[filename] = content |
191 return FILES_CACHE[filename] | 190 return FILES_CACHE[filename] |
192 | 191 |
193 | 192 |
194 def GetCodeReviewSetting(key): | 193 def GetCodeReviewSetting(key): |
195 """Returns a value for the given key for this repository.""" | 194 """Returns a value for the given key for this repository.""" |
196 # Use '__just_initialized' as a flag to determine if the settings were | 195 # Use '__just_initialized' as a flag to determine if the settings were |
197 # already initialized. | 196 # already initialized. |
198 global CODEREVIEW_SETTINGS | 197 global CODEREVIEW_SETTINGS |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 return output, p.returncode | 243 return output, p.returncode |
245 | 244 |
246 | 245 |
247 def RunShell(command, print_output=False): | 246 def RunShell(command, print_output=False): |
248 """Executes a command and returns the output.""" | 247 """Executes a command and returns the output.""" |
249 return RunShellWithReturnCode(command, print_output)[0] | 248 return RunShellWithReturnCode(command, print_output)[0] |
250 | 249 |
251 | 250 |
252 def ReadFile(filename, flags='r'): | 251 def ReadFile(filename, flags='r'): |
253 """Returns the contents of a file.""" | 252 """Returns the contents of a file.""" |
254 file = open(filename, flags) | 253 f = open(filename, flags) |
255 result = file.read() | 254 result = f.read() |
256 file.close() | 255 f.close() |
257 return result | 256 return result |
258 | 257 |
259 | 258 |
260 def WriteFile(filename, contents): | 259 def WriteFile(filename, contents): |
261 """Overwrites the file with the given contents.""" | 260 """Overwrites the file with the given contents.""" |
262 file = open(filename, 'w') | 261 f = open(filename, 'w') |
263 file.write(contents) | 262 f.write(contents) |
264 file.close() | 263 f.close() |
265 | 264 |
266 | 265 |
267 def FilterFlag(args, flag): | 266 def FilterFlag(args, flag): |
268 """Returns True if the flag is present in args list. | 267 """Returns True if the flag is present in args list. |
269 | 268 |
270 The flag is removed from args if present. | 269 The flag is removed from args if present. |
271 """ | 270 """ |
272 if flag in args: | 271 if flag in args: |
273 args.remove(flag) | 272 args.remove(flag) |
274 return True | 273 return True |
(...skipping 30 matching lines...) Expand all Loading... |
305 self.patchset = int(patchset) | 304 self.patchset = int(patchset) |
306 self.description = description | 305 self.description = description |
307 if files is None: | 306 if files is None: |
308 files = [] | 307 files = [] |
309 self._files = files | 308 self._files = files |
310 self.patch = None | 309 self.patch = None |
311 self._local_root = local_root | 310 self._local_root = local_root |
312 | 311 |
313 def GetFileNames(self): | 312 def GetFileNames(self): |
314 """Returns the list of file names included in this change.""" | 313 """Returns the list of file names included in this change.""" |
315 return [file[1] for file in self._files] | 314 return [f[1] for f in self._files] |
316 | 315 |
317 def GetFiles(self): | 316 def GetFiles(self): |
318 """Returns the list of files included in this change with their status.""" | 317 """Returns the list of files included in this change with their status.""" |
319 return self._files | 318 return self._files |
320 | 319 |
321 def GetLocalRoot(self): | 320 def GetLocalRoot(self): |
322 """Returns the local repository checkout root directory.""" | 321 """Returns the local repository checkout root directory.""" |
323 return self._local_root | 322 return self._local_root |
324 | 323 |
325 def Exists(self): | 324 def Exists(self): |
326 """Returns True if this change already exists (i.e., is not new).""" | 325 """Returns True if this change already exists (i.e., is not new).""" |
327 return (self.issue or self.description or self._files) | 326 return (self.issue or self.description or self._files) |
328 | 327 |
329 def _NonDeletedFileList(self): | 328 def _NonDeletedFileList(self): |
330 """Returns a list of files in this change, not including deleted files.""" | 329 """Returns a list of files in this change, not including deleted files.""" |
331 return [file[1] for file in self.GetFiles() | 330 return [f[1] for f in self.GetFiles() |
332 if not file[0].startswith("D")] | 331 if not f[0].startswith("D")] |
333 | 332 |
334 def _AddedFileList(self): | 333 def _AddedFileList(self): |
335 """Returns a list of files added in this change.""" | 334 """Returns a list of files added in this change.""" |
336 return [file[1] for file in self.GetFiles() if file[0].startswith("A")] | 335 return [f[1] for f in self.GetFiles() if f[0].startswith("A")] |
337 | 336 |
338 def Save(self): | 337 def Save(self): |
339 """Writes the changelist information to disk.""" | 338 """Writes the changelist information to disk.""" |
340 data = ChangeInfo._SEPARATOR.join([ | 339 data = ChangeInfo._SEPARATOR.join([ |
341 "%d, %d" % (self.issue, self.patchset), | 340 "%d, %d" % (self.issue, self.patchset), |
342 "\n".join([f[0] + f[1] for f in self.GetFiles()]), | 341 "\n".join([f[0] + f[1] for f in self.GetFiles()]), |
343 self.description]) | 342 self.description]) |
344 WriteFile(GetChangelistInfoFile(self.name), data) | 343 WriteFile(GetChangelistInfoFile(self.name), data) |
345 | 344 |
346 def Delete(self): | 345 def Delete(self): |
(...skipping 12 matching lines...) Expand all Loading... |
359 ctype, body = upload.EncodeMultipartFormData(data, []) | 358 ctype, body = upload.EncodeMultipartFormData(data, []) |
360 SendToRietveld("/%d/description" % self.issue, body, ctype) | 359 SendToRietveld("/%d/description" % self.issue, body, ctype) |
361 | 360 |
362 def MissingTests(self): | 361 def MissingTests(self): |
363 """Returns True if the change looks like it needs unit tests but has none. | 362 """Returns True if the change looks like it needs unit tests but has none. |
364 | 363 |
365 A change needs unit tests if it contains any new source files or methods. | 364 A change needs unit tests if it contains any new source files or methods. |
366 """ | 365 """ |
367 SOURCE_SUFFIXES = [".cc", ".cpp", ".c", ".m", ".mm"] | 366 SOURCE_SUFFIXES = [".cc", ".cpp", ".c", ".m", ".mm"] |
368 # Ignore third_party entirely. | 367 # Ignore third_party entirely. |
369 files = [file for file in self._NonDeletedFileList() | 368 files = [f for f in self._NonDeletedFileList() |
370 if file.find("third_party") == -1] | 369 if f.find("third_party") == -1] |
371 added_files = [file for file in self._AddedFileList() | 370 added_files = [f for f in self._AddedFileList() |
372 if file.find("third_party") == -1] | 371 if f.find("third_party") == -1] |
373 | 372 |
374 # If the change is entirely in third_party, we're done. | 373 # If the change is entirely in third_party, we're done. |
375 if len(files) == 0: | 374 if len(files) == 0: |
376 return False | 375 return False |
377 | 376 |
378 # Any new or modified test files? | 377 # Any new or modified test files? |
379 # A test file's name ends with "test.*" or "tests.*". | 378 # A test file's name ends with "test.*" or "tests.*". |
380 test_files = [test for test in files | 379 test_files = [test for test in files |
381 if os.path.splitext(test)[0].rstrip("s").endswith("test")] | 380 if os.path.splitext(test)[0].rstrip("s").endswith("test")] |
382 if len(test_files) > 0: | 381 if len(test_files) > 0: |
383 return False | 382 return False |
384 | 383 |
385 # Any new source files? | 384 # Any new source files? |
386 source_files = [file for file in added_files | 385 source_files = [item for item in added_files |
387 if os.path.splitext(file)[1] in SOURCE_SUFFIXES] | 386 if os.path.splitext(item)[1] in SOURCE_SUFFIXES] |
388 if len(source_files) > 0: | 387 if len(source_files) > 0: |
389 return True | 388 return True |
390 | 389 |
391 # Do the long test, checking the files for new methods. | 390 # Do the long test, checking the files for new methods. |
392 return self._HasNewMethod() | 391 return self._HasNewMethod() |
393 | 392 |
394 def _HasNewMethod(self): | 393 def _HasNewMethod(self): |
395 """Returns True if the changeset contains any new functions, or if a | 394 """Returns True if the changeset contains any new functions, or if a |
396 function signature has been changed. | 395 function signature has been changed. |
397 | 396 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
463 items = split_data[0].split(',') | 462 items = split_data[0].split(',') |
464 issue = 0 | 463 issue = 0 |
465 patchset = 0 | 464 patchset = 0 |
466 if items[0]: | 465 if items[0]: |
467 issue = int(items[0]) | 466 issue = int(items[0]) |
468 if len(items) > 1: | 467 if len(items) > 1: |
469 patchset = int(items[1]) | 468 patchset = int(items[1]) |
470 files = [] | 469 files = [] |
471 for line in split_data[1].splitlines(): | 470 for line in split_data[1].splitlines(): |
472 status = line[:7] | 471 status = line[:7] |
473 file = line[7:] | 472 filename = line[7:] |
474 files.append((status, file)) | 473 files.append((status, filename)) |
475 description = split_data[2] | 474 description = split_data[2] |
476 save = False | 475 save = False |
477 if update_status: | 476 if update_status: |
478 for file in files: | 477 for item in files: |
479 filename = os.path.join(local_root, file[1]) | 478 filename = os.path.join(local_root, item[1]) |
480 status_result = gclient_scm.CaptureSVNStatus(filename) | 479 status_result = gclient_scm.CaptureSVNStatus(filename) |
481 if not status_result or not status_result[0][0]: | 480 if not status_result or not status_result[0][0]: |
482 # File has been reverted. | 481 # File has been reverted. |
483 save = True | 482 save = True |
484 files.remove(file) | 483 files.remove(item) |
485 continue | 484 continue |
486 status = status_result[0][0] | 485 status = status_result[0][0] |
487 if status != file[0]: | 486 if status != item[0]: |
488 save = True | 487 save = True |
489 files[files.index(file)] = (status, file[1]) | 488 files[files.index(item)] = (status, item[1]) |
490 change_info = ChangeInfo(changename, issue, patchset, description, files, | 489 change_info = ChangeInfo(changename, issue, patchset, description, files, |
491 local_root) | 490 local_root) |
492 if save: | 491 if save: |
493 change_info.Save() | 492 change_info.Save() |
494 return change_info | 493 return change_info |
495 | 494 |
496 | 495 |
497 def GetChangelistInfoFile(changename): | 496 def GetChangelistInfoFile(changename): |
498 """Returns the file that stores information about a changelist.""" | 497 """Returns the file that stores information about a changelist.""" |
499 if not changename or re.search(r'[^\w-]', changename): | 498 if not changename or re.search(r'[^\w-]', changename): |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
598 password = getpass.getpass("Password for %s: " % email) | 597 password = getpass.getpass("Password for %s: " % email) |
599 return email, password | 598 return email, password |
600 | 599 |
601 server = GetCodeReviewSetting("CODE_REVIEW_SERVER") | 600 server = GetCodeReviewSetting("CODE_REVIEW_SERVER") |
602 rpc_server = upload.HttpRpcServer(server, | 601 rpc_server = upload.HttpRpcServer(server, |
603 GetUserCredentials, | 602 GetUserCredentials, |
604 host_override=server, | 603 host_override=server, |
605 save_cookies=True) | 604 save_cookies=True) |
606 try: | 605 try: |
607 return rpc_server.Send(request_path, payload, content_type, timeout) | 606 return rpc_server.Send(request_path, payload, content_type, timeout) |
608 except urllib2.URLError, e: | 607 except urllib2.URLError: |
609 if timeout is None: | 608 if timeout is None: |
610 ErrorExit("Error accessing url %s" % request_path) | 609 ErrorExit("Error accessing url %s" % request_path) |
611 else: | 610 else: |
612 return None | 611 return None |
613 | 612 |
614 | 613 |
615 def GetIssueDescription(issue): | 614 def GetIssueDescription(issue): |
616 """Returns the issue description from Rietveld.""" | 615 """Returns the issue description from Rietveld.""" |
617 return SendToRietveld("/%d/description" % issue) | 616 return SendToRietveld("/%d/description" % issue) |
618 | 617 |
619 | 618 |
620 def Opened(show_unknown_files): | 619 def Opened(show_unknown_files): |
621 """Prints a list of modified files in the current directory down.""" | 620 """Prints a list of modified files in the current directory down.""" |
622 files = GetModifiedFiles() | 621 files = GetModifiedFiles() |
623 cl_keys = files.keys() | 622 cl_keys = files.keys() |
624 cl_keys.sort() | 623 cl_keys.sort() |
625 for cl_name in cl_keys: | 624 for cl_name in cl_keys: |
626 if not cl_name: | 625 if not cl_name: |
627 continue | 626 continue |
628 note = "" | 627 note = "" |
629 change_info = ChangeInfo.Load(cl_name, GetRepositoryRoot(), | 628 change_info = ChangeInfo.Load(cl_name, GetRepositoryRoot(), |
630 fail_on_not_found=True, update_status=False) | 629 fail_on_not_found=True, update_status=False) |
631 if len(change_info.GetFiles()) != len(files[cl_name]): | 630 if len(change_info.GetFiles()) != len(files[cl_name]): |
632 note = " (Note: this changelist contains files outside this directory)" | 631 note = " (Note: this changelist contains files outside this directory)" |
633 print "\n--- Changelist " + cl_name + note + ":" | 632 print "\n--- Changelist " + cl_name + note + ":" |
634 for file in files[cl_name]: | 633 for filename in files[cl_name]: |
635 print "".join(file) | 634 print "".join(filename) |
636 if show_unknown_files: | 635 if show_unknown_files: |
637 unknown_files = UnknownFiles([]) | 636 unknown_files = UnknownFiles([]) |
638 if (files.get('') or (show_unknown_files and len(unknown_files))): | 637 if (files.get('') or (show_unknown_files and len(unknown_files))): |
639 print "\n--- Not in any changelist:" | 638 print "\n--- Not in any changelist:" |
640 for file in files.get('', []): | 639 for item in files.get('', []): |
641 print "".join(file) | 640 print "".join(item) |
642 if show_unknown_files: | 641 if show_unknown_files: |
643 for file in unknown_files: | 642 for filename in unknown_files: |
644 print "? %s" % file | 643 print "? %s" % filename |
645 | 644 |
646 | 645 |
647 def Help(argv=None): | 646 def Help(argv=None): |
648 if argv: | 647 if argv: |
649 if argv[0] == 'try': | 648 if argv[0] == 'try': |
650 TryChange(None, ['--help'], swallow_exception=False) | 649 TryChange(None, ['--help'], swallow_exception=False) |
651 return | 650 return |
652 if argv[0] == 'upload': | 651 if argv[0] == 'upload': |
653 upload.RealMain(['upload.py', '--help']) | 652 upload.RealMain(['upload.py', '--help']) |
654 return | 653 return |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
740 given root. If no root directory is provided, the repository root will be | 739 given root. If no root directory is provided, the repository root will be |
741 used. | 740 used. |
742 """ | 741 """ |
743 previous_cwd = os.getcwd() | 742 previous_cwd = os.getcwd() |
744 if root is None: | 743 if root is None: |
745 os.chdir(GetRepositoryRoot()) | 744 os.chdir(GetRepositoryRoot()) |
746 else: | 745 else: |
747 os.chdir(root) | 746 os.chdir(root) |
748 | 747 |
749 diff = [] | 748 diff = [] |
750 for file in files: | 749 for filename in files: |
751 # Use svn info output instead of os.path.isdir because the latter fails | 750 # Use svn info output instead of os.path.isdir because the latter fails |
752 # when the file is deleted. | 751 # when the file is deleted. |
753 if gclient_scm.CaptureSVNInfo(file).get("Node Kind") in ("dir", | 752 if gclient_scm.CaptureSVNInfo(filename).get("Node Kind") in ("dir", |
754 "directory"): | 753 "directory"): |
755 continue | 754 continue |
756 # If the user specified a custom diff command in their svn config file, | 755 # If the user specified a custom diff command in their svn config file, |
757 # then it'll be used when we do svn diff, which we don't want to happen | 756 # then it'll be used when we do svn diff, which we don't want to happen |
758 # since we want the unified diff. Using --diff-cmd=diff doesn't always | 757 # since we want the unified diff. Using --diff-cmd=diff doesn't always |
759 # work, since they can have another diff executable in their path that | 758 # work, since they can have another diff executable in their path that |
760 # gives different line endings. So we use a bogus temp directory as the | 759 # gives different line endings. So we use a bogus temp directory as the |
761 # config directory, which gets around these problems. | 760 # config directory, which gets around these problems. |
762 if sys.platform.startswith("win"): | 761 if sys.platform.startswith("win"): |
763 parent_dir = tempfile.gettempdir() | 762 parent_dir = tempfile.gettempdir() |
764 else: | 763 else: |
765 parent_dir = sys.path[0] # tempdir is not secure. | 764 parent_dir = sys.path[0] # tempdir is not secure. |
766 bogus_dir = os.path.join(parent_dir, "temp_svn_config") | 765 bogus_dir = os.path.join(parent_dir, "temp_svn_config") |
767 if not os.path.exists(bogus_dir): | 766 if not os.path.exists(bogus_dir): |
768 os.mkdir(bogus_dir) | 767 os.mkdir(bogus_dir) |
769 output = RunShell(["svn", "diff", "--config-dir", bogus_dir, file]) | 768 output = RunShell(["svn", "diff", "--config-dir", bogus_dir, filename]) |
770 if output: | 769 if output: |
771 diff.append(output) | 770 diff.append(output) |
772 elif IsSVNMoved(file): | 771 elif IsSVNMoved(filename): |
773 # svn diff on a mv/cp'd file outputs nothing. | 772 # svn diff on a mv/cp'd file outputs nothing. |
774 # We put in an empty Index entry so upload.py knows about them. | 773 # We put in an empty Index entry so upload.py knows about them. |
775 diff.append("\nIndex: %s\n" % file) | 774 diff.append("\nIndex: %s\n" % filename) |
776 else: | 775 else: |
777 # The file is not modified anymore. It should be removed from the set. | 776 # The file is not modified anymore. It should be removed from the set. |
778 pass | 777 pass |
779 os.chdir(previous_cwd) | 778 os.chdir(previous_cwd) |
780 return "".join(diff) | 779 return "".join(diff) |
781 | 780 |
782 | 781 |
783 | 782 |
784 def OptionallyDoPresubmitChecks(change_info, committing, args): | 783 def OptionallyDoPresubmitChecks(change_info, committing, args): |
785 if FilterFlag(args, "--no_presubmit") or FilterFlag(args, "--force"): | 784 if FilterFlag(args, "--no_presubmit") or FilterFlag(args, "--force"): |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
943 return | 942 return |
944 | 943 |
945 # We face a problem with svn here: Let's say change 'bleh' modifies | 944 # We face a problem with svn here: Let's say change 'bleh' modifies |
946 # svn:ignore on dir1\. but another unrelated change 'pouet' modifies | 945 # svn:ignore on dir1\. but another unrelated change 'pouet' modifies |
947 # dir1\foo.cc. When the user `gcl commit bleh`, foo.cc is *also committed*. | 946 # dir1\foo.cc. When the user `gcl commit bleh`, foo.cc is *also committed*. |
948 # The only fix is to use --non-recursive but that has its issues too: | 947 # The only fix is to use --non-recursive but that has its issues too: |
949 # Let's say if dir1 is deleted, --non-recursive must *not* be used otherwise | 948 # Let's say if dir1 is deleted, --non-recursive must *not* be used otherwise |
950 # you'll get "svn: Cannot non-recursively commit a directory deletion of a | 949 # you'll get "svn: Cannot non-recursively commit a directory deletion of a |
951 # directory with child nodes". Yay... | 950 # directory with child nodes". Yay... |
952 commit_cmd = ["svn", "commit"] | 951 commit_cmd = ["svn", "commit"] |
953 filename = '' | |
954 if change_info.issue: | 952 if change_info.issue: |
955 # Get the latest description from Rietveld. | 953 # Get the latest description from Rietveld. |
956 change_info.description = GetIssueDescription(change_info.issue) | 954 change_info.description = GetIssueDescription(change_info.issue) |
957 | 955 |
958 commit_message = change_info.description.replace('\r\n', '\n') | 956 commit_message = change_info.description.replace('\r\n', '\n') |
959 if change_info.issue: | 957 if change_info.issue: |
960 commit_message += ('\nReview URL: http://%s/%d' % | 958 commit_message += ('\nReview URL: http://%s/%d' % |
961 (GetCodeReviewSetting("CODE_REVIEW_SERVER"), | 959 (GetCodeReviewSetting("CODE_REVIEW_SERVER"), |
962 change_info.issue)) | 960 change_info.issue)) |
963 | 961 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1078 # Update the Rietveld issue with the new description. | 1076 # Update the Rietveld issue with the new description. |
1079 change_info.UpdateRietveldDescription() | 1077 change_info.UpdateRietveldDescription() |
1080 | 1078 |
1081 new_cl_files = [] | 1079 new_cl_files = [] |
1082 for line in cl_files_text.splitlines(): | 1080 for line in cl_files_text.splitlines(): |
1083 if not len(line): | 1081 if not len(line): |
1084 continue | 1082 continue |
1085 if line.startswith("---"): | 1083 if line.startswith("---"): |
1086 break | 1084 break |
1087 status = line[:7] | 1085 status = line[:7] |
1088 file = line[7:] | 1086 filename = line[7:] |
1089 new_cl_files.append((status, file)) | 1087 new_cl_files.append((status, filename)) |
1090 | 1088 |
1091 if (not len(change_info._files)) and (not change_info.issue) and \ | 1089 if (not len(change_info._files)) and (not change_info.issue) and \ |
1092 (not len(new_description) and (not new_cl_files)): | 1090 (not len(new_description) and (not new_cl_files)): |
1093 ErrorExit("Empty changelist not saved") | 1091 ErrorExit("Empty changelist not saved") |
1094 | 1092 |
1095 change_info._files = new_cl_files | 1093 change_info._files = new_cl_files |
1096 | 1094 |
1097 change_info.Save() | 1095 change_info.Save() |
1098 print change_info.name + " changelist saved." | 1096 print change_info.name + " changelist saved." |
1099 if change_info.MissingTests(): | 1097 if change_info.MissingTests(): |
(...skipping 19 matching lines...) Expand all Loading... |
1119 filenames = cpplint.ParseArguments(args + change_info.GetFileNames()) | 1117 filenames = cpplint.ParseArguments(args + change_info.GetFileNames()) |
1120 | 1118 |
1121 white_list = GetCodeReviewSetting("LINT_REGEX") | 1119 white_list = GetCodeReviewSetting("LINT_REGEX") |
1122 if not white_list: | 1120 if not white_list: |
1123 white_list = DEFAULT_LINT_REGEX | 1121 white_list = DEFAULT_LINT_REGEX |
1124 white_regex = re.compile(white_list) | 1122 white_regex = re.compile(white_list) |
1125 black_list = GetCodeReviewSetting("LINT_IGNORE_REGEX") | 1123 black_list = GetCodeReviewSetting("LINT_IGNORE_REGEX") |
1126 if not black_list: | 1124 if not black_list: |
1127 black_list = DEFAULT_LINT_IGNORE_REGEX | 1125 black_list = DEFAULT_LINT_IGNORE_REGEX |
1128 black_regex = re.compile(black_list) | 1126 black_regex = re.compile(black_list) |
1129 for file in filenames: | 1127 for filename in filenames: |
1130 if white_regex.match(file): | 1128 if white_regex.match(filename): |
1131 if black_regex.match(file): | 1129 if black_regex.match(filename): |
1132 print "Ignoring file %s" % file | 1130 print "Ignoring file %s" % filename |
1133 else: | 1131 else: |
1134 cpplint.ProcessFile(file, cpplint._cpplint_state.verbose_level) | 1132 cpplint.ProcessFile(filename, cpplint._cpplint_state.verbose_level) |
1135 else: | 1133 else: |
1136 print "Skipping file %s" % file | 1134 print "Skipping file %s" % filename |
1137 | 1135 |
1138 print "Total errors found: %d\n" % cpplint._cpplint_state.error_count | 1136 print "Total errors found: %d\n" % cpplint._cpplint_state.error_count |
1139 os.chdir(previous_cwd) | 1137 os.chdir(previous_cwd) |
1140 | 1138 |
1141 | 1139 |
1142 def DoPresubmitChecks(change_info, committing, may_prompt): | 1140 def DoPresubmitChecks(change_info, committing, may_prompt): |
1143 """Imports presubmit, then calls presubmit.DoPresubmitChecks.""" | 1141 """Imports presubmit, then calls presubmit.DoPresubmitChecks.""" |
1144 # Need to import here to avoid circular dependency. | 1142 # Need to import here to avoid circular dependency. |
1145 import presubmit_support | 1143 import presubmit_support |
1146 root_presubmit = GetCachedFile('PRESUBMIT.py', use_root=True) | 1144 root_presubmit = GetCachedFile('PRESUBMIT.py', use_root=True) |
(...skipping 13 matching lines...) Expand all Loading... |
1160 if not result and may_prompt: | 1158 if not result and may_prompt: |
1161 print "\nPresubmit errors, can't continue (use --no_presubmit to bypass)" | 1159 print "\nPresubmit errors, can't continue (use --no_presubmit to bypass)" |
1162 return result | 1160 return result |
1163 | 1161 |
1164 | 1162 |
1165 def Changes(): | 1163 def Changes(): |
1166 """Print all the changelists and their files.""" | 1164 """Print all the changelists and their files.""" |
1167 for cl in GetCLs(): | 1165 for cl in GetCLs(): |
1168 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True) | 1166 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True) |
1169 print "\n--- Changelist " + change_info.name + ":" | 1167 print "\n--- Changelist " + change_info.name + ":" |
1170 for file in change_info.GetFiles(): | 1168 for filename in change_info.GetFiles(): |
1171 print "".join(file) | 1169 print "".join(filename) |
1172 | 1170 |
1173 | 1171 |
1174 def DeleteEmptyChangeLists(): | 1172 def DeleteEmptyChangeLists(): |
1175 """Delete all changelists that have no files.""" | 1173 """Delete all changelists that have no files.""" |
1176 print "\n--- Deleting:" | 1174 print "\n--- Deleting:" |
1177 for cl in GetCLs(): | 1175 for cl in GetCLs(): |
1178 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True) | 1176 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True) |
1179 if not len(change_info._files): | 1177 if not len(change_info._files): |
1180 print change_info.name | 1178 print change_info.name |
1181 change_info.Delete() | 1179 change_info.Delete() |
(...skipping 10 matching lines...) Expand all Loading... |
1192 try: | 1190 try: |
1193 # Create the directories where we store information about changelists if it | 1191 # Create the directories where we store information about changelists if it |
1194 # doesn't exist. | 1192 # doesn't exist. |
1195 if not os.path.exists(GetInfoDir()): | 1193 if not os.path.exists(GetInfoDir()): |
1196 os.mkdir(GetInfoDir()) | 1194 os.mkdir(GetInfoDir()) |
1197 if not os.path.exists(GetChangesDir()): | 1195 if not os.path.exists(GetChangesDir()): |
1198 os.mkdir(GetChangesDir()) | 1196 os.mkdir(GetChangesDir()) |
1199 # For smooth upgrade support, move the files in GetInfoDir() to | 1197 # For smooth upgrade support, move the files in GetInfoDir() to |
1200 # GetChangesDir(). | 1198 # GetChangesDir(). |
1201 # TODO(maruel): Remove this code in August 2009. | 1199 # TODO(maruel): Remove this code in August 2009. |
1202 for file in os.listdir(unicode(GetInfoDir())): | 1200 for filename in os.listdir(unicode(GetInfoDir())): |
1203 file_path = os.path.join(unicode(GetInfoDir()), file) | 1201 file_path = os.path.join(unicode(GetInfoDir()), filename) |
1204 if os.path.isfile(file_path) and file != CODEREVIEW_SETTINGS_FILE: | 1202 if os.path.isfile(file_path) and filename != CODEREVIEW_SETTINGS_FILE: |
1205 shutil.move(file_path, GetChangesDir()) | 1203 shutil.move(file_path, GetChangesDir()) |
1206 if not os.path.exists(GetCacheDir()): | 1204 if not os.path.exists(GetCacheDir()): |
1207 os.mkdir(GetCacheDir()) | 1205 os.mkdir(GetCacheDir()) |
1208 except gclient_utils.Error: | 1206 except gclient_utils.Error: |
1209 # Will throw an exception if not run in a svn checkout. | 1207 # Will throw an exception if not run in a svn checkout. |
1210 pass | 1208 pass |
1211 | 1209 |
1212 # Commands that don't require an argument. | 1210 # Commands that don't require an argument. |
1213 command = argv[1] | 1211 command = argv[1] |
1214 if command == "opened" or command == "status": | 1212 if command == "opened" or command == "status": |
1215 Opened(command == "status") | 1213 Opened(command == "status") |
1216 return 0 | 1214 return 0 |
1217 if command == "nothave": | 1215 if command == "nothave": |
1218 unknown_files = UnknownFiles(argv[2:]) | 1216 __pychecker__ = 'no-returnvalues' |
1219 for file in unknown_files: | 1217 for filename in UnknownFiles(argv[2:]): |
1220 print "? " + "".join(file) | 1218 print "? " + "".join(filename) |
1221 return 0 | 1219 return 0 |
1222 if command == "changes": | 1220 if command == "changes": |
1223 Changes() | 1221 Changes() |
1224 return 0 | 1222 return 0 |
1225 if command == "help": | 1223 if command == "help": |
1226 Help(argv[2:]) | 1224 Help(argv[2:]) |
1227 return 0 | 1225 return 0 |
1228 if command == "diff" and len(argv) == 2: | 1226 if command == "diff" and len(argv) == 2: |
1229 files = GetFilesNotInCL() | 1227 files = GetFilesNotInCL() |
1230 print GenerateDiff([x[1] for x in files]) | 1228 print GenerateDiff([x[1] for x in files]) |
1231 return 0 | 1229 return 0 |
1232 if command == "settings": | 1230 if command == "settings": |
1233 ignore = GetCodeReviewSetting("UNKNOWN"); | 1231 # Force load settings |
| 1232 GetCodeReviewSetting("UNKNOWN"); |
1234 del CODEREVIEW_SETTINGS['__just_initialized'] | 1233 del CODEREVIEW_SETTINGS['__just_initialized'] |
1235 print '\n'.join(("%s: %s" % (str(k), str(v)) | 1234 print '\n'.join(("%s: %s" % (str(k), str(v)) |
1236 for (k,v) in CODEREVIEW_SETTINGS.iteritems())) | 1235 for (k,v) in CODEREVIEW_SETTINGS.iteritems())) |
1237 return 0 | 1236 return 0 |
1238 if command == "deleteempties": | 1237 if command == "deleteempties": |
1239 DeleteEmptyChangeLists() | 1238 DeleteEmptyChangeLists() |
1240 return 0 | 1239 return 0 |
1241 | 1240 |
1242 if command == "change": | 1241 if command == "change": |
1243 if len(argv) == 2: | 1242 if len(argv) == 2: |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1294 return 0 | 1293 return 0 |
1295 args =["svn", command] | 1294 args =["svn", command] |
1296 root = GetRepositoryRoot() | 1295 root = GetRepositoryRoot() |
1297 args.extend([os.path.join(root, x) for x in change_info.GetFileNames()]) | 1296 args.extend([os.path.join(root, x) for x in change_info.GetFileNames()]) |
1298 RunShell(args, True) | 1297 RunShell(args, True) |
1299 return 0 | 1298 return 0 |
1300 | 1299 |
1301 | 1300 |
1302 if __name__ == "__main__": | 1301 if __name__ == "__main__": |
1303 sys.exit(main()) | 1302 sys.exit(main()) |
OLD | NEW |