blob: 5be00e25dec176b8a6bdc0ba77e5982227827fdc [file] [log] [blame]
import os
import tarfile as tarfile
import tempfile
from cfg_checker.common import logger_cli
from cfg_checker.common.exception import ConfigException
class TGZFile(object):
basefile = None
_labelname = "labelfile"
def __init__(self, _filepath, label=None):
# Check if this filename exists
if not os.path.exists(_filepath):
# If the archive not exists, create it
# simple labelfile for a non-empty archive
if not label:
label = "MCP Checker TGZ file"
with tempfile.TemporaryFile() as _tempfile:
_tempfile.write(label.encode('utf-8'))
_tempfile.flush()
_tempfile.seek(0)
# create tgz
with tarfile.open(_filepath, "w:gz") as tgz:
_info = tgz.gettarinfo(
arcname=self._labelname,
fileobj=_tempfile
)
tgz.addfile(_info, fileobj=_tempfile)
logger_cli.debug("... created file '{}'".format(_filepath))
self.basefile = _filepath
elif not os.path.isfile(_filepath):
# if path exists, and it is not a file
raise ConfigException(
"Supplied path of '{}' is not a file".format(
_filepath
)
)
elif not tarfile.is_tarfile(_filepath):
# if file exists, and it is not a tar file
raise ConfigException(
"Supplied file of '{}' is not a TAR stream".format(
_filepath
)
)
else:
self.basefile = _filepath
def get_file(self, name, decode=False):
if self.has_file(name):
with tarfile.open(self.basefile, "r:gz") as tgz:
_tgzitem = tgz.extractfile(tgz.getmember(name))
if decode:
return _tgzitem.read().decode('utf-8')
else:
return _tgzitem.read()
else:
return None
def add_file(self, name, buf=None, replace=False):
_files = []
with tarfile.open(self.basefile) as r:
_files = r.getnames()
_exists = name in _files
if _exists and not replace:
# file exists and replace flag is not set
return False
# check if there is work to do
if not buf and not os.path.exists(name):
# Nothing to do: no buffer or file to add
return False
elif name in self.list_files() and not replace:
# file already there and replace flag not set
return False
_a = "replace" if replace else "add"
logger_cli.debug("... about to {} '{}' ({:.2f}MB) -> '{}'".format(
_a,
name,
float(len(buf))/1024/1024,
self.basefile
))
# unzip tar, add file, zip it back
_tmpdir = tempfile.mkdtemp()
logger_cli.debug("... created tempdir '{}'".format(_tmpdir))
# extract them
_files = []
with tarfile.open(self.basefile) as r:
# all names extracted
_files = r.getnames()
# extract 'em
logger_cli.debug("... extracting contents")
r.extractall(_tmpdir)
# create file
if buf:
_p = os.path.join(_tmpdir, name)
logger_cli.debug("... writing new file to '{}'".format(
_p
))
if not _exists or replace:
with open(_p, "w") as w:
w.write(buf)
if not _exists:
_files.append(name)
# create the archive
logger_cli.debug("... rebuilding archive")
with tarfile.open(self.basefile, "w:gz") as tgz:
for _file in _files:
_p = os.path.join(_tmpdir, _file)
tgz.add(_p, arcname=_file)
os.remove(_p)
os.rmdir(_tmpdir)
return True
def list_files(self):
# get names
with tarfile.open(self.basefile, "r:gz") as tgz:
_names = tgz.getnames()
# filter filenames only, skip path
if any(['/' in _n for _n in _names]):
_n = []
for f in _names:
if '/' in f:
_n.append(f.rsplit('/', 1)[1])
else:
_n.append(f)
_names = _n
# remove label file from output
if self._labelname in _names:
_names.remove(self._labelname)
return _names
def has_file(self, name):
if name in self.list_files():
logger_cli.debug("... '{}' has '{}'".format(self.basefile, name))
return True
else:
logger_cli.debug("... '{}' lacks '{}'".format(self.basefile, name))
return False