Kaydet (Commit) b13d04c9 authored tarafından Matthias Klose's avatar Matthias Klose

- Issue #8140: extend compileall to compile single files. Add -i option.

üst dc364724
...@@ -17,7 +17,7 @@ import py_compile ...@@ -17,7 +17,7 @@ import py_compile
import struct import struct
import imp import imp
__all__ = ["compile_dir","compile_path"] __all__ = ["compile_dir","compile_files","compile_path"]
def compile_dir(dir, maxlevels=10, ddir=None, def compile_dir(dir, maxlevels=10, ddir=None,
force=0, rx=None, quiet=0): force=0, rx=None, quiet=0):
...@@ -44,6 +44,34 @@ def compile_dir(dir, maxlevels=10, ddir=None, ...@@ -44,6 +44,34 @@ def compile_dir(dir, maxlevels=10, ddir=None,
success = 1 success = 1
for name in names: for name in names:
fullname = os.path.join(dir, name) fullname = os.path.join(dir, name)
if ddir is not None:
dfile = os.path.join(ddir, name)
else:
dfile = None
if not os.path.isdir(fullname):
if not compile_file(fullname, ddir, force, rx, quiet):
success = 0
elif maxlevels > 0 and \
name != os.curdir and name != os.pardir and \
os.path.isdir(fullname) and \
not os.path.islink(fullname):
if not compile_dir(fullname, maxlevels - 1, dfile, force, rx,
quiet):
success = 0
return success
def compile_file(fullname, ddir=None, force=0, rx=None, quiet=0):
"""Byte-compile file.
file: the file to byte-compile
ddir: if given, purported directory name (this is the
directory name that will show up in error messages)
force: if 1, force compilation, even if timestamps are up-to-date
quiet: if 1, be quiet during compilation
"""
success = 1
name = os.path.basename(fullname)
if ddir is not None: if ddir is not None:
dfile = os.path.join(ddir, name) dfile = os.path.join(ddir, name)
else: else:
...@@ -51,7 +79,7 @@ def compile_dir(dir, maxlevels=10, ddir=None, ...@@ -51,7 +79,7 @@ def compile_dir(dir, maxlevels=10, ddir=None,
if rx is not None: if rx is not None:
mo = rx.search(fullname) mo = rx.search(fullname)
if mo: if mo:
continue return success
if os.path.isfile(fullname): if os.path.isfile(fullname):
head, tail = name[:-3], name[-3:] head, tail = name[:-3], name[-3:]
if tail == '.py': if tail == '.py':
...@@ -63,7 +91,7 @@ def compile_dir(dir, maxlevels=10, ddir=None, ...@@ -63,7 +91,7 @@ def compile_dir(dir, maxlevels=10, ddir=None,
with open(cfile, 'rb') as chandle: with open(cfile, 'rb') as chandle:
actual = chandle.read(8) actual = chandle.read(8)
if expect == actual: if expect == actual:
continue return success
except IOError: except IOError:
pass pass
if not quiet: if not quiet:
...@@ -81,13 +109,6 @@ def compile_dir(dir, maxlevels=10, ddir=None, ...@@ -81,13 +109,6 @@ def compile_dir(dir, maxlevels=10, ddir=None,
else: else:
if ok == 0: if ok == 0:
success = 0 success = 0
elif maxlevels > 0 and \
name != os.curdir and name != os.pardir and \
os.path.isdir(fullname) and \
not os.path.islink(fullname):
if not compile_dir(fullname, maxlevels - 1, dfile, force, rx,
quiet):
success = 0
return success return success
def compile_path(skip_curdir=1, maxlevels=0, force=0, quiet=0): def compile_path(skip_curdir=1, maxlevels=0, force=0, quiet=0):
...@@ -110,15 +131,34 @@ def compile_path(skip_curdir=1, maxlevels=0, force=0, quiet=0): ...@@ -110,15 +131,34 @@ def compile_path(skip_curdir=1, maxlevels=0, force=0, quiet=0):
force, quiet=quiet) force, quiet=quiet)
return success return success
def expand_args(args, flist):
"""read names in flist and append to args"""
expanded = args[:]
if flist:
try:
if flist == '-':
fd = sys.stdin
else:
fd = open(flist)
while 1:
line = fd.readline()
if not line:
break
expanded.append(line[:-1])
except IOError:
print "Error reading file list %s" % flist
raise
return expanded
def main(): def main():
"""Script main program.""" """Script main program."""
import getopt import getopt
try: try:
opts, args = getopt.getopt(sys.argv[1:], 'lfqd:x:') opts, args = getopt.getopt(sys.argv[1:], 'lfqd:x:i:')
except getopt.error, msg: except getopt.error, msg:
print msg print msg
print "usage: python compileall.py [-l] [-f] [-q] [-d destdir] " \ print "usage: python compileall.py [-l] [-f] [-q] [-d destdir] " \
"[-x regexp] [directory ...]" "[-x regexp] [-i list] [directory|file ...]"
print "-l: don't recurse down" print "-l: don't recurse down"
print "-f: force rebuild even if timestamps are up-to-date" print "-f: force rebuild even if timestamps are up-to-date"
print "-q: quiet operation" print "-q: quiet operation"
...@@ -126,12 +166,14 @@ def main(): ...@@ -126,12 +166,14 @@ def main():
print " if no directory arguments, -l sys.path is assumed" print " if no directory arguments, -l sys.path is assumed"
print "-x regexp: skip files matching the regular expression regexp" print "-x regexp: skip files matching the regular expression regexp"
print " the regexp is searched for in the full path of the file" print " the regexp is searched for in the full path of the file"
print "-i list: expand list with its content (file and directory names)"
sys.exit(2) sys.exit(2)
maxlevels = 10 maxlevels = 10
ddir = None ddir = None
force = 0 force = 0
quiet = 0 quiet = 0
rx = None rx = None
flist = None
for o, a in opts: for o, a in opts:
if o == '-l': maxlevels = 0 if o == '-l': maxlevels = 0
if o == '-d': ddir = a if o == '-d': ddir = a
...@@ -140,17 +182,28 @@ def main(): ...@@ -140,17 +182,28 @@ def main():
if o == '-x': if o == '-x':
import re import re
rx = re.compile(a) rx = re.compile(a)
if o == '-i': flist = a
if ddir: if ddir:
if len(args) != 1: if len(args) != 1 and not os.path.isdir(args[0]):
print "-d destdir require exactly one directory argument" print "-d destdir require exactly one directory argument"
sys.exit(2) sys.exit(2)
success = 1 success = 1
try: try:
if args: if args or flist:
for dir in args: try:
if not compile_dir(dir, maxlevels, ddir, if flist:
args = expand_args(args, flist)
except IOError:
success = 0
if success:
for arg in args:
if os.path.isdir(arg):
if not compile_dir(arg, maxlevels, ddir,
force, rx, quiet): force, rx, quiet):
success = 0 success = 0
else:
if not compile_file(arg, ddir, force, rx, quiet):
success = 0
else: else:
success = compile_path() success = compile_path()
except KeyboardInterrupt: except KeyboardInterrupt:
......
...@@ -17,6 +17,9 @@ class CompileallTests(unittest.TestCase): ...@@ -17,6 +17,9 @@ class CompileallTests(unittest.TestCase):
self.bc_path = self.source_path + ('c' if __debug__ else 'o') self.bc_path = self.source_path + ('c' if __debug__ else 'o')
with open(self.source_path, 'w') as file: with open(self.source_path, 'w') as file:
file.write('x = 123\n') file.write('x = 123\n')
self.source_path2 = os.path.join(self.directory, '_test2.py')
self.bc_path2 = self.source_path2 + ('c' if __debug__ else 'o')
shutil.copyfile(self.source_path, self.source_path2)
def tearDown(self): def tearDown(self):
shutil.rmtree(self.directory) shutil.rmtree(self.directory)
...@@ -52,6 +55,22 @@ class CompileallTests(unittest.TestCase): ...@@ -52,6 +55,22 @@ class CompileallTests(unittest.TestCase):
# Test a change in mtime leads to a new .pyc. # Test a change in mtime leads to a new .pyc.
self.recreation_check(b'\0\0\0\0') self.recreation_check(b'\0\0\0\0')
def test_compile_files(self):
# Test compiling a single file, and complete directory
for fn in (self.bc_path, self.bc_path2):
try:
os.unlink(fn)
except:
pass
compileall.compile_file(self.source_path, force=False, quiet=True)
self.assertTrue(os.path.isfile(self.bc_path) \
and not os.path.isfile(self.bc_path2))
os.unlink(self.bc_path)
compileall.compile_dir(self.directory, force=False, quiet=True)
self.assertTrue(os.path.isfile(self.bc_path) \
and os.path.isfile(self.bc_path2))
os.unlink(self.bc_path)
os.unlink(self.bc_path2)
def test_main(): def test_main():
test_support.run_unittest(CompileallTests) test_support.run_unittest(CompileallTests)
......
...@@ -20,6 +20,8 @@ Core and Builtins ...@@ -20,6 +20,8 @@ Core and Builtins
Library Library
------- -------
- Issue #8140: extend compileall to compile single files. Add -i option.
- Issue #7356: ctypes.util: Make parsing of ldconfig output independent of - Issue #7356: ctypes.util: Make parsing of ldconfig output independent of
the locale. the locale.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment