Package turbogears :: Package command :: Module base
[hide private]

Source Code for Module turbogears.command.base

  1  """Commands for the TurboGears command line tool.""" 
  2   
  3  import optparse 
  4  import sys 
  5  import os 
  6  import os.path 
  7  import glob 
  8   
  9  import pkg_resources 
 10  import dispatch 
 11   
 12  import configobj 
 13   
 14  import turbogears 
 15  from turbogears.util import get_model, load_project_config, \ 
 16          get_project_config, get_package_name 
 17  from turbogears.identity import SecureObject, from_any_host 
 18  from turbogears import config, database 
 19  from sacommand import sacommand 
 20   
 21  sys.path.insert(0, os.getcwd()) 
 22   
 23  no_connection_param = ["help", "list"] 
 24  no_model_param = ["help"] 
 25   
26 -def silent_os_remove(fname):
27 """ 28 Tries to remove file FNAME but mutes any error that may happen. 29 30 Returns True if file was actually removed and false otherwise 31 """ 32 try: 33 os.remove(fname) 34 return True 35 except os.error: 36 pass 37 return False
38
39 -class CommandWithDB(object):
40 "Base class for commands that need to use the database" 41 config = None 42
43 - def __init__(self, version):
44 pass
45
46 - def find_config(self):
47 """Chooses the config file, trying to guess whether this is a 48 development or installed project.""" 49 load_project_config(self.config) 50 self.dburi = config.get("sqlobject.dburi", None) 51 if self.dburi and self.dburi.startswith("notrans_"): 52 self.dburi = self.dburi[8:]
53 54
55 -class SQL(CommandWithDB):
56 """ 57 Wrapper command for sqlobject-admin, and provide some sqlalchemy support. 58 59 This automatically supplies sqlobject-admin with the database that 60 is found in the config file. Will also supply the model module as 61 appropriate.""" 62 63 desc = "Run the database provider manager" 64 need_project = True 65
66 - def __init__(self, version):
67 if len(sys.argv) == 1 or sys.argv[1][0] == "-": 68 parser = optparse.OptionParser( 69 usage="%prog sql [command]\n\n" \ 70 "hint: '%prog sql help' will list the sqlobject " \ 71 "commands", 72 version="%prog " + version) 73 parser.add_option("-c", "--config", help="config file", 74 dest="config") 75 (options, args) = parser.parse_args(sys.argv[1:3]) 76 77 if not options.config: 78 parser.error("Please provide a valid option or command.") 79 self.config = options.config 80 # get rid of our config option 81 if not args: 82 del sys.argv[1:3] 83 else: 84 del sys.argv[1] 85 86 self.find_config()
87
88 - def run(self):
89 "Executes the sqlobject-admin code." 90 if not "--egg" in sys.argv and not turbogears.util.get_project_name(): 91 print "this don't look like a turbogears project" 92 return 93 else: 94 command = sys.argv[1] 95 96 if config.get("sqlalchemy.dburi"): 97 try: 98 sacommand(command, sys.argv) 99 except dispatch.interfaces.NoApplicableMethods: 100 sacommand("help", []) 101 return 102 103 sqlobjcommand = command 104 if sqlobjcommand not in no_connection_param: 105 if not self.dburi: 106 print """Database URI not specified in the config file (%s). 107 Please be sure it's on the command line.""" % self.config 108 else: 109 print "Using database URI %s" % self.dburi 110 sys.argv.insert(2, self.dburi) 111 sys.argv.insert(2, "-c") 112 113 if sqlobjcommand not in no_model_param: 114 if not "--egg" in sys.argv: 115 eggname = glob.glob("*.egg-info") 116 if not eggname or not \ 117 os.path.exists(os.path.join(eggname[0], "sqlobject.txt")): 118 eggname = self.fix_egginfo(eggname) 119 eggname = eggname[0].replace(".egg-info", "") 120 if not "." in sys.path: 121 sys.path.append(".") 122 pkg_resources.working_set.add_entry(".") 123 sys.argv.insert(2, eggname) 124 sys.argv.insert(2, "--egg") 125 126 from sqlobject.manager import command 127 command.the_runner.run(sys.argv)
128
129 - def fix_egginfo(self, eggname):
130 print """ 131 This project seems incomplete. In order to use the sqlobject commands 132 without manually specifying a model, there needs to be an 133 egg-info directory with an appropriate sqlobject.txt file. 134 135 I can fix this automatically. Would you like me to? 136 """ 137 dofix = raw_input("Enter [y] or n: ") 138 if not dofix or dofix.lower()[0] == 'y': 139 oldargs = sys.argv 140 sys.argv = ["setup.py", "egg_info"] 141 import imp 142 imp.load_module("setup", *imp.find_module("setup", ["."])) 143 sys.argv = oldargs 144 145 import setuptools 146 package = setuptools.find_packages()[0] 147 eggname = glob.glob("*.egg-info") 148 sqlobjectmeta = open(os.path.join(eggname[0], "sqlobject.txt"), "w") 149 sqlobjectmeta.write("""db_module=%(package)s.model 150 history_dir=$base/%(package)s/sqlobject-history 151 """ % dict(package=package)) 152 else: 153 sys.exit(0) 154 return eggname
155 156
157 -class Shell(CommandWithDB):
158 """Convenient version of the Python interactive shell. 159 This shell attempts to locate your configuration file and model module 160 so that it can import everything from your model and make it available 161 in the Python shell namespace.""" 162 163 desc = "Start a Python prompt with your database available" 164 need_project = True 165
166 - def run(self):
167 "Run the shell" 168 self.find_config() 169 170 mod = get_model() 171 if mod: 172 locals = mod.__dict__ 173 else: 174 locals = dict(__name__="tg-admin") 175 176 if config.get("sqlalchemy.dburi"): 177 using_sqlalchemy = True 178 database.get_engine() 179 locals.update(dict(session=database.session, 180 metadata=database.metadata)) 181 else: 182 using_sqlalchemy = False 183 184 try: 185 # try to use IPython if possible 186 import IPython 187 188 class CustomIPShell(IPython.iplib.InteractiveShell): 189 def raw_input(self, *args, **kw): 190 try: 191 return IPython.iplib.InteractiveShell.raw_input(self, 192 *args, **kw) # needs decoding (see below)? 193 except EOFError: 194 r = raw_input("Do you wish to commit your " 195 "database changes? [yes]") 196 if not r.lower().startswith("n"): 197 if using_sqlalchemy: 198 self.push("session.flush()") 199 else: 200 self.push("hub.commit()") 201 raise EOFError
202 203 shell = IPython.Shell.IPShell(user_ns=locals, 204 shell_class=CustomIPShell) 205 shell.mainloop() 206 except ImportError: 207 import code 208 209 class CustomShell(code.InteractiveConsole): 210 def raw_input(self, *args, **kw): 211 try: 212 import readline 213 except ImportError: 214 pass 215 try: 216 r = code.InteractiveConsole.raw_input(self, 217 *args, **kw) 218 for encoding in (getattr(sys.stdin, 'encoding', None), 219 sys.getdefaultencoding(), 'utf-8', 'latin-1'): 220 if encoding: 221 try: 222 return r.decode(encoding) 223 except UnicodeError: 224 pass 225 return r 226 except EOFError: 227 r = raw_input("Do you wish to commit your " 228 "database changes? [yes]") 229 if not r.lower().startswith("n"): 230 if using_sqlalchemy: 231 self.push("session.flush()") 232 else: 233 self.push("hub.commit()") 234 raise EOFError 235 236 shell = CustomShell(locals=locals) 237 shell.interact() 238
239 -class ToolboxCommand(CommandWithDB):
240 241 desc = "Launch the TurboGears Toolbox" 242
243 - def __init__(self, version):
244 self.hostlist = ['127.0.0.1','::1'] 245 246 parser = optparse.OptionParser( 247 usage="%prog toolbox [options]", version="%prog " + version) 248 parser.add_option("-n", "--no-open", 249 help="don't open browser automatically", 250 dest="noopen", action="store_true", 251 default=False) 252 parser.add_option("-c", "--add-client", 253 help="allow the client ip address specified to connect to toolbox (Can be specified more than once)", 254 dest="host", action="append", default=None) 255 parser.add_option("-p", "--port", 256 help="port to run the Toolbox on", dest="port", default=7654) 257 parser.add_option("--conf", help="config file to use", 258 dest="config", default=get_project_config()) 259 260 (options, args) = parser.parse_args(sys.argv[1:]) 261 self.port = int(options.port) 262 self.noopen = options.noopen 263 self.config = options.config 264 265 if options.host: 266 self.hostlist = self.hostlist + options.host 267 268 turbogears.widgets.load_widgets()
269
270 - def openbrowser(self):
271 import webbrowser 272 webbrowser.open("http://localhost:%d" % self.port)
273
274 - def run(self):
275 import cherrypy 276 from turbogears import toolbox 277 278 # Make sure we have full configuration with every option 279 # in it so other plugins or whatever find what they need 280 # when starting even inside the toolblox 281 conf = get_package_name() 282 conf = conf and "%s.config" % conf or None 283 conf = config.config_obj(configfile=self.config, modulename=conf) 284 285 if 'global' in conf: 286 config.update({'global': conf['global']}) 287 288 root = SecureObject(toolbox.Toolbox(), from_any_host(self.hostlist), 289 exclude=['noaccess']) 290 291 cherrypy.tree.mount(root, "/") 292 293 # amend some parameters since we are running from the command 294 # line in order to change port, log methods... 295 config.update({"global" : { 296 "server.socket_port" : self.port, 297 "server.environment" : "development", 298 "server.log_to_screen" : True, 299 "autoreload.on" : False, 300 "server.package" : "turbogears.toolbox", 301 "log_debug_info_filter.on" : False, 302 "identity.failure_url" : "/noaccess", 303 'tg.defaultview': 'kid', 304 'kid.outputformat': "html default", 305 'kid.encoding': "utf-8" 306 }}) 307 308 if not self.noopen: 309 cherrypy.server.start_with_callback(self.openbrowser) 310 else: 311 cherrypy.server.start()
312 313 commands = None 314
315 -def main():
316 "Main command runner. Manages the primary command line arguments." 317 # add commands defined by entrypoints 318 commands = {} 319 for entrypoint in pkg_resources.iter_entry_points("turbogears.command"): 320 command = entrypoint.load() 321 commands[entrypoint.name] = (command.