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 |