Module linux_plus_plus.app

linux++ — User Applications (Layer 5)

This module bundles higher-level user-facing applications and helpers that register into the shell as built-in commands. It depends on the lower layers (HAL, Stdlib, Kernel and Shell) and intentionally keeps implementations in pure Python using the standard library where possible. Some components may optionally use third-party libraries when available (e.g. paramiko for SSH features) but fall back gracefully.

Responsibilities and noteworthy apps provided here: - PackageManager (lpp): install, remove, list and search linux++ packages. - TextEditor (lppedit): a small terminal text editor for editing files. - ManSystem (man): built-in manual pages for bundled commands. - FTPClient (ftp): interactive FTP client for file transfers. - SSHClient / SSHDaemon (ssh / sshd): optional SSH client and server integrations with fallbacks to system tools when third-party libraries are not installed. - SysInfo (sysinfo, neofetch): display system information in a friendly format. - ScriptRunner (sh): execute a linux++ script file line-by-line in the current shell context.

The module exposes register_all()(shell) which attaches the commands to the provided Shell instance. This design lets the shell remain lightweight and loads applications on demand during startup.

Global variables

var MAN_PAGES : dict[str, str]

Collection of built-in manual pages used by ManSystem.

Each key is a command name and each value is the plain-text manual page content. The man builtin uses this dictionary to present usage and examples for the shell's built-in commands and commonly bundled apps.

Functions

def main()
Expand source code
def main():
    from .kernel import Kernel
    from .shell  import Shell

    k = Kernel()
    k.boot()

    shell = Shell(k)
    register_all(shell) # attach Layer 5

    sys.exit(shell.run())
def register_all(shell: Shell) ‑> None
Expand source code
def register_all(shell: "Shell") -> None:
    """
    Register Layer 5 applications and builtins into the provided `shell`.

    This function is invoked once at startup after the `Kernel` and `Shell`
    instances are created. It creates application helpers (package manager,
    script runner, sshd instance, etc.) and registers top-level commands
    such as `lpp`, `lppman`, `edit`, `ftp`, `sysinfo`, `sh`, `ssh` and `sshd`.

    The function mutates the supplied `shell` by calling
    `shell.builtins.register(name, callable)` for each command. It also
    performs any necessary package initialization such as loading installed
    packages via the package manager.
    """
    kernel  = shell.kernel
    pm      = PackageManager(shell)
    runner  = ScriptRunner(shell)

    # --- lpp (package manager) ---
    def _lpp(args: list[str]) -> int:
        if not args:
            IOManager.write(
                "usage: lpp <command> [args]\n"
                "commands: install  remove  list  search  update  info"
            )
            return 1
        cmd  = args[0]
        rest = args[1:]
        if cmd == "install": return pm.install(rest[0] if rest else "")
        if cmd == "remove":  return pm.remove(rest[0] if rest else "")
        if cmd == "list":    return pm.list_installed()
        if cmd == "search":  return pm.search(rest[0] if rest else "")
        if cmd == "update":  return pm.update(rest[0] if rest else "")
        if cmd == "info":    return pm.info(rest[0] if rest else "")
        IOManager.error(f"lpp: unknown command {cmd!r}")
        return 1

    # --- man (manual) ---
    def _man(args: list[str]) -> int:
        if not args:
            IOManager.write(f"Available manual pages:\n  {', '.join(sorted(MAN_PAGES))}")
            return 0
        return ManSystem.show(args[0])

    # --- edit (text editor) ---
    def _edit(args: list[str]) -> int:
        if not args:
            IOManager.error("edit: usage: edit <file>")
            return 1
        return TextEditor(kernel.vfs.resolve(args[0])).run()

    # --- ftp (file transfer) ---
    def _ftp(args: list[str]) -> int:
        if not args:
            IOManager.error("ftp: usage: ftp <host> [port]")
            return 1
        host = args[0]
        port = int(args[1]) if len(args) > 1 else 21
        return FTPClient(host, port).run_interactive()

    # --- sysinfo ---
    def _sysinfo(args: list[str]) -> int:
        return SysInfo.display(args)

    # --- sh (script runner) ---
    def _sh(args: list[str]) -> int:
        if not args:
            IOManager.error("sh: usage: sh <script.lpp> [args...]")
            return 1
        return runner.run(args[0], args[1:])

    # --- pkg create (scaffold a new package) ---
    def _pkg_create(args: list[str]) -> int:
        if not args:
            IOManager.error("pkg-create: usage: pkg-create <name>")
            return 1
        name = args[0]
        d    = kernel.vfs.resolve(name)
        os.makedirs(d, exist_ok=True)

        meta = {
            "name":        name,
            "version":     "0.1.0",
            "description": f"{name} package",
            "author":      EnvManager.username(),
            "entry":       name,
        }
        with open(os.path.join(d, "pkg.json"), "w") as f:
            json.dump(meta, f, indent=2)

        entry_py = os.path.join(d, name + ".py")
        with open(entry_py, "w") as f:
            f.write(f'''"""
{name} — linux++ package
"""
from stdlib import IOManager

def main(args):
    IOManager.write("Hello from {name}!")
    return 0
''')

        IOManager.write(
            f"Package scaffold created in ./{name}/\n"
            f"  pkg.json  — manifest\n"
            f"  {name}.py — entry point (edit this)\n\n"
            f"To install locally:\n"
            f"  cd {name} && zip -r ../{name}.lpp . && cd ..\n"
            f"  lpp install {name}.lpp"
        )
        return 0

    # --- ssh ---
    def _ssh(args: list[str]) -> int:
        if not args:
            IOManager.error(
                "ssh: usage: ssh [user@]host [port] [command]\n"
                "  examples:\n"
                "    ssh myserver.local\n"
                "    ssh root@192.168.1.10\n"
                "    ssh user@host 2222\n"
                "    ssh user@host ls -la"
            )
            return 1

        # parse  [user@]host  [port]  [command...]
        target  = args[0]
        rest    = args[1:]

        # split user@host
        if "@" in target:
            user, host = target.split("@", 1)
        else:
            user = EnvManager.username()
            host = target

        # optional port (second arg if it's a number)
        port = 22
        if rest and rest[0].isdigit():
            port = int(rest[0])
            rest = rest[1:]

        # remaining args = remote command (optional)
        command = " ".join(rest) if rest else None

        return SSHClient(host, user, port).run_interactive(command)

    # --- register all ---
    shell.builtins.register("lpp",        _lpp)
    shell.builtins.register("man",        _man)
    shell.builtins.register("lppedit",       _edit)
    shell.builtins.register("ftp",        _ftp)
    shell.builtins.register("sysinfo",    _sysinfo)
    shell.builtins.register("neofetch",   _sysinfo)
    shell.builtins.register("sh",         _sh)
    shell.builtins.register("pkg-create", _pkg_create)
    shell.builtins.register("ssh",        _ssh)

    # --- sshd (SSH daemon) ---
    _sshd_instance = SSHDaemon(shell)

    def _sshd(args: list[str]) -> int:
        if not args:
            IOManager.write(
                "usage: sshd <command> [port]\n"
                "commands:\n"
                "  sshd start [port]   start daemon (default port 2222)\n"
                "  sshd stop           stop daemon\n"
                "  sshd status         show status and connected clients\n"
                "  sshd keygen         regenerate host key\n"
            )
            return 1
        cmd  = args[0]
        rest = args[1:]
        if cmd == "start":
            port = int(rest[0]) if rest and rest[0].isdigit() else SSHDaemon.DEFAULT_PORT
            return _sshd_instance.start(port)
        if cmd == "stop":
            return _sshd_instance.stop()
        if cmd == "status":
            return _sshd_instance.status()
        if cmd == "keygen":
            return _sshd_instance.keygen()
        IOManager.error(f"sshd: unknown command {cmd!r}")
        return 1

    shell.builtins.register("sshd", _sshd)

    # --- license ---
    def _license(args: list[str]) -> int:
        """Display the project's LICENSE file contents."""
        # try a few likely locations: package root, project root, cwd
        candidates = [
            os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "LICENSE")),
            os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "LICENSE")),
            os.path.abspath(os.path.join(os.getcwd(), "LICENSE")),
        ]
        for p in candidates:
            if os.path.exists(p):
                try:
                    with open(p, encoding="utf-8") as f:
                        IOManager.write(f.read())
                    return 0
                except Exception as e:
                    IOManager.error(f"license: error reading LICENSE: {e}")
                    return 1
        IOManager.error("license: LICENSE file not found")
        return 1

    shell.builtins.register("license", _license)

    # load previously installed packages
    pm.load_installed()

Register Layer 5 applications and builtins into the provided shell.

This function is invoked once at startup after the Kernel and Shell instances are created. It creates application helpers (package manager, script runner, sshd instance, etc.) and registers top-level commands such as lpp, lppman, edit, ftp, sysinfo, sh, ssh and sshd.

The function mutates the supplied shell by calling shell.builtins.register(name, callable) for each command. It also performs any necessary package initialization such as loading installed packages via the package manager.

Classes

class ManSystem
Expand source code
class ManSystem:
    """Simple manual-page viewer for bundled application topics.

    `ManSystem` looks up text in the `MAN_PAGES` mapping and presents it to
    the user. On non-Windows platforms a lightweight pager interaction is
    provided so long pages can be read screen-by-screen.
    """

    @staticmethod
    def show(topic: str) -> int:
        """Display the manual page for `topic`.

        The function normalises the requested topic name and looks it up in
        `MAN_PAGES`. If found, the page is displayed either directly (on
        Windows) or with a simple `-- More --` pager on POSIX-like systems.

        Returns 0 when the page was shown successfully, or 1 if the topic was
        not found.
        """
        topic = topic.lower().strip()
        page = MAN_PAGES.get(topic)
        if not page:
            IOManager.error(f"man: no manual entry for {topic!r}")
            IOManager.write(f"Available topics: {', '.join(sorted(MAN_PAGES))}")
            return 1

        if not IS_WINDOWS:
            # paginate with a simple pager
            lines   = page.splitlines()
            _, rows = TextEditor._term_size()
            page_h  = rows - 2
            for i in range(0, len(lines), page_h):
                for line in lines[i:i+page_h]:
                    IOManager.write(line)
                if i + page_h < len(lines):
                    try:
                        k = input("-- More -- (Enter/q) ")
                        if k.lower() == "q":
                            break
                    except (EOFError, KeyboardInterrupt):
                        break
        else:
            IOManager.write(page)
        return 0

Simple manual-page viewer for bundled application topics.

ManSystem looks up text in the MAN_PAGES mapping and presents it to the user. On non-Windows platforms a lightweight pager interaction is provided so long pages can be read screen-by-screen.

Static methods

def show(topic: str) ‑> int
Expand source code
@staticmethod
def show(topic: str) -> int:
    """Display the manual page for `topic`.

    The function normalises the requested topic name and looks it up in
    `MAN_PAGES`. If found, the page is displayed either directly (on
    Windows) or with a simple `-- More --` pager on POSIX-like systems.

    Returns 0 when the page was shown successfully, or 1 if the topic was
    not found.
    """
    topic = topic.lower().strip()
    page = MAN_PAGES.get(topic)
    if not page:
        IOManager.error(f"man: no manual entry for {topic!r}")
        IOManager.write(f"Available topics: {', '.join(sorted(MAN_PAGES))}")
        return 1

    if not IS_WINDOWS:
        # paginate with a simple pager
        lines   = page.splitlines()
        _, rows = TextEditor._term_size()
        page_h  = rows - 2
        for i in range(0, len(lines), page_h):
            for line in lines[i:i+page_h]:
                IOManager.write(line)
            if i + page_h < len(lines):
                try:
                    k = input("-- More -- (Enter/q) ")
                    if k.lower() == "q":
                        break
                except (EOFError, KeyboardInterrupt):
                    break
    else:
        IOManager.write(page)
    return 0

Display the manual page for topic.

The function normalises the requested topic name and looks it up in MAN_PAGES. If found, the page is displayed either directly (on Windows) or with a simple -- More -- pager on POSIX-like systems.

Returns 0 when the page was shown successfully, or 1 if the topic was not found.