File: base.py

package info (click to toggle)
datapm 0.10-1.1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd, wheezy
  • size: 472 kB
  • ctags: 590
  • sloc: python: 2,760; makefile: 2
file content (230 lines) | stat: -rw-r--r-- 7,134 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
'''dpm command line interface.

See dpm help for details.
'''
import sys
import os
import optparse
import logging
from StringIO import StringIO
import traceback
import time

logger = logging.getLogger('dpm.cli')
# set this up below
# logging.basicConfig(level=logging.DEBUG)

import dpm
import dpm.spec

parser = optparse.OptionParser(
    usage='''%prog COMMAND [OPTIONS]

Use "help" command to see a list of commands.''',
    version=dpm.__version__)

parser.add_option(
    '-v', '--verbose',
    dest='verbose',
    action='count',
    default=0,
    help='Give more output')
parser.add_option(
    '-d', '--debug',
    dest='debug',
    default=False,
    action='store_true',
    help='Print debug output')
parser.add_option(
    '-q', '--quiet',
    dest='quiet',
    action='count',
    default=0,
    help='Give less output')
parser.add_option(
    '--log',
    dest='log',
    metavar='FILENAME',
    help='Log file where a complete (maximum verbosity) record will be kept')
# TODO: put in defaults for repo and config
import dpm.config
parser.add_option(
    '-c', '--config',
    dest='config',
    help='Path to config file (if any) - defaults to %s' % dpm.config.default_config_path)
parser.add_option(
    '-r', '--repository',
    dest='repository',
    help='Path to repository - overrides value in config'
    )
parser.add_option(
    '-k', '--api-key',
    dest='api_key',
    default=None,
    help='CKAN API Key (overrides value in config)')


class Command(object):
    '''Base command class that all dpm Commands should inherit from.
    
    An inheriting class should provide a `run` method and can define the
    following class level attributes (documented below):

    * name
    * summary
    * usage
    * min_args
    * max_args
    '''
    #: The name of the command as used on the command line and in help
    name = None
    #: one line summary of this command (used in printing help)
    summary = None
    #: A multiline detailed description of the command
    usage = None
    #: Minimum number of args to the command (not used if set to None)
    min_args = None
    #: Maximum number of args to the command (not used if set to None)
    max_args = None

    def __init__(self):
        assert self.name
        self.parser = optparse.OptionParser(
            usage=self.usage,
            prog='%s %s' % (sys.argv[0], self.name),
            version=parser.version)
        for option in parser.option_list:
            if not option.dest:
                # -h, --version, etc
                continue
            self.parser.add_option(option)
        self.logger = logger

    def merge_options(self, initial_options, options):
        for attr in ['log']:
            setattr(options, attr, getattr(initial_options, attr) or getattr(options, attr))
        options.quiet += initial_options.quiet
        options.verbose += initial_options.verbose

    def index_from_spec(self, spec_str, all_index=False):
        spec = dpm.spec.Spec.parse_spec(spec_str, all_index=all_index)
        return spec.index_from_spec()

    def _print(self, msg, force=False):
        if self.level >= 1 or force:
            print(msg)

    def _print_pkg(self, pkg):
        print u'## Package: %s' % pkg.name
        print
        out = pkg.pretty_print()
        print out.encode("utf-8") ## should really chech the users terminal capability
    
    def _check_args(self, args):
        if self.min_args is not None and len(args) < self.min_args:
            print 'Insufficient arguments. See command help'
            return False
        if self.max_args is not None and len(args) > self.max_args:
            print 'Too many arguments. See command help'
            return False
        return True

    def main(self, complete_args, args, initial_options):
        options = initial_options
        discarded_options, args = self.parser.parse_args(args)
        # From pip but not needed by us I think
        # self.merge_options(initial_options, options)
        self.options = options
        self.verbose = options.verbose
        import dpm.config
        # dpm.CONFIG now set
        if options.config:
            dpm.CONFIG = dpm.config.load_config(options.config)
        if options.api_key:
            dpm.CONFIG.set('index:ckan', 'ckan.api_key', self.options.api_key)
        if options.repository:
            dpm.CONFIG.set('dpm', 'repo.default_path',
                    options.repository)

        ## set up logging
        if options.debug:
            logging.basicConfig(level=logging.DEBUG)
        else:
            logging.basicConfig(level=logging.WARN)
        # TODO: fix up logger
        level = 1 # Notify
        level += options.verbose
        level -= options.quiet
        self.level = level

        complete_log = []
        if options.log:
            log_fp = open_logfile_append(options.log)
            # TODO: add additional listener ...
            # logger.consumers.append((logger.DEBUG, log_fp))
        else:
            log_fp = None

        exit = 0
        if not self._check_args(args):
            sys.exit(2)
        try:
            self.run(options, args)
        except Exception, inst:
            print 'Error: %s\n' % inst
            print '[** For (lots) more information run with --debug **]'
            logger.debug('Exception:\n%s' % format_exc())
            exit = 2
        
        if log_fp is not None:
            log_fp.close()
        if exit:
            try:
                log_dir = os.path.expanduser('~/.dpm')
                if not os.path.exists(log_dir):
                    os.makedirs(log_dir)
                log_fn = os.path.join(log_dir, 'dpm-log.txt')
                text = '\n'.join(complete_log)
                # Not sure we need to tell people ...
                # logger.fatal('Storing complete log in %s' % log_fn)
                log_fp = open_logfile_append(log_fn)
                log_fp.write(text)
                log_fp.close()
            except IOError:
                pass
        sys.exit(exit)
    
    def run(self, options, args):
        '''This is the method inheriting classes should override to implement
        their command functionality.

        Inheriting classes should *not* call super to this method -- they
        should just override it.

        :param options: the comand line options (as extracted by optparse).
        :param args: the remaining args (so *not* including the command name).
        '''
        raise NotImplementedError


def format_exc(exc_info=None):
    if exc_info is None:
        exc_info = sys.exc_info()
    out = StringIO()
    traceback.print_exception(*exc_info, **dict(file=out))
    return out.getvalue()

def open_logfile_append(filename):
    """Open the named log file in append mode.

    If the file already exists, a separator will also be printed to
    the file to separate past activity from current activity.
    """
    exists = os.path.exists(filename)
    log_fp = open(filename, 'a')
    if exists:
        print >> log_fp, '-'*60
        print >> log_fp, '%s run on %s' % (sys.argv[0], time.strftime('%c'))
    return log_fp