1
# -*- coding: utf-8 -*-
3
# Copyright 2013 Jaap Karssenberg <jaap.karssenberg@gmail.com>
6
from getopt import gnu_getopt, GetoptError
10
from zim import __version__
11
from zim.errors import Error
14
class UsageError(Error):
15
'''Error raised when commands do not have correct
16
number or type of arguments
21
class Command(object):
22
'''Base class for commandline commands, used by zim to abstract
23
part of the C{main()} functionality and allow better testability
24
of commandline arguments.
26
Sub-classes can define the options and arguments that they require.
27
Then only the C{run()} method needs to be defined to implement the
28
actual command. In the C{run()} method C{self.opts} and C{self.args}
29
can be accessed to get the commandline options (dict) and the
30
commandline arguments (list) respectively.
33
arguments = () #: Define arguments, e.g ('NOTEBOOK', '[PAGE]')
35
options = () #: Define options by 3-tuple of long, short & description.
36
#: E.g. ("foo=", "f", "set parameter for foo")
37
#: For options that can appear multiple times,
38
#: assign a list "[]" in "self.opts" before parse_options is called
41
('verbose', 'V', 'Verbose output'),
42
('debug', 'D', 'Debug output'),
45
use_gtk = False #: Flag whether this command uses a graphical interface
47
def __init__(self, command, *args, **opts):
49
@param command: the command switch (first commandline argument)
50
@param args: positional commandline arguments
51
@param opts: command options
53
self.command = command
54
self.args = list(args)
57
def parse_options(self, *args):
58
'''Parse commandline options for this command
59
Sets the attributes 'args' and 'opts' to a list of arguments
60
and a dictionary of options respectively
61
@param args: all remaining options to be parsed
62
@raises GetOptError: when options are not correct
67
for l, s, desc in self.default_options + self.options:
68
long_options.append(l)
69
if s and l.endswith('='):
71
options_map[s] = l.strip('=')
76
optlist, args = gnu_getopt(args, options, long_options)
81
key = options_map.get(key, key)
84
elif key in self.opts and isinstance(self.opts[key], list):
85
self.opts[key].append(a)
89
def get_options(self, *names):
90
'''Retrieve a dict with a sub-set of the command options
91
@param names: that options in the subset
93
return dict((k, self.opts.get(k)) for k in names)
95
def get_arguments(self):
96
'''Get the arguments, to be used by the implementation of C{run()}
97
@raises UsageError: when arguments are not correct
98
@returns: tuple of arguments, padded with None to correct length
100
minimum = len([a for a in self.arguments if not a.startswith('[')])
101
if len(self.args) < minimum:
102
raise UsageError, 'Command %s takes %i arguments' % (self.command, minimum)
103
elif len(self.args) > len(self.arguments):
104
raise UsageError, 'Command %s takes only %i arguments' % (self.command, len(self.args))
106
return tuple(self.args) \
107
+ (None,) * (len(self.arguments) - len(self.args))
109
def set_logging(self):
110
'''Configure the logging module for output based on the
111
default options -V and -D
113
if self.opts.get('debug'):
114
level = logging.DEBUG
115
elif self.opts.get('verbose'):
120
root = logging.getLogger() # root
123
logger = logging.getLogger('zim')
124
logger.info('This is zim %s', __version__)
125
if level == logging.DEBUG:
130
logger.debug('Python version is %s', str(sys.version_info))
131
logger.debug('Platform is %s', os.name)
132
logger.debug(zim.get_zim_revision())
133
zim.config.log_basedirs()
138
@raises UsageError: when arguments are not correct
139
@implementation: must be implemented by subclasses
141
raise NotImplementedError