CLI-Anwendungen
Bauen Sie einen Kommandozeilenprozess, der in das Terminal schreibt, und erweitern Sie ihn anschließend um Eingabe, Farbe, Systeminformationen und benannte Befehle.
Klassifizierung: Ausführbares Tutorial. Die Begrüßungsanwendung ist vollständig.
Die späteren Abschnitte sind optionale Ersetzungen für src/cli.lua oder den Eintrag
app:cli, wie jeweils angegeben.
Was wir bauen
Ein CLI-Prozess, der eine Begrüßung ausgibt:
$ wippy run -x app:cli
Hello from CLI!
Voraussetzungen
- Die Wippy-Runtime
v0.3.32aist alswippyverfügbar. Prüfen Sie dies mitwippy version --short. - Ein interaktives Terminal. Die Eingabebeispiele benötigen stdin, und die Farbbeispiele benötigen ein Terminal, das ANSI-Escape-Sequenzen darstellen kann.
Projektstruktur
cli-app/
├── wippy.lock
└── src/
├── _index.yaml
└── cli.lua
Schritt 1: Projekt erstellen
mkdir cli-app && cd cli-app
mkdir src
Schritt 2: Entry-Definitionen
Erstellen Sie src/_index.yaml:
version: "1.0"
namespace: app
entries:
# Terminal host connects processes to stdin/stdout
- name: terminal
kind: terminal.host
lifecycle:
auto_start: true
# CLI process
- name: cli
kind: process.lua
source: file://cli.lua
method: main
modules:
- io
terminal.host verbindet Ihren Lua-Prozess mit dem Terminal. Ohne ihn hat io.print() kein Ausgabeziel.
Schritt 3: CLI-Code
Erstellen Sie src/cli.lua:
local io = require("io")
local function main()
io.print("Hello from CLI!")
return 0
end
return { main = main }
Schritt 4: Ausführen
wippy init
wippy run -x app:cli
Erwartete Ausgabe:
Hello from CLI!
-x führt den Prozess als Befehl aus. Es erkennt den einzigen
terminal.host in der Registry automatisch; verwenden Sie --host,
wenn mehrere Terminal Hosts vorhanden sind. Ohne Logging-Flag unterdrückt der
Befehlsmodus Runtime-Logs, damit die Prozessausgabe lesbar bleibt.
Benutzereingaben lesen
Ersetzen Sie src/cli.lua durch diese Version. Sie meldet Fehler beim Lesen und
Schreiben im Terminal, statt sie als leere Eingabe zu behandeln:
local io = require("io")
local function main()
local _, write_err = io.write("Enter your name: ")
if write_err then
io.eprint("Cannot write prompt:", write_err)
return 1
end
local _, flush_err = io.flush()
if flush_err then
io.eprint("Cannot flush prompt:", flush_err)
return 1
end
local name, read_err = io.readline()
if read_err then
io.eprint("Cannot read input:", read_err)
return 1
end
if name and #name > 0 then
io.print("Hello, " .. name .. "!")
else
io.print("Hello, stranger!")
end
return 0
end
return { main = main }
Farbige Ausgabe
Ersetzen Sie src/cli.lua durch diese Version, um ANSI-Escape-Codes für Farben zu verwenden:
local io = require("io")
local reset = "\027"
local function red(s) return "\027" .. s .. reset end
local function green(s) return "\027" .. s .. reset end
local function yellow(s) return "\027" .. s .. reset end
local function cyan(s) return "\027" .. s .. reset end
local function bold(s) return "\027" .. s .. reset end
local function main()
io.print(bold(cyan("Welcome!")))
local _, write_err = io.write(yellow("Enter a number: "))
if write_err then
io.eprint("Cannot write prompt:", write_err)
return 1
end
local _, flush_err = io.flush()
if flush_err then
io.eprint("Cannot flush prompt:", flush_err)
return 1
end
local input, read_err = io.readline()
if read_err then
io.eprint("Cannot read input:", read_err)
return 1
end
local n = tonumber(input)
if n then
io.print("Squared: " .. green(tostring(n * n)))
return 0
else
io.print(red("Error: ") .. "not a number")
return 1
end
end
return { main = main }
Systeminformationen
Zugriff auf Runtime-Statistiken mit dem system-Modul. Jeder Lesezugriff ist durch die Aktion system.read abgesichert, der Prozess braucht also zusätzlich eine Policy, die sie erlaubt:
# Zu den Entries hinzufügen
- name: system_read
kind: security.policy
policy:
actions:
- system.read
resources: "*"
effect: allow
# Den CLI-Eintrag aktualisieren
- name: cli
kind: process.lua
source: file://cli.lua
method: main
security:
policies:
- app:system_read
modules:
- io
- system
Ersetzen Sie anschließend src/cli.lua:
local io = require("io")
local system = require("system")
local function main()
local hostname, hostname_err = system.process.hostname()
if hostname_err then
io.eprint("Cannot read hostname:", hostname_err)
return 1
end
local cpu_count, cpu_err = system.runtime.cpu_count()
if cpu_err then
io.eprint("Cannot read CPU count:", cpu_err)
return 1
end
local goroutines, goroutine_err = system.runtime.goroutines()
if goroutine_err then
io.eprint("Cannot read goroutine count:", goroutine_err)
return 1
end
local mem, memory_err = system.memory.stats()
if memory_err then
io.eprint("Cannot read memory stats:", memory_err)
return 1
end
io.print("Host: " .. hostname)
io.print("CPUs: " .. cpu_count)
io.print("Goroutines: " .. goroutines)
io.print("Memory: " .. string.format("%.1f MB", mem.heap_alloc / 1024 / 1024))
return 0
end
return { main = main }
Benannte Befehle
Um den Prozess nach Namen statt mit -x app:cli aufzurufen, fügen Sie Command-Metadaten hinzu:
Ersetzen Sie den Eintrag app:cli durch diese Version. Behalten Sie den Eintrag
terminal.host aus dem Basisprojekt bei.
- name: cli
kind: process.lua
meta:
command:
name: greet
short: Greet the user
source: file://cli.lua
method: main
modules:
- io
Führen Sie den benannten Befehl aus:
wippy run greet
Listen Sie alle verfügbaren Befehle auf:
wippy run list
Available commands:
greet Greet the user (app:cli)
Run with: wippy run <command>
Exit-Codes
Geben Sie aus main() eine Zahl zurück, um den Exit-Code festzulegen:
local function main()
if error_occurred then
return 1 -- Error
end
return 0 -- Success
end
I/O-Referenz
| Funktion | Rückgabe | Beschreibung |
|---|---|---|
io.print(...) |
boolean oder ohne Terminal-Kontext nil, error |
Mit Tabs und abschließendem Zeilenumbruch nach stdout schreiben |
io.write(...) |
boolean, error |
Ohne Trennzeichen oder Zeilenumbruch nach stdout schreiben |
io.eprint(...) |
boolean oder ohne Terminal-Kontext nil, error |
Mit Tabs und abschließendem Zeilenumbruch nach stderr schreiben |
io.readline() |
string, error |
Eine Zeile ohne abschließenden Zeilenumbruch lesen; EOF ohne Daten ist ein Fehler |
io.flush() |
boolean, error |
stdout leeren, wenn der Stream dies unterstützt |
CLI-Flags
| Flag | Beschreibung |
|---|---|
wippy run -x app:cli |
CLI-Prozess ausführen (erkennt terminal.host automatisch) |
wippy run -x app:cli --host app:terminal |
Expliziter Terminal Host |
wippy run -x app:cli -v |
Mit ausführlichem Logging |
Fehlerbehebung und Bereinigung
no terminal host foundbedeutet, dass die Registry keinenterminal.hostenthält; verwenden Sie den Eintrag aus Schritt 2. Wenn mehrere Hosts vorhanden sind, übergeben Sie--host app:terminal.no terminal contextbedeutet, dass der Prozess nicht über einen Terminal Host gestartet wurde. Verwenden Siewippy run -x app:clistatt eines im Hintergrund laufendenprocess.service.- Eingabefehler bei EOF sind zu erwarten, wenn stdin geschlossen ist. Führen Sie die Eingabebeispiele in einem interaktiven Terminal aus.
- Wenn ANSI-Sequenzen als Zeichen angezeigt werden, verwenden Sie das Beispiel ohne Farben oder ein Terminal mit ANSI-Unterstützung.
- Der Befehl endet, wenn
main()zurückkehrt. Löschen Sie nach dem Verlassen des Verzeichnissescli-app/, wenn es nur eine vorübergehende Übung war.
Nächste Schritte
- I/O-Modul — Referenz der I/O-API
- Systemmodul — Runtime- und Systeminformationen
- Echo-Service — Eine Anwendung mit mehreren Prozessen bauen