main.py revision 608d8bcdfc1762cde31efdf02a6379a06d7964b1
1""" 2Main program for 2to3. 3""" 4 5import sys 6import os 7import logging 8import shutil 9import optparse 10 11from . import refactor 12 13class StdoutRefactoringTool(refactor.MultiprocessRefactoringTool): 14 """ 15 Prints output to stdout. 16 """ 17 18 def __init__(self, fixers, options, explicit, nobackups): 19 self.nobackups = nobackups 20 super(StdoutRefactoringTool, self).__init__(fixers, options, explicit) 21 22 def log_error(self, msg, *args, **kwargs): 23 self.errors.append((msg, args, kwargs)) 24 self.logger.error(msg, *args, **kwargs) 25 26 def write_file(self, new_text, filename, old_text): 27 if not self.nobackups: 28 # Make backup 29 backup = filename + ".bak" 30 if os.path.lexists(backup): 31 try: 32 os.remove(backup) 33 except os.error as err: 34 self.log_message("Can't remove backup %s", backup) 35 try: 36 os.rename(filename, backup) 37 except os.error as err: 38 self.log_message("Can't rename %s to %s", filename, backup) 39 # Actually write the new file 40 super(StdoutRefactoringTool, self).write_file(new_text, 41 filename, old_text) 42 if not self.nobackups: 43 shutil.copymode(backup, filename) 44 45 def print_output(self, lines): 46 for line in lines: 47 print(line) 48 49 50def main(fixer_pkg, args=None): 51 """Main program. 52 53 Args: 54 fixer_pkg: the name of a package where the fixers are located. 55 args: optional; a list of command line arguments. If omitted, 56 sys.argv[1:] is used. 57 58 Returns a suggested exit status (0, 1, 2). 59 """ 60 # Set up option parser 61 parser = optparse.OptionParser(usage="2to3 [options] file|dir ...") 62 parser.add_option("-d", "--doctests_only", action="store_true", 63 help="Fix up doctests only") 64 parser.add_option("-f", "--fix", action="append", default=[], 65 help="Each FIX specifies a transformation; default: all") 66 parser.add_option("-j", "--processes", action="store", default=1, 67 type="int", help="Run 2to3 concurrently") 68 parser.add_option("-x", "--nofix", action="append", default=[], 69 help="Prevent a fixer from being run.") 70 parser.add_option("-l", "--list-fixes", action="store_true", 71 help="List available transformations (fixes/fix_*.py)") 72 parser.add_option("-p", "--print-function", action="store_true", 73 help="Modify the grammar so that print() is a function") 74 parser.add_option("-v", "--verbose", action="store_true", 75 help="More verbose logging") 76 parser.add_option("-w", "--write", action="store_true", 77 help="Write back modified files") 78 parser.add_option("-n", "--nobackups", action="store_true", default=False, 79 help="Don't write backups for modified files.") 80 81 # Parse command line arguments 82 refactor_stdin = False 83 options, args = parser.parse_args(args) 84 if not options.write and options.nobackups: 85 parser.error("Can't use -n without -w") 86 if options.list_fixes: 87 print("Available transformations for the -f/--fix option:") 88 for fixname in refactor.get_all_fix_names(fixer_pkg): 89 print(fixname) 90 if not args: 91 return 0 92 if not args: 93 print("At least one file or directory argument required.", file=sys.stderr) 94 print("Use --help to show usage.", file=sys.stderr) 95 return 2 96 if "-" in args: 97 refactor_stdin = True 98 if options.write: 99 print("Can't write to stdin.", file=sys.stderr) 100 return 2 101 102 # Set up logging handler 103 level = logging.DEBUG if options.verbose else logging.INFO 104 logging.basicConfig(format='%(name)s: %(message)s', level=level) 105 106 # Initialize the refactoring tool 107 rt_opts = {"print_function" : options.print_function} 108 avail_fixes = set(refactor.get_fixers_from_package(fixer_pkg)) 109 unwanted_fixes = set(fixer_pkg + ".fix_" + fix for fix in options.nofix) 110 explicit = set() 111 if options.fix: 112 all_present = False 113 for fix in options.fix: 114 if fix == "all": 115 all_present = True 116 else: 117 explicit.add(fixer_pkg + ".fix_" + fix) 118 requested = avail_fixes.union(explicit) if all_present else explicit 119 else: 120 requested = avail_fixes.union(explicit) 121 fixer_names = requested.difference(unwanted_fixes) 122 rt = StdoutRefactoringTool(sorted(fixer_names), rt_opts, sorted(explicit), 123 options.nobackups) 124 125 # Refactor all files and directories passed as arguments 126 if not rt.errors: 127 if refactor_stdin: 128 rt.refactor_stdin() 129 else: 130 try: 131 rt.refactor(args, options.write, options.doctests_only, 132 options.processes) 133 except refactor.MultiprocessingUnsupported: 134 assert options.processes > 1 135 print >> sys.stderr, "Sorry, -j isn't " \ 136 "supported on this platform." 137 return 1 138 rt.summarize() 139 140 # Return error status (0 if rt.errors is zero) 141 return int(bool(rt.errors)) 142