Module lib.shell.shellcore

Class defining a minimalist shell, directly executable on the board. We modify directories, list, delete, move files, edit files … The commands are : - cd : change directory - pwd : current directory - cat : display the content of file - cls : clear screen - mkdir : create directory - mv : move file - rmdir : remove directory - cp : copy file - rm : remove file - ls : list file - ll : list file long - date : get the system date or synchronize with Ntp - setdate : set date and time - uptime : the amount of time system is running - find : find a file - run : execute python script - download : transfer files from device to computer (only available with camflasher) - upload : transfer files from computer to device (only available with camflasher) - edit : edit a text file - exit : exit of shell - gc : garbage collection - grep : grep text in many files - mount : mount sd card - umount : umount sd card - temperature : device temperature - meminfo : memory informations - flashinfo : flash informations - sysinfo : system informations - deepsleep : deepsleep of board - ping : ping host - reboot : reboot board - help : list all command available - man : manual of one command - df : display free disk space - ip2host : convert ip address in hostname - host2ip : convert hostname in ip address - eval : evaluation python string - exec : execute python string - dump : display hexadecimal dump of the content of file

Expand source code
# Distributed under Pycameresp License
# Copyright (c) 2023 Remi BERTHOLET
# pylint:disable=too-many-lines
# pylint:disable=consider-using-f-string
# pylint:disable=unspecified-encoding
""" Class defining a minimalist shell, directly executable on the board.
We modify directories, list, delete, move files, edit files ...
The commands are :
- cd          : change directory
- pwd         : current directory
- cat         : display the content of file
- cls         : clear screen
- mkdir       : create directory
- mv          : move file
- rmdir       : remove directory
- cp          : copy file
- rm          : remove file
- ls          : list file
- ll          : list file long
- date        : get the system date or synchronize with Ntp
- setdate     : set date and time
- uptime      : the amount of time system is running
- find        : find a file
- run         : execute python script
- download    : transfer files from device to computer (only available with camflasher)
- upload      : transfer files from computer to device (only available with camflasher)
- edit        : edit a text file
- exit        : exit of shell
- gc          : garbage collection
- grep        : grep text in many files
- mount       : mount sd card
- umount      : umount sd card
- temperature : device temperature
- meminfo     : memory informations
- flashinfo   : flash informations
- sysinfo     : system informations
- deepsleep   : deepsleep of board
- ping        : ping host
- reboot      : reboot board
- help        : list all command available
- man         : manual of one command
- df          : display free disk space
- ip2host     : convert ip address in hostname
- host2ip     : convert hostname in ip address
- eval        : evaluation python string
- exec        : execute python string
- dump        : display hexadecimal dump of the content of file
"""
# pylint:disable=wrong-import-position
import sys
sys.path.append("lib")
sys.path.append("simul")
import io
import os
import uos
import machine
from tools import useful,logger,sdcard,filesystem,exchange,info,strings,terminal,watchdog,lang,date
from tools.console import Console

shell_commands = None

def get_screen_size():
        """ Return the screen size and check if output redirected """
        # pylint:disable=global-variable-not-assigned
        if Console.is_redirected() is False:
                height, width = terminal.get_screen_size()
        else:
                height, width = terminal.MAXINT, 80
        return height, width

def cd(directory = "/"):
        """ Change directory """
        try:
                uos.chdir(filesystem.normpath(directory))
        except:
                if directory != ".":
                        Console.print("No such file or directory '%s'"%directory)

def pwd():
        """ Display the current directory """
        Console.print("%s"%uos.getcwd())

def mkdir(directory, recursive=False, quiet=False):
        """ Make directory """
        try:
                if quiet is False:
                        Console.print("mkdir '%s'"%directory)
                filesystem.makedir(filesystem.normpath(directory), recursive)
        except:
                Console.print("Cannot mkdir '%s'"%directory)

def removedir(directory, force=False, quiet=False, simulate=False, ignore_error=False):
        """ Remove directory """
        try:
                if filesystem.exists(directory+"/.DS_Store"):
                        rmfile(directory+"/.DS_Store", quiet, force, simulate)
                if (filesystem.ismicropython() or force) and simulate is False:
                        uos.rmdir(directory)
                if quiet is False:
                        Console.print("rmdir '%s'"%(directory))
        except:
                if ignore_error is False:
                        Console.print("rmdir '%s' not removed"%(directory))

def rmdir(directory, recursive=False, force=False, quiet=False, simulate=False, ignore_error=False):
        """ Remove directory """
        directory = filesystem.normpath(directory)
        if recursive is False:
                removedir(directory, force=force, quiet=quiet, simulate=simulate, ignore_error=ignore_error)
        else:
                directories = [directory]
                d = directory
                while 1:
                        parts = filesystem.split(d)
                        if parts[1] == "" or parts[0] == "":
                                break
                        directories.append(parts[0])
                        d = parts[0]
                if "/" in directories:
                        directories.remove("/")
                if sdcard.SdCard.get_mountpoint() in directories:
                        directories.remove(sdcard.SdCard.get_mountpoint())
                for d in directories:
                        if filesystem.exists(d) and d != ".":
                                removedir(d, force=force, quiet=quiet, simulate=simulate, ignore_error=ignore_error)

def mv(source, destination):
        """ Move or rename file """
        try:
                uos.rename(filesystem.normpath(source),filesystem.normpath(destination))
        except:
                Console.print("Cannot mv '%s'->'%s'"%(source,destination))

def copyfile(src,dst,quiet):
        """ Copy file """
        dst = dst.replace("//","/")
        dst = dst.replace("//","/")
        dstdir, dstfile = filesystem.split(dst)
        try:
                if not filesystem.exists(dstdir):
                        if dstdir != "." and dstdir != "":
                                mkdir(dstdir, recursive=True, quiet=quiet)
                src_file = open(src, 'rb')
                dst_file = open(dst, 'wb')
                if quiet is False:
                        Console.print("cp '%s' -> '%s'"%(src,dst))
                while True:
                        buf = src_file.read(256)
                        if len(buf) > 0:
                                dst_file.write(buf)
                        if len(buf) < 256:
                                break
                src_file.close()
                dst_file.close()
        except:
                Console.print("Cannot cp '%s' -> '%s'"%(src, dst))

def cp(source, destination, recursive=False, quiet=False):
        """ Copy file command """
        source = filesystem.normpath(source)
        destination = filesystem.normpath(destination)
        if filesystem.isfile(source):
                copyfile(source,destination,quiet)
        else:
                if filesystem.isdir(source):
                        path = source
                        pattern = "*"
                else:
                        path, pattern = filesystem.split(source)

                _, filenames = filesystem.scandir(path, pattern, recursive)

                for src in filenames:
                        dst = destination + "/" + src[len(path):]
                        copyfile(src,dst,quiet)

def rmfile(filename, quiet=False, force=False, simulate=False):
        """ Remove file """
        try:
                if (filesystem.ismicropython() or force) and simulate is False:
                        uos.remove(filesystem.normpath(filename))
                if quiet is False:
                        Console.print("rm '%s'"%(filename))
        except:
                Console.print("rm '%s' not removed"%(filename))

def rm(file, recursive=False, quiet=False, force=False, simulate=False):
        """ Remove file command """
        file = filesystem.normpath(file)
        filenames   = []
        directories = []

        if filesystem.isfile(file):
                path = file
                rmfile(file, force=force, quiet=quiet, simulate=simulate)
        else:
                if filesystem.isdir(file):
                        if recursive:
                                directories.append(file)
                                path = file
                                pattern = "*"
                        else:
                                path = None
                                pattern = None
                else:
                        path, pattern = filesystem.split(file)

                if path is None:
                        Console.print("Cannot rm '%s'"%file)
                else:
                        dirs, filenames = filesystem.scandir(path, pattern, recursive)
                        directories += dirs

                        for filename in filenames:
                                rmfile(filename, force=force, quiet=quiet, simulate=simulate)

                        if recursive:
                                directories.sort()
                                directories.reverse()

                                for directory in directories:
                                        rmdir(directory, recursive=recursive, force=force, quiet=quiet, simulate=simulate, ignore_error=True)

class LsDisplayer:
        """ Ls displayer class """
        def __init__(self, path, showdir, long):
                """ Constructor """
                self.height, self.width = get_screen_size()
                self.count = 1
                self.long = long
                self.path = path
                self.showdir = showdir

        def purge_path(self, path):
                """ Purge the path for the display """
                path = path.encode("utf8")
                path = filesystem.normpath(path)
                prefix = filesystem.prefix([path, self.path.encode("utf8")])
                return path[len(prefix):].lstrip(b"/")

        def show(self, path):
                """ Show the information of a file or directory """
                fileinfo = filesystem.fileinfo(path)
                file_date = fileinfo[8]
                size = fileinfo[6]

                # If directory
                if fileinfo[0] & 0x4000 == 0x4000:
                        if self.showdir:
                                if self.long:
                                        message = b"%s %s [%s]"%(date.date_to_bytes(file_date),b" "*7,self.purge_path(path))
                                else:
                                        message = b"[%s]"%self.purge_path(path)
                                self.count = print_part(message, self.width, self.height, self.count)
                else:
                        if self.long:
                                fileinfo = filesystem.fileinfo(path)
                                file_date = fileinfo[8]
                                size = fileinfo[6]
                                message = b"%s %s %s"%(date.date_to_bytes(file_date),strings.size_to_bytes(size),self.purge_path(path))
                        else:
                                message = self.purge_path(path)
                        self.count = print_part(message, self.width, self.height, self.count)

        def show_dir(self, state):
                """ Indicates if the directory must show """
                self.showdir = state

def ls(file="", recursive=False, long=False):
        """ List files command """
        searchfile(file, recursive, LsDisplayer(uos.getcwd(), True, long))

def ll(file="", recursive=False):
        """ List files long command """
        searchfile(file, recursive, LsDisplayer(uos.getcwd(), True, True))

def searchfile(file, recursive, obj = None):
        """ Search file """
        file = filesystem.normpath(file)
        p = filesystem.abspath(uos.getcwd(), file)
        filenames = []
        try:
                if file == "":
                        _,filenames = filesystem.scandir(uos.getcwd(), "*", recursive, obj)
                elif filesystem.isfile(p):
                        if obj is not None:
                                obj.show_dir(False)
                                obj.show(p)
                        filenames = [p]
                elif filesystem.isdir(p):
                        _, filenames = filesystem.scandir(p, "*", recursive, obj)
                else:
                        path, pattern = filesystem.split(p)
                        if obj is not None:
                                obj.show_dir(False)
                        _, filenames = filesystem.scandir(path, pattern, recursive, obj)
        except Exception as err:
                Console.print(err)
        if len(filenames) == 0 and file != "" and file != ".":
                Console.print("%s : No such file or directory"%file)
        return filenames

def find(file):
        """ Find a file in directories """
        filenames = searchfile(file, True)
        for filename in filenames:
                Console.print(filename)

def print_part(message, width, height, count):
        """ Print a part of text """
        # pylint:disable=global-variable-not-assigned
        if isinstance(message , bytes):
                message = message.decode("utf8")
        if count is not None and count >= height:
                Console.print(message,end="")
                if Console.is_redirected() is False:
                        key = terminal.getch()
                else:
                        key = " "
                count = 1
                if key in ["x","X","q","Q","\x1B"]:
                        return None
                Console.print("\n", end="")
        else:
                if count is None:
                        count = 1
                else:
                        count += 1
                Console.print(message)
        return count

def grep(file, text, recursive=False, ignorecase=False, regexp=False):
        """ Grep command """
        from re import search
        file = filesystem.normpath(file)
        def __search(text, content, ignorecase, regexp):
                if ignorecase:
                        content  = content.lower()
                        text = text.lower()
                if regexp:
                        if search(text, content):
                                return True
                else:
                        if content.find(text) != -1:
                                return True
                return False

        def __grep(text, filename, ignorecase, regexp, width, height, count):
                lineNumber = 1
                with open(filename,"r", encoding="latin-1") as f:
                        while 1:
                                line = f.readline()
                                if line:
                                        if __search(text, line, ignorecase, regexp):
                                                line = line.replace("\t","    ")
                                                message = "%s:%d:%s"%(filename, lineNumber, line)
                                                message = message.rstrip()[:width]
                                                count = print_part(message, width, height, count)
                                                if count is None:
                                                        Console.print("")
                                                        return None
                                        lineNumber += 1
                                else:
                                        break
                return count

        if filesystem.isfile(file):
                filenames = [file]
        else:
                path, pattern = filesystem.split(file)
                _, filenames = filesystem.scandir(path, pattern, recursive)

        height, width = get_screen_size()
        count = 1
        for filename in filenames:
                count = __grep(text, filename, ignorecase, regexp, width, height, count)
                if count is None:
                        break

def ping(host):
        """ Ping host """
        try:
                from server.ping import ping as ping_
                ping_(host, count=4, timeout=1)
        except:
                Console.print("Not available")

def ip2host(ip_address):
        """ Convert ip to hostname """
        try:
                import wifi
                _, _, _, dns = wifi.Station.get_info()
                from server.dnsclient import resolve_hostname
                Console.print(resolve_hostname(dns, ip_address))
        except:
                Console.print("Not available")

def host2ip(hostname):
        """ Convert hostname to ip """
        try:
                import wifi
                _, _, _, dns = wifi.Station.get_info()
                from server.dnsclient import resolve_ip_address
                Console.print(resolve_ip_address(dns, hostname))
        except:
                Console.print("Not available")

def mountsd(mountpoint="/sd"):
        """ Mount command """
        try:
                sdcard.SdCard.mount(mountpoint)
                Console.print("Sd mounted on '%s'"%mountpoint)
        except:
                Console.print("Cannot mount sd on '%s'"%mountpoint)

def umountsd(mountpoint="/sd"):
        """ Umount command """
        try:
                sdcard.SdCard.umount(mountpoint)
                Console.print("Sd umounted from '%s'"%mountpoint)
        except:
                Console.print("Cannot umount sd from '%s'"%mountpoint)

def date_time(update=False, offsetUTC=+1, noDst=False):
        """ Get or set date """
        try:
                from server.timesetting import set_date
                if update:
                        if noDst:
                                dst = False
                        else:
                                dst = True
                        set_date(offsetUTC, dst)
                del sys.modules["server.timesetting"]
        except:
                pass
        Console.print(date.date_to_string())

def setdate(datetime=""):
        """ Set date and time """
        import re
        file_date=re.compile("[/: ]")
        failed = False
        try:
                spls = file_date.split(datetime)

                lst = []
                if len(spls) > 1:
                        for spl in spls:
                                if len(spl) > 0:
                                        try:
                                                r = spl.lstrip("0")
                                                if len(r) == 0:
                                                        lst.append(0)
                                                else:
                                                        lst.append(eval(r))
                                        except:
                                                failed = True
                                                break
                        if len(lst) == 6:
                                # pylint: disable=unbalanced-tuple-unpacking
                                year,month,day,hour,minute,second = lst
                                machine.RTC().datetime((year, month, day, 0, hour, minute, second, 0))
                        else:
                                failed = True
                else:
                        failed = True
        except Exception as err:
                failed = True
                logger.syslog(err)

        if failed is True:
                Console.print('Expected format "YYYY/MM/DD hh:mm:ss"')

def formatsd(fstype="FAT"):
        """ Format sd card """
        if fstype in ["FAT","LFS"]:
                if sdcard.SdCard.is_mounted() is False:
                        res = input("All data will be lost on Sd card ? proceed with format (y/n) :")
                        if res in ["y","Y"]:
                                if sdcard.SdCard.formatsd() is True:
                                        Console.print("Formatting terminated")
                                else:
                                        Console.print("Formatting failed")
                else:
                        Console.print("Sd card is mounted, a reboot required")
        else:
                Console.print("Filesystem supported : FAT or LFS")

def reboot():
        """ Reboot command """
        try:
                from tools import system
                system.reboot("Reboot device with command")
        except:
                machine.deepsleep(1000)

def deepsleep(seconds=60):
        """ Deep sleep command """
        machine.deepsleep(int(seconds)*1000)

def ligthsleep(seconds=60):
        """ Light sleep command """
        machine.lightsleep(int(seconds)*1000)

edit_class = None
def edit(file, no_color=False, read_only=False):
        """ Edit command """
        # pylint:disable=global-variable-not-assigned
        global edit_class
        if Console.is_redirected() is False:
                if edit_class is None:
                        try:
                                from shell.editor import Editor
                        except:
                                from editor import Editor
                        edit_class = Editor
                edit_class(file, no_color=no_color, read_only=read_only)

def cat(file):
        """ Cat command """
        try:
                f = open(file, "r")
                height, width = get_screen_size()
                count = 1
                while 1:
                        line = f.readline()
                        if not line:
                                break
                        message = line.replace("\t","    ").rstrip()[:width]
                        count = print_part(message, width, height, count)
                        if count is None:
                                break
                f.close()
        except:
                Console.print("Cannot cat '%s'"%(file))

def df(mountpoint = None):
        """ Display free disk space """
        Console.print(strings.tostrings(info.flashinfo(mountpoint=mountpoint)))

def gc():
        """ Garbage collector command """
        from gc import collect
        collect()

def uptime():
        """ Tell how long the system has been running """
        Console.print(strings.tostrings(info.uptime()))

def man(command):
        """ Man command """
        Console.print(man_one(command))

def man_one(command_name):
        """ Manual of one command """
        try:
                command_name, command_function, command_params, command_flags = get_command(command_name)
                text = "  " + command_name + " "
                for param in command_params:
                        text += param + " "
                text += "\n"
                for flag,flagName,val in command_flags:
                        text += "    %s : %s\n"%(flag,flagName)
                result = text[:-1]
        except:
                result = "Unknown command '%s'"%command_name
        return result

# pylint: disable=redefined-builtin
def help():
        """ Help command """
        height, width = get_screen_size()
        count = 1
        cmds = list(shell_commands.keys())
        cmds.sort()
        for command in cmds:
                lines = man_one(command)
                lines = "-"*30+"\n" + lines
                for line in lines.split("\n"):
                        count = print_part(line, width, height, count)
                        if count is None:
                                return

def eval_(string):
        """ Evaluate content of string """
        Console.print(eval(string))

def exec_(string):
        """ Execute content of string """
        exec(string)

shell_exited = False
def exit():
        """ Exit shell command """
        global shell_exited
        shell_exited = True

def dump_(filename):
        """ dump file content """
        height, width = get_screen_size()
        if Console.is_redirected() is False:
                width = (width - 12)//4
        else:
                width = 16
        offset = 0
        file = open(filename, "rb")
        data = b' '
        count = 1
        while True:
                line = io.BytesIO()
                line.write(b'%08X  ' % offset)
                data = file.read(width)
                if len(data) <= 0:
                        break
                strings.dump_line (data, line, width)
                offset += width
                count = print_part(line.getvalue(), width, height, count)
                if count is None:
                        break

def cls():
        """ clear screen """
        Console.print("\x1B[2J\x1B[0;0f", end="")

def check_cam_flasher():
        """ Check if the terminal is CamFlasher """
        # pylint:disable=global-variable-not-assigned
        if Console.is_redirected() is False:
                # Request terminal device attribut
                sys.stdout.write(b"\x1B[0c")

                # Wait terminal device attribut response
                response = terminal.getch(duration=1000)

                # If CamFlasher detected
                if response == "\x1B[?3;2c":
                        return True
        return False

def upload(file="", recursive=False):
        """ Upload file from computer to device """
        if check_cam_flasher():
                Console.print("Upload to device start")
                try:
                        command = exchange.UploadCommand(uos.getcwd())
                        command.write(file, recursive, sys.stdin.buffer, sys.stdout.buffer)
                        result = True
                        while result:
                                file_reader = exchange.FileReader()
                                result = file_reader.read(uos.getcwd(), sys.stdin.buffer, sys.stdout.buffer)
                                watchdog.WatchDog.feed()
                        Console.print("Upload end")
                except Exception as err:
                        logger.syslog(err, display=False)
                        Console.print("Upload failed")
        else:
                Console.print("CamFlasher application required for this command")

class Exporter:
        """ Exporter file to camflasher """
        def __init__(self):
                """ Constructor """

        def send_file(self, path):
                """ Send the file """
                result = True
                fileinfo = filesystem.fileinfo(path)

                # If a file
                if fileinfo[0] & 0x4000 != 0x4000:
                        file_write = exchange.FileWriter()
                        if filesystem.exists(path):
                                sys.stdout.buffer.write("࿊".encode("utf8"))
                                result = file_write.write(path, sys.stdin.buffer, sys.stdout.buffer)
                                watchdog.WatchDog.feed()
                return result

        def show(self, path):
                """ Show the information of a file or directory """
                for _ in range(3):
                        # If the send successful exit, else retry three time
                        if self.send_file(path) is True:
                                break

        def show_dir(self, state):
                """ Indicates if the directory must show """

def download(file="", recursive=False):
        """ Download file from device to computer """
        if check_cam_flasher():
                Console.print("Download from device start")
                try:
                        searchfile(file, recursive, Exporter())
                        Console.print ("Download end")
                except Exception as err:
                        logger.syslog(err, display=False)
                        Console.print("Download failed")
        else:
                Console.print("CamFlasher application required for this command")

def temperature():
        """ Get the internal temperature """
        celcius, farenheit = info.temperature()
        Console.print("%.2f°C, %d°F"%(celcius, farenheit))

def meminfo():
        """ Get memory informations """
        Console.print(strings.tostrings(b"%s : %s"%(lang.memory_label, info.meminfo())))

def flashinfo(mountpoint=None):
        """ Get flash informations """
        Console.print(strings.tostrings(b"%s : %s"%(lang.flash_info, info.flashinfo(mountpoint=mountpoint))))

def sysinfo():
        """ Get system informations """
        Console.print(strings.tostrings(info.sysinfo()))

def vtcolors():
        """ Show all VT100 colors """
        res = b'\x1B[4m4 bits colors\x1B[m\n'
        for i in range(16):
                if i % 8 == 0:
                        res += b"\n  "
                if i < 9:
                        forecolor = 15
                else:
                        forecolor = 0
                res += b"\x1B[38;5;%dm\x1B[48;5;%dm %2d \x1B[0m"%(forecolor, i,i)
        res += b'\n\n\x1B[4m8 bits colors\x1B[m\n'
        j = 0
        for i in range(16,256):
                if j % 12== 0:
                        res += b"\n  "
                backcolor = i
                if j % 36 < 36//2:
                        forecolor = 15
                else:
                        forecolor = 0
                res += b"\x1B[38;5;%dm\x1B[48;5;%dm %3d \x1B[0m"%(forecolor,backcolor,i)
                j += 1
        res += b'\n\n\x1B[4mModifiers\x1B[m\n\n'

        for i,j in [(0,"reset/normal"),(1,b"bold"),(3,b"italic"),(4,b"underline"),(7,b"reverse")]:
                res += b"  %d : \x1B[%dm%s\x1B[0m\n"%(i,i,j)
        res += b'\n\x1B[4mExamples\x1B[m\n\n'
        res += b'  >>> print("\\033[\033[1m1\033[m;\033[7m7\033[mmBold reverse\\033[0m")\n'
        res += b"  \033[1;7mBold reverse\033[0m"
        res += b"\n\n"
        res += b'  >>> print("\033[38;5;15m\033[48;5;1m\\033[48;5;1m\033[m\033[38;5;13m\\033[38;5;13m\033[mHello\\033[m")\n'
        res += b"  \033[48;5;1m\033[38;5;13mHello\033[m\n"

        Console.print(res.decode("utf8"))

def get_command(command_name):
        """ Get a command callback according to the command name """
        try:
                # pylint:disable=global-variable-not-assigned
                global shell_commands
                command = shell_commands[command_name]
                command_function = command[0]
                command_params = []
                command_flags  = []
                for item in command[1:]:
                        if type(item) == type(""):
                                command_params.append(item)
                        if type(item) == type((0,)):
                                command_flags.append(item)
        except  Exception as err:
                # pylint: disable=raise-missing-from
                raise RuntimeError("Command not found '%s'"%command_name)
        return command_name, command_function, command_params, command_flags

def exec_command(args):
        """ Execute command """
        # pylint:disable=global-variable-not-assigned
        command_name = ""
        command_function = None
        command_params = []
        command_flags = []
        output_redirection = None
        output_filename = None
        try:
                if len(args) >= 1:
                        paramsCount = 0
                        flags   = {}
                        for arg in args:
                                arg = arg.strip()
                                if len(arg) > 0:
                                        if command_name == "":
                                                command_name, command_function, command_params, command_flags = get_command(arg)
                                        else:
                                                if len(arg) >= 2 and arg[:2] == "--":
                                                        for commandFlag in command_flags:
                                                                if arg.strip()[2:] == commandFlag[1].strip():
                                                                        flags[commandFlag[1]] = commandFlag[2]
                                                                        break
                                                        else:
                                                                raise RuntimeError("Illegal option '%s'"%arg)
                                                elif arg[0] == "-":
                                                        for commandFlag in command_flags:
                                                                if arg.strip() == commandFlag[0].strip():
                                                                        flags[commandFlag[1]] = commandFlag[2]
                                                                        break
                                                        else:
                                                                raise RuntimeError("Illegal option '%s'"%arg)
                                                elif arg[0] == ">":
                                                        output_redirection = True
                                                else:
                                                        if output_redirection is None:
                                                                if paramsCount >= len(command_params):
                                                                        raise RuntimeError("Too many parameters on '%s'"%command_name)
                                                                else:
                                                                        flags[command_params[paramsCount]] = arg
                                                                        paramsCount += 1
                                                        elif output_redirection is True:
                                                                output_filename = arg

        except Exception as err:
                Console.print(err)
                return
        Console.close()
        try:
                if command_name.strip() != "":
                        if output_filename is not None:
                                try:
                                        Console.open(output_filename)
                                except:
                                        pass
                        command_function(**flags)
        except TypeError as err:
                logger.syslog(err, display=False)
                Console.print("Missing parameters for '%s'"%command_name)
        except KeyboardInterrupt as err:
                logger.syslog(err)
                Console.print(" [Canceled]")
        except Exception as err:
                logger.syslog(err)
        finally:
                Console.close()

def parse_command_line(commandLine):
        """ Parse command line """
        commands = []
        args = []
        quote = None
        arg = ""
        for char in commandLine:
                if char == '"' or char == "'":
                        if quote is not None:
                                if quote == char:
                                        args.append(arg)
                                        arg = ""
                                        quote = None
                                else:
                                        arg += char
                        else:
                                quote = char
                elif char == " ":
                        if quote is not None:
                                arg += char
                        else:
                                args.append(arg)
                                arg = ""
                elif char == ";":
                        if quote is not None:
                                arg += char
                        else:
                                if len(arg) > 0:
                                        args.append(arg)
                                commands.append(args)
                                arg = ""
                                args = []
                else:
                        arg += char
        if len(arg) > 0:
                args.append(arg)
        if len(args) > 0:
                commands.append(args)

        for command in commands:
                exec_command(command)

def shell_sh(path=None, throw=False):
        """ Start the shell """
        global shell_exited, shell_commands
        current_dir = uos.getcwd()

        create_shell_commands()

        if path is not None:
                uos.chdir(path)

        shell_exited = False
        while shell_exited is False:
                try:
                        commandLine = ""
                        commandLine = input("%s=> "%os.getcwd())
                        watchdog.WatchDog.feed()
                except EOFError:
                        Console.print("")
                        break
                except KeyboardInterrupt:
                        Console.print("Ctr-C detected, use 'exit' to restart server or 'quit' to get python prompt")

                if commandLine.strip() == "quit":
                        if throw is True:
                                raise KeyboardInterrupt()
                        else:
                                break
                parse_command_line(commandLine)

        shell_commands = None
        uos.chdir(current_dir)

def create_shell_commands():
        """ Return the shell commands """
        global shell_commands
        shell_commands = \
        {
                "cd"         :[cd              ,"directory"            ],
                "pwd"        :[pwd                                     ],
                "cat"        :[cat             ,"file"                 ],
                "cls"        :[cls                                     ],
                "mkdir"      :[mkdir           ,"directory",             ("-r","recursive",True)],
                "mv"         :[mv              ,"source","destination" ],
                "rmdir"      :[rmdir           ,"directory",             ("-r","recursive",True),("-f","force",True),("-q","quiet",True),("-s","simulate",True)],
                "cp"         :[cp              ,"source","destination",  ("-r","recursive",True),("-q","quiet",True)],
                "rm"         :[rm              ,"file",                  ("-r","recursive",True),("-f","force",True),("-s","simulate",True)],
                "ls"         :[ls              ,"file",                  ("-r","recursive",True),("-l","long",True)],
                "ll"         :[ll              ,"file",                  ("-r","recursive",True)],
                "date"       :[date_time       ,"offsetUTC" ,            ("-u","update",True),   ("-n","noDst",True)],
                "setdate"    :[setdate         ,"datetime"             ],
                "uptime"     :[uptime                                  ],
                "find"       :[find            ,"file"                 ],
                "run"        :[useful.run      ,"filename"             ],
                "download"   :[download        ,"file",                  ("-r","recursive",True)],
                "upload"     :[upload          ,"file",                  ("-r","recursive",True)],
                "edit"       :[edit            ,"file",                  ("-n","no_color",True),("-r","read_only",True)],
                "exit"       :[exit                                    ],
                "gc"         :[gc                                      ],
                "grep"       :[grep            ,"text","file",           ("-r","recursive",True),("-i","ignorecase",True),("-e","regexp",True)],
                "mount"      :[mountsd         ,"mountpoint"           ],
                "umount"     :[umountsd        ,"mountpoint"           ],
                "temperature":[temperature                             ],
                "meminfo"    :[meminfo                                 ],
                "flashinfo"  :[flashinfo                               ],
                "sysinfo"    :[sysinfo                                 ],
                "deepsleep"  :[deepsleep       ,"seconds"              ],
                "lightsleep" :[ligthsleep      ,"seconds"              ],
                "ping"       :[ping            ,"host"                 ],
                "reboot"     :[reboot                                  ],
                "help"       :[help                                    ],
                "man"        :[man             ,"command"              ],
                "memdump"    :[info.memdump                            ],
                "df"         :[df              ,"mountpoint"           ],
                "ip2host"    :[ip2host         ,"ip_address"           ],
                "host2ip"    :[host2ip         ,"hostname"             ],
                "eval"       :[eval_           ,"string"               ],
                "exec"       :[exec_           ,"string"               ],
                "dump"       :[dump_           ,"filename"             ],
                "formatsd"   :[formatsd        ,"fstype"               ],
                "vtcolors"   :[vtcolors                                ],
        }

if __name__ == "__main__":
        sh(sys.argv[1])

Functions

def cat(file)

Cat command

Expand source code
def cat(file):
        """ Cat command """
        try:
                f = open(file, "r")
                height, width = get_screen_size()
                count = 1
                while 1:
                        line = f.readline()
                        if not line:
                                break
                        message = line.replace("\t","    ").rstrip()[:width]
                        count = print_part(message, width, height, count)
                        if count is None:
                                break
                f.close()
        except:
                Console.print("Cannot cat '%s'"%(file))
def cd(directory='/')

Change directory

Expand source code
def cd(directory = "/"):
        """ Change directory """
        try:
                uos.chdir(filesystem.normpath(directory))
        except:
                if directory != ".":
                        Console.print("No such file or directory '%s'"%directory)
def check_cam_flasher()

Check if the terminal is CamFlasher

Expand source code
def check_cam_flasher():
        """ Check if the terminal is CamFlasher """
        # pylint:disable=global-variable-not-assigned
        if Console.is_redirected() is False:
                # Request terminal device attribut
                sys.stdout.write(b"\x1B[0c")

                # Wait terminal device attribut response
                response = terminal.getch(duration=1000)

                # If CamFlasher detected
                if response == "\x1B[?3;2c":
                        return True
        return False
def cls()

clear screen

Expand source code
def cls():
        """ clear screen """
        Console.print("\x1B[2J\x1B[0;0f", end="")
def copyfile(src, dst, quiet)

Copy file

Expand source code
def copyfile(src,dst,quiet):
        """ Copy file """
        dst = dst.replace("//","/")
        dst = dst.replace("//","/")
        dstdir, dstfile = filesystem.split(dst)
        try:
                if not filesystem.exists(dstdir):
                        if dstdir != "." and dstdir != "":
                                mkdir(dstdir, recursive=True, quiet=quiet)
                src_file = open(src, 'rb')
                dst_file = open(dst, 'wb')
                if quiet is False:
                        Console.print("cp '%s' -> '%s'"%(src,dst))
                while True:
                        buf = src_file.read(256)
                        if len(buf) > 0:
                                dst_file.write(buf)
                        if len(buf) < 256:
                                break
                src_file.close()
                dst_file.close()
        except:
                Console.print("Cannot cp '%s' -> '%s'"%(src, dst))
def cp(source, destination, recursive=False, quiet=False)

Copy file command

Expand source code
def cp(source, destination, recursive=False, quiet=False):
        """ Copy file command """
        source = filesystem.normpath(source)
        destination = filesystem.normpath(destination)
        if filesystem.isfile(source):
                copyfile(source,destination,quiet)
        else:
                if filesystem.isdir(source):
                        path = source
                        pattern = "*"
                else:
                        path, pattern = filesystem.split(source)

                _, filenames = filesystem.scandir(path, pattern, recursive)

                for src in filenames:
                        dst = destination + "/" + src[len(path):]
                        copyfile(src,dst,quiet)
def create_shell_commands()

Return the shell commands

Expand source code
def create_shell_commands():
        """ Return the shell commands """
        global shell_commands
        shell_commands = \
        {
                "cd"         :[cd              ,"directory"            ],
                "pwd"        :[pwd                                     ],
                "cat"        :[cat             ,"file"                 ],
                "cls"        :[cls                                     ],
                "mkdir"      :[mkdir           ,"directory",             ("-r","recursive",True)],
                "mv"         :[mv              ,"source","destination" ],
                "rmdir"      :[rmdir           ,"directory",             ("-r","recursive",True),("-f","force",True),("-q","quiet",True),("-s","simulate",True)],
                "cp"         :[cp              ,"source","destination",  ("-r","recursive",True),("-q","quiet",True)],
                "rm"         :[rm              ,"file",                  ("-r","recursive",True),("-f","force",True),("-s","simulate",True)],
                "ls"         :[ls              ,"file",                  ("-r","recursive",True),("-l","long",True)],
                "ll"         :[ll              ,"file",                  ("-r","recursive",True)],
                "date"       :[date_time       ,"offsetUTC" ,            ("-u","update",True),   ("-n","noDst",True)],
                "setdate"    :[setdate         ,"datetime"             ],
                "uptime"     :[uptime                                  ],
                "find"       :[find            ,"file"                 ],
                "run"        :[useful.run      ,"filename"             ],
                "download"   :[download        ,"file",                  ("-r","recursive",True)],
                "upload"     :[upload          ,"file",                  ("-r","recursive",True)],
                "edit"       :[edit            ,"file",                  ("-n","no_color",True),("-r","read_only",True)],
                "exit"       :[exit                                    ],
                "gc"         :[gc                                      ],
                "grep"       :[grep            ,"text","file",           ("-r","recursive",True),("-i","ignorecase",True),("-e","regexp",True)],
                "mount"      :[mountsd         ,"mountpoint"           ],
                "umount"     :[umountsd        ,"mountpoint"           ],
                "temperature":[temperature                             ],
                "meminfo"    :[meminfo                                 ],
                "flashinfo"  :[flashinfo                               ],
                "sysinfo"    :[sysinfo                                 ],
                "deepsleep"  :[deepsleep       ,"seconds"              ],
                "lightsleep" :[ligthsleep      ,"seconds"              ],
                "ping"       :[ping            ,"host"                 ],
                "reboot"     :[reboot                                  ],
                "help"       :[help                                    ],
                "man"        :[man             ,"command"              ],
                "memdump"    :[info.memdump                            ],
                "df"         :[df              ,"mountpoint"           ],
                "ip2host"    :[ip2host         ,"ip_address"           ],
                "host2ip"    :[host2ip         ,"hostname"             ],
                "eval"       :[eval_           ,"string"               ],
                "exec"       :[exec_           ,"string"               ],
                "dump"       :[dump_           ,"filename"             ],
                "formatsd"   :[formatsd        ,"fstype"               ],
                "vtcolors"   :[vtcolors                                ],
        }
def date_time(update=False, offsetUTC=1, noDst=False)

Get or set date

Expand source code
def date_time(update=False, offsetUTC=+1, noDst=False):
        """ Get or set date """
        try:
                from server.timesetting import set_date
                if update:
                        if noDst:
                                dst = False
                        else:
                                dst = True
                        set_date(offsetUTC, dst)
                del sys.modules["server.timesetting"]
        except:
                pass
        Console.print(date.date_to_string())
def deepsleep(seconds=60)

Deep sleep command

Expand source code
def deepsleep(seconds=60):
        """ Deep sleep command """
        machine.deepsleep(int(seconds)*1000)
def df(mountpoint=None)

Display free disk space

Expand source code
def df(mountpoint = None):
        """ Display free disk space """
        Console.print(strings.tostrings(info.flashinfo(mountpoint=mountpoint)))
def download(file='', recursive=False)

Download file from device to computer

Expand source code
def download(file="", recursive=False):
        """ Download file from device to computer """
        if check_cam_flasher():
                Console.print("Download from device start")
                try:
                        searchfile(file, recursive, Exporter())
                        Console.print ("Download end")
                except Exception as err:
                        logger.syslog(err, display=False)
                        Console.print("Download failed")
        else:
                Console.print("CamFlasher application required for this command")
def dump_(filename)

dump file content

Expand source code
def dump_(filename):
        """ dump file content """
        height, width = get_screen_size()
        if Console.is_redirected() is False:
                width = (width - 12)//4
        else:
                width = 16
        offset = 0
        file = open(filename, "rb")
        data = b' '
        count = 1
        while True:
                line = io.BytesIO()
                line.write(b'%08X  ' % offset)
                data = file.read(width)
                if len(data) <= 0:
                        break
                strings.dump_line (data, line, width)
                offset += width
                count = print_part(line.getvalue(), width, height, count)
                if count is None:
                        break
def edit(file, no_color=False, read_only=False)

Edit command

Expand source code
def edit(file, no_color=False, read_only=False):
        """ Edit command """
        # pylint:disable=global-variable-not-assigned
        global edit_class
        if Console.is_redirected() is False:
                if edit_class is None:
                        try:
                                from shell.editor import Editor
                        except:
                                from editor import Editor
                        edit_class = Editor
                edit_class(file, no_color=no_color, read_only=read_only)
def eval_(string)

Evaluate content of string

Expand source code
def eval_(string):
        """ Evaluate content of string """
        Console.print(eval(string))
def exec_(string)

Execute content of string

Expand source code
def exec_(string):
        """ Execute content of string """
        exec(string)
def exec_command(args)

Execute command

Expand source code
def exec_command(args):
        """ Execute command """
        # pylint:disable=global-variable-not-assigned
        command_name = ""
        command_function = None
        command_params = []
        command_flags = []
        output_redirection = None
        output_filename = None
        try:
                if len(args) >= 1:
                        paramsCount = 0
                        flags   = {}
                        for arg in args:
                                arg = arg.strip()
                                if len(arg) > 0:
                                        if command_name == "":
                                                command_name, command_function, command_params, command_flags = get_command(arg)
                                        else:
                                                if len(arg) >= 2 and arg[:2] == "--":
                                                        for commandFlag in command_flags:
                                                                if arg.strip()[2:] == commandFlag[1].strip():
                                                                        flags[commandFlag[1]] = commandFlag[2]
                                                                        break
                                                        else:
                                                                raise RuntimeError("Illegal option '%s'"%arg)
                                                elif arg[0] == "-":
                                                        for commandFlag in command_flags:
                                                                if arg.strip() == commandFlag[0].strip():
                                                                        flags[commandFlag[1]] = commandFlag[2]
                                                                        break
                                                        else:
                                                                raise RuntimeError("Illegal option '%s'"%arg)
                                                elif arg[0] == ">":
                                                        output_redirection = True
                                                else:
                                                        if output_redirection is None:
                                                                if paramsCount >= len(command_params):
                                                                        raise RuntimeError("Too many parameters on '%s'"%command_name)
                                                                else:
                                                                        flags[command_params[paramsCount]] = arg
                                                                        paramsCount += 1
                                                        elif output_redirection is True:
                                                                output_filename = arg

        except Exception as err:
                Console.print(err)
                return
        Console.close()
        try:
                if command_name.strip() != "":
                        if output_filename is not None:
                                try:
                                        Console.open(output_filename)
                                except:
                                        pass
                        command_function(**flags)
        except TypeError as err:
                logger.syslog(err, display=False)
                Console.print("Missing parameters for '%s'"%command_name)
        except KeyboardInterrupt as err:
                logger.syslog(err)
                Console.print(" [Canceled]")
        except Exception as err:
                logger.syslog(err)
        finally:
                Console.close()
def exit()

Exit shell command

Expand source code
def exit():
        """ Exit shell command """
        global shell_exited
        shell_exited = True
def find(file)

Find a file in directories

Expand source code
def find(file):
        """ Find a file in directories """
        filenames = searchfile(file, True)
        for filename in filenames:
                Console.print(filename)
def flashinfo(mountpoint=None)

Get flash informations

Expand source code
def flashinfo(mountpoint=None):
        """ Get flash informations """
        Console.print(strings.tostrings(b"%s : %s"%(lang.flash_info, info.flashinfo(mountpoint=mountpoint))))
def formatsd(fstype='FAT')

Format sd card

Expand source code
def formatsd(fstype="FAT"):
        """ Format sd card """
        if fstype in ["FAT","LFS"]:
                if sdcard.SdCard.is_mounted() is False:
                        res = input("All data will be lost on Sd card ? proceed with format (y/n) :")
                        if res in ["y","Y"]:
                                if sdcard.SdCard.formatsd() is True:
                                        Console.print("Formatting terminated")
                                else:
                                        Console.print("Formatting failed")
                else:
                        Console.print("Sd card is mounted, a reboot required")
        else:
                Console.print("Filesystem supported : FAT or LFS")
def gc()

Garbage collector command

Expand source code
def gc():
        """ Garbage collector command """
        from gc import collect
        collect()
def get_command(command_name)

Get a command callback according to the command name

Expand source code
def get_command(command_name):
        """ Get a command callback according to the command name """
        try:
                # pylint:disable=global-variable-not-assigned
                global shell_commands
                command = shell_commands[command_name]
                command_function = command[0]
                command_params = []
                command_flags  = []
                for item in command[1:]:
                        if type(item) == type(""):
                                command_params.append(item)
                        if type(item) == type((0,)):
                                command_flags.append(item)
        except  Exception as err:
                # pylint: disable=raise-missing-from
                raise RuntimeError("Command not found '%s'"%command_name)
        return command_name, command_function, command_params, command_flags
def get_screen_size()

Return the screen size and check if output redirected

Expand source code
def get_screen_size():
        """ Return the screen size and check if output redirected """
        # pylint:disable=global-variable-not-assigned
        if Console.is_redirected() is False:
                height, width = terminal.get_screen_size()
        else:
                height, width = terminal.MAXINT, 80
        return height, width
def grep(file, text, recursive=False, ignorecase=False, regexp=False)

Grep command

Expand source code
def grep(file, text, recursive=False, ignorecase=False, regexp=False):
        """ Grep command """
        from re import search
        file = filesystem.normpath(file)
        def __search(text, content, ignorecase, regexp):
                if ignorecase:
                        content  = content.lower()
                        text = text.lower()
                if regexp:
                        if search(text, content):
                                return True
                else:
                        if content.find(text) != -1:
                                return True
                return False

        def __grep(text, filename, ignorecase, regexp, width, height, count):
                lineNumber = 1
                with open(filename,"r", encoding="latin-1") as f:
                        while 1:
                                line = f.readline()
                                if line:
                                        if __search(text, line, ignorecase, regexp):
                                                line = line.replace("\t","    ")
                                                message = "%s:%d:%s"%(filename, lineNumber, line)
                                                message = message.rstrip()[:width]
                                                count = print_part(message, width, height, count)
                                                if count is None:
                                                        Console.print("")
                                                        return None
                                        lineNumber += 1
                                else:
                                        break
                return count

        if filesystem.isfile(file):
                filenames = [file]
        else:
                path, pattern = filesystem.split(file)
                _, filenames = filesystem.scandir(path, pattern, recursive)

        height, width = get_screen_size()
        count = 1
        for filename in filenames:
                count = __grep(text, filename, ignorecase, regexp, width, height, count)
                if count is None:
                        break
def help()

Help command

Expand source code
def help():
        """ Help command """
        height, width = get_screen_size()
        count = 1
        cmds = list(shell_commands.keys())
        cmds.sort()
        for command in cmds:
                lines = man_one(command)
                lines = "-"*30+"\n" + lines
                for line in lines.split("\n"):
                        count = print_part(line, width, height, count)
                        if count is None:
                                return
def host2ip(hostname)

Convert hostname to ip

Expand source code
def host2ip(hostname):
        """ Convert hostname to ip """
        try:
                import wifi
                _, _, _, dns = wifi.Station.get_info()
                from server.dnsclient import resolve_ip_address
                Console.print(resolve_ip_address(dns, hostname))
        except:
                Console.print("Not available")
def ip2host(ip_address)

Convert ip to hostname

Expand source code
def ip2host(ip_address):
        """ Convert ip to hostname """
        try:
                import wifi
                _, _, _, dns = wifi.Station.get_info()
                from server.dnsclient import resolve_hostname
                Console.print(resolve_hostname(dns, ip_address))
        except:
                Console.print("Not available")
def ligthsleep(seconds=60)

Light sleep command

Expand source code
def ligthsleep(seconds=60):
        """ Light sleep command """
        machine.lightsleep(int(seconds)*1000)
def ll(file='', recursive=False)

List files long command

Expand source code
def ll(file="", recursive=False):
        """ List files long command """
        searchfile(file, recursive, LsDisplayer(uos.getcwd(), True, True))
def ls(file='', recursive=False, long=False)

List files command

Expand source code
def ls(file="", recursive=False, long=False):
        """ List files command """
        searchfile(file, recursive, LsDisplayer(uos.getcwd(), True, long))
def man(command)

Man command

Expand source code
def man(command):
        """ Man command """
        Console.print(man_one(command))
def man_one(command_name)

Manual of one command

Expand source code
def man_one(command_name):
        """ Manual of one command """
        try:
                command_name, command_function, command_params, command_flags = get_command(command_name)
                text = "  " + command_name + " "
                for param in command_params:
                        text += param + " "
                text += "\n"
                for flag,flagName,val in command_flags:
                        text += "    %s : %s\n"%(flag,flagName)
                result = text[:-1]
        except:
                result = "Unknown command '%s'"%command_name
        return result
def meminfo()

Get memory informations

Expand source code
def meminfo():
        """ Get memory informations """
        Console.print(strings.tostrings(b"%s : %s"%(lang.memory_label, info.meminfo())))
def mkdir(directory, recursive=False, quiet=False)

Make directory

Expand source code
def mkdir(directory, recursive=False, quiet=False):
        """ Make directory """
        try:
                if quiet is False:
                        Console.print("mkdir '%s'"%directory)
                filesystem.makedir(filesystem.normpath(directory), recursive)
        except:
                Console.print("Cannot mkdir '%s'"%directory)
def mountsd(mountpoint='/sd')

Mount command

Expand source code
def mountsd(mountpoint="/sd"):
        """ Mount command """
        try:
                sdcard.SdCard.mount(mountpoint)
                Console.print("Sd mounted on '%s'"%mountpoint)
        except:
                Console.print("Cannot mount sd on '%s'"%mountpoint)
def mv(source, destination)

Move or rename file

Expand source code
def mv(source, destination):
        """ Move or rename file """
        try:
                uos.rename(filesystem.normpath(source),filesystem.normpath(destination))
        except:
                Console.print("Cannot mv '%s'->'%s'"%(source,destination))
def parse_command_line(commandLine)

Parse command line

Expand source code
def parse_command_line(commandLine):
        """ Parse command line """
        commands = []
        args = []
        quote = None
        arg = ""
        for char in commandLine:
                if char == '"' or char == "'":
                        if quote is not None:
                                if quote == char:
                                        args.append(arg)
                                        arg = ""
                                        quote = None
                                else:
                                        arg += char
                        else:
                                quote = char
                elif char == " ":
                        if quote is not None:
                                arg += char
                        else:
                                args.append(arg)
                                arg = ""
                elif char == ";":
                        if quote is not None:
                                arg += char
                        else:
                                if len(arg) > 0:
                                        args.append(arg)
                                commands.append(args)
                                arg = ""
                                args = []
                else:
                        arg += char
        if len(arg) > 0:
                args.append(arg)
        if len(args) > 0:
                commands.append(args)

        for command in commands:
                exec_command(command)
def ping(host)

Ping host

Expand source code
def ping(host):
        """ Ping host """
        try:
                from server.ping import ping as ping_
                ping_(host, count=4, timeout=1)
        except:
                Console.print("Not available")
def print_part(message, width, height, count)

Print a part of text

Expand source code
def print_part(message, width, height, count):
        """ Print a part of text """
        # pylint:disable=global-variable-not-assigned
        if isinstance(message , bytes):
                message = message.decode("utf8")
        if count is not None and count >= height:
                Console.print(message,end="")
                if Console.is_redirected() is False:
                        key = terminal.getch()
                else:
                        key = " "
                count = 1
                if key in ["x","X","q","Q","\x1B"]:
                        return None
                Console.print("\n", end="")
        else:
                if count is None:
                        count = 1
                else:
                        count += 1
                Console.print(message)
        return count
def pwd()

Display the current directory

Expand source code
def pwd():
        """ Display the current directory """
        Console.print("%s"%uos.getcwd())
def reboot()

Reboot command

Expand source code
def reboot():
        """ Reboot command """
        try:
                from tools import system
                system.reboot("Reboot device with command")
        except:
                machine.deepsleep(1000)
def removedir(directory, force=False, quiet=False, simulate=False, ignore_error=False)

Remove directory

Expand source code
def removedir(directory, force=False, quiet=False, simulate=False, ignore_error=False):
        """ Remove directory """
        try:
                if filesystem.exists(directory+"/.DS_Store"):
                        rmfile(directory+"/.DS_Store", quiet, force, simulate)
                if (filesystem.ismicropython() or force) and simulate is False:
                        uos.rmdir(directory)
                if quiet is False:
                        Console.print("rmdir '%s'"%(directory))
        except:
                if ignore_error is False:
                        Console.print("rmdir '%s' not removed"%(directory))
def rm(file, recursive=False, quiet=False, force=False, simulate=False)

Remove file command

Expand source code
def rm(file, recursive=False, quiet=False, force=False, simulate=False):
        """ Remove file command """
        file = filesystem.normpath(file)
        filenames   = []
        directories = []

        if filesystem.isfile(file):
                path = file
                rmfile(file, force=force, quiet=quiet, simulate=simulate)
        else:
                if filesystem.isdir(file):
                        if recursive:
                                directories.append(file)
                                path = file
                                pattern = "*"
                        else:
                                path = None
                                pattern = None
                else:
                        path, pattern = filesystem.split(file)

                if path is None:
                        Console.print("Cannot rm '%s'"%file)
                else:
                        dirs, filenames = filesystem.scandir(path, pattern, recursive)
                        directories += dirs

                        for filename in filenames:
                                rmfile(filename, force=force, quiet=quiet, simulate=simulate)

                        if recursive:
                                directories.sort()
                                directories.reverse()

                                for directory in directories:
                                        rmdir(directory, recursive=recursive, force=force, quiet=quiet, simulate=simulate, ignore_error=True)
def rmdir(directory, recursive=False, force=False, quiet=False, simulate=False, ignore_error=False)

Remove directory

Expand source code
def rmdir(directory, recursive=False, force=False, quiet=False, simulate=False, ignore_error=False):
        """ Remove directory """
        directory = filesystem.normpath(directory)
        if recursive is False:
                removedir(directory, force=force, quiet=quiet, simulate=simulate, ignore_error=ignore_error)
        else:
                directories = [directory]
                d = directory
                while 1:
                        parts = filesystem.split(d)
                        if parts[1] == "" or parts[0] == "":
                                break
                        directories.append(parts[0])
                        d = parts[0]
                if "/" in directories:
                        directories.remove("/")
                if sdcard.SdCard.get_mountpoint() in directories:
                        directories.remove(sdcard.SdCard.get_mountpoint())
                for d in directories:
                        if filesystem.exists(d) and d != ".":
                                removedir(d, force=force, quiet=quiet, simulate=simulate, ignore_error=ignore_error)
def rmfile(filename, quiet=False, force=False, simulate=False)

Remove file

Expand source code
def rmfile(filename, quiet=False, force=False, simulate=False):
        """ Remove file """
        try:
                if (filesystem.ismicropython() or force) and simulate is False:
                        uos.remove(filesystem.normpath(filename))
                if quiet is False:
                        Console.print("rm '%s'"%(filename))
        except:
                Console.print("rm '%s' not removed"%(filename))
def searchfile(file, recursive, obj=None)

Search file

Expand source code
def searchfile(file, recursive, obj = None):
        """ Search file """
        file = filesystem.normpath(file)
        p = filesystem.abspath(uos.getcwd(), file)
        filenames = []
        try:
                if file == "":
                        _,filenames = filesystem.scandir(uos.getcwd(), "*", recursive, obj)
                elif filesystem.isfile(p):
                        if obj is not None:
                                obj.show_dir(False)
                                obj.show(p)
                        filenames = [p]
                elif filesystem.isdir(p):
                        _, filenames = filesystem.scandir(p, "*", recursive, obj)
                else:
                        path, pattern = filesystem.split(p)
                        if obj is not None:
                                obj.show_dir(False)
                        _, filenames = filesystem.scandir(path, pattern, recursive, obj)
        except Exception as err:
                Console.print(err)
        if len(filenames) == 0 and file != "" and file != ".":
                Console.print("%s : No such file or directory"%file)
        return filenames
def setdate(datetime='')

Set date and time

Expand source code
def setdate(datetime=""):
        """ Set date and time """
        import re
        file_date=re.compile("[/: ]")
        failed = False
        try:
                spls = file_date.split(datetime)

                lst = []
                if len(spls) > 1:
                        for spl in spls:
                                if len(spl) > 0:
                                        try:
                                                r = spl.lstrip("0")
                                                if len(r) == 0:
                                                        lst.append(0)
                                                else:
                                                        lst.append(eval(r))
                                        except:
                                                failed = True
                                                break
                        if len(lst) == 6:
                                # pylint: disable=unbalanced-tuple-unpacking
                                year,month,day,hour,minute,second = lst
                                machine.RTC().datetime((year, month, day, 0, hour, minute, second, 0))
                        else:
                                failed = True
                else:
                        failed = True
        except Exception as err:
                failed = True
                logger.syslog(err)

        if failed is True:
                Console.print('Expected format "YYYY/MM/DD hh:mm:ss"')
def shell_sh(path=None, throw=False)

Start the shell

Expand source code
def shell_sh(path=None, throw=False):
        """ Start the shell """
        global shell_exited, shell_commands
        current_dir = uos.getcwd()

        create_shell_commands()

        if path is not None:
                uos.chdir(path)

        shell_exited = False
        while shell_exited is False:
                try:
                        commandLine = ""
                        commandLine = input("%s=> "%os.getcwd())
                        watchdog.WatchDog.feed()
                except EOFError:
                        Console.print("")
                        break
                except KeyboardInterrupt:
                        Console.print("Ctr-C detected, use 'exit' to restart server or 'quit' to get python prompt")

                if commandLine.strip() == "quit":
                        if throw is True:
                                raise KeyboardInterrupt()
                        else:
                                break
                parse_command_line(commandLine)

        shell_commands = None
        uos.chdir(current_dir)
def sysinfo()

Get system informations

Expand source code
def sysinfo():
        """ Get system informations """
        Console.print(strings.tostrings(info.sysinfo()))
def temperature()

Get the internal temperature

Expand source code
def temperature():
        """ Get the internal temperature """
        celcius, farenheit = info.temperature()
        Console.print("%.2f°C, %d°F"%(celcius, farenheit))
def umountsd(mountpoint='/sd')

Umount command

Expand source code
def umountsd(mountpoint="/sd"):
        """ Umount command """
        try:
                sdcard.SdCard.umount(mountpoint)
                Console.print("Sd umounted from '%s'"%mountpoint)
        except:
                Console.print("Cannot umount sd from '%s'"%mountpoint)
def upload(file='', recursive=False)

Upload file from computer to device

Expand source code
def upload(file="", recursive=False):
        """ Upload file from computer to device """
        if check_cam_flasher():
                Console.print("Upload to device start")
                try:
                        command = exchange.UploadCommand(uos.getcwd())
                        command.write(file, recursive, sys.stdin.buffer, sys.stdout.buffer)
                        result = True
                        while result:
                                file_reader = exchange.FileReader()
                                result = file_reader.read(uos.getcwd(), sys.stdin.buffer, sys.stdout.buffer)
                                watchdog.WatchDog.feed()
                        Console.print("Upload end")
                except Exception as err:
                        logger.syslog(err, display=False)
                        Console.print("Upload failed")
        else:
                Console.print("CamFlasher application required for this command")
def uptime()

Tell how long the system has been running

Expand source code
def uptime():
        """ Tell how long the system has been running """
        Console.print(strings.tostrings(info.uptime()))
def vtcolors()

Show all VT100 colors

Expand source code
def vtcolors():
        """ Show all VT100 colors """
        res = b'\x1B[4m4 bits colors\x1B[m\n'
        for i in range(16):
                if i % 8 == 0:
                        res += b"\n  "
                if i < 9:
                        forecolor = 15
                else:
                        forecolor = 0
                res += b"\x1B[38;5;%dm\x1B[48;5;%dm %2d \x1B[0m"%(forecolor, i,i)
        res += b'\n\n\x1B[4m8 bits colors\x1B[m\n'
        j = 0
        for i in range(16,256):
                if j % 12== 0:
                        res += b"\n  "
                backcolor = i
                if j % 36 < 36//2:
                        forecolor = 15
                else:
                        forecolor = 0
                res += b"\x1B[38;5;%dm\x1B[48;5;%dm %3d \x1B[0m"%(forecolor,backcolor,i)
                j += 1
        res += b'\n\n\x1B[4mModifiers\x1B[m\n\n'

        for i,j in [(0,"reset/normal"),(1,b"bold"),(3,b"italic"),(4,b"underline"),(7,b"reverse")]:
                res += b"  %d : \x1B[%dm%s\x1B[0m\n"%(i,i,j)
        res += b'\n\x1B[4mExamples\x1B[m\n\n'
        res += b'  >>> print("\\033[\033[1m1\033[m;\033[7m7\033[mmBold reverse\\033[0m")\n'
        res += b"  \033[1;7mBold reverse\033[0m"
        res += b"\n\n"
        res += b'  >>> print("\033[38;5;15m\033[48;5;1m\\033[48;5;1m\033[m\033[38;5;13m\\033[38;5;13m\033[mHello\\033[m")\n'
        res += b"  \033[48;5;1m\033[38;5;13mHello\033[m\n"

        Console.print(res.decode("utf8"))

Classes

class Exporter

Exporter file to camflasher

Constructor

Expand source code
class Exporter:
        """ Exporter file to camflasher """
        def __init__(self):
                """ Constructor """

        def send_file(self, path):
                """ Send the file """
                result = True
                fileinfo = filesystem.fileinfo(path)

                # If a file
                if fileinfo[0] & 0x4000 != 0x4000:
                        file_write = exchange.FileWriter()
                        if filesystem.exists(path):
                                sys.stdout.buffer.write("࿊".encode("utf8"))
                                result = file_write.write(path, sys.stdin.buffer, sys.stdout.buffer)
                                watchdog.WatchDog.feed()
                return result

        def show(self, path):
                """ Show the information of a file or directory """
                for _ in range(3):
                        # If the send successful exit, else retry three time
                        if self.send_file(path) is True:
                                break

        def show_dir(self, state):
                """ Indicates if the directory must show """

Methods

def send_file(self, path)

Send the file

Expand source code
def send_file(self, path):
        """ Send the file """
        result = True
        fileinfo = filesystem.fileinfo(path)

        # If a file
        if fileinfo[0] & 0x4000 != 0x4000:
                file_write = exchange.FileWriter()
                if filesystem.exists(path):
                        sys.stdout.buffer.write("࿊".encode("utf8"))
                        result = file_write.write(path, sys.stdin.buffer, sys.stdout.buffer)
                        watchdog.WatchDog.feed()
        return result
def show(self, path)

Show the information of a file or directory

Expand source code
def show(self, path):
        """ Show the information of a file or directory """
        for _ in range(3):
                # If the send successful exit, else retry three time
                if self.send_file(path) is True:
                        break
def show_dir(self, state)

Indicates if the directory must show

Expand source code
def show_dir(self, state):
        """ Indicates if the directory must show """
class LsDisplayer (path, showdir, long)

Ls displayer class

Constructor

Expand source code
class LsDisplayer:
        """ Ls displayer class """
        def __init__(self, path, showdir, long):
                """ Constructor """
                self.height, self.width = get_screen_size()
                self.count = 1
                self.long = long
                self.path = path
                self.showdir = showdir

        def purge_path(self, path):
                """ Purge the path for the display """
                path = path.encode("utf8")
                path = filesystem.normpath(path)
                prefix = filesystem.prefix([path, self.path.encode("utf8")])
                return path[len(prefix):].lstrip(b"/")

        def show(self, path):
                """ Show the information of a file or directory """
                fileinfo = filesystem.fileinfo(path)
                file_date = fileinfo[8]
                size = fileinfo[6]

                # If directory
                if fileinfo[0] & 0x4000 == 0x4000:
                        if self.showdir:
                                if self.long:
                                        message = b"%s %s [%s]"%(date.date_to_bytes(file_date),b" "*7,self.purge_path(path))
                                else:
                                        message = b"[%s]"%self.purge_path(path)
                                self.count = print_part(message, self.width, self.height, self.count)
                else:
                        if self.long:
                                fileinfo = filesystem.fileinfo(path)
                                file_date = fileinfo[8]
                                size = fileinfo[6]
                                message = b"%s %s %s"%(date.date_to_bytes(file_date),strings.size_to_bytes(size),self.purge_path(path))
                        else:
                                message = self.purge_path(path)
                        self.count = print_part(message, self.width, self.height, self.count)

        def show_dir(self, state):
                """ Indicates if the directory must show """
                self.showdir = state

Methods

def purge_path(self, path)

Purge the path for the display

Expand source code
def purge_path(self, path):
        """ Purge the path for the display """
        path = path.encode("utf8")
        path = filesystem.normpath(path)
        prefix = filesystem.prefix([path, self.path.encode("utf8")])
        return path[len(prefix):].lstrip(b"/")
def show(self, path)

Show the information of a file or directory

Expand source code
def show(self, path):
        """ Show the information of a file or directory """
        fileinfo = filesystem.fileinfo(path)
        file_date = fileinfo[8]
        size = fileinfo[6]

        # If directory
        if fileinfo[0] & 0x4000 == 0x4000:
                if self.showdir:
                        if self.long:
                                message = b"%s %s [%s]"%(date.date_to_bytes(file_date),b" "*7,self.purge_path(path))
                        else:
                                message = b"[%s]"%self.purge_path(path)
                        self.count = print_part(message, self.width, self.height, self.count)
        else:
                if self.long:
                        fileinfo = filesystem.fileinfo(path)
                        file_date = fileinfo[8]
                        size = fileinfo[6]
                        message = b"%s %s %s"%(date.date_to_bytes(file_date),strings.size_to_bytes(size),self.purge_path(path))
                else:
                        message = self.purge_path(path)
                self.count = print_part(message, self.width, self.height, self.count)
def show_dir(self, state)

Indicates if the directory must show

Expand source code
def show_dir(self, state):
        """ Indicates if the directory must show """
        self.showdir = state