diff options
Diffstat (limited to 'morphlib/bins.py')
-rw-r--r-- | morphlib/bins.py | 61 |
1 files changed, 34 insertions, 27 deletions
diff --git a/morphlib/bins.py b/morphlib/bins.py index 560e68bb..40a0cb50 100644 --- a/morphlib/bins.py +++ b/morphlib/bins.py @@ -1,4 +1,4 @@ -# Copyright (C) 2011-2014 Codethink Limited +# Copyright (C) 2011-2015 Codethink Limited # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -79,12 +79,8 @@ if sys.version_info < (2, 7, 3): # pragma: no cover raise ExtractError("could not change owner") tarfile.TarFile.chown = fixed_chown -def create_chunk(rootdir, f, include, dump_memory_profile=None): - '''Create a chunk from the contents of a directory. - - ``f`` is an open file handle, to which the tar file is written. - - ''' +def create_chunk(rootdir, chunkdir, include, dump_memory_profile=None): + '''Create a chunk from the contents of a directory.''' dump_memory_profile = dump_memory_profile or (lambda msg: None) @@ -92,31 +88,42 @@ def create_chunk(rootdir, f, include, dump_memory_profile=None): # chunk artifact. This is useful to avoid problems from smallish # clock skew. It needs to be recent enough, however, that GNU tar # does not complain about an implausibly old timestamp. - normalized_timestamp = 683074800 + normalized_timestamp = (683074800, 683074800) dump_memory_profile('at beginning of create_chunk') - - path_pairs = [(relname, os.path.join(rootdir, relname)) - for relname in include] - tar = tarfile.open(fileobj=f, mode='w') - for relname, filename in path_pairs: + + def check_parent(name, paths): + parent = os.path.dirname(name) + if parent: + path = os.path.join(rootdir, parent) + if parent != rootdir and path not in paths: + paths.append(path) + check_parent(parent, paths) + + def filter_contents(dirname, filenames): + paths = [os.path.join(rootdir, relname) for relname in include] + for name in include: + check_parent(name, paths) + + return [f for f in filenames if os.path.join(dirname, f) not in paths] + + logging.debug('Copying artifact into %s.' % chunkdir) + shutil.copytree(rootdir, chunkdir, + symlinks=True, ignore=filter_contents) + + path_triplets = [(relname, os.path.join(chunkdir, relname), + os.path.join(rootdir, relname)) + for relname in include] + for relname, filename, orig in path_triplets: # Normalize mtime for everything. - tarinfo = tar.gettarinfo(filename, - arcname=relname) - tarinfo.ctime = normalized_timestamp - tarinfo.mtime = normalized_timestamp - if tarinfo.isreg(): - with open(filename, 'rb') as f: - tar.addfile(tarinfo, fileobj=f) - else: - tar.addfile(tarinfo) - tar.close() + if not os.path.islink(filename): + os.utime(filename, normalized_timestamp) - for relname, filename in reversed(path_pairs): - if os.path.isdir(filename) and not os.path.islink(filename): + for relname, filename, orig in reversed(path_triplets): + if os.path.isdir(orig) and not os.path.islink(orig): continue else: - os.remove(filename) + os.remove(orig) dump_memory_profile('after removing in create_chunks') @@ -210,7 +217,7 @@ def unpack_binary_from_file(f, dirname): # pragma: no cover tf.close() -def unpack_binary(filename, dirname): +def unpack_binary(filename, dirname): # pragma: no cover with open(filename, "rb") as f: unpack_binary_from_file(f, dirname) |