compileall.py 5.16 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
"""Module/script to "compile" all .py files to .pyc (or .pyo) file.

When called as a script with arguments, this compiles the directories
given as arguments recursively; the -l option prevents it from
recursing into directories.

Without arguments, if compiles all modules on sys.path, without
recursing into subdirectories.  (Even though it should do so for
packages -- for now, you'll have to deal with packages separately.)

See module py_compile for details of the actual byte-compilation.

"""
14 15 16 17 18

import os
import sys
import py_compile

19 20
__all__ = ["compile_dir","compile_path"]

21 22
def compile_dir(dir, maxlevels=10, ddir=None,
                force=0, rx=None, quiet=0):
23 24 25 26 27 28 29 30
    """Byte-compile all modules in the given directory tree.

    Arguments (only dir is required):

    dir:       the directory to byte-compile
    maxlevels: maximum recursion level (default 10)
    ddir:      if given, purported directory name (this is the
               directory name that will show up in error messages)
31
    force:     if 1, force compilation, even if timestamps are up-to-date
32
    quiet:     if 1, be quiet during compilation
33

34
    """
35 36
    if not quiet:
        print 'Listing', dir, '...'
37
    try:
38
        names = os.listdir(dir)
39
    except os.error:
40 41
        print "Can't list", dir
        names = []
42
    names.sort()
43
    success = 1
44
    for name in names:
45
        fullname = os.path.join(dir, name)
46
        if ddir is not None:
47 48 49
            dfile = os.path.join(ddir, name)
        else:
            dfile = None
50
        if rx is not None:
51 52 53
            mo = rx.search(fullname)
            if mo:
                continue
54 55 56
        if os.path.isfile(fullname):
            head, tail = name[:-3], name[-3:]
            if tail == '.py':
57
                cfile = fullname + (__debug__ and 'c' or 'o')
58 59
                ftime = os.stat(fullname).st_mtime
                try: ctime = os.stat(cfile).st_mtime
60 61
                except os.error: ctime = 0
                if (ctime > ftime) and not force: continue
62 63
                if not quiet:
                    print 'Compiling', fullname, '...'
64
                try:
65
                    ok = py_compile.compile(fullname, None, dfile, True)
66 67
                except KeyboardInterrupt:
                    raise KeyboardInterrupt
68
                except py_compile.PyCompileError,err:
69 70
                    if quiet:
                        print 'Compiling', fullname, '...'
71
                    print err.msg
72
                    success = 0
Martin v. Löwis's avatar
Martin v. Löwis committed
73 74 75
                except IOError, e:
                    print "Sorry", e
                    success = 0
76 77 78
                else:
                    if ok == 0:
                        success = 0
79 80 81 82
        elif maxlevels > 0 and \
             name != os.curdir and name != os.pardir and \
             os.path.isdir(fullname) and \
             not os.path.islink(fullname):
83
            if not compile_dir(fullname, maxlevels - 1, dfile, force, rx, quiet):
84
                success = 0
85
    return success
86

87
def compile_path(skip_curdir=1, maxlevels=0, force=0, quiet=0):
88 89 90 91 92 93
    """Byte-compile all module on sys.path.

    Arguments (all optional):

    skip_curdir: if true, skip current directory (default true)
    maxlevels:   max recursion level (default 0)
94
    force: as for compile_dir() (default 0)
95
    quiet: as for compile_dir() (default 0)
96 97

    """
98
    success = 1
99
    for dir in sys.path:
100 101 102
        if (not dir or dir == os.curdir) and skip_curdir:
            print 'Skipping current directory'
        else:
103 104
            success = success and compile_dir(dir, maxlevels, None,
                                              force, quiet=quiet)
105
    return success
106 107

def main():
108 109 110
    """Script main program."""
    import getopt
    try:
111
        opts, args = getopt.getopt(sys.argv[1:], 'lfqd:x:')
112
    except getopt.error, msg:
113
        print msg
114
        print "usage: python compileall.py [-l] [-f] [-q] [-d destdir] " \
115
              "[-x regexp] [directory ...]"
116
        print "-l: don't recurse down"
117
        print "-f: force rebuild even if timestamps are up-to-date"
118
        print "-q: quiet operation"
119
        print "-d destdir: purported directory name for error messages"
120 121 122
        print "   if no directory arguments, -l sys.path is assumed"
        print "-x regexp: skip files matching the regular expression regexp"
        print "   the regexp is search for in the full path of the file"
123
        sys.exit(2)
124 125
    maxlevels = 10
    ddir = None
126
    force = 0
127
    quiet = 0
128
    rx = None
129
    for o, a in opts:
130 131
        if o == '-l': maxlevels = 0
        if o == '-d': ddir = a
132
        if o == '-f': force = 1
133
        if o == '-q': quiet = 1
134 135 136
        if o == '-x':
            import re
            rx = re.compile(a)
137
    if ddir:
138 139 140
        if len(args) != 1:
            print "-d destdir require exactly one directory argument"
            sys.exit(2)
141
    success = 1
142
    try:
143 144
        if args:
            for dir in args:
145 146
                if not compile_dir(dir, maxlevels, ddir,
                                   force, rx, quiet):
147
                    success = 0
148
        else:
149
            success = compile_path()
150
    except KeyboardInterrupt:
151
        print "\n[interrupt]"
152 153
        success = 0
    return success
154 155

if __name__ == '__main__':
156
    exit_status = int(not main())
157
    sys.exit(exit_status)