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 7GRIT tools. 8""" 9 10import os 11import sys 12if __name__ == '__main__': 13 sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 14 15import getopt 16 17from grit import util 18 19import 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. 23def ToolFactoryBuild(): 24 import grit.tool.build 25 return grit.tool.build.RcBuilder() 26 27def ToolFactoryBuildInfo(): 28 import grit.tool.buildinfo 29 return grit.tool.buildinfo.DetermineBuildInfo() 30 31def ToolFactoryCount(): 32 import grit.tool.count 33 return grit.tool.count.CountMessage() 34 35def ToolFactoryDiffStructures(): 36 import grit.tool.diff_structures 37 return grit.tool.diff_structures.DiffStructures() 38 39def ToolFactoryMenuTranslationsFromParts(): 40 import grit.tool.menu_from_parts 41 return grit.tool.menu_from_parts.MenuTranslationsFromParts() 42 43def ToolFactoryNewGrd(): 44 import grit.tool.newgrd 45 return grit.tool.newgrd.NewGrd() 46 47def ToolFactoryResizeDialog(): 48 import grit.tool.resize 49 return grit.tool.resize.ResizeDialog() 50 51def ToolFactoryRc2Grd(): 52 import grit.tool.rc2grd 53 return grit.tool.rc2grd.Rc2Grd() 54 55def ToolFactoryTest(): 56 import grit.tool.test 57 return grit.tool.test.TestTool() 58 59def ToolFactoryTranslationToTc(): 60 import grit.tool.transl2tc 61 return grit.tool.transl2tc.TranslationToTc() 62 63def ToolFactoryUnit(): 64 import grit.tool.unit 65 return grit.tool.unit.UnitTestTool() 66 67def ToolFactoryXmb(): 68 import grit.tool.xmb 69 return grit.tool.xmb.OutputXmb() 70 71def 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 108def 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 122Usage: grit [GLOBALOPTIONS] TOOL [args to tool] 123 124Global 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 142Tools: 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 151class 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 197def _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 207def 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 271if __name__ == '__main__': 272 sys.exit(Main(sys.argv[1:])) 273