2 # vim: set ts=4 sts=4 sw=4 textwidth=112 :
7 import os, sys, optparse, logging
9 import RarslaveDetector
11 # Global options from the rsutil.globals class
12 options = rsutil.globals.options
13 config = rsutil.globals.config
15 # A tiny class to hold logging output until we're finished
16 class DelayedLogger (object):
17 def __init__ (self, output=sys.stdout.write):
19 self.__output = output
21 def write (self, msg):
22 self.__messages.append (msg)
28 """Returns the number of messages queued for printing"""
29 return len (self.__messages)
32 """Print all messages, clear the queue"""
33 for m in self.__messages:
38 # A tiny class used to find unique PAR2 sets
39 class CompareSet (object):
41 def __init__ (self, dir, p2file):
45 self.basename = rsutil.common.get_basename (self.p2file)
46 self.name_matches = rsutil.common.find_name_matches (self.dir, self.basename)
48 def __eq__ (self, rhs):
49 return (self.dir == rhs.dir) \
50 and (self.basename == rhs.basename) \
51 and rsutil.common.list_eq (self.name_matches, rhs.name_matches)
54 def find_all_par2_files (dir):
55 """Finds all par2 files in a directory"""
56 # NOTE: does NOT return absolute paths
58 if not os.path.isdir (os.path.abspath (dir)):
59 raise ValueError # bad directory given
61 dir = os.path.abspath (dir)
62 files = os.listdir (dir)
64 return rsutil.common.find_par2_files (files)
66 def generate_all_parsets (dir):
67 # Generate all parsets in the given directory.
69 assert os.path.isdir (dir) # Directory MUST be valid
72 p2files = find_all_par2_files (dir)
75 p = CompareSet (dir, f)
79 return [(p.dir, p.p2file) for p in parsets]
81 def check_required_progs():
82 """Check if the required programs are installed"""
84 shell_not_found = 32512
87 if rsutil.common.run_command ('par2repair --help > /dev/null 2>&1') == shell_not_found:
88 needed.append ('par2repair')
90 if rsutil.common.run_command ('unrar --help > /dev/null 2>&1') == shell_not_found:
91 needed.append ('unrar')
93 if rsutil.common.run_command ('unzip --help > /dev/null 2>&1') == shell_not_found:
94 needed.append ('unzip')
98 print 'Needed program "%s" not found in $PATH' % (n, )
102 def run_options (options):
105 options.work_dir = rsutil.common.full_abspath (options.work_dir)
107 # Make sure that the directory is valid
108 if not os.path.isdir (options.work_dir):
109 sys.stderr.write ('\"%s\" is not a valid directory. Use the \"-d\"\n' % options.work_dir)
110 sys.stderr.write ('option to override the working directory temporarily, or edit the\n')
111 sys.stderr.write ('configuration file to override the working directory permanently.\n')
114 if options.extract_dir != None:
115 options.extract_dir = rsutil.common.full_abspath (options.extract_dir)
118 print PROGRAM + ' - ' + VERSION
120 print 'Copyright (c) 2005,2006 Ira W. Snyder (devel@irasnyder.com)'
122 print 'This program comes with ABSOLUTELY NO WARRANTY.'
123 print 'This is free software, and you are welcome to redistribute it'
124 print 'under certain conditions. See the file COPYING for details.'
127 if options.check_progs:
128 check_required_progs ()
130 if options.write_def_config:
131 config.write_config (default=True)
133 if options.write_config:
134 config.write_config ()
136 def find_loglevel (options):
138 loglevel = options.verbose - options.quiet
146 LEVELS = { 1 : logging.DEBUG,
153 return LEVELS [loglevel]
158 logger = DelayedLogger ()
159 logging.basicConfig (stream=logger, level=logging.WARNING, \
160 format='%(levelname)-8s %(message)s')
162 # Build the OptionParser
163 parser = optparse.OptionParser()
164 parser.add_option('-n', '--not-recursive', action='store_false', dest='recursive',
165 default=rsutil.common.config_get_value('options', 'recursive'),
166 help="Don't run recursively")
168 parser.add_option('-d', '--work-dir', dest='work_dir', type='string',
169 default=rsutil.common.config_get_value('directories', 'working_directory'),
170 help="Start running at DIR", metavar='DIR')
172 parser.add_option('-e', '--extract-dir', dest='extract_dir', type='string',
173 default=rsutil.common.config_get_value('directories', 'extract_directory'),
174 help="Extract to DIR", metavar='DIR')
176 parser.add_option('-p', '--check-required-programs',
177 action='store_true', dest='check_progs',
179 help="Check for required programs")
181 parser.add_option('-f', '--write-default-config',
182 action='store_true', dest='write_def_config',
183 default=False, help="Write out a new default config")
185 parser.add_option('-c', '--write-new-config',
186 action='store_true', dest='write_config',
187 default=False, help="Write out the current config")
189 parser.add_option('-i', '--interactive', dest='interactive', action='store_true',
190 default=rsutil.common.config_get_value('options', 'interactive'),
191 help="Confirm before removing files")
193 parser.add_option('-q', '--quiet', dest='quiet', action='count',
194 default=0, help="Output fatal messages only")
196 parser.add_option('-v', '--verbose', dest='verbose', action='count',
197 default=0, help="Output extra information")
199 parser.add_option('-V', '--version', dest='version', action='store_true',
200 default=False, help="Output version information")
202 parser.version = VERSION
204 # Parse the given options
206 (rsutil.globals.options, args) = parser.parse_args()
207 options = rsutil.globals.options
209 # Run any special actions that are needed on these options
210 run_options (options)
212 # Find the loglevel using the options given
213 logging.getLogger().setLevel (find_loglevel (options))
216 if options.recursive:
217 for (dir, subdirs, files) in os.walk (options.work_dir):
218 parsets = generate_all_parsets (dir)
219 for (p2dir, p2file) in parsets:
220 detector = RarslaveDetector.RarslaveDetector (p2dir, p2file)
221 ret = detector.runMatchingTypes ()
225 parsets = generate_all_parsets (options.work_dir)
226 for (p2dir, p2file) in parsets:
227 detector = RarslaveDetector.RarslaveDetector (p2dir, p2file)
228 ret = detector.runMatchingTypes ()
231 if logger.size () > 0:
232 print '\nLog\n' + '=' * 80
238 if __name__ == '__main__':