def do_version(self, line): """version Print shell49 and MicroPython version information. """ db = self.boards.default release, machine, version = db.remote_eval(upy_version) fmt = "{:>10s} = {}" oprint(fmt.format("board", db.name)) oprint(fmt.format("firmware", version)) oprint(fmt.format("release", release)) oprint(fmt.format("machine", machine)) oprint(fmt.format("shell49", __version__))
def _load(self): qprint("Loading configuration '{}'".format(self._config_file)) try: with open(self._config_file) as f: self._config = literal_eval(f.read()) except FileNotFoundError: oprint("WARNING: configuration '{}' does not exist, creating default".format(self._config_file)) self._create_default() self._modified = True except SyntaxError as e: eprint("Syntax error in {}: {}".format(self._config_file, e)) eprint("If the problem persists, manually check the file for " "invalid Python syntax or delete it and re-enter the configuration information.") sys.exit()
def do_ls(self, line): """ls [-a] [-l] [FILE|DIRECTORY|PATTERN]... PATTERN supports * ? [seq] [!seq] Unix filename matching List directory contents. """ args = self.line_to_args(line) if len(args.filenames) == 0: args.filenames = ['.'] for idx, fn in enumerate(args.filenames): if not is_pattern(fn): filename = resolve_path(self.cur_dir, fn) stat = auto(self.boards, get_stat, filename) mode = stat_mode(stat) if not mode_exists(mode): err = "Cannot access '{}': No such file or directory" eprint(err.format(filename)) continue if not mode_isdir(mode): if args.long: print_long(filename, stat, oprint) else: oprint(filename) continue if len(args.filenames) > 1: if idx > 0: oprint('') oprint("%s:" % filename) pattern = '*' else: # A pattern was specified filename, pattern = validate_pattern(self.boards, self.cur_dir, fn) if filename is None: # An error was printed continue files = [] ldir_stat = auto(self.boards, listdir_stat, filename) if ldir_stat is None: err = "Cannot access '{}': No such file or directory" eprint(err.format(filename)) else: for filename, stat in sorted(ldir_stat, key=lambda entry: entry[0]): if is_visible(filename) or args.all: if fnmatch(filename, pattern): if args.long: print_long(filename, stat, oprint) else: files.append(decorated_filename(filename, stat)) if len(files) > 0: print_cols(sorted(files), oprint, shutil.get_terminal_size().columns)
def do_config(self, line): """config Print option values. config [-u] [-d] [--default] OPTION [VALUE] Set/delete OPTION to VALUE. """ default_board = None board_id = 'default' try: default_board = self.boards.default board_id = default_board.id except BoardError: pass if line == '': # print configuration print_config(self.config, board_id, color=printing.MPY_COLOR) if default_board: oprint("Defaults:") keys = self.config.options(board_id) print_config(self.config, 'default', exc=keys) return # parse arguments args = self.line_to_args(line) if args.default: board_id = 'default' default_board = None value = ' '.join(args.value) try: # try to convert value to Python object (e.g. for numbers) value = literal_eval(value) except: pass if not args.default and not default_board: eprint( "*** No board connected, use --default to change default configuration" ) return # delete / set option value if args.delete: # delete option self.config.remove(board_id, args.option) else: # set option try: self.config.set(board_id, args.option, value) except ConfigError as e: eprint("*** {}".format(e)) # upload if args.upload: if not default_board: eprint("*** No board connected, cannot upload configuration") return with NamedTemporaryFile() as temp: temp.close() f = open(temp.name, 'w') now = datetime.now().strftime("%Y-%b-%d %H:%M:%S") print("# config.py, created on {}".format(now), file=f) for key in default_board.config_options(): print("{} = {}".format(key, repr(default_board.get_config(key))), file=f) print("mac_table = {}".format(repr(self.config.mac_table())), file=f) f.close() dst = os.path.join( default_board.get_config('remote_dir', '/flash'), 'config.py') cp(self.boards, temp.name, dst) os.unlink(temp.name)
def print_bytes(byte_str): """Prints a string or converts bytes to a string and then prints.""" if isinstance(byte_str, str): oprint(byte_str) else: oprint(str(byte_str, encoding='utf8'))
def main(): """The main program.""" if sys.version_info.major < 3: v = sys.version_info eprint("Shell49 requires Python 3.6 (not {}.{}.{})".format( v.major, v.minor, v.micro)) return default_config = os.getenv('SHELL49_CONFIG_FILE') or '~/.shell49_rc.py' default_editor = os.getenv('SHELL49_EDITOR') or os.getenv( 'VISUAL') or os.getenv('EDITOR') or 'vi' default_nocolor = 'win32' in sys.platform default_debug = False default_quiet = False parser = argparse.ArgumentParser( prog="shell49", usage="%(prog)s [options] [cmd]", description="Remote Shell for MicroPython boards.", epilog=(""" Environment variables: SHELL49_CONFIG_FILE configuration file (Default: '{}') SHELL49_EDITOR editor (Default: {}) """.format(default_config, default_editor)), formatter_class=argparse.RawTextHelpFormatter) parser.add_argument( "-c", "--config", dest="config", help="Set path of the configuration file (default: '%s')" % default_config, default=default_config) parser.add_argument("-e", "--editor", dest="editor", help="Set the editor to use (default: '%s')" % default_editor, default=default_editor) parser.add_argument("-d", "--debug", dest="debug", action="store_true", help="Enable debug features (default %s)" % default_debug, default=default_debug) parser.add_argument("-n", "--nocolor", dest="nocolor", action="store_true", help="Turn off colorized output (default: %s)" % default_nocolor, default=default_nocolor) parser.add_argument("--quiet", dest="quiet", action="store_true", help="Turn off some output (default: %s)" % default_quiet, default=False) parser.add_argument( "-a", "--no_auto_connect", dest="auto_connect", action="store_false", help="Do not automatically connect to board connected to serial port", default=True) parser.add_argument('-V', '--version', dest='version', action='store_true', help='Report the version and exit.', default=False) parser.add_argument("-f", "--file", dest="filename", help="File of commands to process (non-interactive).") parser.add_argument("cmd", nargs=argparse.REMAINDER, help="Optional command to execute and quit.") args = parser.parse_args(sys.argv[1:]) debug(args.debug) quiet(args.quiet or args.cmd or args.filename) if args.nocolor: nocolor() dprint("config = %s" % args.config) dprint("editor = %s" % args.editor) dprint("debug = %s" % args.debug) dprint("quiet = %s" % args.quiet) dprint("nocolor = %s" % args.nocolor) dprint("auto_connect = %s" % args.auto_connect) dprint("version = %s" % __version__) dprint("cmd = [%s]" % ', '.join(args.cmd)) if args.version: print(__version__) return cmd_line = ' '.join(args.cmd) if not args.filename and cmd_line == '': oprint( "Welcome to shell49 version {}. Type 'help' for information; Control-D to exit." .format(__version__)) args.config = os.path.expanduser(args.config) args.config = os.path.normpath(args.config) with Config(args.config) as config: boards = ActiveBoards(config) # connect to board ... try: if args.auto_connect: boards.connect_serial(config.get('default', 'port')) except (ConnectionError, BoardError) as err: eprint(err) except KeyboardInterrupt: pass # start command shell attach_commands() if args.filename: with open(args.filename) as cmd_file: shell = Shell(boards, args.editor, stdin=cmd_file) shell.cmdloop('') else: if boards.num_boards() == 0: eprint( "No MicroPython boards connected - use the connect command to add one." ) shell = Shell(boards, args.editor) try: shell.cmdloop(cmd_line) except KeyboardInterrupt: qprint("Bye") print(printing.NO_COLOR)