Mercurial > libervia-backend
annotate libervia/cli/loops.py @ 4210:9218d4331bb2
cli (call): `tui` output implementation:
- Moved original UI to a separated class, and use if with the `simple` output
- By default, best output is automatically selected. For now `gui` is selected if possible,
and `simple` is used as fallback.
- The new `tui` output can be used to have the videos directly embedded in the terminal,
either with real videos for compatible terminal emulators, or with Unicode blocks.
- Text contrôls are used for both `simple` and `tui` outputs
- several options can be used with `--oo` (will be documented in next commit).
rel 428
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 16 Feb 2024 18:46:06 +0100 |
parents | 0f8ea0768a3b |
children | 0d7bb4df2343 |
rev | line source |
---|---|
3043 | 1 #!/usr/bin/env python3 |
2 | |
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
3 # Libervia CLI |
3479 | 4 # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org) |
3043 | 5 |
6 # This program is free software: you can redistribute it and/or modify | |
7 # it under the terms of the GNU Affero General Public License as published by | |
8 # the Free Software Foundation, either version 3 of the License, or | |
9 # (at your option) any later version. | |
10 | |
11 # This program is distributed in the hope that it will be useful, | |
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 # GNU Affero General Public License for more details. | |
15 | |
16 # You should have received a copy of the GNU Affero General Public License | |
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | |
19 import sys | |
20 import asyncio | |
21 import logging as log | |
4071
4b842c1fb686
refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents:
4037
diff
changeset
|
22 from libervia.backend.core.i18n import _ |
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
23 from libervia.cli.constants import Const as C |
4141
ba8ddfdd334f
cli (loops): run GLib loop in same thread as asyncio:
Goffi <goffi@goffi.org>
parents:
4075
diff
changeset
|
24 from libervia.frontends.tools import aio |
3043 | 25 |
26 log.basicConfig(level=log.WARNING, | |
27 format='[%(name)s] %(message)s') | |
28 | |
29 USER_INTER_MSG = _("User interruption: good bye") | |
30 | |
31 | |
32 class QuitException(BaseException): | |
33 """Quitting is requested | |
34 | |
35 This is used to stop execution when host.quit() is called | |
36 """ | |
37 | |
38 | |
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
39 def get_libervia_cli_loop(bridge_name): |
3043 | 40 if 'dbus' in bridge_name: |
41 import signal | |
42 | |
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
43 class LiberviaCLILoop: |
3043 | 44 |
4141
ba8ddfdd334f
cli (loops): run GLib loop in same thread as asyncio:
Goffi <goffi@goffi.org>
parents:
4075
diff
changeset
|
45 def __init__(self): |
4206 | 46 self.loop = asyncio.get_event_loop() |
4141
ba8ddfdd334f
cli (loops): run GLib loop in same thread as asyncio:
Goffi <goffi@goffi.org>
parents:
4075
diff
changeset
|
47 |
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
48 def run(self, libervia_cli, args, namespace): |
4141
ba8ddfdd334f
cli (loops): run GLib loop in same thread as asyncio:
Goffi <goffi@goffi.org>
parents:
4075
diff
changeset
|
49 aio.install_glib_asyncio_iteration() |
3043 | 50 signal.signal(signal.SIGINT, self._on_sigint) |
4141
ba8ddfdd334f
cli (loops): run GLib loop in same thread as asyncio:
Goffi <goffi@goffi.org>
parents:
4075
diff
changeset
|
51 loop = self.loop |
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
52 loop.run_until_complete(libervia_cli.main(args=args, namespace=namespace)) |
3043 | 53 loop.run_forever() |
54 | |
55 def quit(self, exit_code): | |
56 loop = asyncio.get_event_loop() | |
57 loop.stop() | |
58 sys.exit(exit_code) | |
59 | |
60 def call_later(self, delay, callback, *args): | |
61 """call a callback repeatedly | |
62 | |
63 @param delay(int): delay between calls in s | |
64 @param callback(callable): method to call | |
65 if the callback return True, the call will continue | |
66 else the calls will stop | |
67 @param *args: args of the callbac | |
68 """ | |
69 loop = asyncio.get_event_loop() | |
70 loop.call_later(delay, callback, *args) | |
71 | |
72 def _on_sigint(self, sig_number, stack_frame): | |
73 """Called on keyboard interruption | |
74 | |
75 Print user interruption message, set exit code and stop reactor | |
76 """ | |
77 print("\r" + USER_INTER_MSG) | |
78 self.quit(C.EXIT_USER_CANCELLED) | |
79 else: | |
80 import signal | |
81 from twisted.internet import asyncioreactor | |
82 asyncioreactor.install() | |
83 from twisted.internet import reactor, defer | |
84 | |
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
85 class LiberviaCLILoop: |
3043 | 86 |
87 def __init__(self): | |
88 # exit code must be set when using quit, so if it's not set | |
89 # something got wrong and we must report it | |
90 self._exit_code = C.EXIT_INTERNAL_ERROR | |
91 | |
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
92 def run(self, libervia_cli, *args): |
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
93 self.libervia_cli = libervia_cli |
3043 | 94 signal.signal(signal.SIGINT, self._on_sigint) |
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
95 defer.ensureDeferred(self._start(libervia_cli, *args)) |
3043 | 96 try: |
97 reactor.run(installSignalHandlers=False) | |
98 except SystemExit as e: | |
99 self._exit_code = e.code | |
100 sys.exit(self._exit_code) | |
101 | |
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
102 async def _start(self, libervia_cli, *args): |
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
103 fut = asyncio.ensure_future(libervia_cli.main(*args)) |
3043 | 104 try: |
105 await defer.Deferred.fromFuture(fut) | |
106 except BaseException: | |
107 import traceback | |
108 traceback.print_exc() | |
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
109 libervia_cli.quit(1) |
3043 | 110 |
111 def quit(self, exit_code): | |
112 self._exit_code = exit_code | |
113 reactor.stop() | |
114 | |
115 def _timeout_cb(self, args, callback, delay): | |
116 try: | |
117 ret = callback(*args) | |
118 # FIXME: temporary hack to avoid traceback when using XMLUI | |
119 # to be removed once create_task is not used anymore in | |
4074
26b7ed2817da
refactoring: rename `sat_frontends` to `libervia.frontends`
Goffi <goffi@goffi.org>
parents:
4071
diff
changeset
|
120 # xmlui_manager (i.e. once libervia.frontends.tools.xmlui fully supports |
3043 | 121 # async syntax) |
122 except QuitException: | |
123 return | |
124 if ret: | |
125 reactor.callLater(delay, self._timeout_cb, args, callback, delay) | |
126 | |
127 def call_later(self, delay, callback, *args): | |
128 reactor.callLater(delay, self._timeout_cb, args, callback, delay) | |
129 | |
130 def _on_sigint(self, sig_number, stack_frame): | |
131 """Called on keyboard interruption | |
132 | |
133 Print user interruption message, set exit code and stop reactor | |
134 """ | |
135 print("\r" + USER_INTER_MSG) | |
136 self._exit_code = C.EXIT_USER_CANCELLED | |
137 reactor.callFromThread(reactor.stop) | |
138 | |
139 | |
140 if bridge_name == "embedded": | |
141 raise NotImplementedError | |
142 # from sat.core import sat_main | |
143 # sat = sat_main.SAT() | |
144 | |
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
145 return LiberviaCLILoop |