+ extractor = __getExtractor(source, env)
+ if not extractor :
+ raise SCons.Errors.StopError( "can not find any extractor value for the source file [%s]" % (source[0]) )
+
+ # we do a little trick, because in some cases we do not have got a physical
+ # file (eg we download a packed archive), so we don't get a list or knows
+ # the targets. On physical files we can do this with the LISTCMD, but on
+ # non-physical files we hope the user knows the target files, so we inject
+ # this knowledge into the return target.
+ if "UNPACKLIST" in env :
+ if not SCons.Util.is_List(env["UNPACKLIST"]) and not SCons.Util.is_String(env["UNPACKLIST"]) :
+ raise SCons.Errors.StopError( "manual target list of [%s] must be a string or list" % (source[0]) )
+ if not env["UNPACKLIST"] :
+ raise SCons.Errors.StopError( "manual target list of [%s] need not be empty" % (source[0]) )
+ return env["UNPACKLIST"], source
+
+
+ # we check if the source file exists, because we would like to read the data
+ if not source[0].exists() :
+ raise SCons.Errors.StopError( "source file [%s] must be exist" % (source[0]) )
+
+ # create the list command and run it in a subprocess and pipes the output to a variable,
+ # we need the shell for reading data from the stdout
+ cmd = env.subst(extractor["LISTCMD"], source=source, target=target)
+ handle = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE )
+ target = handle.stdout.readlines()
+ handle.communicate()
+ if handle.returncode != 0 :
+ raise SCons.Errors.StopError("error on running list command [%s] of the source file [%s]" % (cmd, source[0]) )
+
+ # if the returning output exists and the listseperator is a callable structure
+ # we run it for each line of the output and if the return of the callable is
+ # a string we push it back to the target list
+ try :
+ if callable(extractor["LISTEXTRACTOR"]) :
+ target = [s for s in [ extractor["LISTEXTRACTOR"]( env, len(target), no, i) for no, i in enumerate(target) ] if SCons.Util.is_String(s)]
+ except Exception as e :
+ raise SCons.Errors.StopError( "%s" % (e) )
+
+ # the line removes duplicated names - we need this line, otherwise an cyclic dependency error will occured,
+ # because the list process can create redundant data (an archive file can not store redundant content in a filepath)
+ target = [i.strip() for i in list(set(target))]
+ if not target :
+ SCons.Warnings.warn(UnpackWarning, "emitter file list on target [%s] is empty, please check your extractor list function [%s]" % (source[0], cmd) )
+
+ # we append the extractdir to each target if is not absolut
+ if env["UNPACK"]["EXTRACTDIR"] != "." :
+ target = [i if os.path.isabs(i) else os.path.join(env["UNPACK"]["EXTRACTDIR"], i) for i in target]
+