Chromium Code Reviews| 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 """Enables directory-specific presubmit checks to run at upload and/or commit. | 6 """Enables directory-specific presubmit checks to run at upload and/or commit. |
| 7 """ | 7 """ |
| 8 | 8 |
| 9 __version__ = '1.3.2' | 9 __version__ = '1.3.2' |
| 10 | 10 |
| 11 # TODO(joi) Add caching where appropriate/needed. The API is designed to allow | 11 # TODO(joi) Add caching where appropriate/needed. The API is designed to allow |
| 12 # caching (between all different invocations of presubmit scripts for a given | 12 # caching (between all different invocations of presubmit scripts for a given |
| 13 # change). We should add it as our presubmit scripts start feeling slow. | 13 # change). We should add it as our presubmit scripts start feeling slow. |
| 14 | 14 |
| 15 import cPickle # Exposed through the API. | 15 import cPickle # Exposed through the API. |
| 16 import cStringIO # Exposed through the API. | 16 import cStringIO # Exposed through the API. |
| 17 import exceptions | 17 import exceptions |
| 18 import fnmatch | 18 import fnmatch |
| 19 import glob | 19 import glob |
| 20 import logging | 20 import logging |
| 21 import marshal # Exposed through the API. | 21 import marshal # Exposed through the API. |
| 22 import optparse | 22 import optparse |
| 23 import os # Somewhat exposed through the API. | 23 import os # Somewhat exposed through the API. |
| 24 import pickle # Exposed through the API. | 24 import pickle # Exposed through the API. |
| 25 import random | |
| 25 import re # Exposed through the API. | 26 import re # Exposed through the API. |
| 26 import subprocess # Exposed through the API. | 27 import subprocess # Exposed through the API. |
| 27 import sys # Parts exposed through API. | 28 import sys # Parts exposed through API. |
| 28 import tempfile # Exposed through the API. | 29 import tempfile # Exposed through the API. |
| 29 import traceback # Exposed through the API. | 30 import traceback # Exposed through the API. |
| 30 import types | 31 import types |
| 31 import unittest # Exposed through the API. | 32 import unittest # Exposed through the API. |
| 32 import urllib2 # Exposed through the API. | 33 import urllib2 # Exposed through the API. |
| 33 import warnings | 34 import warnings |
| 34 | 35 |
| 35 # Local imports. | 36 # Local imports. |
| 36 # TODO(joi) Would be cleaner to factor out utils in gcl to separate module, but | 37 # TODO(joi) Would be cleaner to factor out utils in gcl to separate module, but |
| 37 # for now it would only be a couple of functions so hardly worth it. | 38 # for now it would only be a couple of functions so hardly worth it. |
| 38 import gcl | 39 import gcl |
| 39 import gclient | 40 import gclient |
| 40 import presubmit_canned_checks | 41 import presubmit_canned_checks |
| 41 | 42 |
| 42 | 43 |
| 44 # Ask for feedback only once in program lifetime. | |
| 45 _ASKED_FOR_FEEDBACK = False | |
| 46 | |
| 47 | |
| 43 class NotImplementedException(Exception): | 48 class NotImplementedException(Exception): |
| 44 """We're leaving placeholders in a bunch of places to remind us of the | 49 """We're leaving placeholders in a bunch of places to remind us of the |
| 45 design of the API, but we have not implemented all of it yet. Implement as | 50 design of the API, but we have not implemented all of it yet. Implement as |
| 46 the need arises. | 51 the need arises. |
| 47 """ | 52 """ |
| 48 pass | 53 pass |
| 49 | 54 |
| 50 | 55 |
| 51 def normpath(path): | 56 def normpath(path): |
| 52 '''Version of os.path.normpath that also changes backward slashes to | 57 '''Version of os.path.normpath that also changes backward slashes to |
| (...skipping 720 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 773 | 778 |
| 774 Args: | 779 Args: |
| 775 change: The Change object. | 780 change: The Change object. |
| 776 committing: True if 'gcl commit' is running, False if 'gcl upload' is. | 781 committing: True if 'gcl commit' is running, False if 'gcl upload' is. |
| 777 verbose: Prints debug info. | 782 verbose: Prints debug info. |
| 778 output_stream: A stream to write output from presubmit tests to. | 783 output_stream: A stream to write output from presubmit tests to. |
| 779 input_stream: A stream to read input from the user. | 784 input_stream: A stream to read input from the user. |
| 780 default_presubmit: A default presubmit script to execute in any case. | 785 default_presubmit: A default presubmit script to execute in any case. |
| 781 may_prompt: Enable (y/n) questions on warning or error. | 786 may_prompt: Enable (y/n) questions on warning or error. |
| 782 | 787 |
| 788 Warning: | |
| 789 If may_prompt is true, output_streeam SHOULD be sys.stdout and input_stream | |
|
Jói Sigurðsson
2009/06/25 21:19:28
output_streeam -> output_stream
| |
| 790 SHOULD be sys.stdin. | |
| 791 | |
| 783 Return: | 792 Return: |
| 784 True if execution can continue, False if not. | 793 True if execution can continue, False if not. |
| 785 """ | 794 """ |
| 786 presubmit_files = ListRelevantPresubmitFiles(change.AbsoluteLocalPaths(True), | 795 presubmit_files = ListRelevantPresubmitFiles(change.AbsoluteLocalPaths(True), |
| 787 change.RepositoryRoot()) | 796 change.RepositoryRoot()) |
| 788 if not presubmit_files and verbose: | 797 if not presubmit_files and verbose: |
| 789 output_stream.write("Warning, no presubmit.py found.\n") | 798 output_stream.write("Warning, no presubmit.py found.\n") |
| 790 results = [] | 799 results = [] |
| 791 executer = PresubmitExecuter(change, committing) | 800 executer = PresubmitExecuter(change, committing) |
| 792 if default_presubmit: | 801 if default_presubmit: |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 823 if not item._Handle(output_stream, input_stream, | 832 if not item._Handle(output_stream, input_stream, |
| 824 may_prompt=False): | 833 may_prompt=False): |
| 825 error_count += 1 | 834 error_count += 1 |
| 826 output_stream.write('\n') | 835 output_stream.write('\n') |
| 827 if not errors and warnings and may_prompt: | 836 if not errors and warnings and may_prompt: |
| 828 output_stream.write( | 837 output_stream.write( |
| 829 'There were presubmit warnings. Sure you want to continue? (y/N): ') | 838 'There were presubmit warnings. Sure you want to continue? (y/N): ') |
| 830 response = input_stream.readline() | 839 response = input_stream.readline() |
| 831 if response.strip().lower() != 'y': | 840 if response.strip().lower() != 'y': |
| 832 error_count += 1 | 841 error_count += 1 |
| 842 | |
| 843 global _ASKED_FOR_FEEDBACK | |
| 844 # Ask for feedback one time out of 5. | |
| 845 if (len(results) and random.randint(0, 4) == 0 and not _ASKED_FOR_FEEDBACK): | |
| 846 output_stream.write("Was the presubmit check useful? Please send feedback " | |
| 847 "& hate mail to maruel@chromium.org!\n") | |
| 848 _ASKED_FOR_FEEDBACK = True | |
| 833 return (error_count == 0) | 849 return (error_count == 0) |
| 834 | 850 |
| 835 | 851 |
| 836 def ScanSubDirs(mask, recursive): | 852 def ScanSubDirs(mask, recursive): |
| 837 if not recursive: | 853 if not recursive: |
| 838 return [x for x in glob.glob(mask) if '.svn' not in x and '.git' not in x] | 854 return [x for x in glob.glob(mask) if '.svn' not in x and '.git' not in x] |
| 839 else: | 855 else: |
| 840 results = [] | 856 results = [] |
| 841 for root, dirs, files in os.walk('.'): | 857 for root, dirs, files in os.walk('.'): |
| 842 if '.svn' in dirs: | 858 if '.svn' in dirs: |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 908 options.commit, | 924 options.commit, |
| 909 options.verbose, | 925 options.verbose, |
| 910 sys.stdout, | 926 sys.stdout, |
| 911 sys.stdin, | 927 sys.stdin, |
| 912 options.default_presubmit, | 928 options.default_presubmit, |
| 913 options.may_prompt) | 929 options.may_prompt) |
| 914 | 930 |
| 915 | 931 |
| 916 if __name__ == '__main__': | 932 if __name__ == '__main__': |
| 917 sys.exit(Main(sys.argv)) | 933 sys.exit(Main(sys.argv)) |
| OLD | NEW |