+VERSION="2.0.0"
+PROGRAM="rarslave2"
+
+import re, os, sys, optparse
+import par2parser
+import RarslaveConfig
+import RarslaveLogger
+
+# Global Variables
+(TYPE_OLDRAR, TYPE_NEWRAR, TYPE_ZIP, TYPE_NOEXTRACT) = range (4)
+(SUCCESS, ECHECK, EEXTRACT, EDELETE) = range(4)
+config = RarslaveConfig.RarslaveConfig()
+logger = RarslaveLogger.RarslaveLogger ()
+
+# Global options to be set / used later.
+options = None
+
+class RarslaveExtractor (object):
+
+ def __init__ (self, type):
+ self.type = type
+ self.heads = []
+
+ def addHead (self, dir, head):
+ assert os.path.isdir (dir)
+ assert os.path.isfile (os.path.join (dir, head))
+
+ full_head = os.path.join (dir, head)
+ logger.addMessage ('Adding extraction head: %s' % full_head, RarslaveLogger.MessageType.Debug)
+ self.heads.append (full_head)
+
+ def extract (self, todir=None):
+ # Extract all heads of this set
+
+ # Create the directory $todir if it doesn't exist
+ if todir != None and not os.path.isdir (todir):
+ logger.addMessage ('Creating directory: %s' % todir, RarslaveLogger.MessageType.Verbose)
+ try:
+ os.makedirs (todir)
+ except OSError:
+ logger.addMessage ('FAILED to create directory: %s' % todir, RarslaveLogger.MessageType.Fatal)
+ return -EEXTRACT
+
+ # Extract all heads
+ extraction_func = \
+ { TYPE_OLDRAR : self.__extract_rar,
+ TYPE_NEWRAR : self.__extract_rar,
+ TYPE_ZIP : self.__extract_zip,
+ TYPE_NOEXTRACT : self.__extract_noextract }[self.type]
+
+ # Call the extraction function on each head
+ for h in self.heads:
+ if todir == None:
+ # Run in the head's directory
+ ret = extraction_func (h, os.path.dirname (h))
+ else:
+ ret = extraction_func (h, todir)
+
+ logger.addMessage ('Extraction Function returned: %d' % ret, RarslaveLogger.MessageType.Debug)
+
+ # Check error code
+ if ret != SUCCESS:
+ logger.addMessage ('Failed extracting: %s' % h, RarslaveLogger.MessageType.Fatal)
+ return -EEXTRACT
+
+ return SUCCESS
+
+ def __extract_rar (self, file, todir):
+ assert os.path.isfile (file)
+ assert os.path.isdir (todir)
+
+ RAR_CMD = config.get_value ('commands', 'unrar')
+
+ cmd = '%s \"%s\"' % (RAR_CMD, file)
+ ret = run_command (cmd, todir)
+
+ # Check error code
+ if ret != 0:
+ return -EEXTRACT
+
+ return SUCCESS
+
+ def __extract_zip (self, file, todir):
+ ZIP_CMD = config.get_value ('commands', 'unzip')
+
+ cmd = ZIP_CMD % (file, todir)
+ ret = run_command (cmd)
+
+ # Check error code
+ if ret != 0:
+ return -EEXTRACT
+
+ return SUCCESS
+
+ def __extract_noextract (self, file, todir):
+ # Just move this file to the $todir, since no extraction is needed
+ # FIXME: NOTE: mv will fail by itself if you're moving to the same dir!
+ NOEXTRACT_CMD = config.get_value ('commands', 'noextract')
+
+ # Make sure that both files are not the same file. If they are, don't run at all.
+ if os.path.samefile (file, os.path.join (todir, file)):
+ return SUCCESS
+
+ cmd = NOEXTRACT_CMD % (file, todir)
+ ret = run_command (cmd)
+
+ # Check error code
+ if ret != 0:
+ return -EEXTRACT
+
+ return SUCCESS
+
+
+
+class RarslaveRepairer (object):
+ # Verify (and repair) the set
+ # Make sure it worked, otherwise clean up and return failure
+
+ def __init__ (self, dir, file, join=False):
+ self.dir = dir # the directory containing the par2 file
+ self.file = file # the par2 file
+ self.join = join # True if the par2 set is 001 002 ...
+
+ assert os.path.isdir (dir)
+ assert os.path.isfile (os.path.join (dir, file))
+
+ def checkAndRepair (self):
+ # Form the command:
+ # par2repair -- PAR2 PAR2_EXTRA [JOIN_FILES]
+ PAR2_CMD = config.get_value ('commands', 'par2repair')
+
+ # Get set up
+ basename = get_basename (self.file)
+ all_files = find_likely_files (self.dir, self.file)
+ all_files.sort ()
+ par2_files = find_par2_files (all_files)
+
+ # assemble the command
+ command = "%s \"%s\" " % (PAR2_CMD, self.file)
+
+ for f in par2_files:
+ if f != self.file:
+ command += "\"%s\" " % os.path.split (f)[1]
+
+ if self.join:
+ for f in all_files:
+ if f not in par2_files:
+ 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.file, RarslaveLogger.MessageType.Fatal)
+ return -ECHECK
+
+ 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)
+
+ ret = os.system (cmd)
+ os.chdir (pwd)
+ return ret
+
+def full_abspath (p):
+ return os.path.abspath (os.path.expanduser (p))