+ regex = config.get_value ('regular expressions', 'basename_regex')
+ r = re.compile (regex, re.IGNORECASE)
+ done = False
+
+ while not done:
+ done = True
+
+ if r.match (name):
+ g = r.match (name).groups()
+ name = g[0]
+ done = False
+
+ return name
+
+ def __parse_all_par2 (self):
+ """Searches though self.all_p2files and tries to parse at least one of them"""
+ done = False
+ files = []
+
+ for f in self.all_p2files:
+
+ # Exit early if we've found a good file
+ if done:
+ break
+
+ try:
+ files = Par2Parser.get_protected_files (self.dir, f)
+ done = True
+ except (EnvironmentError, OSError, OverflowError):
+ logger.addMessage ('Corrupt PAR2 file: %s' % f, RarslaveLogger.MessageType.Fatal)
+
+ # Now that we're out of the loop, check if we really finished
+ if not done:
+ logger.addMessage ('All PAR2 files corrupt for: %s' % self.p2file, RarslaveLogger.MessageType.Fatal)
+
+ # Return whatever we've got, empty or not
+ return files
+
+ def __find_name_matches (self, dir, basename):
+ """Finds files which are likely to be part of the set corresponding
+ to $name in the directory $dir"""
+
+ assert os.path.isdir (dir)
+
+ ename = re.escape (basename)
+ regex = re.compile ('^%s.*$' % (ename, ))
+
+ return [f for f in os.listdir (dir) if regex.match (f)]
+
+ def __update_name_matches (self):
+ """Updates the self.name_matched_files variable with the most current information.
+ This should be called after the directory contents are likely to change."""
+
+ self.name_matched_files = self.__find_name_matches (self.dir, self.basename)
+
+ def __is_joinfile (self, filename):
+ regex = re.compile ('^.*\.\d\d\d$', re.IGNORECASE)
+ if regex.match (filename):
+ return True
+
+ return False
+
+ def __should_be_joined (self, files):
+ for f in files:
+ if self.__is_joinfile (f):
+ return True
+
+ def runCheckAndRepair (self):
+ PAR2_CMD = config.get_value ('commands', 'par2repair')
+
+ # Get set up
+ all_files = no_duplicates (self.name_matched_files + self.prot_matched_files)
+ join = self.__should_be_joined (all_files)
+
+ # assemble the command
+ # par2repair -- PAR2 PAR2_EXTRA [JOIN_FILES]
+ command = "%s \"%s\" " % (PAR2_CMD, self.p2file)
+
+ for f in self.all_p2files:
+ if f != self.p2file:
+ command += "\"%s\" " % os.path.split (f)[1]
+
+ # Only needed when using par2 to join
+ if join:
+ for f in all_files:
+ if self.__is_joinfile (f):
+ command += "\"%s\" " % os.path.split (f)[1]
+
+ # run the command
+ ret = run_command (command, self.dir)
+
+ # check the result
+ if ret != 0:
+ logger.addMessage ('PAR2 Check / Repair failed: %s' % self.p2file, RarslaveLogger.MessageType.Fatal)
+ return -ECHECK
+
+ return SUCCESS
+
+ def __find_deleteable_files (self):
+ all_files = no_duplicates (self.name_matched_files + self.prot_matched_files)
+ DELETE_REGEX = config.get_value ('regular expressions', 'delete_regex')
+ dregex = re.compile (DELETE_REGEX, re.IGNORECASE)
+
+ return [f for f in all_files if dregex.match (f)]
+
+ def __delete_list_of_files (self, dir, files, interactive=False):
+ # Delete a list of files
+
+ assert os.path.isdir (dir)
+
+ done = False
+ valid_y = ['Y', 'YES']
+ valid_n = ['N', 'NO', '']
+
+ if interactive:
+ while not done:
+ print 'Do you want to delete the following?:'
+ for f in files:
+ print f
+ s = raw_input ('Delete [y/N]: ').upper()
+
+ if s in valid_y + valid_n:
+ done = True
+
+ if s in valid_n:
+ return SUCCESS
+
+ for f in files:
+ try:
+ os.remove (os.path.join (dir, f))
+ logger.addMessage ('Deleteing: %s' % os.path.join (dir, f), RarslaveLogger.MessageType.Debug)
+ except:
+ logger.addMessage ('Failed to delete: %s' % os.path.join (dir, f),
+ RarslaveLogger.MessageType.Fatal)
+ return -EDELETE
+
+ return SUCCESS
+
+ def runDelete (self):
+ deleteable_files = self.__find_deleteable_files ()
+ ret = self.__delete_list_of_files (self.dir, deleteable_files, options.interactive)
+
+ return ret
+
+ def run_all (self):
+ all_files = no_duplicates (self.name_matched_files + self.prot_matched_files)
+
+ # Repair Stage
+ ret = self.runCheckAndRepair ()
+
+ if ret != SUCCESS:
+ logger.addMessage ('Repair stage failed for: %s' % self.p2file, RarslaveLogger.MessageType.Fatal)
+ return -ECHECK
+
+ self.__update_name_matches ()
+ all_files = no_duplicates (self.name_matched_files + self.prot_matched_files)
+
+ # Extraction Stage
+ extractor = RarslaveExtractor (self.dir, self.all_p2files, \
+ self.name_matched_files, self.prot_matched_files)
+ ret = extractor.runExtract (options.extract_dir)
+
+ if ret != SUCCESS:
+ logger.addMessage ('Extraction stage failed for: %s' % self.p2file, RarslaveLogger.MessageType.Fatal)
+ return -EEXTRACT
+
+ self.__update_name_matches ()
+ all_files = no_duplicates (self.name_matched_files + self.prot_matched_files)
+
+ # Deletion Stage
+ ret = self.runDelete ()
+
+ if ret != SUCCESS:
+ logger.addMessage ('Deletion stage failed for: %s' % self.p2file, RarslaveLogger.MessageType.Fatal)
+ return -EDELETE
+
+ logger.addMessage ('Successfully completed: %s' % self.p2file)
+ return SUCCESS
+
+def run_command (cmd, indir=None):
+ # Runs the specified command-line in the directory given (or, in the current directory
+ # if none is given). It returns the status code given by the application.
+
+ pwd = os.getcwd ()
+
+ if indir != None:
+ assert os.path.isdir (indir) # MUST be a directory!
+ os.chdir (indir)
+
+ print 'RUNNING (%s): %s' % (indir, cmd)
+ ret = os.system (cmd)
+ os.chdir (pwd)
+ return ret
+
+def full_abspath (p):
+ return os.path.abspath (os.path.expanduser (p))
+
+def find_par2_files (files):
+ """Find all par2 files in the list $files"""
+
+ PAR2_REGEX = config.get_value ('regular expressions', 'par2_regex')
+ regex = re.compile (PAR2_REGEX, re.IGNORECASE)
+ return [f for f in files if regex.match (f)]