1
0
Fork 0
gnuviechadmin-historic/gnuviechadmin/cli/CliCommand.py

226 lines
8.0 KiB
Python

# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
#
# 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, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
#
# Version: $Id$
import getopt
import sys
import logging
from gnuviechadmin.exceptions import GnuviechadminError
class CliCommand:
"""Base class for command line interface.
A specific implementation class must define the fields name,
description and _optionmap.
The field name is the name of the subcommand.
The field description is a short, one line description of the
command.
The field _optionmap is a map which maps the subcommand names to
lists of tuples. Each tuple consists of four elements. The first
element is a list of command line arguments, short arguments start
with dash, long arguments with a double dash. The second element
is the name of the field in the data map of the command, it will
directly be sent to the underlying entity. The third field is a
description for the group of command line options in field
one. The fourth field is True for mandatory fields and False
otherwise.
"""
def _usage(self):
"""This method shows usage information. The implementation
relies on the information in the fields name, description and
_optionmap in the implementation classes."""
print """GNUViechAdmin command line interface
Subcommand: %(command)s
%(description)s
Usage:
%(called)s %(command)s -h|--help
gives this usage information.
Common options:
%(option)s
%(mandatory)s %(optiondesc)s
""" % {'called': sys.argv[0],
'command': self.name,
'description': self.description,
'option': '-v, --verbose',
'optiondesc': 'verbose operation',
'mandatory': " "}
for commandname in self._optionmap.keys():
cmdl = "%(called)s %(command)s %(subcommand)s [-v|--verbose]" % {
'called': sys.argv[0],
'command': self.name,
'subcommand': commandname}
desc = """
%s
""" % (self._optionmap[commandname][0])
for (options, field, optiondesc, mandatory) in \
self._optionmap[commandname][1]:
cmd = " "
pairs = []
for option in options:
if field:
if option.startswith("--"):
pairs.append("%s=<%s>" % (option, field))
else:
pairs.append("%s <%s>" % (option, field))
else:
pairs.append(option)
if not mandatory:
cmd = cmd + "["
cmd = cmd + "|".join(pairs)
if not mandatory:
cmd = cmd + "]"
descmap = {
'option': ", ".join(pairs),
'optiondesc': optiondesc,
'mandatory': ' '}
if mandatory:
descmap['mandatory'] = '*'
desc = desc + """ %(option)s
%(mandatory)s %(optiondesc)s
""" % descmap
if (len(cmdl) + len(cmd)) > 79:
print cmdl
cmdl = cmd
else:
cmdl = cmdl + cmd
print cmdl
print desc
print "Mandatory options are marked with *"
def _subcommands(self):
"""Convenience method for retrieving the subcommand names from
the _optionmap field."""
return self._optionmap.keys()
def _longopts(self, subcommand):
"""This method retrieves available long options in a format
valid for getopt.gnu_getopt(...) from the _optionmap field."""
longopts = []
for cur in [(option[0], option[1]) for option in \
self._optionmap[subcommand][1]]:
for command in cur[0]:
if command.startswith("--"):
if cur[1]:
longopts.append(command[2:] + "=")
else:
longopts.append(command[2:])
return longopts
def _shortopts(self, subcommand):
"""This method retrieves available short options in a format
valid for getopt.gnu_getopt(...) from the _optionmap field."""
shortopts = ""
for cur in [(option[0], option[1]) for option in \
self._optionmap[subcommand][1]]:
for command in cur[0]:
if not command.startswith("--"):
if cur[1]:
shortopts = shortopts + command[1:] + ":"
else:
shortopts = shortopts + command[1:]
return shortopts
def _checkrequired(self, subcommand):
"""Checks whether the required fields of the given subcommand
are set."""
reqcheck = [True, []]
for req in [option for option in \
self._optionmap[subcommand][1] if option[3]]:
if not req[1] in self._data:
reqcheck[0] = False
reqcheck[1].append(""" %s
* %s""" % (", ".join(req[0]), req[2]))
return reqcheck
def _handleoption(self, subcommand, o, a):
"""Handles a command line option by assigning it to the
matching key as defined in the _optionmap property of the
implementation class."""
optionmap = [(option[0], option[1]) for option in \
self._optionmap[subcommand][1]]
if optionmap:
for (options, datakey) in optionmap:
if o in options:
self._data[datakey] = a
def _execute(self, subcommand):
"""This method is called when the subcommand of the command is
executed."""
raise NotImplementedError
def _parseopts(self, subcommand, args):
"""This method parses the options given on the command line."""
longopts = ["help", "verbose"]
longopts.extend(self._longopts(subcommand))
try:
opts, args = getopt.gnu_getopt(
args,
"hv" + self._shortopts(subcommand),
longopts)
except getopt.GetoptError:
self._usage()
sys.exit(2)
self._verbose = False
for o, a in opts:
if o in ("-v", "--verbose"):
self._verbose = True
if o in ("-h", "--help"):
self._usage()
sys.exit()
self._handleoption(subcommand, o, a)
def __init__(self, args):
"""This initializes the command with the given command line
arguments and executes it."""
self.logger = logging.getLogger("%s.%s" % (
self.__class__.__module__, self.__class__.__name__))
self._data = {}
if len(args) > 0:
if args[0] in self._subcommands():
self._parseopts(args[0], args[1:])
reqcheck = self._checkrequired(args[0])
if reqcheck[0]:
try:
self._execute(args[0])
except GnuviechadminError, e:
print e
else:
self._usage()
print """
the following required arguments are missing:
"""
print "\n".join(reqcheck[1])
else:
self._usage()
print "invalid sub command"
else:
self._usage()