scripts/dtrx

branch
trunk
changeset 106
dcf005ef7070
parent 105
f76ac41fe061
child 108
b8316c2b36df
equal deleted inserted replaced
105:f76ac41fe061 106:dcf005ef7070
169 for index, code in enumerate(self.exit_codes): 169 for index, code in enumerate(self.exit_codes):
170 if code != 0: 170 if code != 0:
171 return index 171 return index
172 return None 172 return None
173 173
174 def add_process(self, processes, command, stdin, stdout):
175 try:
176 processes.append(subprocess.Popen(command, stdin=stdin,
177 stdout=stdout,
178 stderr=self.stderr))
179 except OSError, error:
180 if error.errno == errno.ENOENT:
181 raise ExtractorUnusable("could not run %s" % (command[0],))
182 raise
183
174 def run_pipes(self, final_stdout=None): 184 def run_pipes(self, final_stdout=None):
175 if not self.pipes: 185 if not self.pipes:
176 return 186 return
177 elif final_stdout is None: 187 elif final_stdout is None:
178 # FIXME: Buffering this might be dumb. 188 final_stdout = open('/dev/null', 'w')
179 final_stdout = tempfile.TemporaryFile()
180 num_pipes = len(self.pipes) 189 num_pipes = len(self.pipes)
181 last_pipe = num_pipes - 1 190 last_pipe = num_pipes - 1
182 processes = [] 191 processes = []
183 for index, command in enumerate([pipe[0] for pipe in self.pipes]): 192 for index, command in enumerate([pipe[0] for pipe in self.pipes]):
184 if index == 0: 193 if index == 0:
187 stdin = processes[-1].stdout 196 stdin = processes[-1].stdout
188 if index == last_pipe: 197 if index == last_pipe:
189 stdout = final_stdout 198 stdout = final_stdout
190 else: 199 else:
191 stdout = subprocess.PIPE 200 stdout = subprocess.PIPE
192 try: 201 self.add_process(processes, command, stdin, stdout)
193 processes.append(subprocess.Popen(command, stdin=stdin,
194 stdout=stdout,
195 stderr=self.stderr))
196 except OSError, error:
197 if error.errno == errno.ENOENT:
198 raise ExtractorUnusable("could not run %s" % (command[0],))
199 raise
200 self.exit_codes = [pipe.wait() for pipe in processes] 202 self.exit_codes = [pipe.wait() for pipe in processes]
201 self.archive.close() 203 self.archive.close()
202 for index in range(last_pipe): 204 for index in range(last_pipe):
203 processes[index].stdout.close() 205 processes[index].stdout.close()
204 self.archive = final_stdout 206 self.archive = final_stdout
288 self.archive.close() 290 self.archive.close()
289 os.chdir(old_path) 291 os.chdir(old_path)
290 292
291 def get_filenames(self): 293 def get_filenames(self):
292 self.pipe(self.list_pipe, "listing") 294 self.pipe(self.list_pipe, "listing")
293 self.run_pipes() 295 processes = []
296 stdin = self.archive
297 for command in [pipe[0] for pipe in self.pipes]:
298 self.add_process(processes, command, stdin, subprocess.PIPE)
299 stdin = processes[-1].stdout
300 get_output_line = processes[-1].stdout.readline
301 while True:
302 line = get_output_line()
303 if not line:
304 break
305 yield line.rstrip('\n')
306 self.exit_codes = [pipe.wait() for pipe in processes]
307 self.archive.close()
308 for process in processes:
309 process.stdout.close()
294 self.check_success(False) 310 self.check_success(False)
295 self.archive.seek(0, 0)
296 while True:
297 line = self.archive.readline()
298 if not line:
299 self.archive.close()
300 return
301 yield line.rstrip('\n')
302 311
303 312
304 class CompressionExtractor(BaseExtractor): 313 class CompressionExtractor(BaseExtractor):
305 file_type = 'compressed file' 314 file_type = 'compressed file'
306 name_checker = FilenameChecker 315 name_checker = FilenameChecker
950 class BaseAction(object): 959 class BaseAction(object):
951 def __init__(self, options, filenames): 960 def __init__(self, options, filenames):
952 self.options = options 961 self.options = options
953 self.filenames = filenames 962 self.filenames = filenames
954 self.target = None 963 self.target = None
964 self.do_print = False
955 965
956 def report(self, function, *args): 966 def report(self, function, *args):
957 try: 967 try:
958 error = function(*args) 968 error = function(*args)
959 except EXTRACTION_ERRORS, exception: 969 except EXTRACTION_ERRORS, exception:
960 error = str(exception) 970 error = str(exception)
961 logger.debug(''.join(traceback.format_exception(*sys.exc_info()))) 971 logger.debug(''.join(traceback.format_exception(*sys.exc_info())))
962 return error 972 return error
963 973
974 def show_filename(self, filename):
975 if len(self.filenames) < 2:
976 return
977 elif self.do_print:
978 print
979 else:
980 self.do_print = True
981 print "%s:" % (filename,)
982
964 983
965 class ExtractionAction(BaseAction): 984 class ExtractionAction(BaseAction):
966 handlers = [FlatHandler, OverwriteHandler, MatchHandler, EmptyHandler, 985 handlers = [FlatHandler, OverwriteHandler, MatchHandler, EmptyHandler,
967 BombHandler] 986 BombHandler]
968
969 def __init__(self, options, filenames):
970 BaseAction.__init__(self, options, filenames)
971 self.did_print = False
972 987
973 def get_handler(self, extractor): 988 def get_handler(self, extractor):
974 if extractor.content_type in ONE_ENTRY_UNKNOWN: 989 if extractor.content_type in ONE_ENTRY_UNKNOWN:
975 self.options.one_entry_policy.prep(self.current_filename, 990 self.options.one_entry_policy.prep(self.current_filename,
976 extractor) 991 extractor)
981 break 996 break
982 997
983 def show_extraction(self, extractor): 998 def show_extraction(self, extractor):
984 if self.options.log_level > logging.INFO: 999 if self.options.log_level > logging.INFO:
985 return 1000 return
986 elif self.did_print: 1001 self.show_filename(self.current_filename)
987 print
988 else:
989 self.did_print = True
990 print "%s:" % (self.current_filename,)
991 if extractor.contents is None: 1002 if extractor.contents is None:
992 print self.current_handler.target 1003 print self.current_handler.target
993 return 1004 return
994 def reverser(x, y): 1005 def reverser(x, y):
995 return cmp(y, x) 1006 return cmp(y, x)
1021 self.target = self.current_handler.target 1032 self.target = self.current_handler.target
1022 return error 1033 return error
1023 1034
1024 1035
1025 class ListAction(BaseAction): 1036 class ListAction(BaseAction):
1026 def __init__(self, options, filenames): 1037 def list_filenames(self, extractor, filename):
1027 BaseAction.__init__(self, options, filenames) 1038 # We get a line first to make sure there's not going to be some
1028 self.count = 0 1039 # basic error before we show what filename we're listing.
1029 1040 filename_lister = extractor.get_filenames()
1030 def get_list(self, extractor): 1041 try:
1031 # Note: The reason I'm getting all the filenames up front is 1042 first_line = filename_lister.next()
1032 # because if we run into trouble partway through the archive, we'll 1043 except StopIteration:
1033 # try another extractor. So before we display anything we have to 1044 self.show_filename(filename)
1034 # be sure this one is successful. We maybe don't have to be quite 1045 else:
1035 # this conservative but this is the easy way out for now. 1046 self.did_list = True
1036 self.filelist = list(extractor.get_filenames()) 1047 self.show_filename(filename)
1037 1048 print first_line
1038 def show_list(self, filename): 1049 for line in filename_lister:
1039 self.count += 1 1050 print line
1040 if len(self.filenames) != 1: 1051
1041 if self.count > 1:
1042 print
1043 print "%s:" % (filename,)
1044 print '\n'.join(self.filelist)
1045
1046 def run(self, filename, extractor): 1052 def run(self, filename, extractor):
1047 return (self.report(self.get_list, extractor) or 1053 self.did_list = False
1048 self.report(self.show_list, filename)) 1054 error = self.report(self.list_filenames, extractor, filename)
1055 if error and self.did_list:
1056 logger.error("lister failed: ignore above listing for %s" %
1057 (filename,))
1058 return error
1049 1059
1050 1060
1051 class ExtractorApplication(object): 1061 class ExtractorApplication(object):
1052 def __init__(self, arguments): 1062 def __init__(self, arguments):
1053 for signal_num in (signal.SIGINT, signal.SIGTERM): 1063 for signal_num in (signal.SIGINT, signal.SIGTERM):

mercurial