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