56 lines
1.6 KiB
Python
56 lines
1.6 KiB
Python
import tarfile
|
|
|
|
from cStringIO import StringIO
|
|
|
|
from util.tarlayerformat import TarLayerFormat
|
|
from util.gzipwrap import GzipWrap
|
|
|
|
class TarfileAppender(TarLayerFormat):
|
|
""" Helper class which allows for appending entries to a gzipped-tarfile and doing so
|
|
in a streaming manner.
|
|
"""
|
|
def __init__(self, base_tar_file, entries):
|
|
super(TarfileAppender, self).__init__(self._get_tar_iterator)
|
|
self.entries = entries
|
|
self.base_tar_file = base_tar_file
|
|
self.first_info = None
|
|
|
|
def get_stream(self):
|
|
return GzipWrap(self.get_generator())
|
|
|
|
def after_tar_layer(self, current_layer):
|
|
pass
|
|
|
|
def check_tar_info(self, tar_info):
|
|
if not self.first_info:
|
|
self.first_info = tar_info
|
|
return True
|
|
|
|
def _get_tar_iterator(self):
|
|
# Yield the contents of the base tar.
|
|
yield self.base_tar_file
|
|
|
|
# Construct an in-memory tar containing the entries to append, and then yield
|
|
# its data.
|
|
def add_entry(arch, dir_path, contents=None):
|
|
info = tarfile.TarInfo(dir_path)
|
|
info.uid = self.first_info.uid
|
|
info.gid = self.first_info.gid
|
|
info.mode = self.first_info.mode
|
|
info.mtime = self.first_info.mtime
|
|
|
|
info.type = tarfile.REGTYPE if contents else tarfile.DIRTYPE
|
|
|
|
if contents:
|
|
info.size = len(contents)
|
|
|
|
arch.addfile(info, fileobj=StringIO(contents) if contents else None)
|
|
|
|
append_tarball = StringIO()
|
|
with tarfile.open(fileobj=append_tarball, mode='w') as updated_archive:
|
|
for entry in self.entries:
|
|
add_entry(updated_archive, entry, self.entries[entry])
|
|
|
|
# To make tarfile happy.
|
|
append_tarball.seek(0)
|
|
yield append_tarball
|