2 # vim: set ts=4 sts=4 sw=4 textwidth=112 :
7 import os, sys, optparse, logging
8 import RarslaveDetector
10 from RarslaveCommon import *
12 # Global options from the RarslaveGlobals class
13 options = RarslaveGlobals.options
14 config = RarslaveGlobals.config
16 # A tiny class to hold logging output until we're finished
17 class DelayedLogger (object):
18 def __init__ (self, output=sys.stdout.write):
20 self.__output = output
22 def write (self, msg):
23 self.__messages.append (msg)
29 """Returns the number of messages queued for printing"""
30 return len (self.__messages)
33 """Print all messages, clear the queue"""
34 for m in self.__messages:
39 # A tiny class used to find unique PAR2 sets
40 class CompareSet (object):
42 def __init__ (self, dir, p2file):
46 self.basename = get_basename (self.p2file)
47 self.name_matches = find_name_matches (self.dir, self.basename)
49 def __eq__ (self, rhs):
50 return (self.dir == rhs.dir) \
51 and (self.basename == rhs.basename) \
52 and list_eq (self.name_matches, rhs.name_matches)
55 def find_all_par2_files (dir):
56 """Finds all par2 files in a directory"""
57 # NOTE: does NOT return absolute paths
59 if not os.path.isdir (os.path.abspath (dir)):
60 raise ValueError # bad directory given
62 dir = os.path.abspath (dir)
63 files = os.listdir (dir)
65 return find_par2_files (files)
67 def generate_all_parsets (dir):
68 # Generate all parsets in the given directory.
70 assert os.path.isdir (dir) # Directory MUST be valid
73 p2files = find_all_par2_files (dir)
76 p = CompareSet (dir, f)
80 return [(p.dir, p.p2file) for p in parsets]
82 def check_required_progs():
83 """Check if the required programs are installed"""
85 shell_not_found = 32512
88 if run_command ('par2repair --help > /dev/null 2>&1') == shell_not_found:
89 needed.append ('par2repair')
91 if run_command ('unrar --help > /dev/null 2>&1') == shell_not_found:
92 needed.append ('unrar')
94 if run_command ('unzip --help > /dev/null 2>&1') == shell_not_found:
95 needed.append ('unzip')
99 print 'Needed program "%s" not found in $PATH' % (n, )
103 def run_options (options):
106 options.work_dir = full_abspath (options.work_dir)
108 # Make sure that the directory is valid
109 if not os.path.isdir (options.work_dir):
110 sys.stderr.write ('\"%s\" is not a valid directory. Use the \"-d\"\n' % options.work_dir)
111 sys.stderr.write ('option to override the working directory temporarily, or edit the\n')
112 sys.stderr.write ('configuration file to override the working directory permanently.\n')
115 if options.extract_dir != None:
116 options.extract_dir = full_abspath (options.extract_dir)
119 print PROGRAM + ' - ' + VERSION
121 print 'Copyright (c) 2005,2006 Ira W. Snyder (devel@irasnyder.com)'
123 print 'This program comes with ABSOLUTELY NO WARRANTY.'
124 print 'This is free software, and you are welcome to redistribute it'
125 print 'under certain conditions. See the file COPYING for details.'
128 if options.check_progs:
129 check_required_progs ()
131 if options.write_def_config:
132 config.write_config (default=True)
134 if options.write_config:
135 config.write_config ()
137 def find_loglevel (options):
139 loglevel = options.verbose - options.quiet
147 LEVELS = { 1 : logging.DEBUG,
154 return LEVELS [loglevel]
159 logger = DelayedLogger ()
160 logging.basicConfig (stream=logger, level=logging.WARNING, \
161 format='%(levelname)-8s %(message)s')
163 # Build the OptionParser
164 parser = optparse.OptionParser()
165 parser.add_option('-n', '--not-recursive',
166 action='store_false', dest='recursive',
167 default=config_get_value('options', 'recursive'),
168 help="Don't run recursively")
170 parser.add_option('-d', '--work-dir',
171 dest='work_dir', type='string',
172 default=config_get_value('directories', 'working_directory'),
173 help="Start running at DIR", metavar='DIR')
175 parser.add_option('-e', '--extract-dir',
176 dest='extract_dir', type='string',
177 default=config_get_value('directories', 'extract_directory'),
178 help="Extract to DIR", metavar='DIR')
180 parser.add_option('-p', '--check-required-programs',
181 action='store_true', dest='check_progs',
183 help="Check for required programs")
185 parser.add_option('-f', '--write-default-config',
186 action='store_true', dest='write_def_config',
187 default=False, help="Write out a new default config")
189 parser.add_option('-c', '--write-new-config',
190 action='store_true', dest='write_config',
191 default=False, help="Write out the current config")
193 parser.add_option('-i', '--interactive', dest='interactive', action='store_true',
194 default=config_get_value('options', 'interactive'),
195 help="Confirm before removing files")
197 parser.add_option('-q', '--quiet', dest='quiet', action='count',
198 default=0, help="Output fatal messages only")
200 parser.add_option('-v', '--verbose', dest='verbose', action='count',
201 default=0, help="Output extra information")
203 parser.add_option('-V', '--version', dest='version', action='store_true',
204 default=False, help="Output version information")
206 parser.version = VERSION
208 # Parse the given options
210 (RarslaveGlobals.options, args) = parser.parse_args()
211 options = RarslaveGlobals.options
213 # Run any special actions that are needed on these options
214 run_options (options)
216 # Find the loglevel using the options given
217 logging.getLogger().setLevel (find_loglevel (options))
220 if options.recursive:
221 for (dir, subdirs, files) in os.walk (options.work_dir):
222 parsets = generate_all_parsets (dir)
223 for (p2dir, p2file) in parsets:
224 detector = RarslaveDetector.RarslaveDetector (p2dir, p2file)
225 ret = detector.runMatchingTypes ()
229 parsets = generate_all_parsets (options.work_dir)
230 for (p2dir, p2file) in parsets:
231 detector = RarslaveDetector.RarslaveDetector (p2dir, p2file)
232 ret = detector.runMatchingTypes ()
235 if logger.size () > 0:
236 print 'Log\n' + '=' * 80
242 if __name__ == '__main__':