import hashlib import json from jail import jail_run import shutil def filehash(fname): h = hashlib.sha256() with open(fname, 'rb') as f: while True: data = f.read(1024*1024*4) if not data: break h.update(data) res = h.hexdigest() return res class RunStep(object): def __init__(self, spec): if not isinstance(spec, list) and \ not isinstance(spec, str): raise ValueError('Run spec must be a list or a string') self.spec = spec def hash(self, base): res = hashlib.sha256( json.dumps(( base, self.spec )) .encode('utf-8')).hexdigest() return res def execute(self, path): spec = self.spec if isinstance(spec, list) spec = ' && ' .join(self.spec) jail_run(path, spec) class CopyStep(object): def __init__(self, spec): if not isinstance(spec, list): raise ValueError('CopyStep spec should be a list') self.spec = spec def hash(self, base): if len(self.spec) == 0: fh = [] elif isinstance(self.spec[0], list): fh = list(map(lambda a: filehash(a[0]), self.spec)) else: fh = [ filehash(self.spec[0]) ] res = hashlib.sha256( json.dumps(( base, fh, self.spec )) .encode('utf-8')).hexdigest() return res def execute(self, path): lst = [ self.spec ] \ if not isinstance(self.spec[0], list) \ else self.spec for a in lst: shutil.copyfile(a[0], os.path.join(path, a[1])) def create_step(spec): if not isinstance(spec, dict): raise ValueError('Step specification must be a dictionary') if 'copy' in spec: return CopyStep(spec['copy']) elif 'run' in spec: return RunStep(spec['run']) raise ValueError('Unrecognized step spec: ' + json.dumps(spec))