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__.sver, 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          try:
    139              import psyco
    140          except Exception:
    141              return
    142          psycomodes = ["none", "full", "profile"]
    143          psycooption = optparse.Option(None, "--psyco", dest="psyco", default=None,
    144              choices=psycomodes, metavar="MODE",
    145              help="use psyco to speed up the operation, modes: %s" % (", ".join(psycomodes)))
    146          self.define_option(psycooption)
    147
    148 -    def usepsyco(self, options):
    149          # options.psyco == None means the default, which is "full", but don't give a warning...
    150          # options.psyco == "none" means don't use psyco at all...
    151          if getattr(options, "psyco", "none") == "none":
    152              return
    153          try:
    154              import psyco
    155          except Exception:
    156              if options.psyco is not None:
    157                  self.warning("psyco unavailable", options, sys.exc_info())
    158              return
    159          if options.psyco is None:
    160              options.psyco = "full"
    161          if options.psyco == "full":
    162              psyco.full()
    163          elif options.psyco == "profile":
    164              psyco.profile()
    165          # tell psyco the functions it cannot compile, to prevent warnings
    166          import encodings
    167          psyco.cannotcompile(encodings.search_function)
    168
    169 -    def set_usage(self, usage=None):
    170          """sets the usage string - if usage not given, uses getusagestring for each option"""
    171          if usage is None:
    172              self.usage = "%prog " + " ".join([self.getusagestring(option) for option in self.option_list])
    173          else:
    174              super(RecursiveOptionParser, self).set_usage(usage)
    175
    176 -    def warning(self, msg, options=None, exc_info=None):
    177          """Print a warning message incorporating 'msg' to stderr and exit."""
    178          if options:
    179              if options.errorlevel == "traceback":
    180                  errorinfo = "\n".join(traceback.format_exception(exc_info[0], exc_info[1], exc_info[2]))
    181              elif options.errorlevel == "exception":
    182                  errorinfo = "\n".join(traceback.format_exception_only(exc_info[0], exc_info[1]))
    183              elif options.errorlevel == "message":
    184                  errorinfo = str(exc_info[1])
    185              else:
    186                  errorinfo = ""
    187              if errorinfo:
    188                  msg += ": " + errorinfo
    189          print >> sys.stderr, "\n%s: warning: %s" % (self.get_prog_name(), msg)
    190
    191 -    def getusagestring(self, option):
    192          """returns the usage string for the given option"""
    193          optionstring = "|".join(option._short_opts + option._long_opts)
    194          if getattr(option, "optionalswitch", False):
    195              optionstring = "[%s]" % optionstring
    196          if option.metavar:
    197              optionstring += " " + option.metavar
    198          if getattr(option, "required", False):
    199              return optionstring
    200          else:
    201              return "[%s]" % optionstring
    202
    203 -    def getusageman(self, option):
    204          """returns the usage string for the given option"""
    205          optionstring = "\\fR|\\fP".join(option._short_opts + option._long_opts)
    206          if getattr(option, "optionalswitch", False):
    207              optionstring = "\\fR[\\fP%s\\fR]\\fP" % optionstring
    208          if option.metavar:
    209              optionstring += " \\fI%s\\fP" % option.metavar
    210          if getattr(option, "required", False):
    211              return optionstring
    212          else:
    213              return "\\fR[\\fP%s\\fR]\\fP" % optionstring
    214
    215 -    def define_option(self, option):
    216          """defines the given option, replacing an existing one of the same short name if neccessary..."""
    217          for short_opt in option._short_opts:
    218              if self.has_option(short_opt):
    219                  self.remove_option(short_opt)
    220          for long_opt in option._long_opts:
    221              if self.has_option(long_opt):
    222                  self.remove_option(long_opt)
    223          self.add_option(option)
    224
    225 -    def setformats(self, formats, usetemplates):
    226          """Sets the format options using the given format dictionary.
    227
    228          @type formats: Dictionary
    229          @param formats: The dictionary I{keys} should be:
    230              - single strings (or 1-tuples) containing an input format (if not usetemplates)
    231              - tuples containing an input format and template format (if usetemplates)
    232              - formats can be None to indicate what to do with standard input
    233          The dictionary I{values} should be tuples of outputformat (string) and processor method.
    234
    235          """
    236
    237          inputformats = []
    238          outputformats = []
    239          templateformats = []
    240          self.outputoptions = {}
    241          self.usetemplates = usetemplates
    242          for formatgroup, outputoptions in formats.iteritems():
    243              if isinstance(formatgroup, (str, unicode)) or formatgroup is None:
    244                  formatgroup = (formatgroup, )
    245              if not isinstance(formatgroup, tuple):
    246                  raise ValueError("formatgroups must be tuples or None/str/unicode")
    247              if len(formatgroup) < 1 or len(formatgroup) > 2:
    248                  raise ValueError("formatgroups must be tuples of length 1 or 2")
    249              if len(formatgroup) == 1:
    250                  formatgroup += (None, )
    251              inputformat, templateformat = formatgroup
    252              if not isinstance(outputoptions, tuple) or len(outputoptions) != 2:
    253                  raise ValueError("output options must be tuples of length 2")
    254              outputformat, processor = outputoptions
    255              if not inputformat in inputformats:
    256                  inputformats.append(inputformat)
    257              if not outputformat in outputformats:
    258                  outputformats.append(outputformat)
    259              if not templateformat in templateformats:
    260                  templateformats.append(templateformat)
    261              self.outputoptions[(inputformat, templateformat)] = (outputformat, processor)
    262          self.inputformats = inputformats
    263          inputformathelp = self.getformathelp(inputformats)
    264          inputoption = optparse.Option("-i", "--input", dest="input", default=None, metavar="INPUT",
    265                  help="read from INPUT in %s" % (inputformathelp))
    266          inputoption.optionalswitch = True
    267          inputoption.required = True
    268          self.define_option(inputoption)
    269          excludeoption = optparse.Option("-x", "--exclude", dest="exclude", action="append",
    270                  type="string", default=["CVS", ".svn", "_darcs", ".git", ".hg", ".bzr"], metavar="EXCLUDE",
    271                  help="exclude names matching EXCLUDE from input paths")
    272          self.define_option(excludeoption)
    273          outputformathelp = self.getformathelp(outputformats)
    274          outputoption = optparse.Option("-o", "--output", dest="output", default=None, metavar="OUTPUT",
    275                  help="write to OUTPUT in %s" % (outputformathelp))
    276          outputoption.optionalswitch = True
    277          outputoption.required = True
    278          self.define_option(outputoption)
    279          if self.usetemplates:
    280              self.templateformats = templateformats
    281              templateformathelp = self.getformathelp(self.templateformats)
    282              templateoption = optparse.Option("-t", "--template", dest="template", default=None, metavar="TEMPLATE",
    283                  help="read from TEMPLATE in %s" % (templateformathelp))
    284              self.define_option(templateoption)
    285
    286 -    def setprogressoptions(self):
    287          """sets the progress options"""
    288          self.progresstypes = {
    289                  "none": progressbar.NoProgressBar,
    290                  "bar": progressbar.HashProgressBar,
    291                  "dots": progressbar.DotsProgressBar,
    292                  "names": progressbar.MessageProgressBar,
    293                  "verbose": progressbar.VerboseProgressBar
    294          }
    295          progressoption = optparse.Option(None, "--progress", dest="progress", default="bar",
    296                  choices = self.progresstypes.keys(), metavar="PROGRESS",
    297                  help="show progress as: %s" % (", ".join(self.progresstypes)))
    298          self.define_option(progressoption)
    299
    300 -    def seterrorleveloptions(self):
    301          """sets the errorlevel options"""
    302          self.errorleveltypes = ["none", "message", "exception", "traceback"]
    303          errorleveloption = optparse.Option(None, "--errorlevel", dest="errorlevel", default="message",
    304                  choices = self.errorleveltypes, metavar="ERRORLEVEL",
    305                  help="show errorlevel as: %s" % (", ".join(self.errorleveltypes)))
    306          self.define_option(errorleveloption)
    307
    308 -    def getformathelp(self, formats):
    309          """make a nice help string for describing formats..."""
    310          if None in formats:
    311              formats = filter(lambda format: format is not None, formats)
    312          if len(formats) == 0:
    313              return ""
    314          elif len(formats) == 1:
    315              return "%s format" % (", ".join(formats))
    316          else:
    317              return "%s formats" % (", ".join(formats))
    318
    319 -    def isrecursive(self, fileoption, filepurpose='input'):
    320          """checks if fileoption is a recursive file"""
    321          if fileoption is None:
    322              return False
    323          elif isinstance(fileoption, list):
    324              return True
    325          else:
    326              return os.path.isdir(fileoption)
    327
    328 -    def parse_args(self, args=None, values=None):
    329          """parses the command line options, handling implicit input/output args"""
    330          (options, args) = super(RecursiveOptionParser, self).parse_args(args, values)
    331          # some intelligent as to what reasonable people might give on the command line
    332          if args and not options.input:
    333              if len(args) > 1:
    334                  options.input = args[:-1]
    335                  args = args[-1:]
    336              else:
    337                  options.input = args[0]
    338                  args = []
    339          if args and not options.output:
    340              options.output = args[-1]
    341              args = args[:-1]
    342          if args:
    343              self.error("You have used an invalid combination of --input, --output and freestanding args")
    344          if isinstance(options.input, list) and len(options.input) == 1:
    345              options.input = options.input[0]
    346          if options.input is None:
    347              self.error("You need to give an inputfile or use - for stdin ; use --help for full usage instructions")
    348          elif options.input == '-':
    349              options.input = None
    350          return (options, args)
    351
    352 -    def getpassthroughoptions(self, options):
    353          """get the options required to pass to the filtermethod..."""
    354          passthroughoptions = {}
    355          for optionname in dir(options):
    356              if optionname in self.passthrough:
    357                  passthroughoptions[optionname] = getattr(options, optionname)
    358          return passthroughoptions
    359
    360 -    def getoutputoptions(self, options, inputpath, templatepath):
    361          """works out which output format and processor method to use..."""
    362          if inputpath:
    363              inputbase, inputext = self.splitinputext(inputpath)
    364          else:
    365              inputext = None
    366          if templatepath:
    367              templatebase, templateext = self.splittemplateext(templatepath)
    368          else:
    369              templateext = None
    370          if (inputext, templateext) in options.outputoptions:
    371              return options.outputoptions[inputext, templateext]
    372          elif (inputext, "*") in options.outputoptions:
    373              outputformat, fileprocessor = options.outputoptions[inputext, "*"]
    374          elif ("*", templateext) in options.outputoptions:
    375              outputformat, fileprocessor = options.outputoptions["*", templateext]
    376          elif ("*", "*") in options.outputoptions:
    377              outputformat, fileprocessor = options.outputoptions["*", "*"]
    378          elif (inputext, None) in options.outputoptions:
    379              return options.outputoptions[inputext, None]
    380          elif (None, templateext) in options.outputoptions:
    381              return options.outputoptions[None, templateext]
    382          elif ("*", None) in options.outputoptions:
    383              outputformat, fileprocessor = options.outputoptions["*", None]
    384          elif (None, "*") in options.outputoptions:
    385              outputformat, fileprocessor = options.outputoptions[None, "*"]
    386          else:
    387              if self.usetemplates:
    388                  if inputext is None:
    389                      raise ValueError("don't know what to do with input format (no file extension), no template file")
    390                  elif templateext is None:
    391                      raise ValueError("don't know what to do with input format %s, no template file" % (os.extsep + inputext))
    392                  else:
    393                      raise ValueError("don't know what to do with input format %s, template format %s" % (os.extsep + inputext, os.extsep + templateext))
    394              else:
    395                  raise ValueError("don't know what to do with input format %s" % os.extsep + inputext)
    396          if outputformat == "*":
    397              if inputext:
    398                  outputformat = inputext
    399              elif templateext:
    400                  outputformat = templateext
    401              elif ("*", "*") in options.outputoptions:
    402                  outputformat = None
    403              else:
    404                  if self.usetemplates:
    405                      if templateext is None:
    406                          raise ValueError("don't know what to do with input format %s, no template file" % (os.extsep + inputext))
    407                      else:
    408                          raise ValueError("don't know what to do with input format %s, template format %s" % (os.extsep + inputext, os.extsep + templateext))
    409                  else:
    410                      raise ValueError("don't know what to do with input format %s" % os.extsep + inputext)
    411          return outputformat, fileprocessor
    412
    413 -    def initprogressbar(self, allfiles, options):
    414          """sets up a progress bar appropriate to the options and files"""
    415          if options.progress in ('bar', 'verbose'):
    416              self.progressbar = self.progresstypes[options.progress](0, len(allfiles))
    417              print >> sys.stderr, "processing %d files..." % len(allfiles)
    418          else:
    419              self.progressbar = self.progresstypes[options.progress]()
    420
    421 -    def getfullinputpath(self, options, inputpath):
    422          """gets the absolute path to an input file"""
    423          if options.input:
    424              return os.path.join(options.input, inputpath)
    425          else:
    426              return inputpath
    427
    428 -    def getfulloutputpath(self, options, outputpath):
    429          """gets the absolute path to an output file"""
    430          if options.recursiveoutput and options.output:
    431              return os.path.join(options.output, outputpath)
    432          else:
    433              return outputpath
    434
    435 -    def getfulltemplatepath(self, options, templatepath):
    436          """gets the absolute path to a template file"""
    437          if not options.recursivetemplate:
    438              return templatepath
    439          elif templatepath is not None and self.usetemplates and options.template:
    440              return os.path.join(options.template, templatepath)
    441          else:
    442              return None
    443
    444 -    def run(self):
    445          """parses the arguments, and runs recursiveprocess with the resulting options..."""
    446          (options, args) = self.parse_args()
    447          # this is so derived classes can modify the inputformats etc based on the options
    448          options.inputformats = self.inputformats
    449          options.outputoptions = self.outputoptions
    450          self.usepsyco(options)
    451          self.recursiveprocess(options)
    452
    453 -    def recursiveprocess(self, options):
    454          """recurse through directories and process files"""
    455          if self.isrecursive(options.input, 'input') and getattr(options, "allowrecursiveinput", True):
    456              if not self.isrecursive(options.output, 'output'):
    457                  try:
    458                      self.warning("Output directory does not exist. Attempting to create")
    459                      os.mkdir(options.output)
    460                  except IOError, e:
    461                      self.error(optparse.OptionValueError("Output directory does not exist, attempt to create failed"))
    462              if isinstance(options.input, list):
    463                  inputfiles = self.recurseinputfilelist(options)
    464              else:
    465                  inputfiles = self.recurseinputfiles(options)
    466          else:
    467              if options.input:
    468                  inputfiles = [os.path.basename(options.input)]
    469                  options.input = os.path.dirname(options.input)
    470              else:
    471                  inputfiles = [options.input]
    472          options.recursiveoutput = self.isrecursive(options.output, 'output') and getattr(options, "allowrecursiveoutput", True)
    473          options.recursivetemplate = self.usetemplates and self.isrecursive(options.template, 'template') and getattr(options, "allowrecursivetemplate", True)
    474          self.initprogressbar(inputfiles, options)
    475          for inputpath in inputfiles:
    476              try:
    477                  templatepath = self.gettemplatename(options, inputpath)
    478                  # If we have a recursive template, but the template doesn't have this
    479                  # input file, let's drop it.
    480                  if options.recursivetemplate and templatepath is None and not self.allowmissingtemplate:
    481                      self.warning("No template at %s. Skipping %s." % (templatepath, inputpath))
    482                      continue
    483                  outputformat, fileprocessor = self.getoutputoptions(options, inputpath, templatepath)
    484                  fullinputpath = self.getfullinputpath(options, inputpath)
    485                  fulltemplatepath = self.getfulltemplatepath(options, templatepath)
    486                  outputpath = self.getoutputname(options, inputpath, outputformat)
    487                  fulloutputpath = self.getfulloutputpath(options, outputpath)
    488                  if options.recursiveoutput and outputpath:
    489                      self.checkoutputsubdir(options, os.path.dirname(outputpath))
    490              except Exception, error:
    491                  if isinstance(error, KeyboardInterrupt):
    492                      raise
    493                  self.warning("Couldn't handle input file %s" % inputpath, options, sys.exc_info())
    494                  continue
    495              try:
    496                  success = self.processfile(fileprocessor, options, fullinputpath, fulloutputpath, fulltemplatepath)
    497              except Exception, error:
    498                  if isinstance(error, KeyboardInterrupt):
    499                      raise
    500                  self.warning("Error processing: input %s, output %s, template %s" % (fullinputpath, fulloutputpath, fulltemplatepath), options, sys.exc_info())
    501                  success = False
    502              self.reportprogress(inputpath, success)
    503          del self.progressbar
    504
    505 -    def openinputfile(self, options, fullinputpath):
    506          """opens the input file"""
    507          if fullinputpath is None:
    508              return sys.stdin
    509          return open(fullinputpath, 'r')
    510
    511 -    def openoutputfile(self, options, fulloutputpath):
    512          """opens the output file"""
    513          if fulloutputpath is None:
    514              return sys.stdout
    515          return open(fulloutputpath, 'w')
    516
    517 -    def opentempoutputfile(self, options, fulloutputpath):
    518          """opens a temporary output file"""
    519          return StringIO()
    520
    521 -    def finalizetempoutputfile(self, options, outputfile, fulloutputpath):
    522          """write the temp outputfile to its final destination"""
    523          outputfile.reset()
    524          outputstring = outputfile.read()
    525          outputfile = self.openoutputfile(options, fulloutputpath)
    526          outputfile.write(outputstring)
    527          outputfile.close()
    528
    529 -    def opentemplatefile(self, options, fulltemplatepath):
    530          """opens the template file (if required)"""
    531          if fulltemplatepath is not None:
    532              if os.path.isfile(fulltemplatepath):
    533                  return open(fulltemplatepath, 'r')
    534              else:
    535                  self.warning("missing template file %s" % fulltemplatepath)
    536          return None
    537
    538 -    def processfile(self, fileprocessor, options, fullinputpath, fulloutputpath, fulltemplatepath):
    539          """process an individual file"""
    540          inputfile = self.openinputfile(options, fullinputpath)
    541          if fulloutputpath and fulloutputpath in (fullinputpath, fulltemplatepath):
    542              outputfile = self.opentempoutputfile(options, fulloutputpath)
    543              tempoutput = True
    544          else:
    545              outputfile = self.openoutputfile(options, fulloutputpath)
    546              tempoutput = False
    547          templatefile = self.opentemplatefile(options, fulltemplatepath)
    548          passthroughoptions = self.getpassthroughoptions(options)
    549          if fileprocessor(inputfile, outputfile, templatefile, **passthroughoptions):
    550              if tempoutput:
    551                  self.warning("writing to temporary output...")
    552                  self.finalizetempoutputfile(options, outputfile, fulloutputpath)
    553              return True
    554          else:
    555              # remove the file if it is a file (could be stdout etc)
    556              if fulloutputpath and os.path.isfile(fulloutputpath):
    557                  outputfile.close()
    558                  os.unlink(fulloutputpath)
    559              return False
    560
    561 -    def reportprogress(self, filename, success):
    562          """shows that we are progressing..."""
    563          self.progressbar.amount += 1
    564          self.progressbar.show(filename)
    565
    566 -    def mkdir(self, parent, subdir):
    567          """makes a subdirectory (recursively if neccessary)"""
    568          if not os.path.isdir(parent):
    569              raise ValueError("cannot make child directory %r if parent %r does not exist" % (subdir, parent))
    570          currentpath = parent
    571          subparts = subdir.split(os.sep)
    572          for part in subparts:
    573              currentpath = os.path.join(currentpath, part)
    574              if not os.path.isdir(currentpath):
    575                  os.mkdir(currentpath)
    576
    577 -    def checkoutputsubdir(self, options, subdir):
    578          """checks to see if subdir under options.output needs to be created, creates if neccessary"""
    579          fullpath = os.path.join(options.output, subdir)
    580          if not os.path.isdir(fullpath):
    581              self.mkdir(options.output, subdir)
    582
    583 -    def isexcluded(self, options, inputpath):
    584          """checks if this path has been excluded"""
    585          basename = os.path.basename(inputpath)
    586          for excludename in options.exclude:
    587              if fnmatch.fnmatch(basename, excludename):
    588                  return True
    589          return False
    590
    591 -    def recurseinputfilelist(self, options):
    592          """use a list of files, and find a common base directory for them"""
    593          # find a common base directory for the files to do everything relative to
    594          commondir = os.path.dirname(os.path.commonprefix(options.input))
    595          inputfiles = []
    596          for inputfile in options.input:
    597              if self.isexcluded(options, inputfile):
    598                  continue
    599              if inputfile.startswith(commondir+os.sep):
    600                  inputfiles.append(inputfile.replace(commondir+os.sep, "", 1))
    601              else:
    602                  inputfiles.append(inputfile.replace(commondir, "", 1))
    603          options.input = commondir
    604          return inputfiles
    605
    606 -    def recurseinputfiles(self, options):
    607          """recurse through directories and return files to be processed..."""
    608          dirstack = ['']
    609          join = os.path.join
    610          inputfiles = []
    611          while dirstack:
    612              top = dirstack.pop(-1)
    613              names = os.listdir(join(options.input, top))
    614              dirs = []
    615              for name in names:
    616                  inputpath = join(top, name)
    617                  if self.isexcluded(options, inputpath):
    618                      continue
    619                  fullinputpath = self.getfullinputpath(options, inputpath)
    620                  # handle directories...
    621                  if os.path.isdir(fullinputpath):
    622                      dirs.append(inputpath)
    623                  elif os.path.isfile(fullinputpath):
    624                      if not self.isvalidinputname(options, name):
    625                          # only handle names that match recognized input file extensions
    626                          continue
    627                      inputfiles.append(inputpath)
    628              # make sure the directories are processed next time round...
    629              dirs.reverse()
    630              dirstack.extend(dirs)
    631          return inputfiles
    632
    633 -    def splitext(self, pathname):
    634          """Splits L{pathname} into name and ext, and removes the extsep
    635
    636          @param pathname: A file path
    637          @type pathname: string
    638          @return: root, ext
    639          @rtype: tuple
    640          """
    641          root, ext = os.path.splitext(pathname)
    642          ext = ext.replace(os.extsep, "", 1)
    643          return (root, ext)
    644
    645 -    def splitinputext(self, inputpath):
    646          """splits an inputpath into name and extension"""
    647          return self.splitext(inputpath)
    648
    649 -    def splittemplateext(self, templatepath):
    650          """splits a templatepath into name and extension"""
    651          return self.splitext(templatepath)
    652
    653 -    def templateexists(self, options, templatepath):
    654          """returns whether the given template exists..."""
    655          fulltemplatepath = self.getfulltemplatepath(options, templatepath)
    656          return os.path.isfile(fulltemplatepath)
    657
    658 -    def gettemplatename(self, options, inputname):
    659          """gets an output filename based on the input filename"""
    660          if not self.usetemplates:
    661              return None
    662          if not inputname or not options.recursivetemplate:
    663              return options.template
    664          inputbase, inputext = self.splitinputext(inputname)
    665          if options.template:
    666              for inputext1, templateext1 in options.outputoptions:
    667                  if inputext == inputext1:
    668                      if templateext1:
    669                          templatepath = inputbase + os.extsep + templateext1
    670                          if self.templateexists(options, templatepath):
    671                              return templatepath
    672              if "*" in options.inputformats:
    673                  for inputext1, templateext1 in options.outputoptions:
    674                      if (inputext == inputext1) or (inputext1 == "*"):
    675                          if templateext1 == "*":
    676                              templatepath = inputname
    677                              if self.templateexists(options, templatepath):
    678                                  return templatepath
    679                          elif templateext1:
    680                              templatepath = inputbase + os.extsep + templateext1
    681                              if self.templateexists(options, templatepath):
    682                                  return templatepath
    683          return None
    684
    685 -    def getoutputname(self, options, inputname, outputformat):
    686          """gets an output filename based on the input filename"""
    687          if not inputname or not options.recursiveoutput:
    688              return options.output
    689          inputbase, inputext = self.splitinputext(inputname)
    690          outputname = inputbase
    691          if outputformat:
    692              outputname += os.extsep + outputformat
    693          return outputname
    694
    695 -    def isvalidinputname(self, options, inputname):
    696          """checks if this is a valid input filename"""
    697          inputbase, inputext = self.splitinputext(inputname)
    698          return (inputext in options.inputformats) or ("*" in options.inputformats)
    699