1ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh"""
2ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehMain program for 2to3.
3ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh"""
4ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
5ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom __future__ import with_statement
6ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
7ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport sys
8ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport os
9ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport difflib
10ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport logging
11ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport shutil
12ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport optparse
13ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
14ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom . import refactor
15ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
16ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
17ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef diff_texts(a, b, filename):
18ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """Return a unified diff of two strings."""
19ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    a = a.splitlines()
20ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    b = b.splitlines()
21ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    return difflib.unified_diff(a, b, filename, filename,
22ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                "(original)", "(refactored)",
23ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                lineterm="")
24ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
25ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
26ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass StdoutRefactoringTool(refactor.MultiprocessRefactoringTool):
27ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """
28ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    A refactoring tool that can avoid overwriting its input files.
29ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    Prints output to stdout.
30ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
31ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    Output files can optionally be written to a different directory and or
32ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    have an extra file suffix appended to their name for use in situations
33ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    where you do not want to replace the input files.
34ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """
35ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
36ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __init__(self, fixers, options, explicit, nobackups, show_diffs,
37ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                 input_base_dir='', output_dir='', append_suffix=''):
38ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
39ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        Args:
40ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            fixers: A list of fixers to import.
41ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            options: A dict with RefactoringTool configuration.
42ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            explicit: A list of fixers to run even if they are explicit.
43ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            nobackups: If true no backup '.bak' files will be created for those
44ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                files that are being refactored.
45ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            show_diffs: Should diffs of the refactoring be printed to stdout?
46ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            input_base_dir: The base directory for all input files.  This class
47ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                will strip this path prefix off of filenames before substituting
48ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                it with output_dir.  Only meaningful if output_dir is supplied.
49ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                All files processed by refactor() must start with this path.
50ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            output_dir: If supplied, all converted files will be written into
51ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                this directory tree instead of input_base_dir.
52ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            append_suffix: If supplied, all files output by this tool will have
53ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                this appended to their filename.  Useful for changing .py to
54ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                .py3 for example by passing append_suffix='3'.
55ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
56ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.nobackups = nobackups
57ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.show_diffs = show_diffs
58ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if input_base_dir and not input_base_dir.endswith(os.sep):
59ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            input_base_dir += os.sep
60ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self._input_base_dir = input_base_dir
61ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self._output_dir = output_dir
62ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self._append_suffix = append_suffix
63ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        super(StdoutRefactoringTool, self).__init__(fixers, options, explicit)
64ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
65ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def log_error(self, msg, *args, **kwargs):
66ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.errors.append((msg, args, kwargs))
67ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.logger.error(msg, *args, **kwargs)
68ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
69ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def write_file(self, new_text, filename, old_text, encoding):
70ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig_filename = filename
71ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self._output_dir:
72ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if filename.startswith(self._input_base_dir):
73ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                filename = os.path.join(self._output_dir,
74ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                        filename[len(self._input_base_dir):])
75ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
76ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                raise ValueError('filename %s does not start with the '
77ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                 'input_base_dir %s' % (
78ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                         filename, self._input_base_dir))
79ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self._append_suffix:
80ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            filename += self._append_suffix
81ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if orig_filename != filename:
82ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            output_dir = os.path.dirname(filename)
83ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if not os.path.isdir(output_dir):
84ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                os.makedirs(output_dir)
85ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.log_message('Writing converted %s to %s.', orig_filename,
86ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             filename)
87ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.nobackups:
88ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Make backup
89ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            backup = filename + ".bak"
90ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if os.path.lexists(backup):
91ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                try:
92ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    os.remove(backup)
93ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                except os.error, err:
94ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.log_message("Can't remove backup %s", backup)
95ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
96ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                os.rename(filename, backup)
97ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except os.error, err:
98ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.log_message("Can't rename %s to %s", filename, backup)
99ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Actually write the new file
100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        write = super(StdoutRefactoringTool, self).write_file
101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        write(new_text, filename, old_text, encoding)
102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.nobackups:
103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            shutil.copymode(backup, filename)
104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if orig_filename != filename:
105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Preserve the file mode in the new output directory.
106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            shutil.copymode(orig_filename, filename)
107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def print_output(self, old, new, filename, equal):
109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if equal:
110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.log_message("No changes to %s", filename)
111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.log_message("Refactored %s", filename)
113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if self.show_diffs:
114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                diff_lines = diff_texts(old, new, filename)
115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                try:
116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    if self.output_lock is not None:
117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        with self.output_lock:
118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            for line in diff_lines:
119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                print line
120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            sys.stdout.flush()
121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    else:
122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        for line in diff_lines:
123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            print line
124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                except UnicodeEncodeError:
125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    warn("couldn't encode %s's diff for your terminal" %
126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         (filename,))
127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    return
128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef warn(msg):
131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    print >> sys.stderr, "WARNING: %s" % (msg,)
132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef main(fixer_pkg, args=None):
135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """Main program.
136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    Args:
138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        fixer_pkg: the name of a package where the fixers are located.
139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args: optional; a list of command line arguments. If omitted,
140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh              sys.argv[1:] is used.
141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    Returns a suggested exit status (0, 1, 2).
143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """
144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Set up option parser
145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser = optparse.OptionParser(usage="2to3 [options] file|dir ...")
146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser.add_option("-d", "--doctests_only", action="store_true",
147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      help="Fix up doctests only")
148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser.add_option("-f", "--fix", action="append", default=[],
149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      help="Each FIX specifies a transformation; default: all")
150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser.add_option("-j", "--processes", action="store", default=1,
151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      type="int", help="Run 2to3 concurrently")
152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser.add_option("-x", "--nofix", action="append", default=[],
153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      help="Prevent a transformation from being run")
154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser.add_option("-l", "--list-fixes", action="store_true",
155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      help="List available transformations")
156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser.add_option("-p", "--print-function", action="store_true",
157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      help="Modify the grammar so that print() is a function")
158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser.add_option("-v", "--verbose", action="store_true",
159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      help="More verbose logging")
160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser.add_option("--no-diffs", action="store_true",
161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      help="Don't show diffs of the refactoring")
162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser.add_option("-w", "--write", action="store_true",
163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      help="Write back modified files")
164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser.add_option("-n", "--nobackups", action="store_true", default=False,
165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      help="Don't write backups for modified files")
166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser.add_option("-o", "--output-dir", action="store", type="str",
167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      default="", help="Put output files in this directory "
168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      "instead of overwriting the input files.  Requires -n.")
169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser.add_option("-W", "--write-unchanged-files", action="store_true",
170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      help="Also write files even if no changes were required"
171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      " (useful with --output-dir); implies -w.")
172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parser.add_option("--add-suffix", action="store", type="str", default="",
173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      help="Append this string to all output filenames."
174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      " Requires -n if non-empty.  "
175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      "ex: --add-suffix='3' will generate .py3 files.")
176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Parse command line arguments
178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    refactor_stdin = False
179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    flags = {}
180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    options, args = parser.parse_args(args)
181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if options.write_unchanged_files:
182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        flags["write_unchanged_files"] = True
183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not options.write:
184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            warn("--write-unchanged-files/-W implies -w.")
185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        options.write = True
186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # If we allowed these, the original files would be renamed to backup names
187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # but not replaced.
188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if options.output_dir and not options.nobackups:
189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        parser.error("Can't use --output-dir/-o without -n.")
190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if options.add_suffix and not options.nobackups:
191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        parser.error("Can't use --add-suffix without -n.")
192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if not options.write and options.no_diffs:
194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        warn("not writing files and not printing diffs; that's not very useful")
195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if not options.write and options.nobackups:
196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        parser.error("Can't use -n without -w")
197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if options.list_fixes:
198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print "Available transformations for the -f/--fix option:"
199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for fixname in refactor.get_all_fix_names(fixer_pkg):
200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            print fixname
201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not args:
202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return 0
203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if not args:
204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print >> sys.stderr, "At least one file or directory argument required."
205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        print >> sys.stderr, "Use --help to show usage."
206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return 2
207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if "-" in args:
208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        refactor_stdin = True
209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if options.write:
210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            print >> sys.stderr, "Can't write to stdin."
211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return 2
212ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if options.print_function:
213ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        flags["print_function"] = True
214ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
215ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Set up logging handler
216ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    level = logging.DEBUG if options.verbose else logging.INFO
217ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    logging.basicConfig(format='%(name)s: %(message)s', level=level)
218ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    logger = logging.getLogger('lib2to3.main')
219ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
220ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Initialize the refactoring tool
221ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    avail_fixes = set(refactor.get_fixers_from_package(fixer_pkg))
222ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    unwanted_fixes = set(fixer_pkg + ".fix_" + fix for fix in options.nofix)
223ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    explicit = set()
224ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if options.fix:
225ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        all_present = False
226ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for fix in options.fix:
227ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if fix == "all":
228ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                all_present = True
229ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
230ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                explicit.add(fixer_pkg + ".fix_" + fix)
231ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        requested = avail_fixes.union(explicit) if all_present else explicit
232ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    else:
233ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        requested = avail_fixes.union(explicit)
234ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    fixer_names = requested.difference(unwanted_fixes)
235ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    input_base_dir = os.path.commonprefix(args)
236ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if (input_base_dir and not input_base_dir.endswith(os.sep)
237ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        and not os.path.isdir(input_base_dir)):
238ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # One or more similar names were passed, their directory is the base.
239ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # os.path.commonprefix() is ignorant of path elements, this corrects
240ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # for that weird API.
241ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        input_base_dir = os.path.dirname(input_base_dir)
242ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if options.output_dir:
243ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        input_base_dir = input_base_dir.rstrip(os.sep)
244ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        logger.info('Output in %r will mirror the input directory %r layout.',
245ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    options.output_dir, input_base_dir)
246ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    rt = StdoutRefactoringTool(
247ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            sorted(fixer_names), flags, sorted(explicit),
248ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            options.nobackups, not options.no_diffs,
249ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            input_base_dir=input_base_dir,
250ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            output_dir=options.output_dir,
251ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            append_suffix=options.add_suffix)
252ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
253ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Refactor all files and directories passed as arguments
254ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if not rt.errors:
255ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if refactor_stdin:
256ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            rt.refactor_stdin()
257ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
258ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
259ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                rt.refactor(args, options.write, options.doctests_only,
260ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            options.processes)
261ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except refactor.MultiprocessingUnsupported:
262ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                assert options.processes > 1
263ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                print >> sys.stderr, "Sorry, -j isn't " \
264ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    "supported on this platform."
265ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return 1
266ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        rt.summarize()
267ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
268ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Return error status (0 if rt.errors is zero)
269ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    return int(bool(rt.errors))
270