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