Mercurial > libervia-backend
comparison sat_frontends/jp/cmd_shell.py @ 3028:ab2696e34d29
Python 3 port:
/!\ this is a huge commit
/!\ starting from this commit, SàT is needs Python 3.6+
/!\ SàT maybe be instable or some feature may not work anymore, this will improve with time
This patch port backend, bridge and frontends to Python 3.
Roughly this has been done this way:
- 2to3 tools has been applied (with python 3.7)
- all references to python2 have been replaced with python3 (notably shebangs)
- fixed files not handled by 2to3 (notably the shell script)
- several manual fixes
- fixed issues reported by Python 3 that where not handled in Python 2
- replaced "async" with "async_" when needed (it's a reserved word from Python 3.7)
- replaced zope's "implements" with @implementer decorator
- temporary hack to handle data pickled in database, as str or bytes may be returned,
to be checked later
- fixed hash comparison for password
- removed some code which is not needed anymore with Python 3
- deactivated some code which needs to be checked (notably certificate validation)
- tested with jp, fixed reported issues until some basic commands worked
- ported Primitivus (after porting dependencies like urwid satext)
- more manual fixes
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 13 Aug 2019 19:08:41 +0200 |
parents | 003b8b4b56a7 |
children | fee60f17ebac |
comparison
equal
deleted
inserted
replaced
3027:ff5bcb12ae60 | 3028:ab2696e34d29 |
---|---|
16 | 16 |
17 # You should have received a copy of the GNU Affero General Public License | 17 # You should have received a copy of the GNU Affero General Public License |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 | 20 |
21 import base | 21 from . import base |
22 import cmd | 22 import cmd |
23 import sys | 23 import sys |
24 from sat.core.i18n import _ | 24 from sat.core.i18n import _ |
25 from sat.core import exceptions | 25 from sat.core import exceptions |
26 from sat_frontends.jp.constants import Const as C | 26 from sat_frontends.jp.constants import Const as C |
29 import shlex | 29 import shlex |
30 import subprocess | 30 import subprocess |
31 | 31 |
32 __commands__ = ["Shell"] | 32 __commands__ = ["Shell"] |
33 INTRO = _( | 33 INTRO = _( |
34 u"""Welcome to {app_name} shell, the Salut à Toi shell ! | 34 """Welcome to {app_name} shell, the Salut à Toi shell ! |
35 | 35 |
36 This enrironment helps you using several {app_name} commands with similar parameters. | 36 This enrironment helps you using several {app_name} commands with similar parameters. |
37 | 37 |
38 To quit, just enter "quit" or press C-d. | 38 To quit, just enter "quit" or press C-d. |
39 Enter "help" or "?" to know what to do | 39 Enter "help" or "?" to know what to do |
42 | 42 |
43 | 43 |
44 class Shell(base.CommandBase, cmd.Cmd): | 44 class Shell(base.CommandBase, cmd.Cmd): |
45 def __init__(self, host): | 45 def __init__(self, host): |
46 base.CommandBase.__init__( | 46 base.CommandBase.__init__( |
47 self, host, "shell", help=_(u"launch jp in shell (REPL) mode") | 47 self, host, "shell", help=_("launch jp in shell (REPL) mode") |
48 ) | 48 ) |
49 cmd.Cmd.__init__(self) | 49 cmd.Cmd.__init__(self) |
50 | 50 |
51 def parse_args(self, args): | 51 def parse_args(self, args): |
52 """parse line arguments""" | 52 """parse line arguments""" |
53 return shlex.split(args, posix=True) | 53 return shlex.split(args, posix=True) |
54 | 54 |
55 def update_path(self): | 55 def update_path(self): |
56 self._cur_parser = self.host.parser | 56 self._cur_parser = self.host.parser |
57 self.help = u"" | 57 self.help = "" |
58 for idx, path_elt in enumerate(self.path): | 58 for idx, path_elt in enumerate(self.path): |
59 try: | 59 try: |
60 self._cur_parser = arg_tools.get_cmd_choices(path_elt, self._cur_parser) | 60 self._cur_parser = arg_tools.get_cmd_choices(path_elt, self._cur_parser) |
61 except exceptions.NotFound: | 61 except exceptions.NotFound: |
62 self.disp(_(u"bad command path"), error=True) | 62 self.disp(_("bad command path"), error=True) |
63 self.path = self.path[:idx] | 63 self.path = self.path[:idx] |
64 break | 64 break |
65 else: | 65 else: |
66 self.help = self._cur_parser | 66 self.help = self._cur_parser |
67 | 67 |
68 self.prompt = A.color(C.A_PROMPT_PATH, u"/".join(self.path)) + A.color( | 68 self.prompt = A.color(C.A_PROMPT_PATH, "/".join(self.path)) + A.color( |
69 C.A_PROMPT_SUF, u"> " | 69 C.A_PROMPT_SUF, "> " |
70 ) | 70 ) |
71 try: | 71 try: |
72 self.actions = arg_tools.get_cmd_choices(parser=self._cur_parser).keys() | 72 self.actions = list(arg_tools.get_cmd_choices(parser=self._cur_parser).keys()) |
73 except exceptions.NotFound: | 73 except exceptions.NotFound: |
74 self.actions = [] | 74 self.actions = [] |
75 | 75 |
76 def add_parser_options(self): | 76 def add_parser_options(self): |
77 pass | 77 pass |
98 # GLib quit the whole app without possibility to stop it | 98 # GLib quit the whole app without possibility to stop it |
99 # didn't found a nice way to work around it so far | 99 # didn't found a nice way to work around it so far |
100 # Situation should be better when we'll move away from python-dbus | 100 # Situation should be better when we'll move away from python-dbus |
101 if self.verbose: | 101 if self.verbose: |
102 self.disp( | 102 self.disp( |
103 _(u"COMMAND {external}=> {args}").format( | 103 _("COMMAND {external}=> {args}").format( |
104 external=_(u"(external) ") if external else u"", | 104 external=_("(external) ") if external else "", |
105 args=u" ".join(self.format_args(args)), | 105 args=" ".join(self.format_args(args)), |
106 ) | 106 ) |
107 ) | 107 ) |
108 if not external: | 108 if not external: |
109 args = sys.argv[0:1] + args | 109 args = sys.argv[0:1] + args |
110 ret_code = subprocess.call(args) | 110 ret_code = subprocess.call(args) |
122 | 122 |
123 if ret_code != 0: | 123 if ret_code != 0: |
124 self.disp( | 124 self.disp( |
125 A.color( | 125 A.color( |
126 C.A_FAILURE, | 126 C.A_FAILURE, |
127 u"command failed with an error code of {err_no}".format( | 127 "command failed with an error code of {err_no}".format( |
128 err_no=ret_code | 128 err_no=ret_code |
129 ), | 129 ), |
130 ), | 130 ), |
131 error=True, | 131 error=True, |
132 ) | 132 ) |
143 self.do_do(args) | 143 self.do_do(args) |
144 | 144 |
145 def do_help(self, args): | 145 def do_help(self, args): |
146 """show help message""" | 146 """show help message""" |
147 if not args: | 147 if not args: |
148 self.disp(A.color(C.A_HEADER, _(u"Shell commands:")), no_lf=True) | 148 self.disp(A.color(C.A_HEADER, _("Shell commands:")), no_lf=True) |
149 super(Shell, self).do_help(args) | 149 super(Shell, self).do_help(args) |
150 if not args: | 150 if not args: |
151 self.disp(A.color(C.A_HEADER, _(u"Action commands:"))) | 151 self.disp(A.color(C.A_HEADER, _("Action commands:"))) |
152 help_list = self._cur_parser.format_help().split("\n\n") | 152 help_list = self._cur_parser.format_help().split("\n\n") |
153 print("\n\n".join(help_list[1 if self.path else 2 :])) | 153 print(("\n\n".join(help_list[1 if self.path else 2 :]))) |
154 | 154 |
155 def do_debug(self, args): | 155 def do_debug(self, args): |
156 """launch internal debugger""" | 156 """launch internal debugger""" |
157 try: | 157 try: |
158 import ipdb as pdb | 158 import ipdb as pdb |
164 """show verbose mode, or (de)activate it""" | 164 """show verbose mode, or (de)activate it""" |
165 args = self.parse_args(args) | 165 args = self.parse_args(args) |
166 if args: | 166 if args: |
167 self.verbose = C.bool(args[0]) | 167 self.verbose = C.bool(args[0]) |
168 self.disp( | 168 self.disp( |
169 _(u"verbose mode is {status}").format( | 169 _("verbose mode is {status}").format( |
170 status=_(u"ENABLED") if self.verbose else _(u"DISABLED") | 170 status=_("ENABLED") if self.verbose else _("DISABLED") |
171 ) | 171 ) |
172 ) | 172 ) |
173 | 173 |
174 def do_cmd(self, args): | 174 def do_cmd(self, args): |
175 """change command path""" | 175 """change command path""" |
209 ): | 209 ): |
210 # profile is not specified and we are not using the default profile | 210 # profile is not specified and we are not using the default profile |
211 # so we need to add it in arguments to use current user profile | 211 # so we need to add it in arguments to use current user profile |
212 if self.verbose: | 212 if self.verbose: |
213 self.disp( | 213 self.disp( |
214 _(u"arg profile={profile} (logged profile)").format( | 214 _("arg profile={profile} (logged profile)").format( |
215 profile=self.profile | 215 profile=self.profile |
216 ) | 216 ) |
217 ) | 217 ) |
218 use = self.use.copy() | 218 use = self.use.copy() |
219 use["profile"] = self.profile | 219 use["profile"] = self.profile |
231 def do_use(self, args): | 231 def do_use(self, args): |
232 """fix an argument""" | 232 """fix an argument""" |
233 args = self.parse_args(args) | 233 args = self.parse_args(args) |
234 if not args: | 234 if not args: |
235 if not self.use: | 235 if not self.use: |
236 self.disp(_(u"no argument in USE")) | 236 self.disp(_("no argument in USE")) |
237 else: | 237 else: |
238 self.disp(_(u"arguments in USE:")) | 238 self.disp(_("arguments in USE:")) |
239 for arg, value in self.use.iteritems(): | 239 for arg, value in self.use.items(): |
240 self.disp( | 240 self.disp( |
241 _( | 241 _( |
242 A.color( | 242 A.color( |
243 C.A_SUBHEADER, | 243 C.A_SUBHEADER, |
244 arg, | 244 arg, |
245 A.RESET, | 245 A.RESET, |
246 u" = ", | 246 " = ", |
247 arg_tools.escape(value), | 247 arg_tools.escape(value), |
248 ) | 248 ) |
249 ) | 249 ) |
250 ) | 250 ) |
251 elif len(args) != 2: | 251 elif len(args) != 2: |
252 self.disp(u"bad syntax, please use:\nuse [arg] [value]", error=True) | 252 self.disp("bad syntax, please use:\nuse [arg] [value]", error=True) |
253 else: | 253 else: |
254 self.use[args[0]] = u" ".join(args[1:]) | 254 self.use[args[0]] = " ".join(args[1:]) |
255 if self.verbose: | 255 if self.verbose: |
256 self.disp( | 256 self.disp( |
257 "set {name} = {value}".format( | 257 "set {name} = {value}".format( |
258 name=args[0], value=arg_tools.escape(args[1]) | 258 name=args[0], value=arg_tools.escape(args[1]) |
259 ) | 259 ) |
269 try: | 269 try: |
270 del self.use[arg] | 270 del self.use[arg] |
271 except KeyError: | 271 except KeyError: |
272 self.disp( | 272 self.disp( |
273 A.color( | 273 A.color( |
274 C.A_FAILURE, _(u"argument {name} not found").format(name=arg) | 274 C.A_FAILURE, _("argument {name} not found").format(name=arg) |
275 ), | 275 ), |
276 error=True, | 276 error=True, |
277 ) | 277 ) |
278 else: | 278 else: |
279 if self.verbose: | 279 if self.verbose: |
280 self.disp(_(u"argument {name} removed").format(name=arg)) | 280 self.disp(_("argument {name} removed").format(name=arg)) |
281 | 281 |
282 def do_whoami(self, args): | 282 def do_whoami(self, args): |
283 u"""print profile currently used""" | 283 """print profile currently used""" |
284 self.disp(self.profile) | 284 self.disp(self.profile) |
285 | 285 |
286 def do_quit(self, args): | 286 def do_quit(self, args): |
287 u"""quit the shell""" | 287 """quit the shell""" |
288 self.disp(_(u"good bye!")) | 288 self.disp(_("good bye!")) |
289 self.host.quit() | 289 self.host.quit() |
290 | 290 |
291 def do_exit(self, args): | 291 def do_exit(self, args): |
292 u"""alias for quit""" | 292 """alias for quit""" |
293 self.do_quit(args) | 293 self.do_quit(args) |
294 | 294 |
295 def start(self): | 295 def start(self): |
296 default_profile = self.host.bridge.profileNameGet(C.PROF_KEY_DEFAULT) | 296 default_profile = self.host.bridge.profileNameGet(C.PROF_KEY_DEFAULT) |
297 self._not_default_profile = self.profile != default_profile | 297 self._not_default_profile = self.profile != default_profile |