weboobcfg.py 10.8 KB
Newer Older
1 2
# -*- coding: utf-8 -*-

3
# Copyright(C) 2010-2012 Romain Bignon, Christophe Benz
4
#
5
# This file is part of weboob.
6
#
7
# weboob is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU Lesser General Public License as published by
9 10 11 12
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU Lesser General Public License for more details.
16
#
17
# You should have received a copy of the GNU Lesser General Public License
18
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
19

20
from __future__ import print_function
Christophe Benz's avatar
Christophe Benz committed
21

22
import os
23
from collections import OrderedDict
24

25
from weboob.capabilities.account import CapAccount
26
from weboob.exceptions import ModuleLoadError
27
from weboob.tools.application.repl import ReplApplication
28
from weboob.tools.application.console import ConsoleProgress
29
from weboob.tools.application.formatters.iformatter import IFormatter
30 31 32 33

__all__ = ['WeboobCfg']


34 35 36 37 38 39 40 41 42 43 44 45 46 47
class ModuleInfoFormatter(IFormatter):
    def format_dict(self, minfo):
        result = '.------------------------------------------------------------------------------.\n'
        result += '| Module %-69s |\n' % minfo['name']
        result += "+-----------------.------------------------------------------------------------'\n"
        result += '| Version         | %s\n' % minfo['version']
        result += '| Maintainer      | %s\n' % minfo['maintainer']
        result += '| License         | %s\n' % minfo['license']
        result += '| Description     | %s\n' % minfo['description']
        result += '| Capabilities    | %s\n' % ', '.join(minfo['capabilities'])
        result += '| Installed       | %s\n' % minfo['installed']
        result += '| Location        | %s\n' % minfo['location']
        if 'config' in minfo:
            first = True
48
            for key, field in minfo['config'].items():
49 50 51 52
                label = field['label']
                if field['default'] is not None:
                    label += ' (default: %s)' % field['default']

53 54
                if first:
                    result += '|                 | \n'
55
                    result += '| Configuration   | %s: %s\n' % (key, label)
56 57
                    first = False
                else:
58
                    result += '|                 | %s: %s\n' % (key, label)
59 60 61 62
        result += "'-----------------'\n"
        return result


63
class WeboobCfg(ReplApplication):
64
    APPNAME = 'weboob-config'
Romain Bignon's avatar
Romain Bignon committed
65
    VERSION = '1.5'
66
    COPYRIGHT = 'Copyright(C) 2010-YEAR Christophe Benz, Romain Bignon'
67 68
    DESCRIPTION = "Weboob-Config is a console application to add/edit/remove backends, " \
                  "and to register new website accounts."
69
    SHORT_DESCRIPTION = "manage backends or register new accounts"
70
    EXTRA_FORMATTERS = {'info_formatter': ModuleInfoFormatter}
71
    COMMANDS_FORMATTERS = {'modules':     'table',
72
                           'list':        'table',
73
                           'info':        'info_formatter',
74
                           }
75 76
    DISABLE_REPL = True

77 78 79
    def load_default_backends(self):
        pass

80 81
    def do_add(self, line):
        """
82
        add MODULE_NAME [BACKEND_NAME] [PARAMETERS ...]
83

84 85 86 87
        Create a backend from a module. By default, if BACKEND_NAME is omitted,
        that's the module name which is used.

        You can specify parameters from command line in form "key=value".
88
        """
89
        if not line:
90
            print('You must specify a module name. Hint: use the "modules" command.', file=self.stderr)
91
            return 2
92

93
        module_name, options = self.parse_command_args(line, 2, 1)
94 95 96 97 98
        if options:
            options = options.split(' ')
        else:
            options = ()

99
        backend_name = None
100

101 102 103 104 105 106
        params = {}
        # set backend params from command-line arguments
        for option in options:
            try:
                key, value = option.split('=', 1)
            except ValueError:
107 108 109 110 111 112 113
                if backend_name is None:
                    backend_name = option
                else:
                    print('Parameters have to be formatted "key=value"', file=self.stderr)
                    return 2
            else:
                params[key] = value
114

115
        self.add_backend(module_name, backend_name or module_name, params)
116

117 118
    def do_register(self, line):
        """
119
        register MODULE
120

121
        Register a new account on a module.
122 123 124
        """
        self.register_backend(line)

125 126 127 128 129 130 131 132
    def do_confirm(self, backend_name):
        """
        confirm BACKEND

        For a backend which support CapAccount, parse a confirmation mail
        after using the 'register' command to automatically confirm the
        subscribe.

Christophe Benz's avatar
Christophe Benz committed
133
        It takes mail from stdin. Use it with postfix for example.
134 135 136 137 138 139 140
        """
        # Do not use the ReplApplication.load_backends() method because we
        # don't want to prompt user to create backend.
        self.weboob.load_backends(names=[backend_name])
        try:
            backend = self.weboob.get_backend(backend_name)
        except KeyError:
141
            print('Error: backend "%s" not found.' % backend_name, file=self.stderr)
142 143
            return 1

144
        if not backend.has_caps(CapAccount):
145
            print('Error: backend "%s" does not support accounts management' % backend_name, file=self.stderr)
146 147
            return 1

148
        mail = self.acquire_input()
149
        if not backend.confirm_account(mail):
150
            print('Error: Unable to confirm account creation', file=self.stderr)
151 152 153
            return 1
        return 0

154
    def do_list(self, line):
155
        """
156
        list [CAPS ..]
157

158
        Show backends.
159
        """
160
        caps = line.split()
161
        for backend_name, module_name, params in sorted(self.weboob.backends_config.iter_backends()):
162
            try:
163
                module = self.weboob.modules_loader.get_or_load_module(module_name)
164
            except ModuleLoadError as e:
165
                self.logger.warning('Unable to load module %r: %s' % (module_name, e))
166 167
                continue

168
            if caps and not module.has_caps(*caps):
169
                continue
170 171
            row = OrderedDict([('Name', backend_name),
                               ('Module', module_name),
Christophe Benz's avatar
Christophe Benz committed
172
                               ('Configuration', ', '.join(
173 174
                                   '%s=%s' % (key, ('*****' if key in module.config and module.config[key].masked
                                                    else value))
175
                                   for key, value in params.items())),
176 177 178
                               ])
            self.format(row)

179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
    def do_enable(self, backend_name):
        """
        enable NAME

        Enable a backend.
        """
        try:
            self.weboob.backends_config.edit_backend(backend_name, {'_enabled': '1'})
        except KeyError:
            print('Backend instance "%s" does not exist' % backend_name, file=self.stderr)
            return 1

    def do_disable(self, backend_name):
        """
        disable NAME

        Disable a backend.
        """
        try:
            self.weboob.backends_config.edit_backend(backend_name, {'_enabled': '0'})
        except KeyError:
            print('Backend instance "%s" does not exist' % backend_name, file=self.stderr)
            return 1

203
    def do_remove(self, backend_name):
204 205 206
        """
        remove NAME

207
        Remove a backend.
208
        """
209 210
        if not self.weboob.backends_config.remove_backend(backend_name):
            print('Backend instance "%s" does not exist' % backend_name, file=self.stderr)
211 212
            return 1

213
    def do_edit(self, line):
214
        """
215
        edit BACKEND
216

217
        Edit a backend
218
        """
219 220
        try:
            self.edit_backend(line)
Romain Bignon's avatar
Romain Bignon committed
221
        except KeyError:
222
            print('Error: backend "%s" not found' % line, file=self.stderr)
223
            return 1
Christophe Benz's avatar
Christophe Benz committed
224

225
    def do_modules(self, line):
226
        """
227
        modules [CAPS ...]
228

229
        Show available modules.
230
        """
231
        caps = line.split()
232
        for name, info in sorted(self.weboob.repositories.get_all_modules_info(caps).items()):
Christophe Benz's avatar
Christophe Benz committed
233
            row = OrderedDict([('Name', name),
234
                               ('Capabilities', info.capabilities),
235
                               ('Description', info.description),
236
                               ('Installed', info.is_installed()),
Christophe Benz's avatar
Christophe Benz committed
237 238 239
                               ])
            self.format(row)

240
    def do_info(self, line):
241 242 243
        """
        info NAME

244
        Display information about a module.
245
        """
246
        if not line:
247
            print('You must specify a module name. Hint: use the "modules" command.', file=self.stderr)
248
            return 2
249

250 251
        minfo = self.weboob.repositories.get_module_info(line)
        if not minfo:
252
            print('Module "%s" does not exist.' % line, file=self.stderr)
253 254
            return 1

255
        try:
256
            module = self.weboob.modules_loader.get_or_load_module(line)
257
        except ModuleLoadError:
258
            module = None
Christophe Benz's avatar
Christophe Benz committed
259

260 261 262 263 264 265 266 267 268 269 270 271 272 273
        self.start_format()
        self.format(self.create_minfo_dict(minfo, module))


    def create_minfo_dict(self, minfo, module):
        module_info = {}
        module_info['name'] = minfo.name
        module_info['version'] = minfo.version
        module_info['maintainer'] = minfo.maintainer
        module_info['license'] = minfo.license
        module_info['description'] = minfo.description
        module_info['capabilities'] = minfo.capabilities
        module_info['installed'] = '%s%s' % (('yes' if module else 'no'), ' (new version available)' if self.weboob.repositories.versions.get(minfo.name) > minfo.version else '')
        module_info['location'] = '%s' % (minfo.url or os.path.join(minfo.path, minfo.name))
274
        if module:
275
            module_info['config'] = {}
276
            for key, field in module.config.items():
277 278 279 280 281 282 283
                module_info['config'][key] = {'label': field.label,
                                              'default': field.default,
                                              'description': field.description,
                                              'regexp': field.regexp,
                                              'choices': field.choices,
                                              'masked': field.masked,
                                              'required': field.required}
284
        return module_info
Christophe Benz's avatar
Christophe Benz committed
285

286 287 288 289 290 291
    def do_update(self, line):
        """
        update

        Update weboob.
        """
292
        self.weboob.update(ConsoleProgress(self))
293 294 295 296 297
        if self.weboob.repositories.errors:
            print('Errors building modules: %s' % ', '.join(self.weboob.repositories.errors.keys()), file=self.stderr)
            if not self.options.debug:
                print('Use --debug to get more information.', file=self.stderr)
            return 1