Files

176 lines
6.1 KiB
Python

# only tested with cpython!
import optparse, os, shutil, sys
from os import path
from testlib import filters
__doc__ = """
Creates and maintains a 'clone' of the test suite, optionally transforming
the source code through a filter. The primary purpose of this utility is
to allow the tests to run on Python VMs that do not implement a parser that
groks 2.4 style @decorations.
Creating a clone:
Create a new, exact clone of the suite:
$ python test/clone.py -c myclone
Create a new clone using the 2.3 filter:
$ python test/clone.py -c --filter=py23 myclone
After the clone is set up, changes in the master can be pulled into the clone
with the -u or --update switch. If the clone was created with a filter, it
will be applied automatically when updating.
Update the clone:
$ python test/clone.py -u myclone
The updating algorithm is very simple: if the version in test/ is newer than
the one in your clone, the clone version is overwritten.
"""
options = None
clone, clone_path = None, None
filter = lambda x: x[:]
def optparser():
parser = optparse.OptionParser(
usage=('usage: %prog [options] CLONE-NAME\n' + __doc__ ).rstrip())
parser.add_option('-n', '--dry-run', dest='dryrun',
action='store_true',
help=('Do not actually change any files; '
'just print what would happen.'))
parser.add_option('-u', '--update', dest='update', action='store_true',
help='Update an existing clone.')
parser.add_option('-c', '--create', dest='create', action='store_true',
help='Create a new clone.')
parser.add_option('--filter', dest='filter',
help='Run source code through a filter.')
parser.add_option('-l', '--filter-list', dest='filter_list',
action='store_true',
help='Show available filters.')
parser.add_option('-f', '--force', dest='force', action='store_true',
help='Overwrite clone files even if unchanged.')
parser.add_option('-q', '--quiet', dest='quiet', action='store_true',
help='Run quietly.')
parser.set_defaults(update=False, create=False,
dryrun=False, filter_list=False,
force=False, quiet=False)
return parser
def config():
global clone, clone_path, options, filter
parser = optparser()
(options, args) = parser.parse_args()
if options.filter_list:
if options.quiet:
print '\n'.join(filters.__all__)
else:
print 'Available filters:'
for name in filters.__all__:
print '\t%s' % name
sys.exit(0)
if not options.update and not options.create:
parser.error('One of -u or -c is required.')
if len(args) != 1:
parser.error('A clone name is required.')
clone = args[0]
clone_path = path.abspath(clone)
if options.update and not path.exists(clone_path):
parser.error(
'Clone %s does not exist; create it with --create first.' % clone)
if options.create and path.exists(clone_path):
parser.error('Clone %s already exists.' % clone)
if options.filter:
if options.filter not in filters.__all__:
parser.error(('Filter "%s" unknown; use --filter-list to see '
'available filters.') % options.filter)
filter = getattr(filters, options.filter)
def setup():
global filter
if options.create:
if not options.quiet:
print "mkdir %s" % clone_path
if not options.dryrun:
os.mkdir(clone_path)
if options.filter and not options.dryrun:
if not options.quiet:
print 'storing filter "%s" in %s/.filter' % (
options.filter, clone)
stash = open(path.join(clone_path, '.filter'), 'w')
stash.write(options.filter)
stash.close()
else:
stash_file = path.join(clone_path, '.filter')
if path.exists(stash_file):
stash = open(stash_file)
stashed = stash.read().strip()
stash.close()
if options.filter:
if (options.filter != stashed and stashed in filters.__all__ and
not options.quiet):
print (('Warning: --filter=%s overrides %s specified in '
'%s/.filter') % (options.filter, stashed, clone))
else:
if stashed not in filters.__all__:
sys.stderr.write(
'Filter "%s" in %s/.filter is not valid, aborting.' %
(stashed, clone))
sys.exit(-1)
filter = getattr(filters, stashed)
def sync():
source_path, _ = path.split(path.abspath(__file__))
ls = lambda root: [fn
for fn in os.listdir(root)
if (fn.endswith('.py') and not fn.startswith('.'))]
def walker(x, dirname, fnames):
if '.svn' in fnames:
fnames.remove('.svn')
rel_path = dirname[len(source_path) + 1:]
dest_path = path.join(clone_path, rel_path)
if not path.exists(dest_path):
if not options.quiet:
print "mkdir %s/%s" % (clone, rel_path)
if not options.dryrun:
os.mkdir(dest_path)
for filename in ls(dirname):
source_file = path.join(source_path, rel_path, filename)
dest_file = path.join(dest_path, filename)
if (options.force or
(not path.exists(dest_file) or
os.stat(source_file)[-1] > os.stat(dest_file)[-1])):
if not options.quiet:
print "syncing %s" % path.join(rel_path, filename)
raw = open(source_file)
filtered = filter(raw.readlines())
raw.close()
if not options.dryrun:
synced = open(dest_file, 'w')
synced.writelines(filtered)
synced.close()
os.path.walk(source_path, walker, None)
if __name__ == '__main__':
config()
setup()
sync()