diff options
Diffstat (limited to 'buildscripts/make_archive.py')
| -rwxr-xr-x | buildscripts/make_archive.py | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/buildscripts/make_archive.py b/buildscripts/make_archive.py new file mode 100755 index 00000000000..4c12e901a64 --- /dev/null +++ b/buildscripts/make_archive.py @@ -0,0 +1,116 @@ +#!/usr/bin/python + +'''Helper script for constructing an archive (zip or tar) from a list of files. + +The output format (tar, tgz, zip) is determined from the file name, unless the user specifies +--format on the command line. + +This script simplifies the specification of filename transformations, so that, e.g., +src/mongo/foo.cpp and build/linux2/normal/buildinfo.cpp can get put into the same +directory in the archive, perhaps mongodb-2.0.2/src/mongo. + +Usage: + +make_archive.py -o <output-file> [--format (tar|tgz|zip)] \ + [--transform match1=replacement1 [--transform match2=replacement2 [...]]] \ + <input file 1> [...] + +If the input file names start with "@", the file is expected to contain a list of +whitespace-separated file names to include in the archive. This helps get around the Windows +command line length limit. + +Transformations are processed in command-line order and are short-circuiting. So, if a file matches +match1, it is never compared against match2 or later. Matches are just python startswith() +comparisons. + +For a detailed usage example, see src/SConscript.client or src/mongo/SConscript. +''' + +import optparse +import os +import sys + +def main(argv): + opts = parse_options(argv[1:]) + archive = open_archive_for_write(opts.output_filename, opts.archive_format) + try: + for input_filename in opts.input_filenames: + archive.add(input_filename, arcname=get_preferred_filename(input_filename, + opts.transformations)) + finally: + archive.close() + +def parse_options(args): + parser = optparse.OptionParser() + parser.add_option('-o', dest='output_filename', default=None, + help='Name of the archive to output.', metavar='FILE') + parser.add_option('--format', dest='archive_format', default=None, + choices=('zip', 'tar', 'tgz'), + help='Format of archive to create. ' + 'If omitted, use the suffix of the output filename to decide.') + parser.add_option('--transform', action='append', dest='transformations', default=[]) + + (opts, input_filenames) = parser.parse_args(args) + opts.input_filenames = [] + + for input_filename in input_filenames: + if input_filename.startswith('@'): + opts.input_filenames.extend(open(input_filename[1:], 'r').read().split()) + else: + opts.input_filenames.append(input_filename) + + if opts.output_filename is None: + parser.error('-o switch is required') + + if opts.archive_format is None: + if opts.output_filename.endswith('.zip'): + opts.archive_format = 'zip' + elif opts.output_filename.endswith('tar.gz') or opts.output_filename.endswith('.tgz'): + opts.archive_format = 'tgz' + elif opts.output_filename.endswith('.tar'): + opts.archive_format = 'tar' + else: + parser.error('Could not deduce archive format from output filename "%s"' % + opts.output_filename) + + try: + opts.transformations = [ + xform.replace(os.path.altsep or os.path.sep, os.path.sep).split('=', 1) + for xform in opts.transformations] + except Exception, e: + parser.error(e) + + return opts + +def open_archive_for_write(filename, archive_format): + '''Open a tar or zip archive for write, with the given format, and return it. + + The type of archive is determined by the "archive_format" parameter, which should be + "tar", "tgz" (for gzipped tar) or "zip". + ''' + + if archive_format in ('tar', 'tgz'): + import tarfile + mode = 'w' + if archive_format is 'tgz': + mode += '|gz' + return tarfile.open(filename, mode) + if archive_format is 'zip': + import zipfile + # Infuriatingly, Zipfile calls the "add" method "write", but they're otherwise identical, + # for our purposes. WrappedZipFile is a minimal adapter class. + class WrappedZipFile(zipfile.ZipFile): + def add(self, filename, arcname): + return self.write(filename, arcname) + return WrappedZipFile(filename, 'w', zipfile.ZIP_DEFLATED) + raise ValueError('Unsupported archive format "%s"' % archive_format) + +def get_preferred_filename(input_filename, transformations): + for match, replace in transformations: + if input_filename.startswith(match): + return replace + input_filename[len(match):] + return input_filename + +if __name__ == '__main__': + main(sys.argv) + sys.exit(0) |
