Mercurial > libervia-backend
annotate sat_frontends/jp/base.py @ 3040:fee60f17ebac
jp: jp asyncio port:
/!\ this commit is huge. Jp is temporarily not working with `dbus` bridge /!\
This patch implements the port of jp to asyncio, so it is now correctly using the bridge
asynchronously, and it can be used with bridges like `pb`. This also simplify the code,
notably for things which were previously implemented with many callbacks (like pagination
with RSM).
During the process, some behaviours have been modified/fixed, in jp and backends, check
diff for details.
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 25 Sep 2019 08:56:41 +0200 |
parents | ab2696e34d29 |
children | 3df611adb598 |
rev | line source |
---|---|
1945 | 1 #!/usr/bin/env python2 |
0 | 2 # -*- coding: utf-8 -*- |
3 | |
609
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
601
diff
changeset
|
4 # jp: a SAT command line tool |
2771 | 5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) |
0 | 6 |
609
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
601
diff
changeset
|
7 # This program is free software: you can redistribute it and/or modify |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
601
diff
changeset
|
8 # it under the terms of the GNU Affero General Public License as published by |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
601
diff
changeset
|
9 # the Free Software Foundation, either version 3 of the License, or |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
601
diff
changeset
|
10 # (at your option) any later version. |
0 | 11 |
609
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
601
diff
changeset
|
12 # This program is distributed in the hope that it will be useful, |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
601
diff
changeset
|
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
601
diff
changeset
|
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
601
diff
changeset
|
15 # GNU Affero General Public License for more details. |
0 | 16 |
609
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
601
diff
changeset
|
17 # You should have received a copy of the GNU Affero General Public License |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
601
diff
changeset
|
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
0 | 19 |
3040 | 20 import asyncio |
771 | 21 from sat.core.i18n import _ |
402
f03688bdb858
jp: use with statement to open fifo
Goffi <goffi@goffi.org>
parents:
401
diff
changeset
|
22 |
0 | 23 ### logging ### |
1605
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
24 import logging as log |
3040 | 25 log.basicConfig(level=log.WARNING, |
26 format='[%(name)s] %(message)s') | |
0 | 27 ### |
28 | |
29 import sys | |
3040 | 30 import os |
817 | 31 import os.path |
32 import argparse | |
3040 | 33 import inspect |
34 from pathlib import Path | |
817 | 35 from glob import iglob |
36 from importlib import import_module | |
1139
75025461141f
move sat.tools.jid to sat_frontends.tools.jid
souliane <souliane@mailoo.org>
parents:
1033
diff
changeset
|
37 from sat_frontends.tools.jid import JID |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
38 from sat.tools import config |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
39 from sat.tools.common import dynamic_import |
2532 | 40 from sat.tools.common import uri |
2704
ab37d1c7c38c
jp (base): new date_decoder to specify dates in arguments
Goffi <goffi@goffi.org>
parents:
2692
diff
changeset
|
41 from sat.tools.common import date_utils |
817 | 42 from sat.core import exceptions |
43 import sat_frontends.jp | |
970
2e052998c7eb
jp: using C.APP_URL for application url
Goffi <goffi@goffi.org>
parents:
965
diff
changeset
|
44 from sat_frontends.jp.constants import Const as C |
2532 | 45 from sat_frontends.tools import misc |
1840
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
46 import xml.etree.ElementTree as ET # FIXME: used temporarily to manage XMLUI |
1950 | 47 from collections import OrderedDict |
1872
df1ca137b0cb
jp (blog/edit): editor arguments can now be specified on sat.conf, and default on are applied for known editors:
Goffi <goffi@goffi.org>
parents:
1869
diff
changeset
|
48 |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
49 ## bridge handling |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
50 # we get bridge name from conf and initialise the right class accordingly |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
51 main_config = config.parseMainConf() |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
52 bridge_name = config.getConfig(main_config, '', 'bridge', 'dbus') |
3040 | 53 USER_INTER_MSG = _("User interruption: good bye") |
54 | |
55 | |
56 class QuitException(BaseException): | |
57 """Quitting is requested | |
58 | |
59 This is used to stop execution when host.quit() is called | |
60 """ | |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
61 |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
62 |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
63 # TODO: move loops handling in a separated module |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
64 if 'dbus' in bridge_name: |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
65 from gi.repository import GLib |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
66 |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
67 |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
68 class JPLoop(object): |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
69 |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
70 def __init__(self): |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
71 self.loop = GLib.MainLoop() |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
72 |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
73 def run(self): |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
74 self.loop.run() |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
75 |
3040 | 76 def quit(self, exit_code): |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
77 self.loop.quit() |
3040 | 78 sys.exit(exit_code) |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
79 |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
80 def call_later(self, delay, callback, *args): |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
81 """call a callback repeatedly |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
82 |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
83 @param delay(int): delay between calls in ms |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
84 @param callback(callable): method to call |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
85 if the callback return True, the call will continue |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
86 else the calls will stop |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
87 @param *args: args of the callbac |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
88 """ |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
89 GLib.timeout_add(delay, callback, *args) |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
90 |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
91 else: |
3040 | 92 import signal |
93 from twisted.internet import asyncioreactor | |
94 asyncioreactor.install() | |
95 from twisted.internet import reactor, defer | |
96 | |
97 class JPLoop(object): | |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
98 |
3040 | 99 def __init__(self): |
100 # exit code must be set when using quit, so if it's not set | |
101 # something got wrong and we must report it | |
102 self._exit_code = C.EXIT_INTERNAL_ERROR | |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
103 |
3040 | 104 def run(self, jp, *args): |
105 self.jp = jp | |
106 signal.signal(signal.SIGINT, self._on_sigint) | |
107 defer.ensureDeferred(self._start(jp, *args)) | |
108 try: | |
109 reactor.run(installSignalHandlers=False) | |
110 except SystemExit as e: | |
111 self._exit_code = e.code | |
112 sys.exit(self._exit_code) | |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
113 |
3040 | 114 async def _start(self, jp, *args): |
115 fut = asyncio.ensure_future(jp.main(*args)) | |
116 try: | |
117 await defer.Deferred.fromFuture(fut) | |
118 except BaseException: | |
119 import traceback | |
120 traceback.print_exc() | |
121 jp.quit(1) | |
122 | |
123 def quit(self, exit_code): | |
124 self._exit_code = exit_code | |
125 reactor.stop() | |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
126 |
3040 | 127 def _timeout_cb(self, args, callback, delay): |
128 try: | |
129 ret = callback(*args) | |
130 # FIXME: temporary hack to avoid traceback when using XMLUI | |
131 # to be removed once create_task is not used anymore in | |
132 # xmlui_manager (i.e. once sat_frontends.tools.xmlui fully supports | |
133 # async syntax) | |
134 except QuitException: | |
135 return | |
136 if ret: | |
137 reactor.callLater(delay, self._timeout_cb, args, callback, delay) | |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
138 |
3040 | 139 def call_later(self, delay, callback, *args): |
140 delay = float(delay) / 1000 | |
141 reactor.callLater(delay, self._timeout_cb, args, callback, delay) | |
142 | |
143 def _on_sigint(self, sig_number, stack_frame): | |
144 """Called on keyboard interruption | |
145 | |
146 Print user interruption message, set exit code and stop reactor | |
147 """ | |
148 print("\r" + USER_INTER_MSG) | |
149 self._exit_code = C.EXIT_USER_CANCELLED | |
150 reactor.callFromThread(reactor.stop) | |
151 | |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
152 |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
153 if bridge_name == "embedded": |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
154 from sat.core import sat_main |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
155 sat = sat_main.SAT() |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
156 |
0 | 157 try: |
817 | 158 import progressbar |
159 except ImportError: | |
3040 | 160 msg = (_('ProgressBar not available, please download it at ' |
161 'http://pypi.python.org/pypi/progressbar\n' | |
162 'Progress bar deactivated\n--\n')) | |
163 print(msg, file=sys.stderr) | |
817 | 164 progressbar=None |
165 | |
166 #consts | |
3028 | 167 PROG_NAME = "jp" |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
168 DESCRIPTION = """This software is a command line tool for XMPP. |
970
2e052998c7eb
jp: using C.APP_URL for application url
Goffi <goffi@goffi.org>
parents:
965
diff
changeset
|
169 Get the latest version at """ + C.APP_URL |
817 | 170 |
3028 | 171 COPYLEFT = """Copyright (C) 2009-2019 Jérôme Poisson, Adrien Cossa |
817 | 172 This program comes with ABSOLUTELY NO WARRANTY; |
173 This is free software, and you are welcome to redistribute it under certain conditions. | |
174 """ | |
0 | 175 |
3040 | 176 PROGRESS_DELAY = 0.1 # the progression will be checked every PROGRESS_DELAY s |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
177 |
0 | 178 |
2704
ab37d1c7c38c
jp (base): new date_decoder to specify dates in arguments
Goffi <goffi@goffi.org>
parents:
2692
diff
changeset
|
179 def date_decoder(arg): |
ab37d1c7c38c
jp (base): new date_decoder to specify dates in arguments
Goffi <goffi@goffi.org>
parents:
2692
diff
changeset
|
180 return date_utils.date_parse_ext(arg, default_tz=date_utils.TZ_LOCAL) |
ab37d1c7c38c
jp (base): new date_decoder to specify dates in arguments
Goffi <goffi@goffi.org>
parents:
2692
diff
changeset
|
181 |
ab37d1c7c38c
jp (base): new date_decoder to specify dates in arguments
Goffi <goffi@goffi.org>
parents:
2692
diff
changeset
|
182 |
817 | 183 class Jp(object): |
814 | 184 """ |
185 This class can be use to establish a connection with the | |
186 bridge. Moreover, it should manage a main loop. | |
187 | |
188 To use it, you mainly have to redefine the method run to perform | |
189 specify what kind of operation you want to perform. | |
190 | |
191 """ | |
817 | 192 def __init__(self): |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
193 """ |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
194 |
3040 | 195 @attribute quit_on_progress_end (bool): set to False if you manage yourself |
196 exiting, or if you want the user to stop by himself | |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
197 @attribute progress_success(callable): method to call when progress just started |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
198 by default display a message |
3040 | 199 @attribute progress_success(callable): method to call when progress is |
200 successfully finished by default display a message | |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
201 @attribute progress_failure(callable): method to call when progress failed |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
202 by default display a message |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
203 """ |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
204 bridge_module = dynamic_import.bridge(bridge_name, 'sat_frontends.bridge') |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
205 if bridge_module is None: |
3028 | 206 log.error("Can't import {} bridge".format(bridge_name)) |
165
8a2053de6f8c
Frontends: management of unlaunched SàT Backend (information message and exit)
Goffi <goffi@goffi.org>
parents:
156
diff
changeset
|
207 sys.exit(1) |
814 | 208 |
3040 | 209 self.bridge = bridge_module.AIOBridge() |
210 self._onQuitCallbacks = [] | |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
211 |
3040 | 212 def _bridgeConnected(self): |
213 self.parser = argparse.ArgumentParser( | |
214 formatter_class=argparse.RawDescriptionHelpFormatter, description=DESCRIPTION) | |
817 | 215 self._make_parents() |
216 self.add_parser_options() | |
3040 | 217 self.subparsers = self.parser.add_subparsers( |
218 title=_('Available commands'), dest='command', required=True) | |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
219 |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
220 # progress attributes |
817 | 221 self._progress_id = None # TODO: manage several progress ids |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
222 self.quit_on_progress_end = True |
817 | 223 |
1950 | 224 # outputs |
225 self._outputs = {} | |
226 for type_ in C.OUTPUT_TYPES: | |
227 self._outputs[type_] = OrderedDict() | |
2189
a25a256688e2
jp (base): output can now specify a default when registering
Goffi <goffi@goffi.org>
parents:
2188
diff
changeset
|
228 self.default_output = {} |
1950 | 229 |
2705
0bb811aaf11d
jp (base): new own_jid host attribute:
Goffi <goffi@goffi.org>
parents:
2704
diff
changeset
|
230 self.own_jid = None # must be filled at runtime if needed |
0bb811aaf11d
jp (base): new own_jid host attribute:
Goffi <goffi@goffi.org>
parents:
2704
diff
changeset
|
231 |
817 | 232 @property |
233 def progress_id(self): | |
234 return self._progress_id | |
235 | |
3040 | 236 async def set_progress_id(self, progress_id): |
237 # because we use async, we need an explicit setter | |
238 self._progress_id = progress_id | |
239 await self.replayCache('progress_ids_cache') | |
817 | 240 |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
241 @property |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
242 def watch_progress(self): |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
243 try: |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
244 self.pbar |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
245 except AttributeError: |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
246 return False |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
247 else: |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
248 return True |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
249 |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
250 @watch_progress.setter |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
251 def watch_progress(self, watch_progress): |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
252 if watch_progress: |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
253 self.pbar = None |
1604
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
254 |
1605
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
255 @property |
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
256 def verbosity(self): |
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
257 try: |
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
258 return self.args.verbose |
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
259 except AttributeError: |
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
260 return 0 |
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
261 |
3040 | 262 async def replayCache(self, cache_attribute): |
1642
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
263 """Replay cached signals |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
264 |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
265 @param cache_attribute(str): name of the attribute containing the cache |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
266 if the attribute doesn't exist, there is no cache and the call is ignored |
3040 | 267 else the cache must be a list of tuples containing the replay callback as |
268 first item, then the arguments to use | |
1642
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
269 """ |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
270 try: |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
271 cache = getattr(self, cache_attribute) |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
272 except AttributeError: |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
273 pass |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
274 else: |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
275 for cache_data in cache: |
3040 | 276 await cache_data[0](*cache_data[1:]) |
1642
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
277 |
2277
637886ac35f6
jp (base): added no_lf in disp() to avoid printing a line feed
Goffi <goffi@goffi.org>
parents:
2237
diff
changeset
|
278 def disp(self, msg, verbosity=0, error=False, no_lf=False): |
1605
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
279 """Print a message to user |
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
280 |
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
281 @param msg(unicode): message to print |
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
282 @param verbosity(int): minimal verbosity to display the message |
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
283 @param error(bool): if True, print to stderr instead of stdout |
2277
637886ac35f6
jp (base): added no_lf in disp() to avoid printing a line feed
Goffi <goffi@goffi.org>
parents:
2237
diff
changeset
|
284 @param no_lf(bool): if True, do not emit line feed at the end of line |
1605
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
285 """ |
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
286 if self.verbosity >= verbosity: |
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
287 if error: |
2277
637886ac35f6
jp (base): added no_lf in disp() to avoid printing a line feed
Goffi <goffi@goffi.org>
parents:
2237
diff
changeset
|
288 if no_lf: |
3028 | 289 print(msg, end=' ', file=sys.stderr) |
2277
637886ac35f6
jp (base): added no_lf in disp() to avoid printing a line feed
Goffi <goffi@goffi.org>
parents:
2237
diff
changeset
|
290 else: |
3028 | 291 print(msg, file=sys.stderr) |
1605
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
292 else: |
2277
637886ac35f6
jp (base): added no_lf in disp() to avoid printing a line feed
Goffi <goffi@goffi.org>
parents:
2237
diff
changeset
|
293 if no_lf: |
3028 | 294 print(msg, end=' ') |
2277
637886ac35f6
jp (base): added no_lf in disp() to avoid printing a line feed
Goffi <goffi@goffi.org>
parents:
2237
diff
changeset
|
295 else: |
3028 | 296 print(msg) |
1605
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
297 |
3040 | 298 async def output(self, type_, name, extra_outputs, data): |
2155 | 299 if name in extra_outputs: |
3040 | 300 method = extra_outputs[name] |
2155 | 301 else: |
3040 | 302 method = self._outputs[type_][name]['callback'] |
303 | |
304 ret = method(data) | |
305 if inspect.isawaitable(ret): | |
306 await ret | |
1950 | 307 |
1604
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
308 def addOnQuitCallback(self, callback, *args, **kwargs): |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
309 """Add a callback which will be called on quit command |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
310 |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
311 @param callback(callback): method to call |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
312 """ |
3040 | 313 self._onQuitCallbacks.append((callback, args, kwargs)) |
1604
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
314 |
1950 | 315 def getOutputChoices(self, output_type): |
316 """Return valid output filters for output_type | |
317 | |
318 @param output_type: True for default, | |
319 else can be any registered type | |
320 """ | |
3028 | 321 return list(self._outputs[output_type].keys()) |
1950 | 322 |
817 | 323 def _make_parents(self): |
324 self.parents = {} | |
325 | |
3040 | 326 # we have a special case here as the start-session option is present only if |
327 # connection is not needed, so we create two similar parents, one with the | |
328 # option, the other one without it | |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
329 for parent_name in ('profile', 'profile_session'): |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
330 parent = self.parents[parent_name] = argparse.ArgumentParser(add_help=False) |
3040 | 331 parent.add_argument( |
332 "-p", "--profile", action="store", type=str, default='@DEFAULT@', | |
333 help=_("Use PROFILE profile key (default: %(default)s)")) | |
334 parent.add_argument( | |
335 "--pwd", action="store", default='', metavar='PASSWORD', | |
336 help=_("Password used to connect profile, if necessary")) | |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
337 |
3040 | 338 profile_parent, profile_session_parent = (self.parents['profile'], |
339 self.parents['profile_session']) | |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
340 |
3040 | 341 connect_short, connect_long, connect_action, connect_help = ( |
342 "-c", "--connect", "store_true", | |
343 _("Connect the profile before doing anything else") | |
344 ) | |
345 profile_parent.add_argument( | |
346 connect_short, connect_long, action=connect_action, help=connect_help) | |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
347 |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
348 profile_session_connect_group = profile_session_parent.add_mutually_exclusive_group() |
3040 | 349 profile_session_connect_group.add_argument( |
350 connect_short, connect_long, action=connect_action, help=connect_help) | |
351 profile_session_connect_group.add_argument( | |
352 "--start-session", action="store_true", | |
353 help=_("Start a profile session without connecting")) | |
817 | 354 |
3040 | 355 progress_parent = self.parents['progress'] = argparse.ArgumentParser( |
356 add_help=False) | |
817 | 357 if progressbar: |
3040 | 358 progress_parent.add_argument( |
359 "-P", "--progress", action="store_true", help=_("Show progress bar")) | |
0 | 360 |
1600 | 361 verbose_parent = self.parents['verbose'] = argparse.ArgumentParser(add_help=False) |
3040 | 362 verbose_parent.add_argument( |
363 '--verbose', '-v', action='count', default=0, | |
364 help=_("Add a verbosity level (can be used multiple times)")) | |
1600 | 365 |
2532 | 366 draft_parent = self.parents['draft'] = argparse.ArgumentParser(add_help=False) |
367 draft_group = draft_parent.add_argument_group(_('draft handling')) | |
3040 | 368 draft_group.add_argument( |
369 "-D", "--current", action="store_true", help=_("load current draft")) | |
370 draft_group.add_argument( | |
371 "-F", "--draft-path", type=Path, help=_("path to a draft file to retrieve")) | |
2532 | 372 |
373 | |
2547
2d69a0afe039
jp: new argument pubsub_default can be used in Commands to replace default value in help string
Goffi <goffi@goffi.org>
parents:
2539
diff
changeset
|
374 def make_pubsub_group(self, flags, defaults): |
2532 | 375 """generate pubsub options according to flags |
376 | |
377 @param flags(iterable[unicode]): see [CommandBase.__init__] | |
2547
2d69a0afe039
jp: new argument pubsub_default can be used in Commands to replace default value in help string
Goffi <goffi@goffi.org>
parents:
2539
diff
changeset
|
378 @param defaults(dict[unicode, unicode]): help text for default value |
2d69a0afe039
jp: new argument pubsub_default can be used in Commands to replace default value in help string
Goffi <goffi@goffi.org>
parents:
2539
diff
changeset
|
379 key can be "service" or "node" |
2d69a0afe039
jp: new argument pubsub_default can be used in Commands to replace default value in help string
Goffi <goffi@goffi.org>
parents:
2539
diff
changeset
|
380 value will be set in " (DEFAULT: {value})", or can be None to remove DEFAULT |
2532 | 381 @return (ArgumentParser): parser to add |
382 """ | |
383 flags = misc.FlagsHandler(flags) | |
384 parent = argparse.ArgumentParser(add_help=False) | |
385 pubsub_group = parent.add_argument_group('pubsub') | |
3028 | 386 pubsub_group.add_argument("-u", "--pubsub-url", |
387 help=_("Pubsub URL (xmpp or http)")) | |
2532 | 388 |
3028 | 389 service_help = _("JID of the PubSub service") |
2532 | 390 if not flags.service: |
3028 | 391 default = defaults.pop('service', _('PEP service')) |
2547
2d69a0afe039
jp: new argument pubsub_default can be used in Commands to replace default value in help string
Goffi <goffi@goffi.org>
parents:
2539
diff
changeset
|
392 if default is not None: |
3028 | 393 service_help += _(" (DEFAULT: {default})".format(default=default)) |
394 pubsub_group.add_argument("-s", "--service", default='', | |
2532 | 395 help=service_help) |
396 | |
3028 | 397 node_help = _("node to request") |
2532 | 398 if not flags.node: |
3028 | 399 default = defaults.pop('node', _('standard node')) |
2547
2d69a0afe039
jp: new argument pubsub_default can be used in Commands to replace default value in help string
Goffi <goffi@goffi.org>
parents:
2539
diff
changeset
|
400 if default is not None: |
3028 | 401 node_help += _(" (DEFAULT: {default})".format(default=default)) |
402 pubsub_group.add_argument("-n", "--node", default='', help=node_help) | |
2532 | 403 |
404 if flags.single_item: | |
3028 | 405 item_help = ("item to retrieve") |
2552
38e1e29c48e9
jp (base): added C.ITEM pubsub flag when --item is required
Goffi <goffi@goffi.org>
parents:
2550
diff
changeset
|
406 if not flags.item: |
3028 | 407 default = defaults.pop('item', _('last item')) |
2552
38e1e29c48e9
jp (base): added C.ITEM pubsub flag when --item is required
Goffi <goffi@goffi.org>
parents:
2550
diff
changeset
|
408 if default is not None: |
3028 | 409 item_help += _(" (DEFAULT: {default})".format(default=default)) |
410 pubsub_group.add_argument("-i", "--item", default='', | |
2910
b2f323237fce
jp, plugin merge-requests: used u'' as default for item id in pubsub arguments + fixed some required arguments:
Goffi <goffi@goffi.org>
parents:
2775
diff
changeset
|
411 help=item_help) |
3040 | 412 pubsub_group.add_argument( |
413 "-L", "--last-item", action='store_true', help=_('retrieve last item')) | |
2532 | 414 elif flags.multi_items: |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
415 # mutiple items, this activate several features: max-items, RSM, MAM |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
416 # and Orbder-by |
3040 | 417 pubsub_group.add_argument( |
418 "-i", "--item", action='append', dest='items', default=[], | |
419 help=_("items to retrieve (DEFAULT: all)")) | |
2539 | 420 if not flags.no_max: |
2775
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
421 max_group = pubsub_group.add_mutually_exclusive_group() |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
422 # XXX: defaut value for --max-items or --max is set in parse_pubsub_args |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
423 max_group.add_argument( |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
424 "-M", "--max-items", dest="max", type=int, |
3028 | 425 help=_("maximum number of items to get ({no_limit} to get all items)" |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
426 .format(no_limit=C.NO_LIMIT))) |
2775
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
427 # FIXME: it could be possible to no duplicate max (between pubsub |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
428 # max-items and RSM max)should not be duplicated, RSM could be |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
429 # used when available and pubsub max otherwise |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
430 max_group.add_argument( |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
431 "-m", "--max", dest="rsm_max", type=int, |
3028 | 432 help=_("maximum number of items to get per page (DEFAULT: 10)")) |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
433 |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
434 # RSM |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
435 |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
436 rsm_page_group = pubsub_group.add_mutually_exclusive_group() |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
437 rsm_page_group.add_argument( |
3028 | 438 "-a", "--after", dest="rsm_after", |
439 help=_("find page after this item"), metavar='ITEM_ID') | |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
440 rsm_page_group.add_argument( |
3028 | 441 "-b", "--before", dest="rsm_before", |
442 help=_("find page before this item"), metavar='ITEM_ID') | |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
443 rsm_page_group.add_argument( |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
444 "--index", dest="rsm_index", type=int, |
3028 | 445 help=_("index of the page to retrieve")) |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
446 |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
447 |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
448 # MAM |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
449 |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
450 pubsub_group.add_argument( |
3028 | 451 "-f", "--filter", dest='mam_filters', nargs=2, |
452 action='append', default=[], help=_("MAM filters to use"), | |
453 metavar=("FILTER_NAME", "VALUE") | |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
454 ) |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
455 |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
456 # Order-By |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
457 |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
458 # TODO: order-by should be a list to handle several levels of ordering |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
459 # but this is not yet done in SàT (and not really useful with |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
460 # current specifications, as only "creation" and "modification" are |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
461 # available) |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
462 pubsub_group.add_argument( |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
463 "-o", "--order-by", choices=[C.ORDER_BY_CREATION, |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
464 C.ORDER_BY_MODIFICATION], |
3028 | 465 help=_("how items should be ordered")) |
2532 | 466 |
2615
b4ecbcc2fd08
tools (misc): do not remove flags while using them anymore, instead added "all_used" and "unused" properties in FlagsHandler
Goffi <goffi@goffi.org>
parents:
2614
diff
changeset
|
467 if not flags.all_used: |
3040 | 468 raise exceptions.InternalError('unknown flags: {flags}'.format( |
469 flags=', '.join(flags.unused))) | |
2547
2d69a0afe039
jp: new argument pubsub_default can be used in Commands to replace default value in help string
Goffi <goffi@goffi.org>
parents:
2539
diff
changeset
|
470 if defaults: |
3040 | 471 raise exceptions.InternalError(f'unused defaults: {defaults}') |
2532 | 472 |
473 return parent | |
2235
4db836386641
jp: added use_pubsub and use_pubsub_node_req arguments to CommandBase
Goffi <goffi@goffi.org>
parents:
2213
diff
changeset
|
474 |
817 | 475 def add_parser_options(self): |
3040 | 476 self.parser.add_argument( |
477 '--version', | |
478 action='version', | |
479 version=("{name} {version} {copyleft}".format( | |
480 name = PROG_NAME, | |
481 version = self.version, | |
482 copyleft = COPYLEFT)) | |
483 ) | |
817 | 484 |
2189
a25a256688e2
jp (base): output can now specify a default when registering
Goffi <goffi@goffi.org>
parents:
2188
diff
changeset
|
485 def register_output(self, type_, name, callback, description="", default=False): |
1950 | 486 if type_ not in C.OUTPUT_TYPES: |
3028 | 487 log.error("Invalid output type {}".format(type_)) |
1950 | 488 return |
489 self._outputs[type_][name] = {'callback': callback, | |
490 'description': description | |
491 } | |
2189
a25a256688e2
jp (base): output can now specify a default when registering
Goffi <goffi@goffi.org>
parents:
2188
diff
changeset
|
492 if default: |
a25a256688e2
jp (base): output can now specify a default when registering
Goffi <goffi@goffi.org>
parents:
2188
diff
changeset
|
493 if type_ in self.default_output: |
3040 | 494 self.disp( |
495 _(f'there is already a default output for {type_}, ignoring new one') | |
496 ) | |
2189
a25a256688e2
jp (base): output can now specify a default when registering
Goffi <goffi@goffi.org>
parents:
2188
diff
changeset
|
497 else: |
a25a256688e2
jp (base): output can now specify a default when registering
Goffi <goffi@goffi.org>
parents:
2188
diff
changeset
|
498 self.default_output[type_] = name |
a25a256688e2
jp (base): output can now specify a default when registering
Goffi <goffi@goffi.org>
parents:
2188
diff
changeset
|
499 |
1950 | 500 |
2187
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
501 def parse_output_options(self): |
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
502 options = self.command.args.output_opts |
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
503 options_dict = {} |
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
504 for option in options: |
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
505 try: |
3028 | 506 key, value = option.split('=', 1) |
2187
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
507 except ValueError: |
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
508 key, value = option, None |
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
509 options_dict[key.strip()] = value.strip() if value is not None else None |
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
510 return options_dict |
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
511 |
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
512 def check_output_options(self, accepted_set, options): |
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
513 if not accepted_set.issuperset(options): |
3040 | 514 self.disp( |
515 _("The following output options are invalid: {invalid_options}").format( | |
3028 | 516 invalid_options = ', '.join(set(options).difference(accepted_set))), |
2187
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
517 error=True) |
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
518 self.quit(C.EXIT_BAD_ARG) |
4ec72927a222
jp (outputs): moved output options parsing and checking to base methods
Goffi <goffi@goffi.org>
parents:
2178
diff
changeset
|
519 |
1950 | 520 def import_plugins(self): |
521 """Automaticaly import commands and outputs in jp | |
522 | |
817 | 523 looks from modules names cmd_*.py in jp path and import them |
524 """ | |
525 path = os.path.dirname(sat_frontends.jp.__file__) | |
1950 | 526 # XXX: outputs must be imported before commands as they are used for arguments |
3040 | 527 for type_, pattern in ((C.PLUGIN_OUTPUT, 'output_*.py'), |
528 (C.PLUGIN_CMD, 'cmd_*.py')): | |
529 modules = ( | |
530 os.path.splitext(module)[0] | |
531 for module in map(os.path.basename, iglob(os.path.join(path, pattern)))) | |
1950 | 532 for module_name in modules: |
2162
c9a67eb5bf72
jp (base): improved module import:
Goffi <goffi@goffi.org>
parents:
2161
diff
changeset
|
533 module_path = "sat_frontends.jp." + module_name |
1950 | 534 try: |
2162
c9a67eb5bf72
jp (base): improved module import:
Goffi <goffi@goffi.org>
parents:
2161
diff
changeset
|
535 module = import_module(module_path) |
1950 | 536 self.import_plugin_module(module, type_) |
2178
b9bfc45cea22
jp (base): added generic errback to CommandBase + show error message on plugin ImportError
Goffi <goffi@goffi.org>
parents:
2168
diff
changeset
|
537 except ImportError as e: |
3040 | 538 self.disp( |
539 _(f"Can't import {module_path} plugin, ignoring it: {e}"), | |
540 error=True) | |
2162
c9a67eb5bf72
jp (base): improved module import:
Goffi <goffi@goffi.org>
parents:
2161
diff
changeset
|
541 except exceptions.CancelError: |
1950 | 542 continue |
2162
c9a67eb5bf72
jp (base): improved module import:
Goffi <goffi@goffi.org>
parents:
2161
diff
changeset
|
543 except exceptions.MissingModule as e: |
3028 | 544 self.disp(_("Missing module for plugin {name}: {missing}".format( |
2162
c9a67eb5bf72
jp (base): improved module import:
Goffi <goffi@goffi.org>
parents:
2161
diff
changeset
|
545 name = module_path, |
2188
052d560d0dce
jp (base): replaced log.warning by stderr prints
Goffi <goffi@goffi.org>
parents:
2187
diff
changeset
|
546 missing = e)), error=True) |
2162
c9a67eb5bf72
jp (base): improved module import:
Goffi <goffi@goffi.org>
parents:
2161
diff
changeset
|
547 |
0 | 548 |
1950 | 549 def import_plugin_module(self, module, type_): |
550 """add commands or outpus from a module to jp | |
817 | 551 |
1950 | 552 @param module: module containing commands or outputs |
553 @param type_(str): one of C_PLUGIN_* | |
817 | 554 """ |
555 try: | |
1950 | 556 class_names = getattr(module, '__{}__'.format(type_)) |
817 | 557 except AttributeError: |
3040 | 558 log.disp(_(f"Invalid plugin module [{type_}] {module}"), error=True) |
817 | 559 raise ImportError |
1950 | 560 else: |
561 for class_name in class_names: | |
562 cls = getattr(module, class_name) | |
563 cls(self) | |
817 | 564 |
2532 | 565 def get_xmpp_uri_from_http(self, http_url): |
566 """parse HTML page at http(s) URL, and looks for xmpp: uri""" | |
567 if http_url.startswith('https'): | |
3028 | 568 scheme = 'https' |
2532 | 569 elif http_url.startswith('http'): |
3028 | 570 scheme = 'http' |
2532 | 571 else: |
3028 | 572 raise exceptions.InternalError('An HTTP scheme is expected in this method') |
3040 | 573 self.disp(f"{scheme.upper()} URL found, trying to find associated xmpp: URI", 1) |
2532 | 574 # HTTP URL, we try to find xmpp: links |
575 try: | |
576 from lxml import etree | |
577 except ImportError: | |
3040 | 578 self.disp( |
579 "lxml module must be installed to use http(s) scheme, please install it " | |
580 "with \"pip install lxml\"", | |
581 error=True) | |
2672 | 582 self.quit(1) |
3028 | 583 import urllib.request, urllib.error, urllib.parse |
2532 | 584 parser = etree.HTMLParser() |
585 try: | |
3028 | 586 root = etree.parse(urllib.request.urlopen(http_url), parser) |
2532 | 587 except etree.XMLSyntaxError as e: |
3028 | 588 self.disp(_("Can't parse HTML page : {msg}").format(msg=e)) |
2532 | 589 links = [] |
590 else: | |
591 links = root.xpath("//link[@rel='alternate' and starts-with(@href, 'xmpp:')]") | |
592 if not links: | |
3040 | 593 self.disp( |
594 _('Could not find alternate "xmpp:" URI, can\'t find associated XMPP ' | |
595 'PubSub node/item'), | |
596 error=True) | |
2672 | 597 self.quit(1) |
2532 | 598 xmpp_uri = links[0].get('href') |
599 return xmpp_uri | |
600 | |
601 def parse_pubsub_args(self): | |
602 if self.args.pubsub_url is not None: | |
603 url = self.args.pubsub_url | |
604 | |
605 if url.startswith('http'): | |
606 # http(s) URL, we try to retrieve xmpp one from there | |
607 url = self.get_xmpp_uri_from_http(url) | |
608 | |
609 try: | |
610 uri_data = uri.parseXMPPUri(url) | |
611 except ValueError: | |
3028 | 612 self.parser.error(_('invalid XMPP URL: {url}').format(url=url)) |
2532 | 613 else: |
3028 | 614 if uri_data['type'] == 'pubsub': |
2532 | 615 # URL is alright, we only set data not already set by other options |
616 if not self.args.service: | |
3028 | 617 self.args.service = uri_data['path'] |
2532 | 618 if not self.args.node: |
3028 | 619 self.args.node = uri_data['node'] |
620 uri_item = uri_data.get('item') | |
2532 | 621 if uri_item: |
2556
340128e0b354
jp (base): fixed URI's item with use_pubsub
Goffi <goffi@goffi.org>
parents:
2552
diff
changeset
|
622 # there is an item in URI |
340128e0b354
jp (base): fixed URI's item with use_pubsub
Goffi <goffi@goffi.org>
parents:
2552
diff
changeset
|
623 # we use it only if item is not already set |
340128e0b354
jp (base): fixed URI's item with use_pubsub
Goffi <goffi@goffi.org>
parents:
2552
diff
changeset
|
624 # and item_last is not used either |
2532 | 625 try: |
2556
340128e0b354
jp (base): fixed URI's item with use_pubsub
Goffi <goffi@goffi.org>
parents:
2552
diff
changeset
|
626 item = self.args.item |
2532 | 627 except AttributeError: |
2609
75d2ac872965
jp (base): do not crash when item is specified (e.g. in URL) but not needed in command, but display a message on stderr.
Goffi <goffi@goffi.org>
parents:
2588
diff
changeset
|
628 try: |
75d2ac872965
jp (base): do not crash when item is specified (e.g. in URL) but not needed in command, but display a message on stderr.
Goffi <goffi@goffi.org>
parents:
2588
diff
changeset
|
629 items = self.args.items |
75d2ac872965
jp (base): do not crash when item is specified (e.g. in URL) but not needed in command, but display a message on stderr.
Goffi <goffi@goffi.org>
parents:
2588
diff
changeset
|
630 except AttributeError: |
3040 | 631 self.disp( |
632 _("item specified in URL but not needed in command, " | |
633 "ignoring it"), | |
634 error=True) | |
2609
75d2ac872965
jp (base): do not crash when item is specified (e.g. in URL) but not needed in command, but display a message on stderr.
Goffi <goffi@goffi.org>
parents:
2588
diff
changeset
|
635 else: |
75d2ac872965
jp (base): do not crash when item is specified (e.g. in URL) but not needed in command, but display a message on stderr.
Goffi <goffi@goffi.org>
parents:
2588
diff
changeset
|
636 if not items: |
75d2ac872965
jp (base): do not crash when item is specified (e.g. in URL) but not needed in command, but display a message on stderr.
Goffi <goffi@goffi.org>
parents:
2588
diff
changeset
|
637 self.args.items = [uri_item] |
2532 | 638 else: |
2556
340128e0b354
jp (base): fixed URI's item with use_pubsub
Goffi <goffi@goffi.org>
parents:
2552
diff
changeset
|
639 if not item: |
340128e0b354
jp (base): fixed URI's item with use_pubsub
Goffi <goffi@goffi.org>
parents:
2552
diff
changeset
|
640 try: |
340128e0b354
jp (base): fixed URI's item with use_pubsub
Goffi <goffi@goffi.org>
parents:
2552
diff
changeset
|
641 item_last = self.args.item_last |
340128e0b354
jp (base): fixed URI's item with use_pubsub
Goffi <goffi@goffi.org>
parents:
2552
diff
changeset
|
642 except AttributeError: |
340128e0b354
jp (base): fixed URI's item with use_pubsub
Goffi <goffi@goffi.org>
parents:
2552
diff
changeset
|
643 item_last = False |
340128e0b354
jp (base): fixed URI's item with use_pubsub
Goffi <goffi@goffi.org>
parents:
2552
diff
changeset
|
644 if not item_last: |
340128e0b354
jp (base): fixed URI's item with use_pubsub
Goffi <goffi@goffi.org>
parents:
2552
diff
changeset
|
645 self.args.item = uri_item |
2532 | 646 else: |
3040 | 647 self.parser.error(_(f'XMPP URL is not a pubsub one: {url}')) |
2532 | 648 flags = self.args._cmd._pubsub_flags |
649 # we check required arguments here instead of using add_arguments' required option | |
650 # because the required argument can be set in URL | |
651 if C.SERVICE in flags and not self.args.service: | |
3028 | 652 self.parser.error(_("argument -s/--service is required")) |
2532 | 653 if C.NODE in flags and not self.args.node: |
3028 | 654 self.parser.error(_("argument -n/--node is required")) |
2552
38e1e29c48e9
jp (base): added C.ITEM pubsub flag when --item is required
Goffi <goffi@goffi.org>
parents:
2550
diff
changeset
|
655 if C.ITEM in flags and not self.args.item: |
3028 | 656 self.parser.error(_("argument -i/--item is required")) |
2532 | 657 |
658 # FIXME: mutually groups can't be nested in a group and don't support title | |
659 # so we check conflict here. This may be fixed in Python 3, to be checked | |
660 try: | |
661 if self.args.item and self.args.item_last: | |
3040 | 662 self.parser.error( |
663 _("--item and --item-last can't be used at the same time")) | |
2532 | 664 except AttributeError: |
665 pass | |
666 | |
2775
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
667 try: |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
668 max_items = self.args.max |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
669 rsm_max = self.args.rsm_max |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
670 except AttributeError: |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
671 pass |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
672 else: |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
673 # we need to set a default value for max, but we need to know if we want |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
674 # to use pubsub's max or RSM's max. The later is used if any RSM or MAM |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
675 # argument is set |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
676 if max_items is None and rsm_max is None: |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
677 to_check = ('mam_filters', 'rsm_max', 'rsm_after', 'rsm_before', |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
678 'rsm_index') |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
679 if any((getattr(self.args, name) for name in to_check)): |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
680 # we use RSM |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
681 self.args.rsm_max = 10 |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
682 else: |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
683 # we use pubsub without RSM |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
684 self.args.max = 10 |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
685 if self.args.max is None: |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
686 self.args.max = C.NO_LIMIT |
2dfd5b1d39df
jp (base): fixed default values for --max-items and --max when using pubsub
Goffi <goffi@goffi.org>
parents:
2771
diff
changeset
|
687 |
3040 | 688 async def main(self, args, namespace): |
1884
0fe69871b71f
jp: moved KeyboardInterrupt catch one level higher, so it is also catched if the loop is not started
Goffi <goffi@goffi.org>
parents:
1872
diff
changeset
|
689 try: |
3040 | 690 await self.bridge.bridgeConnect() |
691 except Exception as e: | |
692 if isinstance(e, exceptions.BridgeExceptionNoService): | |
693 print((_("Can't connect to SàT backend, are you sure it's launched ?"))) | |
694 elif isinstance(e, exceptions.BridgeInitError): | |
695 print((_("Can't init bridge"))) | |
696 else: | |
697 print((_(f"Error while initialising bridge: {e}"))) | |
698 self.quit(C.EXIT_BRIDGE_ERROR, raise_exc=False) | |
699 return | |
700 self.version = await self.bridge.getVersion() | |
701 self._bridgeConnected() | |
702 self.import_plugins() | |
703 try: | |
704 self.args = self.parser.parse_args(args, namespace=None) | |
705 if self.args._cmd._use_pubsub: | |
706 self.parse_pubsub_args() | |
707 await self.args._cmd.run() | |
708 except SystemExit as e: | |
709 self.quit(e.code, raise_exc=False) | |
710 return | |
711 except QuitException: | |
712 return | |
817 | 713 |
3040 | 714 def run(self, args=None, namespace=None): |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
715 self.loop = JPLoop() |
3040 | 716 self.loop.run(self, args, namespace) |
0 | 717 |
3040 | 718 def _read_stdin(self, stdin_fut): |
719 """Callback called by ainput to read stdin""" | |
720 line = sys.stdin.readline() | |
721 if line: | |
722 stdin_fut.set_result(line.rstrip(os.linesep)) | |
723 else: | |
724 stdin_fut.set_exception(EOFError()) | |
587
952322b1d490
Remove trailing whitespaces.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
572
diff
changeset
|
725 |
3040 | 726 async def ainput(self, msg=''): |
727 """Asynchronous version of buildin "input" function""" | |
728 self.disp(msg, no_lf=True) | |
729 sys.stdout.flush() | |
730 loop = asyncio.get_running_loop() | |
731 stdin_fut = loop.create_future() | |
732 loop.add_reader(sys.stdin, self._read_stdin, stdin_fut) | |
733 return await stdin_fut | |
734 | |
735 async def confirmOrQuit(self, message, cancel_message=_("action cancelled by user")): | |
2550
1d754bc14381
jp (base): new confirmOrQuit helper method to ask confirmation to user, and quit if he cancel
Goffi <goffi@goffi.org>
parents:
2547
diff
changeset
|
736 """Request user to confirm action, and quit if he doesn't""" |
1d754bc14381
jp (base): new confirmOrQuit helper method to ask confirmation to user, and quit if he cancel
Goffi <goffi@goffi.org>
parents:
2547
diff
changeset
|
737 |
3040 | 738 res = await self.ainput(f"{message} (y/N)? ") |
2550
1d754bc14381
jp (base): new confirmOrQuit helper method to ask confirmation to user, and quit if he cancel
Goffi <goffi@goffi.org>
parents:
2547
diff
changeset
|
739 if res not in ("y", "Y"): |
1d754bc14381
jp (base): new confirmOrQuit helper method to ask confirmation to user, and quit if he cancel
Goffi <goffi@goffi.org>
parents:
2547
diff
changeset
|
740 self.disp(cancel_message) |
1d754bc14381
jp (base): new confirmOrQuit helper method to ask confirmation to user, and quit if he cancel
Goffi <goffi@goffi.org>
parents:
2547
diff
changeset
|
741 self.quit(C.EXIT_USER_CANCELLED) |
1d754bc14381
jp (base): new confirmOrQuit helper method to ask confirmation to user, and quit if he cancel
Goffi <goffi@goffi.org>
parents:
2547
diff
changeset
|
742 |
3040 | 743 def quitFromSignal(self, exit_code=0): |
744 r"""Same as self.quit, but from a signal handler | |
1604
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
745 |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
746 /!\: return must be used after calling this method ! |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
747 """ |
1918
01d56efd488b
jp: fixed traceback shown on a normal quit when a progression is finished
Goffi <goffi@goffi.org>
parents:
1884
diff
changeset
|
748 # XXX: python-dbus will show a traceback if we exit in a signal handler |
1604
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
749 # so we use this little timeout trick to avoid it |
3040 | 750 self.loop.call_later(0, self.quit, exit_code) |
751 | |
752 def quit(self, exit_code=0, raise_exc=True): | |
753 """Terminate the execution with specified exit_code | |
1604
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
754 |
3040 | 755 This will stop the loop. |
756 @param exit_code(int): code to return when quitting the program | |
757 @param raise_exp(boolean): if True raise a QuitException to stop code execution | |
758 The default value should be used most of time. | |
759 """ | |
1604
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
760 # first the onQuitCallbacks |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
761 try: |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
762 callbacks_list = self._onQuitCallbacks |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
763 except AttributeError: |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
764 pass |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
765 else: |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
766 for callback, args, kwargs in callbacks_list: |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
767 callback(*args, **kwargs) |
9ac78437000d
jp (base): added quitFromSignal method to quit from signal handler with errcode without traceback, and addOnQuitCallback to manage cleaning callbacks
Goffi <goffi@goffi.org>
parents:
1600
diff
changeset
|
768 |
3040 | 769 self.loop.quit(exit_code) |
770 if raise_exc: | |
771 raise QuitException | |
587
952322b1d490
Remove trailing whitespaces.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
572
diff
changeset
|
772 |
3040 | 773 async def check_jids(self, jids): |
814 | 774 """Check jids validity, transform roster name to corresponding jids |
110
cb904fa7de3c
jp: profile management (new option: --profile)
Goffi <goffi@goffi.org>
parents:
70
diff
changeset
|
775 |
817 | 776 @param profile: profile name |
777 @param jids: list of jids | |
778 @return: List of jids | |
779 | |
814 | 780 """ |
401
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
781 names2jid = {} |
493
b7c4bb2c0668
jp: - better expandJid: roster's jids' nodes are used after names to expand jid
Goffi <goffi@goffi.org>
parents:
480
diff
changeset
|
782 nodes2jid = {} |
393 | 783 |
3040 | 784 for contact in await self.bridge.getContacts(self.profile): |
1395
1ae9aa94c351
jp: fixed bad try/except hidding errors + fixed bad management of jids without node
Goffi <goffi@goffi.org>
parents:
1290
diff
changeset
|
785 jid_s, attr, groups = contact |
1ae9aa94c351
jp: fixed bad try/except hidding errors + fixed bad management of jids without node
Goffi <goffi@goffi.org>
parents:
1290
diff
changeset
|
786 _jid = JID(jid_s) |
1ae9aa94c351
jp: fixed bad try/except hidding errors + fixed bad management of jids without node
Goffi <goffi@goffi.org>
parents:
1290
diff
changeset
|
787 try: |
1ae9aa94c351
jp: fixed bad try/except hidding errors + fixed bad management of jids without node
Goffi <goffi@goffi.org>
parents:
1290
diff
changeset
|
788 names2jid[attr["name"].lower()] = jid_s |
1ae9aa94c351
jp: fixed bad try/except hidding errors + fixed bad management of jids without node
Goffi <goffi@goffi.org>
parents:
1290
diff
changeset
|
789 except KeyError: |
1ae9aa94c351
jp: fixed bad try/except hidding errors + fixed bad management of jids without node
Goffi <goffi@goffi.org>
parents:
1290
diff
changeset
|
790 pass |
1ae9aa94c351
jp: fixed bad try/except hidding errors + fixed bad management of jids without node
Goffi <goffi@goffi.org>
parents:
1290
diff
changeset
|
791 |
1ae9aa94c351
jp: fixed bad try/except hidding errors + fixed bad management of jids without node
Goffi <goffi@goffi.org>
parents:
1290
diff
changeset
|
792 if _jid.node: |
1ae9aa94c351
jp: fixed bad try/except hidding errors + fixed bad management of jids without node
Goffi <goffi@goffi.org>
parents:
1290
diff
changeset
|
793 nodes2jid[_jid.node.lower()] = jid_s |
401
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
794 |
817 | 795 def expand_jid(jid): |
401
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
796 _jid = jid.lower() |
493
b7c4bb2c0668
jp: - better expandJid: roster's jids' nodes are used after names to expand jid
Goffi <goffi@goffi.org>
parents:
480
diff
changeset
|
797 if _jid in names2jid: |
b7c4bb2c0668
jp: - better expandJid: roster's jids' nodes are used after names to expand jid
Goffi <goffi@goffi.org>
parents:
480
diff
changeset
|
798 expanded = names2jid[_jid] |
b7c4bb2c0668
jp: - better expandJid: roster's jids' nodes are used after names to expand jid
Goffi <goffi@goffi.org>
parents:
480
diff
changeset
|
799 elif _jid in nodes2jid: |
b7c4bb2c0668
jp: - better expandJid: roster's jids' nodes are used after names to expand jid
Goffi <goffi@goffi.org>
parents:
480
diff
changeset
|
800 expanded = nodes2jid[_jid] |
b7c4bb2c0668
jp: - better expandJid: roster's jids' nodes are used after names to expand jid
Goffi <goffi@goffi.org>
parents:
480
diff
changeset
|
801 else: |
b7c4bb2c0668
jp: - better expandJid: roster's jids' nodes are used after names to expand jid
Goffi <goffi@goffi.org>
parents:
480
diff
changeset
|
802 expanded = jid |
2588 | 803 return expanded |
401
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
804 |
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
805 def check(jid): |
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
806 if not jid.is_valid: |
1605
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
807 log.error (_("%s is not a valid JID !"), jid) |
817 | 808 self.quit(1) |
401
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
809 |
814 | 810 dest_jids=[] |
401
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
811 try: |
814 | 812 for i in range(len(jids)): |
817 | 813 dest_jids.append(expand_jid(jids[i])) |
814 | 814 check(dest_jids[i]) |
401
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
815 except AttributeError: |
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
816 pass |
0 | 817 |
814 | 818 return dest_jids |
0 | 819 |
3040 | 820 async def connect_profile(self): |
821 """Check if the profile is connected and do it if requested | |
1401
265ff2bd8d67
jp: fixed crash on commands using profile without "connect" option
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
822 |
817 | 823 @exit: - 1 when profile is not connected and --connect is not set |
824 - 1 when the profile doesn't exists | |
825 - 1 when there is a connection error | |
826 """ | |
827 # FIXME: need better exit codes | |
828 | |
3040 | 829 self.profile = await self.bridge.profileNameGet(self.args.profile) |
0 | 830 |
817 | 831 if not self.profile: |
3040 | 832 log.error(_(f"The profile [{self.args.profile}] doesn't exist")) |
833 self.quit(C.EXIT_ERROR) | |
817 | 834 |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
835 try: |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
836 start_session = self.args.start_session |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
837 except AttributeError: |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
838 pass |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
839 else: |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
840 if start_session: |
3040 | 841 try: |
842 await self.bridge.profileStartSession(self.args.pwd, self.profile) | |
843 except Exception as e: | |
844 self.disp(_(f"Can't start {self.profile}'s session: {e}"), err=True) | |
845 self.quit(1) | |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
846 return |
3040 | 847 elif not await self.bridge.profileIsSessionStarted(self.profile): |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
848 if not self.args.connect: |
3040 | 849 self.disp(_( |
850 f"Session for [{self.profile}] is not started, please start it " | |
851 f"before using jp, or use either --start-session or --connect " | |
852 f"option"), error=True) | |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
853 self.quit(1) |
2692
7d4679ee7ded
jp (base): fixed connection when start_session arg exists but is False
Goffi <goffi@goffi.org>
parents:
2672
diff
changeset
|
854 elif not getattr(self.args, "connect", False): |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
855 return |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
856 |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
857 |
1401
265ff2bd8d67
jp: fixed crash on commands using profile without "connect" option
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
858 if not hasattr(self.args, 'connect'): |
3040 | 859 # a profile can be present without connect option (e.g. on profile |
860 # creation/deletion) | |
1401
265ff2bd8d67
jp: fixed crash on commands using profile without "connect" option
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
861 return |
1588
823a385235ef
jp: fixed bad --connect option check
Goffi <goffi@goffi.org>
parents:
1544
diff
changeset
|
862 elif self.args.connect is True: # if connection is asked, we connect the profile |
3040 | 863 try: |
864 await self.bridge.connect(self.profile, self.args.pwd, {}) | |
865 except Exception as e: | |
866 self.disp(_(f"Can't connect profile: {e}"), error=True) | |
867 self.quit(1) | |
814 | 868 return |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
869 else: |
3040 | 870 if not await self.bridge.isConnected(self.profile): |
871 log.error( | |
872 _(f"Profile [{self.profile}] is not connected, please connect it " | |
873 f"before using jp, or use --connect option")) | |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
874 self.quit(1) |
0 | 875 |
3040 | 876 async def get_full_jid(self, param_jid): |
1290
faa1129559b8
core, frontends: refactoring to base Libervia on QuickFrontend (big mixed commit):
Goffi <goffi@goffi.org>
parents:
1139
diff
changeset
|
877 """Return the full jid if possible (add main resource when find a bare jid)""" |
401
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
878 _jid = JID(param_jid) |
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
879 if not _jid.resource: |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
880 #if the resource is not given, we try to add the main resource |
3040 | 881 main_resource = await self.bridge.getMainResource(param_jid, self.profile) |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
882 if main_resource: |
3040 | 883 return f"{_jid.bare}/{main_resource}" |
401
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
884 return param_jid |
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
885 |
814 | 886 |
817 | 887 class CommandBase(object): |
814 | 888 |
2155 | 889 def __init__(self, host, name, use_profile=True, use_output=False, extra_outputs=None, |
1950 | 890 need_connect=None, help=None, **kwargs): |
2098
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
891 """Initialise CommandBase |
e0066920a661
primitivus, jp: dynamic bridge + fixed D-Bus bridge:
Goffi <goffi@goffi.org>
parents:
2086
diff
changeset
|
892 |
817 | 893 @param host: Jp instance |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
894 @param name(unicode): name of the new command |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
895 @param use_profile(bool): if True, add profile selection/connection commands |
2114
dc5d214f0a3b
jp (info/session): added a command to get data on current session
Goffi <goffi@goffi.org>
parents:
2098
diff
changeset
|
896 @param use_output(bool, unicode): if not False, add --output option |
2155 | 897 @param extra_outputs(dict): list of command specific outputs: |
898 key is output name ("default" to use as main output) | |
3040 | 899 value is a callable which will format the output (data will be used as only |
900 argument) | |
2155 | 901 if a key already exists with normal outputs, the extra one will be used |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
902 @param need_connect(bool, None): True if profile connection is needed |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
903 False else (profile session must still be started) |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
904 None to set auto value (i.e. True if use_profile is set) |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
905 Can't be set if use_profile is False |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
906 @param help(unicode): help message to display |
817 | 907 @param **kwargs: args passed to ArgumentParser |
1950 | 908 use_* are handled directly, they can be: |
909 - use_progress(bool): if True, add progress bar activation option | |
910 progress* signals will be handled | |
911 - use_verbose(bool): if True, add verbosity option | |
2532 | 912 - use_pubsub(bool): if True, add pubsub options |
913 mandatory arguments are controlled by pubsub_req | |
914 - use_draft(bool): if True, add draft handling options | |
915 ** other arguments ** | |
3040 | 916 - pubsub_flags(iterable[unicode]): tuple of flags to set pubsub options, |
917 can be: | |
2532 | 918 C.SERVICE: service is required |
919 C.NODE: node is required | |
2614
a5b96950b81a
jp (event): fixed crash on missing item in get and inviteeGet by making it mandatory.
Goffi <goffi@goffi.org>
parents:
2609
diff
changeset
|
920 C.ITEM: item is required |
2532 | 921 C.SINGLE_ITEM: only one item is allowed |
814 | 922 """ |
817 | 923 try: # If we have subcommands, host is a CommandBase and we need to use host.host |
924 self.host = host.host | |
925 except AttributeError: | |
926 self.host = host | |
927 | |
1950 | 928 # --profile option |
817 | 929 parents = kwargs.setdefault('parents', set()) |
930 if use_profile: | |
3040 | 931 # self.host.parents['profile'] is an ArgumentParser with profile connection |
932 # arguments | |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
933 if need_connect is None: |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
934 need_connect = True |
3040 | 935 parents.add( |
936 self.host.parents['profile' if need_connect else 'profile_session']) | |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
937 else: |
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
938 assert need_connect is None |
1860
afc7f6328394
jp (base): use need_connect attribue to detect if connection is needed instead of self.args.profile, as profile argument can be used by any command even if use_profile is False
Goffi <goffi@goffi.org>
parents:
1840
diff
changeset
|
939 self.need_connect = need_connect |
afc7f6328394
jp (base): use need_connect attribue to detect if connection is needed instead of self.args.profile, as profile argument can be used by any command even if use_profile is False
Goffi <goffi@goffi.org>
parents:
1840
diff
changeset
|
940 # from this point, self.need_connect is None if connection is not needed at all |
afc7f6328394
jp (base): use need_connect attribue to detect if connection is needed instead of self.args.profile, as profile argument can be used by any command even if use_profile is False
Goffi <goffi@goffi.org>
parents:
1840
diff
changeset
|
941 # False if session starting is needed, and True if full connection is needed |
1594
313f2bb7841b
jp: profile session can now be started without connection:
Goffi <goffi@goffi.org>
parents:
1588
diff
changeset
|
942 |
1950 | 943 # --output option |
944 if use_output: | |
2155 | 945 if extra_outputs is None: |
946 extra_outputs = {} | |
947 self.extra_outputs = extra_outputs | |
1950 | 948 if use_output == True: |
949 use_output = C.OUTPUT_TEXT | |
950 assert use_output in C.OUTPUT_TYPES | |
951 self._output_type = use_output | |
952 output_parent = argparse.ArgumentParser(add_help=False) | |
2155 | 953 choices = set(self.host.getOutputChoices(use_output)) |
954 choices.update(extra_outputs) | |
1950 | 955 if not choices: |
3040 | 956 raise exceptions.InternalError( |
957 "No choice found for {} output type".format(use_output)) | |
2189
a25a256688e2
jp (base): output can now specify a default when registering
Goffi <goffi@goffi.org>
parents:
2188
diff
changeset
|
958 try: |
a25a256688e2
jp (base): output can now specify a default when registering
Goffi <goffi@goffi.org>
parents:
2188
diff
changeset
|
959 default = self.host.default_output[use_output] |
a25a256688e2
jp (base): output can now specify a default when registering
Goffi <goffi@goffi.org>
parents:
2188
diff
changeset
|
960 except KeyError: |
3028 | 961 if 'default' in choices: |
962 default = 'default' | |
963 elif 'simple' in choices: | |
964 default = 'simple' | |
2189
a25a256688e2
jp (base): output can now specify a default when registering
Goffi <goffi@goffi.org>
parents:
2188
diff
changeset
|
965 else: |
a25a256688e2
jp (base): output can now specify a default when registering
Goffi <goffi@goffi.org>
parents:
2188
diff
changeset
|
966 default = list(choices)[0] |
3040 | 967 output_parent.add_argument( |
968 '--output', '-O', choices=sorted(choices), default=default, | |
969 help=_("select output format (default: {})".format(default))) | |
970 output_parent.add_argument( | |
971 '--output-option', '--oo', action="append", dest='output_opts', | |
972 default=[], help=_("output specific option")) | |
1950 | 973 parents.add(output_parent) |
2155 | 974 else: |
975 assert extra_outputs is None | |
817 | 976 |
2532 | 977 self._use_pubsub = kwargs.pop('use_pubsub', False) |
978 if self._use_pubsub: | |
2538
0a22dc80d671
jp (base): fixed use_pubsub when pubsub_flags is not needed
Goffi <goffi@goffi.org>
parents:
2532
diff
changeset
|
979 flags = kwargs.pop('pubsub_flags', []) |
2547
2d69a0afe039
jp: new argument pubsub_default can be used in Commands to replace default value in help string
Goffi <goffi@goffi.org>
parents:
2539
diff
changeset
|
980 defaults = kwargs.pop('pubsub_defaults', {}) |
2d69a0afe039
jp: new argument pubsub_default can be used in Commands to replace default value in help string
Goffi <goffi@goffi.org>
parents:
2539
diff
changeset
|
981 parents.add(self.host.make_pubsub_group(flags, defaults)) |
2532 | 982 self._pubsub_flags = flags |
2235
4db836386641
jp: added use_pubsub and use_pubsub_node_req arguments to CommandBase
Goffi <goffi@goffi.org>
parents:
2213
diff
changeset
|
983 |
1950 | 984 # other common options |
3028 | 985 use_opts = {k:v for k,v in kwargs.items() if k.startswith('use_')} |
986 for param, do_use in use_opts.items(): | |
1950 | 987 opt=param[4:] # if param is use_verbose, opt is verbose |
988 if opt not in self.host.parents: | |
3028 | 989 raise exceptions.InternalError("Unknown parent option {}".format(opt)) |
1950 | 990 del kwargs[param] |
991 if do_use: | |
992 parents.add(self.host.parents[opt]) | |
1600 | 993 |
817 | 994 self.parser = host.subparsers.add_parser(name, help=help, **kwargs) |
995 if hasattr(self, "subcommands"): | |
3040 | 996 self.subparsers = self.parser.add_subparsers(dest='subcommand', required=True) |
817 | 997 else: |
2532 | 998 self.parser.set_defaults(_cmd=self) |
817 | 999 self.add_parser_options() |
1000 | |
1001 @property | |
1002 def args(self): | |
1003 return self.host.args | |
1004 | |
1005 @property | |
1006 def profile(self): | |
1007 return self.host.profile | |
1008 | |
1009 @property | |
2490
b4bf282d6354
jp (base): added verbosity property to CommandBase
Goffi <goffi@goffi.org>
parents:
2486
diff
changeset
|
1010 def verbosity(self): |
b4bf282d6354
jp (base): added verbosity property to CommandBase
Goffi <goffi@goffi.org>
parents:
2486
diff
changeset
|
1011 return self.host.verbosity |
b4bf282d6354
jp (base): added verbosity property to CommandBase
Goffi <goffi@goffi.org>
parents:
2486
diff
changeset
|
1012 |
b4bf282d6354
jp (base): added verbosity property to CommandBase
Goffi <goffi@goffi.org>
parents:
2486
diff
changeset
|
1013 @property |
817 | 1014 def progress_id(self): |
1015 return self.host.progress_id | |
814 | 1016 |
3040 | 1017 async def set_progress_id(self, progress_id): |
1018 return await self.host.set_progress_id(progress_id) | |
817 | 1019 |
3040 | 1020 async def progressStartedHandler(self, uid, metadata, profile): |
1627
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1021 if profile != self.profile: |
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1022 return |
1642
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
1023 if self.progress_id is None: |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
1024 # the progress started message can be received before the id |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
1025 # so we keep progressStarted signals in cache to replay they |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
1026 # when the progress_id is received |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
1027 cache_data = (self.progressStartedHandler, uid, metadata, profile) |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
1028 try: |
3040 | 1029 cache = self.host.progress_ids_cache |
1642
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
1030 except AttributeError: |
3040 | 1031 cache = self.host.progress_ids_cache = [] |
1032 cache.append(cache_data) | |
1642
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
1033 else: |
7ec7ce9cdc4c
jp (base): progressStarted signals are cached until progress_id is known, this avoid missing the progression if we have the signal before the id.
Goffi <goffi@goffi.org>
parents:
1641
diff
changeset
|
1034 if self.host.watch_progress and uid == self.progress_id: |
3040 | 1035 await self.onProgressStarted(metadata) |
1036 while True: | |
1037 await asyncio.sleep(PROGRESS_DELAY) | |
1038 cont = await self.progressUpdate() | |
1039 if not cont: | |
1040 break | |
1627
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1041 |
3040 | 1042 async def progressFinishedHandler(self, uid, metadata, profile): |
1627
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1043 if profile != self.profile: |
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1044 return |
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1045 if uid == self.progress_id: |
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1046 try: |
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1047 self.host.pbar.finish() |
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1048 except AttributeError: |
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1049 pass |
3040 | 1050 await self.onProgressFinished(metadata) |
1627
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1051 if self.host.quit_on_progress_end: |
1918
01d56efd488b
jp: fixed traceback shown on a normal quit when a progression is finished
Goffi <goffi@goffi.org>
parents:
1884
diff
changeset
|
1052 self.host.quitFromSignal() |
1627
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1053 |
3040 | 1054 async def progressErrorHandler(self, uid, message, profile): |
1627
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1055 if profile != self.profile: |
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1056 return |
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1057 if uid == self.progress_id: |
1641
44a14f83e64b
jp (base): fixed verbose option + there is a new line on ProgressErrorHandler only if the progress bar is actually displayed
Goffi <goffi@goffi.org>
parents:
1627
diff
changeset
|
1058 if self.args.progress: |
44a14f83e64b
jp (base): fixed verbose option + there is a new line on ProgressErrorHandler only if the progress bar is actually displayed
Goffi <goffi@goffi.org>
parents:
1627
diff
changeset
|
1059 self.disp('') # progress is not finished, so we skip a line |
1627
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1060 if self.host.quit_on_progress_end: |
3040 | 1061 await self.onProgressError(message) |
1062 self.host.quitFromSignal(C.EXIT_ERROR) | |
1627
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1063 |
3040 | 1064 async def progressUpdate(self): |
1065 """This method is continualy called to update the progress bar | |
1066 | |
1067 @return (bool): False to stop being called | |
1068 """ | |
1069 data = await self.host.bridge.progressGet(self.progress_id, self.profile) | |
1832
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1070 if data: |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1071 try: |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1072 size = data['size'] |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1073 except KeyError: |
3040 | 1074 self.disp(_("file size is not known, we can't show a progress bar"), 1, |
1075 error=True) | |
1832
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1076 return False |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1077 if self.host.pbar is None: |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1078 #first answer, we must construct the bar |
3040 | 1079 |
1080 # if the instance has a pbar_template attribute, it is used has model, | |
1081 # else default one is used | |
1082 # template is a list of part, where part can be either a str to show directly | |
1083 # or a list where first argument is a name of a progressbar widget, and others | |
1084 # are used as widget arguments | |
1085 try: | |
1086 template = self.pbar_template | |
1087 except AttributeError: | |
1088 template = [ | |
1089 _("Progress: "), ["Percentage"], " ", ["Bar"], " ", | |
1090 ["FileTransferSpeed"], " ", ["ETA"] | |
1091 ] | |
1092 | |
1093 widgets = [] | |
1094 for part in template: | |
1095 if isinstance(part, str): | |
1096 widgets.append(part) | |
1097 else: | |
1098 widget = getattr(progressbar, part.pop(0)) | |
1099 widgets.append(widget(*part)) | |
1100 | |
1101 self.host.pbar = progressbar.ProgressBar(max_value=int(size), widgets=widgets) | |
1832
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1102 self.host.pbar.start() |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1103 |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1104 self.host.pbar.update(int(data['position'])) |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1105 |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1106 elif self.host.pbar is not None: |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1107 return False |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1108 |
3040 | 1109 await self.onProgressUpdate(data) |
1832
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1110 |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1111 return True |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1112 |
3040 | 1113 async def onProgressStarted(self, metadata): |
1832
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1114 """Called when progress has just started |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1115 |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1116 can be overidden by a command |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1117 @param metadata(dict): metadata as sent by bridge.progressStarted |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1118 """ |
3028 | 1119 self.disp(_("Operation started"), 2) |
1627
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1120 |
3040 | 1121 async def onProgressUpdate(self, metadata): |
1832
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1122 """Method called on each progress updata |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1123 |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1124 can be overidden by a command to handle progress metadata |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1125 @para metadata(dict): metadata as returned by bridge.progressGet |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1126 """ |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1127 pass |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1128 |
3040 | 1129 async def onProgressFinished(self, metadata): |
1832
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1130 """Called when progress has just finished |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1131 |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1132 can be overidden by a command |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1133 @param metadata(dict): metadata as sent by bridge.progressFinished |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1134 """ |
3028 | 1135 self.disp(_("Operation successfully finished"), 2) |
1627
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1136 |
3040 | 1137 async def onProgressError(self, e): |
1832
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1138 """Called when a progress failed |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1139 |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1140 @param error_msg(unicode): error message as sent by bridge.progressError |
39545dc527a1
jp: an onProgressUpdate method is now called on each progress update, allowing to handle metadata
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1141 """ |
3040 | 1142 self.disp(_(f"Error while doing operation: {e}"), error=True) |
1627
5a641e7b858a
jp (base, file): use of new progress API. Progress callbacks are managed through CommandBase.onProgress* method instead of host attributes.
Goffi <goffi@goffi.org>
parents:
1623
diff
changeset
|
1143 |
2277
637886ac35f6
jp (base): added no_lf in disp() to avoid printing a line feed
Goffi <goffi@goffi.org>
parents:
2237
diff
changeset
|
1144 def disp(self, msg, verbosity=0, error=False, no_lf=False): |
637886ac35f6
jp (base): added no_lf in disp() to avoid printing a line feed
Goffi <goffi@goffi.org>
parents:
2237
diff
changeset
|
1145 return self.host.disp(msg, verbosity, error, no_lf) |
1605
0aded9648c5c
jp (base): added a self.disp method which manage verbosity and stderr + verbosity property
Goffi <goffi@goffi.org>
parents:
1604
diff
changeset
|
1146 |
1950 | 1147 def output(self, data): |
2193
33b82250eadd
jp (base): raise InternalError if output is used when use_output is not declared
Goffi <goffi@goffi.org>
parents:
2189
diff
changeset
|
1148 try: |
33b82250eadd
jp (base): raise InternalError if output is used when use_output is not declared
Goffi <goffi@goffi.org>
parents:
2189
diff
changeset
|
1149 output_type = self._output_type |
33b82250eadd
jp (base): raise InternalError if output is used when use_output is not declared
Goffi <goffi@goffi.org>
parents:
2189
diff
changeset
|
1150 except AttributeError: |
3040 | 1151 raise exceptions.InternalError( |
1152 _('trying to use output when use_output has not been set')) | |
2193
33b82250eadd
jp (base): raise InternalError if output is used when use_output is not declared
Goffi <goffi@goffi.org>
parents:
2189
diff
changeset
|
1153 return self.host.output(output_type, self.args.output, self.extra_outputs, data) |
1950 | 1154 |
2761
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1155 def getPubsubExtra(self, extra=None): |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1156 """Helper method to compute extra data from pubsub arguments |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1157 |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1158 @param extra(None, dict): base extra dict, or None to generate a new one |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1159 @return (dict): dict which can be used directly in the bridge for pubsub |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1160 """ |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1161 if extra is None: |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1162 extra = {} |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1163 else: |
3028 | 1164 intersection = {C.KEY_ORDER_BY}.intersection(list(extra.keys())) |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1165 if intersection: |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1166 raise exceptions.ConflictError( |
3028 | 1167 "given extra dict has conflicting keys with pubsub keys " |
1168 "{intersection}".format(intersection=intersection)) | |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1169 |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1170 # RSM |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1171 |
3028 | 1172 for attribute in ('max', 'after', 'before', 'index'): |
1173 key = 'rsm_' + attribute | |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1174 if key in extra: |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1175 raise exceptions.ConflictError( |
3028 | 1176 "This key already exists in extra: u{key}".format(key=key)) |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1177 value = getattr(self.args, key, None) |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1178 if value is not None: |
3028 | 1179 extra[key] = str(value) |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1180 |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1181 # MAM |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1182 |
3028 | 1183 if hasattr(self.args, 'mam_filters'): |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1184 for key, value in self.args.mam_filters: |
3028 | 1185 key = 'filter_' + key |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1186 if key in extra: |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1187 raise exceptions.ConflictError( |
3028 | 1188 "This key already exists in extra: u{key}".format(key=key)) |
2764
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1189 extra[key] = value |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1190 |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1191 # Order-By |
92af49cde255
jp (base): MAM and RSM arguments can now be used for pubsub commands:
Goffi <goffi@goffi.org>
parents:
2761
diff
changeset
|
1192 |
2761
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1193 try: |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1194 order_by = self.args.order_by |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1195 except AttributeError: |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1196 pass |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1197 else: |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1198 if order_by is not None: |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1199 extra[C.KEY_ORDER_BY] = self.args.order_by |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1200 return extra |
4b693ea24d5f
jp (base, pubsub, ticket): handle order-by:
Goffi <goffi@goffi.org>
parents:
2706
diff
changeset
|
1201 |
817 | 1202 def add_parser_options(self): |
1203 try: | |
1204 subcommands = self.subcommands | |
1205 except AttributeError: | |
1206 # We don't have subcommands, the class need to implements add_parser_options | |
1207 raise NotImplementedError | |
1208 | |
1209 # now we add subcommands to ourself | |
1210 for cls in subcommands: | |
1211 cls(self) | |
814 | 1212 |
3040 | 1213 async def run(self): |
1862
6d9c87bdc452
jp (base): added a CommandBase.start method which is called by run or connected, so subclasses can implement it (this is for simplicity sake, as it's not always clear if run or connected must be used)
Goffi <goffi@goffi.org>
parents:
1860
diff
changeset
|
1214 """this method is called when a command is actually run |
1395
1ae9aa94c351
jp: fixed bad try/except hidding errors + fixed bad management of jids without node
Goffi <goffi@goffi.org>
parents:
1290
diff
changeset
|
1215 |
1862
6d9c87bdc452
jp (base): added a CommandBase.start method which is called by run or connected, so subclasses can implement it (this is for simplicity sake, as it's not always clear if run or connected must be used)
Goffi <goffi@goffi.org>
parents:
1860
diff
changeset
|
1216 It set stuff like progression callbacks and profile connection |
6d9c87bdc452
jp (base): added a CommandBase.start method which is called by run or connected, so subclasses can implement it (this is for simplicity sake, as it's not always clear if run or connected must be used)
Goffi <goffi@goffi.org>
parents:
1860
diff
changeset
|
1217 You should not overide this method: you should call self.start instead |
6d9c87bdc452
jp (base): added a CommandBase.start method which is called by run or connected, so subclasses can implement it (this is for simplicity sake, as it's not always clear if run or connected must be used)
Goffi <goffi@goffi.org>
parents:
1860
diff
changeset
|
1218 """ |
2155 | 1219 # we keep a reference to run command, it may be useful e.g. for outputs |
1220 self.host.command = self | |
1863
b2ddd7f5dcdf
jp (base): refactored need_loop so it is set only when the command is run. It can now be set in __init__ methods of commands classes
Goffi <goffi@goffi.org>
parents:
1862
diff
changeset
|
1221 |
817 | 1222 try: |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1223 show_progress = self.args.progress |
817 | 1224 except AttributeError: |
1225 # the command doesn't use progress bar | |
1226 pass | |
1395
1ae9aa94c351
jp: fixed bad try/except hidding errors + fixed bad management of jids without node
Goffi <goffi@goffi.org>
parents:
1290
diff
changeset
|
1227 else: |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1228 if show_progress: |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1229 self.host.watch_progress = True |
3040 | 1230 # we need to register the following signal even if we don't display the |
1231 # progress bar | |
1232 self.host.bridge.register_signal( | |
1233 "progressStarted", self.progressStartedHandler) | |
1234 self.host.bridge.register_signal( | |
1235 "progressFinished", self.progressFinishedHandler) | |
1236 self.host.bridge.register_signal( | |
1237 "progressError", self.progressErrorHandler) | |
817 | 1238 |
1862
6d9c87bdc452
jp (base): added a CommandBase.start method which is called by run or connected, so subclasses can implement it (this is for simplicity sake, as it's not always clear if run or connected must be used)
Goffi <goffi@goffi.org>
parents:
1860
diff
changeset
|
1239 if self.need_connect is not None: |
3040 | 1240 await self.host.connect_profile() |
1241 await self.start() | |
1862
6d9c87bdc452
jp (base): added a CommandBase.start method which is called by run or connected, so subclasses can implement it (this is for simplicity sake, as it's not always clear if run or connected must be used)
Goffi <goffi@goffi.org>
parents:
1860
diff
changeset
|
1242 |
3040 | 1243 async def start(self): |
1244 """This is the starting point of the command, this method must be overriden | |
1862
6d9c87bdc452
jp (base): added a CommandBase.start method which is called by run or connected, so subclasses can implement it (this is for simplicity sake, as it's not always clear if run or connected must be used)
Goffi <goffi@goffi.org>
parents:
1860
diff
changeset
|
1245 |
6d9c87bdc452
jp (base): added a CommandBase.start method which is called by run or connected, so subclasses can implement it (this is for simplicity sake, as it's not always clear if run or connected must be used)
Goffi <goffi@goffi.org>
parents:
1860
diff
changeset
|
1246 at this point, profile are connected if needed |
6d9c87bdc452
jp (base): added a CommandBase.start method which is called by run or connected, so subclasses can implement it (this is for simplicity sake, as it's not always clear if run or connected must be used)
Goffi <goffi@goffi.org>
parents:
1860
diff
changeset
|
1247 """ |
3040 | 1248 raise NotImplementedError |
817 | 1249 |
1250 | |
1251 class CommandAnswering(CommandBase): | |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1252 """Specialised commands which answer to specific actions |
817 | 1253 |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1254 to manage action_types answer, |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1255 """ |
2409
d2ff5ff3de77
jp (ad-hoc): new "list" and "run" commands:
Goffi <goffi@goffi.org>
parents:
2368
diff
changeset
|
1256 action_callbacks = {} # XXX: set managed action types in a dict here: |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1257 # key is the action_type, value is the callable |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1258 # which will manage the answer. profile filtering is |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1259 # already managed when callback is called |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1260 |
2486
031aa3cc67ac
jp (base): fixed assertion error when using CommandAnswering
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
1261 def __init__(self, *args, **kwargs): |
031aa3cc67ac
jp (base): fixed assertion error when using CommandAnswering
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
1262 super(CommandAnswering, self).__init__(*args, **kwargs) |
031aa3cc67ac
jp (base): fixed assertion error when using CommandAnswering
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
1263 |
3040 | 1264 async def onActionNew(self, action_data, action_id, security_limit, profile): |
538
2c4016921403
core, frontends, bridgen plugins: fixed methods which were unproperly managing multi-profiles
Goffi <goffi@goffi.org>
parents:
493
diff
changeset
|
1265 if profile != self.profile: |
2c4016921403
core, frontends, bridgen plugins: fixed methods which were unproperly managing multi-profiles
Goffi <goffi@goffi.org>
parents:
493
diff
changeset
|
1266 return |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1267 try: |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1268 action_type = action_data['meta_type'] |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1269 except KeyError: |
1840
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1270 try: |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1271 xml_ui = action_data["xmlui"] |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1272 except KeyError: |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1273 pass |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1274 else: |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1275 self.onXMLUI(xml_ui) |
1606
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1276 else: |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1277 try: |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1278 callback = self.action_callbacks[action_type] |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1279 except KeyError: |
de785fcf9a7b
jp (base, file): file command and progress fixes and adaptation to new API:
Goffi <goffi@goffi.org>
parents:
1605
diff
changeset
|
1280 pass |
0 | 1281 else: |
3040 | 1282 await callback(action_data, action_id, security_limit, profile) |
587
952322b1d490
Remove trailing whitespaces.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
572
diff
changeset
|
1283 |
1840
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1284 def onXMLUI(self, xml_ui): |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1285 """Display a dialog received from the backend. |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1286 |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1287 @param xml_ui (unicode): dialog XML representation |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1288 """ |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1289 # FIXME: we temporarily use ElementTree, but a real XMLUI managing module |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1290 # should be available in the future |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1291 # TODO: XMLUI module |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1292 ui = ET.fromstring(xml_ui.encode('utf-8')) |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1293 dialog = ui.find("dialog") |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1294 if dialog is not None: |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1295 self.disp(dialog.findtext("message"), error=dialog.get("level") == "error") |
9eabf7fadfdd
frontends (jp): onActionNew displays xmlui message if no meta_type is defined and xmlui is defined
souliane <souliane@mailoo.org>
parents:
1832
diff
changeset
|
1296 |
3040 | 1297 async def start_answering(self): |
1298 """Auto reply to confirmation requests""" | |
2368
3865a772c360
jp (base): fixed CommandAnswering and progress bar
Goffi <goffi@goffi.org>
parents:
2313
diff
changeset
|
1299 self.host.bridge.register_signal("actionNew", self.onActionNew) |
3040 | 1300 actions = await self.host.bridge.actionsGet(self.profile) |
1623 | 1301 for action_data, action_id, security_limit in actions: |
3040 | 1302 await self.onActionNew(action_data, action_id, security_limit, self.profile) |