# 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 . 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)