diff --git a/Tools/PyJobTransforms/python/trfExe.py b/Tools/PyJobTransforms/python/trfExe.py index 8e2a5cea6c897981ba7222af70495f3a3b918c6c..f8920425c94fb3ef56e4fa9c2cc69d70594d061e 100755 --- a/Tools/PyJobTransforms/python/trfExe.py +++ b/Tools/PyJobTransforms/python/trfExe.py @@ -1862,7 +1862,7 @@ class tagMergeExecutor(scriptExecutor): msg.debug('valStop time is {0}'.format(self._valStop)) -## @brief Archive transform - use tar +## @brief Archive transform class archiveExecutor(scriptExecutor): def preExecute(self, input = set(), output = set()): @@ -1872,26 +1872,89 @@ class archiveExecutor(scriptExecutor): if 'exe' in self.conf.argdict: self._exe = self.conf.argdict['exe'] + #unpack archived inputs + import tarfile, zipfile + if 'inputDataFile' in self.conf.argdict: + for f in self.conf.argdict['inputDataFile'].value: + if zipfile.is_zipfile(f): + archive = zipfile.ZipFile(f, mode='r') + print 'Extracting input zip file {0} to temporary directory {1}'.format(f,'tmp') + archive.extractall('tmp') + archive.close() + elif tarfile.is_tarfile(f): + archive = tarfile.open(f, 'r:*') + print 'Extracting input tar file {0} to temporary directory {1}'.format(f,'tmp') + archive.extractall('tmp') + archive.close() + + #proceed to archive if self._exe == 'tar': - self._cmd = [self._exe, '-c', '-v',] - if 'compressionType' in self.conf.argdict: - if self.conf.argdict['compressionType'] == 'gzip': - self._cmd.append('-z') - elif self.conf.argdict['compressionType'] == 'bzip2': - self._cmd.append('-j') - elif self.conf.argdict['compressionType'] == 'none': - pass - self._cmd.extend(['-f', self.conf.argdict['outputArchFile'].value[0]]) - self._cmd.extend(self.conf.argdict['inputDataFile'].value) + #this is needed to keep the transform from scheduling two sub-steps + if 'outputArchFile' not in self.conf.argdict: + raise trfExceptions.TransformExecutionException(trfExit.nameToCode('TRF_ARG_MISSING'), 'Missing output file name') + + self._cmd = ['python'] + try: + with open('tar_wrapper.py', 'w') as tar_wrapper: + print >> tar_wrapper, "import zipfile, tarfile, os, shutil" + if os.path.exists(self.conf.argdict['outputArchFile'].value[0]): + #appending input file(s) to existing archive. Compressed writing in append mode is not possible + print >> tar_wrapper, "tar = tarfile.open('{}', 'a:')".format(self.conf.argdict['outputArchFile'].value[0]) + else: + #creating new archive + if 'compressionType' in self.conf.argdict: + if self.conf.argdict['compressionType'] == 'gzip': + print >> tar_wrapper, "tar = tarfile.open('{}', 'w:gz')".format(self.conf.argdict['outputArchFile'].value[0]) + elif self.conf.argdict['compressionType'] == 'bzip2': + print >> tar_wrapper, "tar = tarfile.open('{}', 'w:bz2')".format(self.conf.argdict['outputArchFile'].value[0]) + elif self.conf.argdict['compressionType'] == 'none': + print >> tar_wrapper, "tar = tarfile.open('{}', 'w:')".format(self.conf.argdict['outputArchFile'].value[0]) + print >> tar_wrapper, "for f in {}:".format(self.conf.argdict['inputDataFile'].value) + print >> tar_wrapper, " if not zipfile.is_zipfile(f) and not tarfile.is_tarfile(f):" + print >> tar_wrapper, " print 'Tarring {}'.format(os.path.basename(f))" + print >> tar_wrapper, " tar.add(f)" + print >> tar_wrapper, "if os.path.isdir('tmp'):" + print >> tar_wrapper, " for root, dirs, files in os.walk('tmp'):" + print >> tar_wrapper, " for name in files:" + print >> tar_wrapper, " print 'Tarring {}'.format(name)" + print >> tar_wrapper, " tar.add(os.path.join(root, name),name)" + print >> tar_wrapper, " shutil.rmtree('tmp')" + print >> tar_wrapper, "tar.close()" + os.chmod('tar_wrapper.py', 0755) + except (IOError, OSError) as e: + errMsg = 'error writing tar wrapper {fileName}: {error}'.format(fileName = 'tar_wrapper.py', + error = e + ) + msg.error(errMsg) + raise trfExceptions.TransformExecutionException(trfExit.nameToCode('TRF_EXEC_SETUP_WRAPPER'), + errMsg + ) + self._cmd.append('tar_wrapper.py') + elif self._exe == 'zip': + if 'outputArchFile' not in self.conf.argdict: + raise trfExceptions.TransformExecutionException(trfExit.nameToCode('TRF_ARG_MISSING'), 'Missing output file name') + self._cmd = ['python'] try: with open('zip_wrapper.py', 'w') as zip_wrapper: - print >> zip_wrapper, "import zipfile" - print >> zip_wrapper, "zf = zipfile.ZipFile('{}', mode='w', allowZip64=True)".format(self.conf.argdict['outputArchFile'].value[0]) + print >> zip_wrapper, "import zipfile, tarfile, os, shutil" + if os.path.exists(self.conf.argdict['outputArchFile'].value[0]): + #appending input file(s) to existing archive + print >> zip_wrapper, "zf = zipfile.ZipFile('{}', mode='a', allowZip64=True)".format(self.conf.argdict['outputArchFile'].value[0]) + else: + #creating new archive + print >> zip_wrapper, "zf = zipfile.ZipFile('{}', mode='w', allowZip64=True)".format(self.conf.argdict['outputArchFile'].value[0]) print >> zip_wrapper, "for f in {}:".format(self.conf.argdict['inputDataFile'].value) - print >> zip_wrapper, " print 'Zipping file {}'.format(f)" - print >> zip_wrapper, " zf.write(f, compress_type=zipfile.ZIP_STORED)" + print >> zip_wrapper, " if not zipfile.is_zipfile(f) and not tarfile.is_tarfile(f):" + print >> zip_wrapper, " print 'Zipping {}'.format(os.path.basename(f))" + print >> zip_wrapper, " zf.write(f, arcname=os.path.basename(f), compress_type=zipfile.ZIP_STORED)" + print >> zip_wrapper, "if os.path.isdir('tmp'):" + print >> zip_wrapper, " for root, dirs, files in os.walk('tmp'):" + print >> zip_wrapper, " for name in files:" + print >> zip_wrapper, " print 'Zipping {}'.format(name)" + print >> zip_wrapper, " zf.write(os.path.join(root, name), name, compress_type=zipfile.ZIP_STORED)" + print >> zip_wrapper, " shutil.rmtree('tmp')" print >> zip_wrapper, "zf.close()" os.chmod('zip_wrapper.py', 0755) except (IOError, OSError) as e: @@ -1903,4 +1966,32 @@ class archiveExecutor(scriptExecutor): errMsg ) self._cmd.append('zip_wrapper.py') + + elif self._exe == 'unarchive': + if not zipfile.is_zipfile(self.conf.argdict['inputArchFile'].value[0]) and not tarfile.is_tarfile(self.conf.argdict['inputArchFile'].value[0]): + raise trfExceptions.TransformExecutionException(trfExit.nameToCode('TRF_INPUT_FILE_ERROR'), + 'The input file is not a zip or tar archive - aborting unpacking') + self._cmd = ['python'] + try: + with open('unarchive_wrapper.py', 'w') as unarchive_wrapper: + print >> unarchive_wrapper, "import zipfile, tarfile" + print >> unarchive_wrapper, "for f in {}:".format(self.conf.argdict['inputArchFile'].value) + print >> unarchive_wrapper, " if zipfile.is_zipfile(f):" + print >> unarchive_wrapper, " archive = zipfile.ZipFile(f, mode='r')" + print >> unarchive_wrapper, " elif tarfile.is_tarfile(f):" + print >> unarchive_wrapper, " archive = tarfile.open(f, 'r:*')" + print >> unarchive_wrapper, " path = '{}'".format(self.conf.argdict['path']) + print >> unarchive_wrapper, " print 'Extracting archive {0} to {1}'.format(f,path)" + print >> unarchive_wrapper, " archive.extractall(path)" + print >> unarchive_wrapper, " archive.close()" + os.chmod('unarchive_wrapper.py', 0755) + except (IOError, OSError) as e: + errMsg = 'error writing unarchive wrapper {fileName}: {error}'.format(fileName = 'unarchive_wrapper.py', + error = e + ) + msg.error(errMsg) + raise trfExceptions.TransformExecutionException(trfExit.nameToCode('TRF_EXEC_SETUP_WRAPPER'), + errMsg + ) + self._cmd.append('unarchive_wrapper.py') super(archiveExecutor, self).preExecute(input=input, output=output) diff --git a/Tools/PyJobTransforms/scripts/Archive_tf.py b/Tools/PyJobTransforms/scripts/Archive_tf.py index d943496b1ce796faaed3df4ec6883c29e51e5376..2798ca5be0863301dc24b4fc24754a442662124e 100755 --- a/Tools/PyJobTransforms/scripts/Archive_tf.py +++ b/Tools/PyJobTransforms/scripts/Archive_tf.py @@ -36,27 +36,35 @@ def main(): sys.exit(trf.exitCode) def getTransform(): - trf = transform(executor = archiveExecutor(name = 'Archiver', exe = 'zip')) + executorSet = set() + executorSet.add(archiveExecutor(name = 'Archiver', exe = 'zip', inData = ['Data'], outData = ['Arch'])) + executorSet.add(archiveExecutor(name = 'Unarchiver', exe = 'unarchive', inData = ['Arch'], outData = ['outNULL'])) + trf = transform(executor = executorSet) addMyArgs(trf.parser) return trf def addMyArgs(parser): # Use arggroup to get these arguments in their own sub-section (of --help) - parser.defineArgGroup('Archive_tf', 'Archive transform options') + parser.defineArgGroup('Archiver', 'Options') + parser.defineArgGroup('Unarchiver', 'Options') parser.defineArgGroup('Tar archiver', 'Options') - parser.add_argument('--exe', group='Archive_tf', - help='Archiving command. Default is zip', choices=['zip', 'tar'], - default='zip') - parser.add_argument('--inputDataFile', '--inputFile', nargs='+', + parser.add_argument('--exe', group='Archiver', + help='Archiving command, default is zip', choices=['zip', 'tar']) + parser.add_argument('--inputDataFile', '--inputFile', nargs='+', type=trfArgClasses.argFactory(trfArgClasses.argFile, io='input', type='misc'), - help='Input file(s)', group='Archive_tf') + help='Input file(s)', group='Archiver') + parser.add_argument('--inputArchFile', + type=trfArgClasses.argFactory(trfArgClasses.argFile, io='input', type='misc'), + help='Input archive file', group='Unarchiver') + parser.add_argument('--path', group='Unarchiver', + help='Specifies a different directory to extract to. The default is the current working directory', default='.') parser.add_argument('--outputArchFile', '--outputFile', type=trfArgClasses.argFactory(trfArgClasses.argFile, io='output', type='misc'), - help='Output archive file', group='Archive_tf') + help='Output archive file', group='Archiver') parser.add_argument('--compressionType', group='Tar archiver', - help='Underlying compression type of tar. Default is none', choices=['gzip', 'bzip2', 'none'], + help='Underlying compression type of tar. The default is none', choices=['gzip', 'bzip2', 'none'], default='none') if __name__ == '__main__':