Add Copyright / License information + Documentation
[rarslave2.git] / PAR2Set / Base.py
index 772e4a5..533ff4f 100644 (file)
@@ -1,12 +1,38 @@
 #!/usr/bin/env python
 # vim: set ts=4 sts=4 sw=4 textwidth=92:
 
-import rsutil.common
+"""
+Holds the PAR2Set base class
+"""
+
+__author__    = "Ira W. Snyder (devel@irasnyder.com)"
+__copyright__ = "Copyright (c) 2006,2007 Ira W. Snyder (devel@irasnyder.com)"
+__license__   = "GNU GPL v2 (or, at your option, any later version)"
+
+#    Base.py
+#
+#    Copyright (C) 2006,2007  Ira W. Snyder (devel@irasnyder.com)
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 import re
 import os
 import logging
 
+import rsutil.common
+
 # This is a fairly generic class which does all of the major things that a PAR2
 # set will need to have done to be verified and extracted. For most "normal" types
 # you won't need to override hardly anything.
@@ -14,11 +40,12 @@ import logging
 # It is ok to override other functions if the need arises, just make sure that you
 # understand why things are done the way that they are in the original versions.
 #
-# Assumptions made about each of the run*() functions:
+# Assumptions made in the runVerifyAndRepair(), runExtract() and runDelete() functions:
 # ==============================================================================
-# The state of self.name_matched_files and self.prot_matched_files will be consistent
-# with the real, in-filesystem state at the time that they are called.
-# (This is why runAll() calls update_matches() all the time.)
+# The state of self.name_matched_files, self.prot_matched_files, and self.all_files
+# will be consistent with the real, in-filesystem state at the time that they are
+# called. This is the reason that runAll() calls update_matches() after running each
+# operation that will possibly change the filesystem.
 #
 # Required overrides:
 # ==============================================================================
@@ -27,6 +54,7 @@ import logging
 #
 
 class Base (object):
+       """Base class for all PAR2Set types"""
 
        # Instance Variables
        # ==========================================================================
@@ -38,6 +66,11 @@ class Base (object):
        # prot_matched_files    -- Files in this set, guessed by parsing the PAR2 only
 
        def __init__ (self, dir, p2file):
+               """Default constructor for all PAR2Set types
+
+                  dir -- a directory
+                  p2file -- a PAR2 file inside the given directory"""
+
                assert os.path.isdir (dir)
                assert os.path.isfile (os.path.join (dir, p2file))
 
@@ -59,18 +92,23 @@ class Base (object):
                self.all_files = rsutil.common.no_duplicates (self.name_matched_files + self.prot_matched_files)
 
        def __eq__ (self, rhs):
+               """Check for equality between PAR2Set types"""
+
                return (self.dir == rhs.dir) and (self.basename == rhs.basename) and \
                                rsutil.common.list_eq (self.name_matched_files, rhs.name_matched_files) and \
                                rsutil.common.list_eq (self.prot_matched_files, rhs.prot_matched_files)
 
        def update_matches (self):
-               """Updates the contents of instance variables which are likely to change after
-               running an operation, usually one which will create new files."""
+               """Updates the contents of instance variables with the current in-filesystem state.
+                  This should be run after any operation which can create or delete files."""
 
                self.name_matched_files = rsutil.common.find_name_matches (self.dir, self.basename)
                self.all_files = rsutil.common.no_duplicates (self.name_matched_files + self.prot_matched_files)
 
        def runVerifyAndRepair (self):
+               """Verify and Repair a PAR2Set. This is done using the par2repair command by
+                  default"""
+
                PAR2_CMD = rsutil.common.config_get_value ('commands', 'par2repair')
 
                # assemble the command
@@ -92,13 +130,20 @@ class Base (object):
                return rsutil.common.SUCCESS
 
        def find_deleteable_files (self):
+               """Find all files which are deletable by using the regular expression from the
+                  configuration file"""
+
                DELETE_REGEX = rsutil.common.config_get_value ('regular expressions', 'delete_regex')
                dregex = re.compile (DELETE_REGEX, re.IGNORECASE)
 
                return [f for f in self.all_files if dregex.match (f)]
 
        def delete_list_of_files (self, dir, files, interactive=False):
-               # Delete a list of files
+               """Attempt to delete all files given
+
+                  dir -- the directory where the files live
+                  files -- the filenames themselves
+                  interactive -- prompt before deleteion"""
 
                assert os.path.isdir (dir)
 
@@ -130,6 +175,8 @@ class Base (object):
                return rsutil.common.SUCCESS
 
        def runDelete (self):
+               """Run the delete operation and return the result"""
+
                deleteable_files = self.find_deleteable_files ()
                ret = self.delete_list_of_files (self.dir, deleteable_files, \
                                rsutil.common.options_get_value ('interactive'))
@@ -137,6 +184,7 @@ class Base (object):
                return ret
 
        def runAll (self):
+               """Run all of the major sections in the class: repair, extraction, and deletion."""
 
                # Repair Stage
                ret = self.runVerifyAndRepair ()
@@ -167,6 +215,10 @@ class Base (object):
                return rsutil.common.SUCCESS
 
        def safe_create_directory (self, dir):
+               """Safely create a directory, logging the result.
+
+                  dir -- the directory to create (None is ignored)"""
+
                if dir == None:
                        return rsutil.common.SUCCESS
 
@@ -183,7 +235,7 @@ class Base (object):
                return rsutil.common.SUCCESS
 
        def runExtract (self, todir=None):
-               """Extract all heads of this set"""
+               """Extract all heads of this set and return the result"""
 
                # Extract to the head's dir if we don't care where to extract
                if todir == None:
@@ -209,14 +261,16 @@ class Base (object):
                return rsutil.common.SUCCESS
 
        def find_extraction_heads (self):
+               """Find all extraction heads associated with this set. This must be
+                  overridden for the associated PAR2Set derived class to work."""
+
                assert False # You MUST override this on a per-type basis
 
        def extraction_function (self, file, todir):
-               # NOTE: Please keep the prototype the same for all overridden functions.
-               # Doing so will guarantee that your life is made much easier.
-               #
-               # Also note that the todir given will always be valid for the current directory
-               # when the function is called.
+               """Extract a single head of this PAR2Set's type.
+
+                  file -- the full path to the file to be extracted
+                  todir -- the directory to extract to"""
 
                assert False # You MUST override this on a per-type basis