Package translate :: Package misc :: Module optrecurse

[hide private]
[frames] | no frames]

# Source Code for Module translate.misc.optrecurse

      1  #!/usr/bin/env python
      2  # -*- coding: utf-8 -*-
      3  #
      4  # Copyright 2002-2006 Zuza Software Foundation
      5  #
      6  # This file is part of translate.
      7  #
      8  # translate is free software; you can redistribute it and/or modify
      9  # it under the terms of the GNU General Public License as published by
     10  # the Free Software Foundation; either version 2 of the License, or
     11  # (at your option) any later version.
     12  #
     13  # translate is distributed in the hope that it will be useful,
     14  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  # GNU General Public License for more details.
     17  #
     18  # You should have received a copy of the GNU General Public License
     19  # along with translate; if not, write to the Free Software
     20  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     21
     22  import sys
     23  import os.path
     24  import fnmatch
     25  import traceback
     26  import optparse
     27  from translate.misc import progressbar
     28  from translate import __version__
     29  try:
     30      from cStringIO import StringIO
     31  except ImportError:
     32      from StringIO import StringIO
     33
     34 -class ManPageOption(optparse.Option, object):
     35      ACTIONS = optparse.Option.ACTIONS + ("manpage",)
     36
     37 -    def take_action(self, action, dest, opt, value, values, parser):
     38          """take_action that can handle manpage as well as standard actions"""
     39          if action == "manpage":
     40              parser.print_manpage()
     41              sys.exit(0)
     42          return super(ManPageOption, self).take_action(action, dest, opt, value, values, parser)
     43
     44 -class ManHelpFormatter (optparse.HelpFormatter):
     45 -    def __init__ (self,
     46              indent_increment=0,
     47              max_help_position=0,
     48              width=80,
     49              short_first=1):
     50          optparse.HelpFormatter.__init__(
     51              self, indent_increment, max_help_position, width, short_first)
     52
     53 -    def format_option_strings (self, option):
     54          """Return a comma-separated list of option strings & metavariables."""
     55          if option.takes_value():
     56              metavar = option.metavar or option.dest.upper()
     57              metavar = '\\fI%s\\fP'%metavar
     58              short_opts = [sopt + metavar for sopt in option._short_opts]
     59              long_opts = [lopt + "\\fR=\\fP" + metavar for lopt in option._long_opts]
     60          else:
     61              short_opts = option._short_opts
     62              long_opts = option._long_opts
     63
     64          if self.short_first:
     65              opts = short_opts + long_opts
     66          else:
     67              opts = long_opts + short_opts
     68
     69          return '\\fB%s\\fP'%("\\fR, \\fP".join(opts))
     70
     71 -class RecursiveOptionParser(optparse.OptionParser, object):
     72      """A specialized Option Parser for recursing through directories."""
     73
     74 -    def __init__(self, formats, usetemplates=False, allowmissingtemplate=False, description=None):
     75          """Construct the specialized Option Parser.
     76
     77          @type formats: Dictionary
     78          @param formats: See L{setformats()} for an explanation of the formats parameter.
     79
     80          """
     81
     82          optparse.OptionParser.__init__(self, version="%prog "+__version__.ver, description=description)
     83          self.setmanpageoption()
     84          self.setprogressoptions()
     85          self.seterrorleveloptions()
     86          self.setformats(formats, usetemplates)
     87          self.setpsycooption()
     88          self.passthrough = []
     89          self.allowmissingtemplate = allowmissingtemplate
     90
     91 -    def get_prog_name(self):
     92          return os.path.basename(sys.argv[0])
     93
     94 -    def setmanpageoption(self):
     95          """creates a manpage option that allows the optionparser to generate a manpage"""
     96          manpageoption = ManPageOption(None, "--manpage", dest="manpage", default=False, action="manpage",
     97              help="output a manpage based on the help")
     98          self.define_option(manpageoption)
     99
    100 -    def format_manpage(self):
    101          """returns a formatted manpage"""
    102          result = []
    103          prog = self.get_prog_name()
    104          formatprog = lambda x: x.replace("%prog", prog)
    105          formatToolkit = lambda x: x.replace("%prog", "Translate Toolkit")
    106          result.append('.\\" Autogenerated manpage\n')
    107          result.append('.TH %s 1 "%s" "" "%s"\n' % (prog,
    108              formatToolkit(self.version),
    109              formatToolkit(self.version)))
    110          result.append('.SH NAME\n')
    111          result.append('%s \\- %s\n' % (self.get_prog_name(), self.description.split('\n\n')[0]))
    112          result.append('.SH SYNOPSIS\n')
    113          result.append('.PP\n')
    114          usage  = "\\fB%prog "
    115          usage += " ".join([self.getusageman(option) for option in self.option_list])
    116          usage += "\\fP"
    117          result.append('%s\n' % formatprog(usage))
    118          description_lines = self.description.split('\n\n')[1:]
    119          if description_lines:
    120              result.append('.SH DESCRIPTION\n')
    121              result.append('\n'.join(description_lines))
    122          result.append('.SH OPTIONS\n')
    123          ManHelpFormatter().store_option_strings(self)
    124          result.append('.PP\n')
    125          for option in self.option_list:
    126              result.append('.TP\n')
    127              result.append('%s\n'%option)
    128              result.append('%s\n'%option.help)
    129          return "".join(result)
    130
    131 -    def print_manpage(self, file=None):
    132          """outputs a manpage for the program using the help information"""
    133          if file is None:
    134              file = sys.stdout
    135          file.write(self.format_manpage())
    136
    137 -    def setpsycooption(self):
    138          psycomodes = ["none", "full", "profile"]
    139          psycooption = optparse.Option(None, "--psyco", dest="psyco", default=None,
    140              choices=psycomodes, metavar="MODE",
    141              help="use psyco to speed up the operation, modes: %s" % (", ".join(psycomodes)))
    142          self.define_option(psycooption)
    143
    144 -    def usepsyco(self, options):
    145          # options.psyco == None means the default, which is "full", but don't give a warning...
    146          # options.psyco == "none" means don't use psyco at all...
    147          if options.psyco == "none":
    148              return
    149          try:
    150              import psyco
    151          except Exception:
    152              if options.psyco is not None:
    153                  self.warning("psyco unavailable", options, sys.exc_info())
    154              return
    155          if options.psyco is None:
    156              options.psyco = "full"
    157          if options.psyco == "full":
    158              psyco.full()
    159          elif options.psyco == "profile":
    160              psyco.profile()
    161          # tell psyco the functions it cannot compile, to prevent warnings
    162          import encodings
    163          psyco.cannotcompile(encodings.search_function)
    164
    165 -    def set_usage(self, usage=None):
    166          """sets the usage string - if usage not given, uses getusagestring for each option"""
    167          if usage is None:
    168              self.usage = "%prog " + " ".join([self.getusagestring(option) for option in self.option_list])
    169          else:
    170              super(RecursiveOptionParser, self).set_usage(usage)
    171
    172 -    def warning(self, msg, options=None, exc_info=None):
    173          """Print a warning message incorporating 'msg' to stderr and exit."""
    174          if options:
    175              if options.errorlevel == "traceback":
    176                  errorinfo = "\n".join(traceback.format_exception(exc_info[0], exc_info[1], exc_info[2]))
    177              elif options.errorlevel == "exception":
    178                  errorinfo = "\n".join(traceback.format_exception_only(exc_info[0], exc_info[1]))
    179              elif options.errorlevel == "message":
    180                  errorinfo = str(exc_info[1])
    181              else:
    182                  errorinfo = ""
    183              if errorinfo:
    184                  msg += ": " + errorinfo
    185          print >> sys.stderr, "\n%s: warning: %s" % (self.get_prog_name(), msg)
    186
    187 -    def getusagestring(self, option):
    188          """returns the usage string for the given option"""
    189          optionstring = "|".join(option._short_opts + option._long_opts)
    190          if getattr(option, "optionalswitch", False):
    191              optionstring = "[%s]" % optionstring
    192          if option.metavar:
    193              optionstring += " " + option.metavar
    194          if getattr(option, "required", False):
    195              return optionstring
    196          else:
    197              return "[%s]" % optionstring
    198
    199 -    def getusageman(self, option):
    200          """returns the usage string for the given option"""
    201          optionstring = "\\fR|\\fP".join(option._short_opts + option._long_opts)
    202          if getattr(option, "optionalswitch", False):
    203              optionstring = "\\fR[\\fP%s\\fR]\\fP" % optionstring
    204          if option.metavar:
    205              optionstring += " \\fI%s\\fP" % option.metavar
    206          if getattr(option, "required", False):
    207              return optionstring
    208          else:
    209              return "\\fR[\\fP%s\\fR]\\fP" % optionstring
    210
    211 -    def define_option(self, option):
    212          """defines the given option, replacing an existing one of the same short name if neccessary..."""
    213          for short_opt in option._short_opts:
    214              if self.has_option(short_opt):
    215                  self.remove_option(short_opt)
    216          for long_opt in option._long_opts:
    217              if self.has_option(long_opt):
    218                  self.remove_option(long_opt)
    219          self.add_option(option)
    220
    221 -    def setformats(self, formats, usetemplates):
    222          """Sets the format options using the given format dictionary.
    223
    224          @type formats: Dictionary
    225          @param formats: The dictionary I{keys} should be:
    226              - single strings (or 1-tuples) containing an input format (if not usetemplates)
    227              - tuples containing an input format and template format (if usetemplates)
    228              - formats can be None to indicate what to do with standard input
    229          The dictionary I{values} should be tuples of outputformat (string) and processor method.
    230
    231          """
    232
    233          inputformats = []
    234          outputformats = []
    235          templateformats = []
    236          self.outputoptions = {}
    237          self.usetemplates = usetemplates
    238          for formatgroup, outputoptions in formats.iteritems():
    239              if isinstance(formatgroup, (str, unicode)) or formatgroup is None:
    240                  formatgroup = (formatgroup, )
    241              if not isinstance(formatgroup, tuple):
    242                  raise ValueError("formatgroups must be tuples or None/str/unicode")
    243              if len(formatgroup) < 1 or len(formatgroup) > 2:
    244                  raise ValueError("formatgroups must be tuples of length 1 or 2")
    245              if len(formatgroup) == 1:
    246                  formatgroup += (None, )
    247              inputformat, templateformat = formatgroup
    248              if not isinstance(outputoptions, tuple) or len(outputoptions) != 2:
    249                  raise ValueError("output options must be tuples of length 2")
    250              outputformat, processor = outputoptions
    251              if not inputformat in inputformats: inputformats.append(inputformat)
    252              if not outputformat in outputformats: outputformats.append(outputformat)
    253              if not templateformat in templateformats: templateformats.append(templateformat)
    254              self.outputoptions[(inputformat, templateformat)] = (outputformat, processor)
    255          self.inputformats = inputformats
    256          inputformathelp = self.getformathelp(inputformats)
    257          inputoption = optparse.Option("-i", "--input", dest="input", default=None, metavar="INPUT",
    258                  help="read from INPUT in %s" % (inputformathelp))
    259          inputoption.optionalswitch = True
    260          inputoption.required = True
    261          self.define_option(inputoption)
    262          excludeoption = optparse.Option("-x", "--exclude", dest="exclude", action="append",
    263                  type="string", default=["CVS", ".svn", "_darcs"], metavar="EXCLUDE",
    264                  help="exclude names matching EXCLUDE from input paths")
    265          self.define_option(excludeoption)
    266          outputformathelp = self.getformathelp(outputformats)
    267          outputoption = optparse.Option("-o", "--output", dest="output", default=None, metavar="OUTPUT",
    268                  help="write to OUTPUT in %s" % (outputformathelp))
    269          outputoption.optionalswitch = True
    270          outputoption.required = True
    271          self.define_option(outputoption)
    272          if self.usetemplates:
    273              self.templateformats = templateformats
    274              templateformathelp = self.getformathelp(self.templateformats)
    275              templateoption = optparse.Option("-t", "--template", dest="template", default=None, metavar="TEMPLATE",
    276                  help="read from TEMPLATE in %s" % (templateformathelp))
    277              self.define_option(templateoption)
    278
    279 -    def setprogressoptions(self):
    280          """sets the progress options"""
    281          self.progresstypes = {
    282                  "none": progressbar.NoProgressBar,
    283                  "bar": progressbar.HashProgressBar,
    284                  "dots": progressbar.DotsProgressBar,
    285                  "names": progressbar.MessageProgressBar,
    286                  "verbose": progressbar.VerboseProgressBar
    287          }
    288          progressoption = optparse.Option(None, "--progress", dest="progress", default="bar",
    289                  choices = self.progresstypes.keys(), metavar="PROGRESS",
    290                  help="show progress as: %s" % (", ".join(self.progresstypes)))
    291          self.define_option(progressoption)
    292
    293 -    def seterrorleveloptions(self):
    294          """sets the errorlevel options"""
    295          self.errorleveltypes = ["none", "message", "exception", "traceback"]
    296          errorleveloption = optparse.Option(None, "--errorlevel", dest="errorlevel", default="message",
    297                  choices = self.errorleveltypes, metavar="ERRORLEVEL",
    298                  help="show errorlevel as: %s" % (", ".join(self.errorleveltypes)))
    299          self.define_option(errorleveloption)
    300
    301 -    def getformathelp(self, formats):
    302          """make a nice help string for describing formats..."""
    303          if None in formats:
    304              formats = filter(lambda format: format is not None, formats)
    305          if len(formats) == 0:
    306              return ""
    307          elif len(formats) == 1:
    308              return "%s format" % (", ".join(formats))
    309          else:
    310              return "%s formats" % (", ".join(formats))
    311
    312 -    def isrecursive(self, fileoption, filepurpose='input'):
    313          """checks if fileoption is a recursive file"""
    314          if fileoption is None:
    315              return False
    316          elif isinstance(fileoption, list):
    317              return True
    318          else:
    319              return os.path.isdir(fileoption)
    320
    321 -    def parse_args(self, args=None, values=None):
    322          """parses the command line options, handling implicit input/output args"""
    323          (options, args) = super(RecursiveOptionParser, self).parse_args(args, values)
    324          # some intelligent as to what reasonable people might give on the command line
    325          if args and not options.input:
    326              if len(args) > 1:
    327                  options.input = args[:-1]
    328                  args = args[-1:]
    329              else:
    330                  options.input = args[0]
    331                  args = []
    332          if args and not options.output:
    333              options.output = args[-1]
    334              args = args[:-1]
    335          if args:
    336              self.error("You have used an invalid combination of --input, --output and freestanding args")
    337          if isinstance(options.input, list) and len(options.input) == 1:
    338              options.input = options.input[0]
    339          if options.input is None:
    340              self.error("You need to give an inputfile or use - for stdin ; use --help for full usage instructions")
    341          elif options.input == '-':
    342              options.input = None
    343          return (options, args)
    344
    345 -    def getpassthroughoptions(self, options):
    346          """get the options required to pass to the filtermethod..."""
    347          passthroughoptions = {}
    348          for optionname in dir(options):
    349              if optionname in self.passthrough:
    350                  passthroughoptions[optionname] = getattr(options, optionname)
    351          return passthroughoptions
    352
    353 -    def getoutputoptions(self, options, inputpath, templatepath):
    354          """works out which output format and processor method to use..."""
    355          if inputpath:
    356              inputbase, inputext = self.splitinputext(inputpath)
    357          else:
    358              inputext = None
    359          if templatepath:
    360              templatebase, templateext = self.splittemplateext(templatepath)
    361          else:
    362              templateext = None
    363          if (inputext, templateext) in options.outputoptions:
    364              return options.outputoptions[inputext, templateext]
    365          elif (inputext, "*") in options.outputoptions:
    366              outputformat, fileprocessor = options.outputoptions[inputext, "*"]
    367          elif ("*", templateext) in options.outputoptions:
    368              outputformat, fileprocessor = options.outputoptions["*", templateext]
    369          elif ("*", "*") in options.outputoptions:
    370              outputformat, fileprocessor = options.outputoptions["*", "*"]
    371          elif (inputext, None) in options.outputoptions:
    372              return options.outputoptions[inputext, None]
    373          elif (None, templateext) in options.outputoptions:
    374              return options.outputoptions[None, templateext]
    375          elif ("*", None) in options.outputoptions:
    376              outputformat, fileprocessor = options.outputoptions["*", None]
    377          elif (None, "*") in options.outputoptions:
    378              outputformat, fileprocessor = options.outputoptions[None, "*"]
    379          else:
    380              if self.usetemplates:
    381                  if inputext is None:
    382                      raise ValueError("don't know what to do with input format (no file extension), no template file")
    383                  elif templateext is None:
    384                      raise ValueError("don't know what to do with input format %s, no template file" % (os.extsep + inputext))
    385                  else:
    386                      raise ValueError("don't know what to do with input format %s, template format %s" % (os.extsep + inputext, os.extsep + templateext))
    387              else:
    388                  raise ValueError("don't know what to do with input format %s" % os.extsep + inputext)
    389          if outputformat == "*":
    390              if inputext:
    391                  outputformat = inputext
    392              elif templateext:
    393                  outputformat = templateext
    394              elif ("*", "*") in options.outputoptions:
    395                  outputformat = None
    396              else:
    397                  if self.usetemplates:
    398                      if templateext is None:
    399                          raise ValueError("don't know what to do with input format %s, no template file" % (os.extsep + inputext))
    400                      else:
    401                          raise ValueError("don't know what to do with input format %s, template format %s" % (os.extsep + inputext, os.extsep + templateext))
    402                  else:
    403                      raise ValueError("don't know what to do with input format %s" % os.extsep + inputext)
    404          return outputformat, fileprocessor
    405
    406 -    def initprogressbar(self, allfiles, options):
    407          """sets up a progress bar appropriate to the options and files"""
    408          if options.progress in ('bar', 'verbose'):
    409              self.progressbar = self.progresstypes[options.progress](0, len(allfiles))
    410              print >> sys.stderr, "processing %d files..." % len(allfiles)
    411          else:
    412              self.progressbar = self.progresstypes[options.progress]()
    413
    414 -    def getfullinputpath(self, options, inputpath):
    415          """gets the absolute path to an input file"""
    416          if options.input:
    417              return os.path.join(options.input, inputpath)
    418          else:
    419              return inputpath
    420
    421 -    def getfulloutputpath(self, options, outputpath):
    422          """gets the absolute path to an output file"""
    423          if options.recursiveoutput and options.output:
    424              return os.path.join(options.output, outputpath)
    425          else:
    426              return outputpath
    427
    428 -    def getfulltemplatepath(self, options, templatepath):
    429          """gets the absolute path to a template file"""
    430          if not options.recursivetemplate:
    431              return templatepath
    432          elif templatepath is not None and self.usetemplates and options.template:
    433              return os.path.join(options.template, templatepath)
    434          else:
    435              return None
    436
    437 -    def run(self):
    438          """parses the arguments, and runs recursiveprocess with the resulting options..."""
    439          (options, args) = self.parse_args()
    440          # this is so derived classes can modify the inputformats etc based on the options
    441          options.inputformats = self.inputformats
    442          options.outputoptions = self.outputoptions
    443          self.usepsyco(options)
    444          self.recursiveprocess(options)
    445
    446 -    def recursiveprocess(self, options):
    447          """recurse through directories and process files"""
    448          if self.isrecursive(options.input, 'input') and getattr(options, "allowrecursiveinput", True):
    449              if not self.isrecursive(options.output, 'output'):
    450                  try:
    451                      self.warning("Output directory does not exist. Attempting to create")
    452                      os.mkdir(options.output)
    453                  except IOError, e:
    454                      self.error(optparse.OptionValueError("Output directory does not exist, attempt to create failed"))
    455              if isinstance(options.input, list):
    456                  inputfiles = self.recurseinputfilelist(options)
    457              else:
    458                  inputfiles = self.recurseinputfiles(options)
    459          else:
    460              if options.input:
    461                  inputfiles = [os.path.basename(options.input)]
    462                  options.input = os.path.dirname(options.input)
    463              else:
    464                  inputfiles = [options.input]
    465          options.recursiveoutput = self.isrecursive(options.output, 'output') and getattr(options, "allowrecursiveoutput", True)
    466          options.recursivetemplate = self.usetemplates and self.isrecursive(options.template, 'template') and getattr(options, "allowrecursivetemplate", True)
    467          self.initprogressbar(inputfiles, options)
    468          for inputpath in inputfiles:
    469              try:
    470                  templatepath = self.gettemplatename(options, inputpath)
    471                  # If we have a recursive template, but the template doesn't have this
    472                  # input file, let's drop it.
    473                  if options.recursivetemplate and templatepath is None and not self.allowmissingtemplate:
    474                      self.warning("No template at %s. Skipping %s." % (templatepath, inputpath))
    475                      continue
    476                  outputformat, fileprocessor = self.getoutputoptions(options, inputpath, templatepath)
    477                  fullinputpath = self.getfullinputpath(options, inputpath)
    478                  fulltemplatepath = self.getfulltemplatepath(options, templatepath)
    479                  outputpath = self.getoutputname(options, inputpath, outputformat)
    480                  fulloutputpath = self.getfulloutputpath(options, outputpath)
    481                  if options.recursiveoutput and outputpath:
    482                      self.checkoutputsubdir(options, os.path.dirname(outputpath))
    483              except Exception, error:
    484                  if isinstance(error, KeyboardInterrupt):
    485                      raise
    486                  self.warning("Couldn't handle input file %s" % inputpath, options, sys.exc_info())
    487                  continue
    488              try:
    489                  success = self.processfile(fileprocessor, options, fullinputpath, fulloutputpath, fulltemplatepath)
    490              except Exception, error:
    491                  if isinstance(error, KeyboardInterrupt):
    492                      raise
    493                  self.warning("Error processing: input %s, output %s, template %s" % (fullinputpath, fulloutputpath, fulltemplatepath), options, sys.exc_info())
    494                  success = False
    495              self.reportprogress(inputpath, success)
    496          del self.progressbar
    497
    498 -    def openinputfile(self, options, fullinputpath):
    499          """opens the input file"""
    500          if fullinputpath is None:
    501              return sys.stdin
    502          return open(fullinputpath, 'r')
    503
    504 -    def openoutputfile(self, options, fulloutputpath):
    505          """opens the output file"""
    506          if fulloutputpath is None:
    507              return sys.stdout
    508          return open(fulloutputpath, 'w')
    509
    510 -    def opentempoutputfile(self, options, fulloutputpath):
    511          """opens a temporary output file"""
    512          return StringIO()
    513
    514 -    def finalizetempoutputfile(self, options, outputfile, fulloutputpath):
    515          """write the temp outputfile to its final destination"""
    516          outputfile.reset()
    517          outputstring = outputfile.read()
    518          outputfile = self.openoutputfile(options, fulloutputpath)
    519          outputfile.write(outputstring)
    520          outputfile.close()
    521
    522 -    def opentemplatefile(self, options, fulltemplatepath):
    523          """opens the template file (if required)"""
    524          if fulltemplatepath is not None:
    525              if os.path.isfile(fulltemplatepath):
    526                  return open(fulltemplatepath, 'r')
    527              else:
    528                  self.warning("missing template file %s" % fulltemplatepath)
    529          return None
    530
    531 -    def processfile(self, fileprocessor, options, fullinputpath, fulloutputpath, fulltemplatepath):
    532          """process an individual file"""
    533          inputfile = self.openinputfile(options, fullinputpath)
    534          if fulloutputpath and fulloutputpath in (fullinputpath, fulltemplatepath):
    535              outputfile = self.opentempoutputfile(options, fulloutputpath)
    536              tempoutput = True
    537          else:
    538              outputfile = self.openoutputfile(options, fulloutputpath)
    539              tempoutput = False
    540          templatefile = self.opentemplatefile(options, fulltemplatepath)
    541          passthroughoptions = self.getpassthroughoptions(options)
    542          if fileprocessor(inputfile, outputfile, templatefile, **passthroughoptions):
    543              if tempoutput:
    544                  self.warning("writing to temporary output...")
    545                  self.finalizetempoutputfile(options, outputfile, fulloutputpath)
    546              return True
    547          else:
    548              # remove the file if it is a file (could be stdout etc)
    549              if fulloutputpath and os.path.isfile(fulloutputpath):
    550                  outputfile.close()
    551                  os.unlink(fulloutputpath)
    552              return False
    553
    554 -    def reportprogress(self, filename, success):
    555          """shows that we are progressing..."""
    556          self.progressbar.amount += 1
    557          self.progressbar.show(filename)
    558
    559 -    def mkdir(self, parent, subdir):
    560          """makes a subdirectory (recursively if neccessary)"""
    561          if not os.path.isdir(parent):
    562              raise ValueError("cannot make child directory %r if parent %r does not exist" % (subdir, parent))
    563          currentpath = parent
    564          subparts = subdir.split(os.sep)
    565          for part in subparts:
    566              currentpath = os.path.join(currentpath, part)
    567              if not os.path.isdir(currentpath):
    568                  os.mkdir(currentpath)
    569
    570 -    def checkoutputsubdir(self, options, subdir):
    571          """checks to see if subdir under options.output needs to be created, creates if neccessary"""
    572          fullpath = os.path.join(options.output, subdir)
    573          if not os.path.isdir(fullpath):
    574              self.mkdir(options.output, subdir)
    575
    576 -    def isexcluded(self, options, inputpath):
    577          """checks if this path has been excluded"""
    578          basename = os.path.basename(inputpath)
    579          for excludename in options.exclude:
    580              if fnmatch.fnmatch(basename, excludename):
    581                  return True
    582          return False
    583
    584 -    def recurseinputfilelist(self, options):
    585          """use a list of files, and find a common base directory for them"""
    586          # find a common base directory for the files to do everything relative to
    587          commondir = os.path.dirname(os.path.commonprefix(options.input))
    588          inputfiles = []
    589          for inputfile in options.input:
    590              if self.isexcluded(options, inputfile):
    591                  continue
    592              if inputfile.startswith(commondir+os.sep):
    593                  inputfiles.append(inputfile.replace(commondir+os.sep, "", 1))
    594              else:
    595                  inputfiles.append(inputfile.replace(commondir, "", 1))
    596          options.input = commondir
    597          return inputfiles
    598
    599 -    def recurseinputfiles(self, options):
    600          """recurse through directories and return files to be processed..."""
    601          dirstack = ['']
    602          join = os.path.join
    603          inputfiles = []
    604          while dirstack:
    605              top = dirstack.pop(-1)
    606              names = os.listdir(join(options.input, top))
    607              dirs = []
    608              for name in names:
    609                  inputpath = join(top, name)
    610                  if self.isexcluded(options, inputpath):
    611                      continue
    612                  fullinputpath = self.getfullinputpath(options, inputpath)
    613                  # handle directories...
    614                  if os.path.isdir(fullinputpath):
    615                      dirs.append(inputpath)
    616                  elif os.path.isfile(fullinputpath):
    617                      if not self.isvalidinputname(options, name):
    618                          # only handle names that match recognized input file extensions
    619                          continue
    620                      inputfiles.append(inputpath)
    621              # make sure the directories are processed next time round...
    622              dirs.reverse()
    623              dirstack.extend(dirs)
    624          return inputfiles
    625
    626 -    def splitext(self, pathname):
    627          """splits into name and ext, and removes the extsep"""
    628          root, ext = os.path.splitext(pathname)
    629          ext = ext.replace(os.extsep, "", 1)
    630          return (root, ext)
    631
    632 -    def splitinputext(self, inputpath):
    633          """splits an inputpath into name and extension"""
    634          return self.splitext(inputpath)
    635
    636 -    def splittemplateext(self, templatepath):
    637          """splits a templatepath into name and extension"""
    638          return self.splitext(templatepath)
    639
    640 -    def templateexists(self, options, templatepath):
    641          """returns whether the given template exists..."""
    642          fulltemplatepath = self.getfulltemplatepath(options, templatepath)
    643          return os.path.isfile(fulltemplatepath)
    644
    645 -    def gettemplatename(self, options, inputname):
    646          """gets an output filename based on the input filename"""
    647          if not self.usetemplates: return None
    648          if not inputname or not options.recursivetemplate: return options.template
    649          inputbase, inputext = self.splitinputext(inputname)
    650          if options.template:
    651              for inputext1, templateext1 in options.outputoptions:
    652                  if inputext == inputext1:
    653                      if templateext1:
    654                          templatepath = inputbase + os.extsep + templateext1
    655                          if self.templateexists(options, templatepath):
    656                              return templatepath
    657              if "*" in options.inputformats:
    658                  for inputext1, templateext1 in options.outputoptions:
    659                      if (inputext == inputext1) or (inputext1 == "*"):
    660                          if templateext1 == "*":
    661                              templatepath = inputname
    662                              if self.templateexists(options, templatepath):
    663                                  return templatepath
    664                          elif templateext1:
    665                              templatepath = inputbase + os.extsep + templateext1
    666                              if self.templateexists(options, templatepath):
    667                                  return templatepath
    668          return None
    669
    670 -    def getoutputname(self, options, inputname, outputformat):
    671          """gets an output filename based on the input filename"""
    672          if not inputname or not options.recursiveoutput: return options.output
    673          inputbase, inputext = self.splitinputext(inputname)
    674          outputname = inputbase
    675          if outputformat:
    676              outputname += os.extsep + outputformat
    677          return outputname
    678
    679 -    def isvalidinputname(self, options, inputname):
    680          """checks if this is a valid input filename"""
    681          inputbase, inputext = self.splitinputext(inputname)
    682          return (inputext in options.inputformats) or ("*" in options.inputformats)
    683