wcs/wcs/qommon/ctl.py

165 lines
6.0 KiB
Python

# w.c.s. - web application for online forms
# Copyright (C) 2005-2010 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import optparse
from optparse import make_option
import sys
import os
__all__ = [
'Command',
]
from django.utils.six.moves import configparser as ConfigParser
from wcs import qommon
from . import _
qommon._commands = {}
class Command(object):
doc = ''
name = None
usage_args = '[ options ... ]'
def __init__(self, options=[]):
self.config = ConfigParser.ConfigParser()
self.options = options + [
make_option('--extra', metavar='DIR', action='append',
dest='extra', default=[]),
make_option('--app-dir', metavar='DIR', action='store',
dest='app_dir', default=None),
make_option('--data-dir', metavar='DIR', action='store',
dest='data_dir', default=None),
]
def run(self, args, base_options):
if base_options.configfile:
if not os.path.exists(base_options.configfile):
print('Missing configuration file %s' % base_options.configfile, file=sys.stderr)
sys.exit(1)
try:
self.config.read(base_options.configfile)
except ConfigParser.ParsingError as e:
print('Invalid configuration file %s' % base_options.configfile, file=sys.stderr)
print(e, file=sys.stderr)
sys.exit(1)
if not self.config.has_section('main'):
self.config.add_section('main')
sub_options, args = self.parse_args(args)
if sub_options.app_dir:
self.config.set("main", "app_dir", sub_options.app_dir)
if sub_options.data_dir:
self.config.set("main", "data_dir", sub_options.data_dir)
if sub_options.extra:
if not self.config.has_section('extra'):
self.config.add_section('extra')
for i, extra in enumerate(sub_options.extra):
self.config.set("extra", "cmd_line_extra_%d" % i, extra)
return self.execute(base_options, sub_options, args)
def parse_args(self, args):
self.parser = optparse.OptionParser(
usage='%%prog %s %s' % (self.name, _(self.usage_args)),
description=self.doc)
self.parser.add_options(self.options)
return self.parser.parse_args(args)
def execute(self, base_options, sub_options, args):
"""The body of the command"""
raise NotImplementedError
@classmethod
def register(cls):
qommon._commands[cls.name] = cls
class Ctl(object):
def __init__(self, cmd_prefixes=[]):
self.cmd_prefixes = cmd_prefixes
self.parser = optparse.OptionParser(
usage='%prog [ -f config ] command [ options ... ]',
add_help_option=False)
self.parser.disable_interspersed_args()
self.parser.add_option('-f', '--file', action='store', metavar='CONFIG',
type='string', dest='configfile',
help=_('use a non default configuration file'))
self.parser.add_option('--help', action='callback',
callback=self.print_help,
help=_("Display this help and exit"))
def load_all_commands(self, ignore_errors=True):
for cmd_prefix in self.cmd_prefixes:
if not cmd_prefix in sys.modules:
__import__(cmd_prefix)
mod = sys.modules.get(cmd_prefix)
if not mod:
continue
if os.path.isdir(mod.__file__):
cmddir = os.path.abspath(mod.__file__)
else:
cmddir = os.path.abspath(os.path.dirname(mod.__file__))
for fname in os.listdir(os.path.join(cmddir)):
name, ext = os.path.splitext(fname)
if not ext == '.py':
continue
if name.startswith('_'):
continue
try:
__import__('%s.%s' % (cmd_prefix, name))
except ImportError as e:
if not ignore_errors:
raise e
def get_commands(self):
return qommon._commands
def print_help(self, *args):
self.parser.print_help()
self.load_all_commands()
print()
commands = [(x.name, x.doc) for x in self.get_commands().values()]
commands.sort()
print('Available commands:')
for name, description in commands:
print(' %-15s %s' % (name, description))
sys.exit(0)
def run(self, args):
options, args = self.parser.parse_args(args)
if not args:
self.parser.error('You must use a command')
command, args = args[0], args[1:]
if command not in self.get_commands():
# load a module named like the command, this is the common case
for cmd_prefix in self.cmd_prefixes:
try:
__import__('%s.%s' % (cmd_prefix, command))
except ImportError:
pass
if command not in self.get_commands():
# if the command could not be loaded from a same-name module,
# go over all modules
self.load_all_commands()
command_class = self.get_commands()[command]
cmd = command_class()
return cmd.run(args, options)