Home | History | Annotate | Download | only in grit
      1 #!/usr/bin/env python
      2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 """Command processor for GRIT.  This is the script you invoke to run the various
      7 GRIT tools.
      8 """
      9 
     10 import os
     11 import sys
     12 if __name__ == '__main__':
     13   sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
     14 
     15 import getopt
     16 
     17 from grit import util
     18 
     19 import grit.extern.FP
     20 
     21 # Tool info factories; these import only within each factory to avoid
     22 # importing most of the GRIT code until required.
     23 def ToolFactoryBuild():
     24   import grit.tool.build
     25   return grit.tool.build.RcBuilder()
     26 
     27 def ToolFactoryBuildInfo():
     28   import grit.tool.buildinfo
     29   return grit.tool.buildinfo.DetermineBuildInfo()
     30 
     31 def ToolFactoryCount():
     32   import grit.tool.count
     33   return grit.tool.count.CountMessage()
     34 
     35 def ToolFactoryDiffStructures():
     36   import grit.tool.diff_structures
     37   return grit.tool.diff_structures.DiffStructures()
     38 
     39 def ToolFactoryMenuTranslationsFromParts():
     40   import grit.tool.menu_from_parts
     41   return grit.tool.menu_from_parts.MenuTranslationsFromParts()
     42 
     43 def ToolFactoryNewGrd():
     44   import grit.tool.newgrd
     45   return grit.tool.newgrd.NewGrd()
     46 
     47 def ToolFactoryResizeDialog():
     48   import grit.tool.resize
     49   return grit.tool.resize.ResizeDialog()
     50 
     51 def ToolFactoryRc2Grd():
     52   import grit.tool.rc2grd
     53   return grit.tool.rc2grd.Rc2Grd()
     54 
     55 def ToolFactoryTest():
     56   import grit.tool.test
     57   return grit.tool.test.TestTool()
     58 
     59 def ToolFactoryTranslationToTc():
     60   import grit.tool.transl2tc
     61   return grit.tool.transl2tc.TranslationToTc()
     62 
     63 def ToolFactoryUnit():
     64   import grit.tool.unit
     65   return grit.tool.unit.UnitTestTool()
     66 
     67 def ToolFactoryXmb():
     68   import grit.tool.xmb
     69   return grit.tool.xmb.OutputXmb()
     70 
     71 def ToolAndroid2Grd():
     72   import grit.tool.android2grd
     73   return grit.tool.android2grd.Android2Grd()
     74 
     75 # Keys for the following map
     76 _FACTORY = 1
     77 _REQUIRES_INPUT = 2
     78 _HIDDEN = 3  # optional key - presence indicates tool is hidden
     79 
     80 # Maps tool names to the tool's module.  Done as a list of (key, value) tuples
     81 # instead of a map to preserve ordering.
     82 _TOOLS = [
     83   ['build', { _FACTORY : ToolFactoryBuild, _REQUIRES_INPUT : True }],
     84   ['buildinfo', { _FACTORY : ToolFactoryBuildInfo, _REQUIRES_INPUT : True }],
     85   ['count', { _FACTORY : ToolFactoryCount, _REQUIRES_INPUT : True }],
     86   ['menufromparts', {
     87       _FACTORY: ToolFactoryMenuTranslationsFromParts,
     88       _REQUIRES_INPUT : True, _HIDDEN : True }],
     89   ['newgrd', { _FACTORY  : ToolFactoryNewGrd, _REQUIRES_INPUT : False }],
     90   ['rc2grd', { _FACTORY : ToolFactoryRc2Grd, _REQUIRES_INPUT : False }],
     91   ['resize', {
     92       _FACTORY : ToolFactoryResizeDialog, _REQUIRES_INPUT : True }],
     93   ['sdiff', { _FACTORY : ToolFactoryDiffStructures,
     94               _REQUIRES_INPUT : False }],
     95   ['test', {
     96       _FACTORY: ToolFactoryTest, _REQUIRES_INPUT : True,
     97       _HIDDEN : True }],
     98   ['transl2tc', { _FACTORY : ToolFactoryTranslationToTc,
     99                   _REQUIRES_INPUT : False }],
    100   ['unit', { _FACTORY : ToolFactoryUnit, _REQUIRES_INPUT : False }],
    101   ['xmb', { _FACTORY : ToolFactoryXmb, _REQUIRES_INPUT : True }],
    102   ['android2grd', {
    103       _FACTORY: ToolAndroid2Grd,
    104       _REQUIRES_INPUT : False }],
    105 ]
    106 
    107 
    108 def PrintUsage():
    109   tool_list = ''
    110   for (tool, info) in _TOOLS:
    111     if not _HIDDEN in info.keys():
    112       tool_list += '    %-12s %s\n' % (tool, info[_FACTORY]().ShortDescription())
    113 
    114   # TODO(joi) Put these back into the usage when appropriate:
    115   #
    116   #  -d    Work disconnected.  This causes GRIT not to attempt connections with
    117   #        e.g. Perforce.
    118   #
    119   #  -c    Use the specified Perforce CLIENT when talking to Perforce.
    120   print """GRIT - the Google Resource and Internationalization Tool
    121 
    122 Usage: grit [GLOBALOPTIONS] TOOL [args to tool]
    123 
    124 Global options:
    125 
    126   -i INPUT  Specifies the INPUT file to use (a .grd file).  If this is not
    127             specified, GRIT will look for the environment variable GRIT_INPUT.
    128             If it is not present either, GRIT will try to find an input file
    129             named 'resource.grd' in the current working directory.
    130 
    131   -h MODULE Causes GRIT to use MODULE.UnsignedFingerPrint instead of
    132             grit.extern.FP.UnsignedFingerprint.  MODULE must be
    133             available somewhere in the PYTHONPATH search path.
    134 
    135   -v        Print more verbose runtime information.
    136 
    137   -x        Print extremely verbose runtime information.  Implies -v
    138 
    139   -p FNAME  Specifies that GRIT should profile its execution and output the
    140             results to the file FNAME.
    141 
    142 Tools:
    143 
    144   TOOL can be one of the following:
    145 %s
    146   For more information on how to use a particular tool, and the specific
    147   arguments you can send to that tool, execute 'grit help TOOL'
    148 """ % (tool_list)
    149 
    150 
    151 class Options(object):
    152   """Option storage and parsing."""
    153 
    154   def __init__(self):
    155     self.disconnected = False
    156     self.client = ''
    157     self.hash = None
    158     self.input = None
    159     self.verbose = False
    160     self.extra_verbose = False
    161     self.output_stream = sys.stdout
    162     self.profile_dest = None
    163     self.psyco = False
    164 
    165   def ReadOptions(self, args):
    166     """Reads options from the start of args and returns the remainder."""
    167     (opts, args) = getopt.getopt(args, 'g:qdvxc:i:p:h:', ('psyco',))
    168     for (key, val) in opts:
    169       if key == '-d': self.disconnected = True
    170       elif key == '-c': self.client = val
    171       elif key == '-h': self.hash = val
    172       elif key == '-i': self.input = val
    173       elif key == '-v':
    174         self.verbose = True
    175         util.verbose = True
    176       elif key == '-x':
    177         self.verbose = True
    178         util.verbose = True
    179         self.extra_verbose = True
    180         util.extra_verbose = True
    181       elif key == '-p': self.profile_dest = val
    182       elif key == '--psyco': self.psyco = True
    183 
    184     if not self.input:
    185       if 'GRIT_INPUT' in os.environ:
    186         self.input = os.environ['GRIT_INPUT']
    187       else:
    188         self.input = 'resource.grd'
    189 
    190     return args
    191 
    192   def __repr__(self):
    193     return '(disconnected: %d, verbose: %d, client: %s, input: %s)' % (
    194         self.disconnected, self.verbose, self.client, self.input)
    195 
    196 
    197 def _GetToolInfo(tool):
    198   """Returns the info map for the tool named 'tool' or None if there is no
    199   such tool."""
    200   matches = [t for t in _TOOLS if t[0] == tool]
    201   if not matches:
    202     return None
    203   else:
    204     return matches[0][1]
    205 
    206 
    207 def Main(args):
    208   """Parses arguments and does the appropriate thing."""
    209   util.ChangeStdoutEncoding()
    210 
    211   if sys.version_info < (2, 6):
    212     print "GRIT requires Python 2.6 or later."
    213     return 2
    214   elif not args or (len(args) == 1 and args[0] == 'help'):
    215     PrintUsage()
    216     return 0
    217   elif len(args) == 2 and args[0] == 'help':
    218     tool = args[1].lower()
    219     if not _GetToolInfo(tool):
    220       print "No such tool.  Try running 'grit help' for a list of tools."
    221       return 2
    222 
    223     print ("Help for 'grit %s' (for general help, run 'grit help'):\n"
    224            % (tool))
    225     print _GetToolInfo(tool)[_FACTORY]().__doc__
    226     return 0
    227   else:
    228     options = Options()
    229     args = options.ReadOptions(args)  # args may be shorter after this
    230     if not args:
    231       print "No tool provided.  Try running 'grit help' for a list of tools."
    232       return 2
    233     tool = args[0]
    234     if not _GetToolInfo(tool):
    235       print "No such tool.  Try running 'grit help' for a list of tools."
    236       return 2
    237 
    238     try:
    239       if _GetToolInfo(tool)[_REQUIRES_INPUT]:
    240         os.stat(options.input)
    241     except OSError:
    242       print ('Input file %s not found.\n'
    243              'To specify a different input file:\n'
    244              '  1. Use the GRIT_INPUT environment variable.\n'
    245              '  2. Use the -i command-line option.  This overrides '
    246              'GRIT_INPUT.\n'
    247              '  3. Specify neither GRIT_INPUT or -i and GRIT will try to load '
    248              "'resource.grd'\n"
    249              '     from the current directory.' % options.input)
    250       return 2
    251 
    252     if options.psyco:
    253       # Psyco is a specializing JIT for Python.  Early tests indicate that it
    254       # could speed up GRIT (at the expense of more memory) for large GRIT
    255       # compilations.  See http://psyco.sourceforge.net/
    256       import psyco
    257       psyco.profile()
    258 
    259     if options.hash:
    260       grit.extern.FP.UseUnsignedFingerPrintFromModule(options.hash)
    261 
    262     toolobject = _GetToolInfo(tool)[_FACTORY]()
    263     if options.profile_dest:
    264       import hotshot
    265       prof = hotshot.Profile(options.profile_dest)
    266       prof.runcall(toolobject.Run, options, args[1:])
    267     else:
    268       toolobject.Run(options, args[1:])
    269 
    270 
    271 if __name__ == '__main__':
    272   sys.exit(Main(sys.argv[1:]))
    273