Author: ianb
Date: 2005-04-10 23:16:53 -0600 (Sun, 10 Apr 2005)
New Revision: 2325
Added:
WSGIKit/trunk/wsgikit/app_templates/__init__.py
WSGIKit/trunk/wsgikit/app_templates/webkit_zpt/__init__.py
WSGIKit/trunk/wsgikit/app_templates/webkit_zpt/command.py
Removed:
WSGIKit/trunk/wsgikit/app_template.py
Modified:
WSGIKit/trunk/scripts/app-setup
WSGIKit/trunk/wsgikit/app_setup.py
Log:
Delegate most of the command processing to the template's command module
Modified: WSGIKit/trunk/scripts/app-setup
===================================================================
--- WSGIKit/trunk/scripts/app-setup 2005-04-11 02:14:36 UTC (rev 2324)
+++ WSGIKit/trunk/scripts/app-setup 2005-04-11 05:16:53 UTC (rev 2325)
@@ -15,4 +15,4 @@
sys.path.insert(0, os.path.dirname(relative_wsgikit))
from wsgikit import app_setup
-sys.exit(app_setup.the_runner.run(sys.argv))
+sys.exit(app_setup.run(sys.argv))
Modified: WSGIKit/trunk/wsgikit/app_setup.py
===================================================================
--- WSGIKit/trunk/wsgikit/app_setup.py 2005-04-11 02:14:36 UTC (rev 2324)
+++ WSGIKit/trunk/wsgikit/app_setup.py 2005-04-11 05:16:53 UTC (rev 2325)
@@ -4,16 +4,106 @@
import fnmatch
import os
import sys
+from cStringIO import StringIO
+import re
+from wsgikit.util.thirdparty import load_new_module
+string = load_new_module('string', (2, 4))
from wsgikit import app_template
+from wsgikit import pyconfig
+from wsgikit import urlparser
+class InvalidCommand(Exception):
+ pass
+
+def find_template_info(args):
+ """
+ Given command-line arguments, this finds the app template
+ (wsgikit.app_templates.<template_name>.command). It looks for a
+ -t or --template option (but ignores all other options), and if
+ none then looks in server.conf for a template_name option.
+
+ Returns template_name, template_dir, module
+ """
+ template_name = None
+ template_name, rest = find_template_option(args)
+ if template_name:
+ next_template_name, rest = find_template_option(rest)
+ if next_template_name:
+ raise InvalidCommand(
+ 'You cannot give two templates on the commandline '
+ '(first I found %r, then %r)'
+ % (template_name, next_template_name))
+ else:
+ template_name = find_template_config(args)
+ if not template_name:
+ raise InvalidCommand(
+ 'Not template given (provide --template=name or run this command '
+ 'from a directory containing server.conf)')
+ if not re.search(r'^[a-zA-Z_][a-zA-Z0-9_]*$', template_name):
+ raise InvalidCommand(
+ 'The template name %r is invalid; template names can contain only '
+ 'letters, numbers, and _.' % template_name)
+ try:
+ template_mod = load_template(template_name)
+ except ImportError, e:
+ raise InvalidCommand(
+ 'No template exists by the name %r (%s)' % (template_name, e))
+ return (template_name, os.path.dirname(template_mod.__file__), template_mod)
+
+def find_template_option(args):
+ copy = args[:]
+ while copy:
+ if copy[0] == '--':
+ return None, copy
+ if copy[0] == '-t' or copy[0] == '--template':
+ if not copy[1:]:
+ raise InvalidCommand(
+ '%s needs to be followed with a template name' % copy[0])
+ return copy[1], copy[2:]
+ if copy[0].startswith('-t'):
+ return copy[0][2:], copy[1:]
+ if copy[0].startswith('--template='):
+ return copy[0][len('--template='):], copy[1:]
+ copy.pop(0)
+ return None, []
+
+def find_template_config(args):
+ conf_fn = os.path.join(os.getcwd(), 'server.conf')
+ if not os.path.exists(conf_fn):
+ return None
+ conf = pyconfig.Config()
+ conf.load(conf_fn)
+ return conf.get('template_name')
+
+def load_template(template_name):
+ base = os.path.join(os.path.dirname(__file__), 'app_templates')
+ full_name = 'wsgikit.app_templates.%s.command' % template_name
+ errors = StringIO()
+ mod = urlparser.load_module_from_name(
+ None, os.path.join(base, template_name, 'command'),
+ full_name, errors)
+ if mod is None:
+ raise InvalidCommand(
+ 'Cannot load module: %s' % errors.getvalue())
+ return mod
+
+def run(args):
+ try:
+ name, dir, mod = find_template_info(args)
+ except InvalidCommand, e:
+ print str(e)
+ return 2
+ return mod.run(args, name, dir, mod)
+
class CommandRunner(object):
def __init__(self):
self.commands = {}
self.command_aliases = {}
+ self.register_standard_commands()
- def run(self, argv):
+ def run(self, argv, template_name, template_dir, template_module):
invoked_as = argv[0]
args = argv[1:]
for i in range(len(args)):
@@ -30,7 +120,8 @@
if real_command not in self.commands.keys():
self.invalid('COMMAND %s unknown' % command)
runner = self.commands[real_command](
- invoked_as, command, args, self)
+ invoked_as, command, args, self,
+ template_name, template_dir, template_module)
runner.run()
def register(self, command):
@@ -43,16 +134,23 @@
print msg
sys.exit(code)
-the_runner = CommandRunner()
-register = the_runner.register
+ def register_standard_commands(self):
+ # @@: these commands shouldn't require a template
+ self.register(CommandHelp)
+ self.register(CommandList)
-def standard_parser(simulate=True, interactive=False):
+############################################################
+## Command framework
+############################################################
+
+def standard_parser(verbose=True, simulate=True, interactive=False):
parser = optparse.OptionParser()
- parser.add_option('-v', '--verbose',
- help='Be verbose (multiple times for more verbosity)',
- action='count',
- dest='verbose',
- default=0)
+ if verbose:
+ parser.add_option('-v', '--verbose',
+ help='Be verbose (multiple times for more verbosity)',
+ action='count',
+ dest='verbose',
+ default=0)
if simulate:
parser.add_option('-n', '--simulate',
help="Don't actually do anything (implies -v)",
@@ -64,6 +162,10 @@
action="count",
dest="interactive",
default=0)
+ parser.add_option('-t', '--template',
+ help='Use this template',
+ metavar='NAME',
+ dest='template_name')
return parser
class Command(object):
@@ -76,11 +178,15 @@
required_args = []
description = None
- def __init__(self, invoked_as, command_name, args, runner):
+ def __init__(self, invoked_as, command_name, args, runner,
+ template_name, template_dir, template_module):
self.invoked_as = invoked_as
self.command_name = command_name
self.raw_args = args
self.runner = runner
+ self.template_name = template_name
+ self.template_dir = template_dir
+ self.template_module = template_module
def run(self):
self.parser.usage = "%%prog [options]\n%s" % self.summary
@@ -88,7 +194,7 @@
os.path.basename(self.invoked_as),
self.command_name)
if self.description:
- self.parser.description = description
+ self.parser.description = self.description
self.options, self.args = self.parser.parse_args(self.raw_args)
if (getattr(self.options, 'simulate', False)
and not self.options.verbose):
@@ -122,20 +228,13 @@
return response[0].lower() == 'y'
print 'Y or N please'
- def template_dir(self):
- return os.path.join(os.path.dirname(__file__), 'app_templates')
-
- def template(self, name):
- dir = os.path.join(self.template_dir(), name)
- if not os.path.exists(dir):
- raise OSError(
- "Template directory %s does not exist (for template %r)"
- % (dir, name))
- return app_template.Template(dir)
-
def _get_prog_name(self):
return os.path.basename(self.invoked_as)
prog_name = property(_get_prog_name)
+
+############################################################
+## Standard commands
+############################################################
class CommandList(Command):
@@ -148,67 +247,48 @@
def command(self):
any = False
- for dir in os.listdir(self.template_dir()):
- dir = os.path.join(self.template_dir(), dir)
+ app_template_dir = os.path.join(os.path.dirname(__file__), 'app_templates')
+ for name in os.listdir(app_template_dir):
+ dir = os.path.join(app_template_dir, name)
if not os.path.exists(os.path.join(dir, 'description.txt')):
if self.options.verbose >= 2:
print 'Skipping %s (no description.txt)' % dir
continue
- template = app_template.Template(dir)
- if self.args and not fnmatch.fnmatch(template.name, self.args[0]):
+ if self.args and not fnmatch.fnmatch(name, self.args[0]):
continue
- print template.describe(verbosity=self.options.verbose)
+ if not self.options.verbose:
+ print '%s: %s\n' % (name, self.template_description().splitlines()[0])
+ else:
+ return '%s: %s\n' % (self.name, self.template_description())
+ # @@: for verbosity >= 2 we should give lots of metadata
any = True
if not any:
print 'No application templates found'
-register(CommandList)
+ def template_description(self):
+ f = open(os.path.join(self.template_dir, 'description.txt'))
+ content = f.read().strip()
+ f.close()
+ return content
-class CommandCreate(Command):
-
- name = 'create'
- summary = 'Create application from template'
-
- max_args = None
- min_args = 1
-
- parser = standard_parser()
- parser.add_option('-o', '--output',
- help="Directory to write to (default current directory)",
- metavar="DIR",
- dest="output_dir",
- default=os.getcwd())
-
- def command(self):
- template = self.template(self.args[0])
- template.create(self.options, self.args[1:])
- if self.options.verbose:
- print 'Now do:'
- print ' cd %s' % self.options.output_dir
- print ' wsgi-server'
-
-
-register(CommandCreate)
-
-
class CommandHelp(Command):
name = 'help'
summary = 'Show help'
- parser = optparse.OptionParser()
+ parser = standard_parser(verbose=False)
max_args = 1
def command(self):
- if self.args:
- the_runner.run([self.invoked_as, self.args[0], '-h'])
+ if args:
+ self.runner.run([self.invoked_as, self.args[0], '-h'])
else:
print 'Available commands:'
print ' (use "%s help COMMAND" or "%s COMMAND -h" ' % (
self.prog_name, self.prog_name)
print ' for more information)'
- items = the_runner.commands.items()
+ items = self.runner.commands.items()
items.sort()
max_len = max([len(cn) for cn, c in items])
for command_name, command in items:
@@ -219,7 +299,107 @@
print '%s (Aliases: %s)' % (
' '*max_len, ', '.join(command.aliases))
-register(CommandHelp)
+############################################################
+## Optional helper commands
+############################################################
+class CommandCreate(Command):
+
+ name = 'create'
+ summary = 'Create application from template'
+
+ max_args = 1
+ min_args = 1
+
+ parser = standard_parser()
+
+ default_options = {
+ 'server': 'wsgiutils',
+ 'verbose': True,
+ 'reload': True,
+ 'debug': True,
+ }
+
+ def command(self):
+ self.output_dir = self.args[0]
+ self.create(self.output_dir)
+ if self.options.verbose:
+ print 'Now do:'
+ print ' cd %s' % self.options.output_dir
+ print ' wsgi-server'
+
+ def create(self, output_dir):
+ file_dir = os.path.join(self.template_dir, 'template')
+ if not os.path.exists(file_dir):
+ raise OSError(
+ 'No %s directory, I don\'t know what to do next' % file_dir)
+ template_options = self.default_options.copy()
+ template_options.update(self.options.__dict__)
+ template_options['app_name'] = os.path.basename(output_dir)
+ template_options['base_dir'] = output_dir
+ template_options['absolute_base_dir'] = os.path.abspath(output_dir)
+ template_options['absolute_parent'] = os.path.dirname(
+ os.path.abspath(output_dir))
+ template_options['template_name'] = self.template_name
+ self.copy_dir(file_dir, output_dir, template_options, self.options.verbose,
+ self.options.simulate)
+
+ def copy_dir(self, *args, **kw):
+ copy_dir(*args, **kw)
+
+def copy_dir(source, dest, vars, verbosity, simulate):
+ names = os.listdir(source)
+ names.sort()
+ if not os.path.exists(dest):
+ if verbosity >= 1:
+ print 'Creating %s/' % dest
+ if not simulate:
+ os.makedirs(dest)
+ elif verbosity >= 2:
+ print 'Directory %s exists' % dest
+ for name in names:
+ full = os.path.join(source, name)
+ if name.startswith('.'):
+ if verbosity >= 2:
+ print 'Skipping hidden file %s' % full
+ continue
+ dest_full = os.path.join(dest, _substitute_filename(name, vars))
+ if os.path.isdir(full):
+ if verbosity:
+ print 'Recursing into %s' % full
+ copy_dir(full, dest_full, vars, verbosity, simulate)
+ continue
+ f = open(full, 'rb')
+ content = f.read()
+ f.close()
+ content = _substitute_content(content, vars)
+ if verbosity:
+ print 'Copying %s to %s' % (full, dest_full)
+ f = open(dest_full, 'wb')
+ f.write(content)
+ f.close()
+
+def _substitute_filename(fn, vars):
+ for var, value in vars.items():
+ fn = fn.replace('+%s+' % var, str(value))
+ return fn
+
+def _substitute_content(content, vars):
+ tmpl = string.Template(content)
+ return tmpl.substitute(TypeMapper(vars))
+
+class TypeMapper(dict):
+
+ def __getitem__(self, item):
+ if item.startswith('str_'):
+ return repr(str(self[item[4:]]))
+ elif item.startswith('bool_'):
+ if self[item[5:]]:
+ return 'True'
+ else:
+ return 'False'
+ else:
+ return dict.__getitem__(self, item)
+
if __name__ == '__main__':
- the_runner.run(sys.argv)
+ run(sys.argv)
Deleted: WSGIKit/trunk/wsgikit/app_template.py
===================================================================
--- WSGIKit/trunk/wsgikit/app_template.py 2005-04-11 02:14:36 UTC (rev 2324)
+++ WSGIKit/trunk/wsgikit/app_template.py 2005-04-11 05:16:53 UTC (rev 2325)
@@ -1,126 +0,0 @@
-import os
-from wsgikit.util.thirdparty import load_new_module
-string = load_new_module('string', (2, 4))
-
-default_options = {
- 'server': 'wsgiutils',
- 'verbose': True,
- 'reload': True,
- 'debug': True,
- }
-
-class Template(object):
-
- def __init__(self, dir):
- self.dir = dir
- self.name = os.path.basename(dir)
-
- def describe(self, verbosity):
- if not verbosity:
- return '%s: %s\n' % (self.name, self.description.splitlines()[0])
- else:
- return '%s: %s\n' % (self.name, self.description)
- # @@: for verbosity >= 2 we should give lots of metadata
-
- def _get_description(self):
- f = open(os.path.join(self.dir, 'description.txt'))
- content = f.read().strip()
- f.close()
- return content
- description = property(_get_description)
-
- def collect_options(self, args):
- result = {}
- while args:
- if args[0].startswith('-') and not args[0].startswith('--'):
- assert 0, (
- 'All template options must be long form (--option=...): %r' % args[0])
- if not args[0].startswith('--'):
- assert 0, (
- 'You can only give options to a template, not unnamed arguments: %r' % args[0])
- name = args[0][2:]
- if '=' in name:
- name, value = name.split('=', 1)
- args = args[1:]
- else:
- if not args[1:]:
- assert 0, (
- 'You did not give a value for the option %r' % args[0])
- value = args[1]
- args = args[2:]
- name = name.replace('-', '_')
- result[name] = value
- return result
-
- def copy_dir(self, source, dest, options, verbosity, simulate):
- names = os.listdir(source)
- names.sort()
- if not os.path.exists(dest):
- if verbosity >= 1:
- print 'Creating %s/' % dest
- if not simulate:
- os.makedirs(dest)
- elif verbosity >= 2:
- print 'Directory %s exists' % dest
- for name in names:
- full = os.path.join(source, name)
- if name.startswith('.'):
- if verbosity >= 2:
- print 'Skipping hidden file %s' % full
- continue
- dest_full = os.path.join(dest, self.substitute_filename(name, options))
- if os.path.isdir(full):
- if verbosity:
- print 'Recursing into %s' % full
- self.copy_dir(full, dest_full, options, verbosity, simulate)
- continue
- f = open(full, 'rb')
- content = f.read()
- f.close()
- content = self.substitute_content(content, options)
- if verbosity:
- print 'Copying %s to %s' % (full, dest_full)
- f = open(dest_full, 'wb')
- f.write(content)
- f.close()
-
- def substitute_filename(self, fn, options):
- for var, value in options.items():
- fn = fn.replace('+%s+' % var, str(value))
- return fn
-
- def substitute_content(self, content, options):
- tmpl = string.Template(content)
- return tmpl.substitute(TypeMapper(options))
-
- def create(self, options, args):
- outdir = options.output_dir
- template_dir = os.path.join(self.dir, 'template')
- if not os.path.exists(template_dir):
- raise OSError(
- 'No %s directory, I don\'t know what to do next' % template_dir)
- template_options = default_options.copy()
- template_options.update(self.collect_options(args))
- template_options['app_name'] = os.path.basename(outdir)
- template_options['base_dir'] = outdir
- template_options['absolute_base_dir'] = os.path.abspath(outdir)
- template_options['absolute_parent'] = os.path.dirname(
- os.path.abspath(outdir))
- template_options['template_name'] = self.name
- self.copy_dir(template_dir, outdir, template_options, options.verbose,
- options.simulate)
-
-
-class TypeMapper(dict):
-
- def __getitem__(self, item):
- if item.startswith('str_'):
- return repr(str(self[item[4:]]))
- elif item.startswith('bool_'):
- if self[item[5:]]:
- return 'True'
- else:
- return 'False'
- else:
- return dict.__getitem__(self, item)
-
Added: WSGIKit/trunk/wsgikit/app_templates/__init__.py
===================================================================
--- WSGIKit/trunk/wsgikit/app_templates/__init__.py 2005-04-11 02:14:36 UTC (rev 2324)
+++ WSGIKit/trunk/wsgikit/app_templates/__init__.py 2005-04-11 05:16:53 UTC (rev 2325)
@@ -0,0 +1 @@
+#
Added: WSGIKit/trunk/wsgikit/app_templates/webkit_zpt/__init__.py
===================================================================
--- WSGIKit/trunk/wsgikit/app_templates/webkit_zpt/__init__.py 2005-04-11 02:14:36 UTC (rev 2324)
+++ WSGIKit/trunk/wsgikit/app_templates/webkit_zpt/__init__.py 2005-04-11 05:16:53 UTC (rev 2325)
@@ -0,0 +1 @@
+#
Added: WSGIKit/trunk/wsgikit/app_templates/webkit_zpt/command.py
===================================================================
--- WSGIKit/trunk/wsgikit/app_templates/webkit_zpt/command.py 2005-04-11 02:14:36 UTC (rev 2324)
+++ WSGIKit/trunk/wsgikit/app_templates/webkit_zpt/command.py 2005-04-11 05:16:53 UTC (rev 2325)
@@ -0,0 +1,6 @@
+from wsgikit.app_setup import CommandRunner, standard_parser, CommandCreate
+
+the_runner = CommandRunner()
+the_runner.register(CommandCreate)
+
+run = the_runner.run
|