| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 """Commit queue executable. | 5 """Commit queue executable. |
| 6 | 6 |
| 7 Reuse Rietveld and the Chromium Try Server to process and automatically commit | 7 Reuse Rietveld and the Chromium Try Server to process and automatically commit |
| 8 patches. | 8 patches. |
| 9 """ | 9 """ |
| 10 | 10 |
| 11 import logging | 11 import logging |
| 12 import logging.handlers | 12 import logging.handlers |
| 13 import optparse | 13 import optparse |
| 14 import os | 14 import os |
| 15 import signal | 15 import signal |
| 16 import sys | 16 import sys |
| 17 import time | 17 import time |
| 18 import traceback | |
| 19 | 18 |
| 20 import find_depot_tools # pylint: disable=W0611 | 19 import find_depot_tools # pylint: disable=W0611 |
| 21 import checkout | 20 import checkout |
| 22 import fix_encoding | 21 import fix_encoding |
| 23 import rietveld | 22 import rietveld |
| 24 import subprocess2 | 23 import subprocess2 |
| 25 | 24 |
| 26 import async_push | 25 import async_push |
| 27 import cq_alerts | 26 import cq_alerts |
| 28 import creds | 27 import creds |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 def AlertOnUncleanCheckout(): | 119 def AlertOnUncleanCheckout(): |
| 121 """Sends an alert if the cq is running live with local edits.""" | 120 """Sends an alert if the cq is running live with local edits.""" |
| 122 diff = subprocess2.capture(['gclient', 'diff'], cwd=ROOT_DIR).strip() | 121 diff = subprocess2.capture(['gclient', 'diff'], cwd=ROOT_DIR).strip() |
| 123 if diff: | 122 if diff: |
| 124 cq_alerts.SendAlert( | 123 cq_alerts.SendAlert( |
| 125 'CQ running with local diff.', | 124 'CQ running with local diff.', |
| 126 ('Ruh-roh! Commit queue was started with an unclean checkout.\n\n' | 125 ('Ruh-roh! Commit queue was started with an unclean checkout.\n\n' |
| 127 '$ gclient diff\n%s' % diff)) | 126 '$ gclient diff\n%s' % diff)) |
| 128 | 127 |
| 129 | 128 |
| 129 def SetupLogging(options): |
| 130 """Configures the logging module.""" |
| 131 logging.getLogger().setLevel(logging.DEBUG) |
| 132 if options.verbose: |
| 133 level = logging.DEBUG |
| 134 else: |
| 135 level = logging.INFO |
| 136 console_logging = logging.StreamHandler() |
| 137 console_logging.setFormatter(logging.Formatter( |
| 138 '%(asctime)s %(levelname)7s %(message)s')) |
| 139 console_logging.setLevel(level) |
| 140 logging.getLogger().addHandler(console_logging) |
| 141 |
| 142 log_directory = 'logs-' + options.project |
| 143 if not os.path.exists(log_directory): |
| 144 os.mkdir(log_directory) |
| 145 |
| 146 logging_rotating_file = logging.handlers.RotatingFileHandler( |
| 147 filename=os.path.join(log_directory, 'commit_queue.log'), |
| 148 maxBytes= 10*1024*1024, |
| 149 backupCount=50) |
| 150 logging_rotating_file.setLevel(logging.DEBUG) |
| 151 logging_rotating_file.setFormatter(logging.Formatter( |
| 152 '%(asctime)s %(levelname)-8s %(module)15s(%(lineno)4d): %(message)s')) |
| 153 logging.getLogger().addHandler(logging_rotating_file) |
| 154 |
| 155 |
| 130 def main(): | 156 def main(): |
| 131 parser = optparse.OptionParser( | 157 parser = optparse.OptionParser( |
| 132 description=sys.modules['__main__'].__doc__) | 158 description=sys.modules['__main__'].__doc__) |
| 133 project_choices = projects.supported_projects() | 159 project_choices = projects.supported_projects() |
| 134 parser.add_option('-v', '--verbose', action='store_true') | 160 parser.add_option('-v', '--verbose', action='store_true') |
| 135 parser.add_option( | 161 parser.add_option( |
| 136 '--no-dry-run', | 162 '--no-dry-run', |
| 137 action='store_false', | 163 action='store_false', |
| 138 dest='dry_run', | 164 dest='dry_run', |
| 139 default=True, | 165 default=True, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 '--user', | 200 '--user', |
| 175 default='commit-bot@chromium.org', | 201 default='commit-bot@chromium.org', |
| 176 help='User to use instead of %default') | 202 help='User to use instead of %default') |
| 177 options, args = parser.parse_args() | 203 options, args = parser.parse_args() |
| 178 if args: | 204 if args: |
| 179 parser.error('Unsupported args: %s' % args) | 205 parser.error('Unsupported args: %s' % args) |
| 180 if not options.project: | 206 if not options.project: |
| 181 parser.error('Need to pass a valid project to --project.\nOptions are: %s' % | 207 parser.error('Need to pass a valid project to --project.\nOptions are: %s' % |
| 182 ', '.join(project_choices)) | 208 ', '.join(project_choices)) |
| 183 | 209 |
| 184 logging.getLogger().setLevel(logging.DEBUG) | 210 SetupLogging(options) |
| 185 if options.verbose: | |
| 186 level = logging.DEBUG | |
| 187 else: | |
| 188 level = logging.INFO | |
| 189 console_logging = logging.StreamHandler() | |
| 190 console_logging.setFormatter(logging.Formatter( | |
| 191 '%(asctime)s %(levelname)7s %(message)s')) | |
| 192 console_logging.setLevel(level) | |
| 193 logging.getLogger().addHandler(console_logging) | |
| 194 | |
| 195 log_directory = 'logs-' + options.project | |
| 196 if not os.path.exists(log_directory): | |
| 197 os.mkdir(log_directory) | |
| 198 | |
| 199 logging_rotating_file = logging.handlers.RotatingFileHandler( | |
| 200 filename=os.path.join(log_directory, 'commit_queue.log'), | |
| 201 maxBytes= 10*1024*1024, | |
| 202 backupCount=50) | |
| 203 logging_rotating_file.setLevel(logging.DEBUG) | |
| 204 logging_rotating_file.setFormatter(logging.Formatter( | |
| 205 '%(asctime)s %(levelname)-8s %(module)15s(%(lineno)4d): %(message)s')) | |
| 206 logging.getLogger().addHandler(logging_rotating_file) | |
| 207 | |
| 208 try: | 211 try: |
| 209 work_dir = os.path.join(ROOT_DIR, 'workdir') | 212 work_dir = os.path.join(ROOT_DIR, 'workdir') |
| 210 # Use our specific subversion config. | 213 # Use our specific subversion config. |
| 211 checkout.SvnMixIn.svn_config = checkout.SvnConfig( | 214 checkout.SvnMixIn.svn_config = checkout.SvnConfig( |
| 212 os.path.join(ROOT_DIR, 'subversion_config')) | 215 os.path.join(ROOT_DIR, 'subversion_config')) |
| 213 | 216 |
| 214 url = 'https://chromiumcodereview.appspot.com' | 217 url = 'https://chromiumcodereview.appspot.com' |
| 215 gaia_creds = creds.Credentials(os.path.join(work_dir, '.gaia_pwd')) | 218 gaia_creds = creds.Credentials(os.path.join(work_dir, '.gaia_pwd')) |
| 216 if options.dry_run: | 219 if options.dry_run: |
| 217 logging.debug('Dry run - skipping SCM check.') | 220 logging.debug('Dry run - skipping SCM check.') |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 329 break | 332 break |
| 330 if sys.stdout.isatty(): | 333 if sys.stdout.isatty(): |
| 331 sys.stdout.write('Sleeping for %1.1f seconds \r' % delay) | 334 sys.stdout.write('Sleeping for %1.1f seconds \r' % delay) |
| 332 sys.stdout.flush() | 335 sys.stdout.flush() |
| 333 time.sleep(min(delay, 0.1)) | 336 time.sleep(min(delay, 0.1)) |
| 334 now = time.time() | 337 now = time.time() |
| 335 if sys.stdout.isatty(): | 338 if sys.stdout.isatty(): |
| 336 sys.stdout.write('Running (please do not interrupt) \r') | 339 sys.stdout.write('Running (please do not interrupt) \r') |
| 337 sys.stdout.flush() | 340 sys.stdout.flush() |
| 338 next_loop = time.time() + options.poll_interval | 341 next_loop = time.time() + options.poll_interval |
| 342 except: # Catch all fatal exit conditions. |
| 343 logging.exception('CQ loop terminating') |
| 344 raise |
| 339 finally: | 345 finally: |
| 340 print >> sys.stderr, 'Saving db... ' | 346 logging.warning('Saving db...') |
| 341 pc.save(db_path) | 347 pc.save(db_path) |
| 342 pc.close() | 348 pc.close() |
| 343 print >> sys.stderr, 'Done! ' | 349 logging.warning('db save successful.') |
| 344 except KeyboardInterrupt as e: | 350 except KeyboardInterrupt as e: |
| 345 print 'Bye bye' | 351 print 'Bye bye' |
| 346 # 23 is an arbitrary value to signal loop.sh that it must stop looping. | 352 # 23 is an arbitrary value to signal loop.sh that it must stop looping. |
| 347 return 23 | 353 return 23 |
| 348 except SystemExit as e: | |
| 349 traceback.print_exc() | |
| 350 print >> sys.stderr, ('Tried to exit: %s', e) | |
| 351 return e.code | |
| 352 except errors.ConfigurationError as e: | 354 except errors.ConfigurationError as e: |
| 353 parser.error(str(e)) | 355 parser.error(str(e)) |
| 354 return 1 | 356 return 1 |
| 355 return 0 | 357 return 0 |
| 356 | 358 |
| 357 | 359 |
| 358 if __name__ == '__main__': | 360 if __name__ == '__main__': |
| 359 fix_encoding.fix_encoding() | 361 fix_encoding.fix_encoding() |
| 360 sys.exit(main()) | 362 sys.exit(main()) |
| OLD | NEW |