1# Copyright 2014 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import argparse 6import lib2to3.refactor 7 8from webkitpy.common.system.systemhost import SystemHost 9from webkitpy.thirdparty import autopep8 10 11 12def parse_args(args=None): 13 parser = argparse.ArgumentParser() 14 parser.add_argument('--chromium', action='store_const', dest='style', const='chromium', default='blink', 15 help="Format according to Chromium's Python coding styles instead of Blink's.") 16 parser.add_argument('--no-backups', action='store_false', default=True, dest='backup', 17 help='Do not back up files before overwriting them.') 18 parser.add_argument('-j', '--jobs', metavar='n', type=int, default=0, 19 help='Number of parallel jobs; match CPU count if less than 1.') 20 parser.add_argument('files', nargs='*', default=['-'], 21 help="files to format or '-' for standard in") 22 parser.add_argument('--double-quote-strings', action='store_const', dest='quoting', const='double', default='single', 23 help='Rewrite string literals to use double quotes instead of single quotes.') 24 parser.add_argument('--no-autopep8', action='store_true', 25 help='Skip the autopep8 code-formatting step.') 26 parser.add_argument('--leave-strings-alone', action='store_true', 27 help='Do not reformat string literals to use a consistent quote style.') 28 return parser.parse_args(args=args) 29 30 31def main(host=None, args=None): 32 options = parse_args(args) 33 if options.no_autopep8: 34 options.style = None 35 36 if options.leave_strings_alone: 37 options.quoting = None 38 39 autopep8_options = _autopep8_options_for_style(options.style) 40 fixers = _fixers_for_quoting(options.quoting) 41 42 if options.files == ['-']: 43 host = host or SystemHost() 44 host.print_(reformat_source(host.stdin.read(), autopep8_options, fixers, '<stdin>'), end='') 45 return 46 47 # We create the arglist before checking if we need to create a Host, because a 48 # real host is non-picklable and can't be passed to host.executive.map(). 49 50 arglist = [(host, name, autopep8_options, fixers, options.backup) for name in options.files] 51 host = host or SystemHost() 52 53 host.executive.map(_reformat_thunk, arglist, processes=options.jobs) 54 55 56def _autopep8_options_for_style(style): 57 return { 58 None: [], 59 'blink': autopep8.parse_args(['--aggressive', 60 '--max-line-length', '132', 61 '--indent-size', '4', 62 '']), 63 'chromium': autopep8.parse_args(['--aggressive', 64 '--max-line-length', '80', 65 '--indent-size', '2', 66 '']), 67 }.get(style) 68 69 70def _fixers_for_quoting(quoting): 71 return { 72 None: [], 73 'double': ['webkitpy.formatter.fix_double_quote_strings'], 74 'single': ['webkitpy.formatter.fix_single_quote_strings'], 75 }.get(quoting) 76 77 78def _reformat_thunk(args): 79 reformat_file(*args) 80 81 82def reformat_file(host, name, autopep8_options, fixers, should_backup_file): 83 host = host or SystemHost() 84 source = host.filesystem.read_text_file(name) 85 dest = reformat_source(source, autopep8_options, fixers, name) 86 if dest != source: 87 if should_backup_file: 88 host.filesystem.write_text_file(name + '.bak', source) 89 host.filesystem.write_text_file(name, dest) 90 91 92def reformat_source(source, autopep8_options, fixers, name): 93 tmp_str = source 94 95 if autopep8_options: 96 tmp_str = autopep8.fix_code(tmp_str, autopep8_options) 97 98 if fixers: 99 tool = lib2to3.refactor.RefactoringTool(fixer_names=fixers, 100 explicit=fixers) 101 tmp_str = unicode(tool.refactor_string(tmp_str, name=name)) 102 103 return tmp_str 104