v0.30.0 lw --tui, compose pipeline on screen
This commit is contained in:
1 parent
2d72772943
commit
883af0fcaa
20 files changed
+2442
-69
No files matched your search
+2
-2
@@ -52,13 +52,13 @@ var shorts = map[string]struct {
|
||||
top bool
|
||||
}{
|
||||
"c": {"config", true}, "h": {"help", true}, "p": {"preset", true},
|
||||
"q": {"quiet", true}, "t": {"check", true}, "V": {"version", true},
|
||||
"q": {"quiet", true}, "t": {"check", true}, "T": {"tui", true}, "V": {"version", true},
|
||||
"u": {"user", false},
|
||||
}
|
||||
|
||||
// switches are lw's own options that take no value and are no setting, so no
|
||||
// file or environment variable turns one on
|
||||
var switches = []string{"check", "dump", "version", "schema"}
|
||||
var switches = []string{"check", "dump", "version", "schema", "tui"}
|
||||
|
||||
// usageError is a command-line mistake: exit status 2 rather than 1
|
||||
type usageError string
|
||||
|
||||
+14
-1
@@ -39,6 +39,7 @@ func TestCommandLineGrammar(t *testing.T) {
|
||||
{[]string{"--quiet", "-h"}, invocation{help: true, load: config.Args{Overrides: []string{"--quiet"}}}},
|
||||
{[]string{"-c", "-h"}, invocation{help: true}},
|
||||
{[]string{"help"}, invocation{help: true}},
|
||||
{[]string{"-T", "-c", "a.toml"}, invocation{on: map[string]bool{"tui": true}, load: config.Args{File: "a.toml"}}},
|
||||
{[]string{"tls", "ca", "-h"}, invocation{command: &commands[1], args: []string{"ca", "-h"}}},
|
||||
{[]string{"-q", "-t", "-V", "-p", "tail,path=x", "-c=a.toml", "--logging.level", "debug", "--logging.file.retention_hours=-1", "--dump"},
|
||||
invocation{on: map[string]bool{"check": true, "version": true, "dump": true},
|
||||
@@ -52,7 +53,7 @@ func TestCommandLineGrammar(t *testing.T) {
|
||||
}
|
||||
for _, argv := range [][]string{{"-c"}, {"--config"}, {"--config="}, {"-c="}, {"-c", "--quiet"},
|
||||
{"-v"}, {"-qt"}, {"-u", "x"}, {"-config", "x"}, {"--logging.level"}, {"--logging.file.retention_hours", "-1"},
|
||||
{"--check=false"}, {"--version=true"}, {"--source"}, {"--sink=", "x"}, {"-p"}, {"--filter", "--sink", "x"}} {
|
||||
{"--check=false"}, {"--version=true"}, {"--tui=x"}, {"-T", "x"}, {"--source"}, {"--sink=", "x"}, {"-p"}, {"--filter", "--sink", "x"}} {
|
||||
if _, err := parseCommandLine(argv); err == nil {
|
||||
t.Errorf("%q accepted", argv)
|
||||
}
|
||||
@@ -435,3 +436,15 @@ func TestCompletionScriptsAreCurrent(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A named configuration file that is missing is a usage error, on the screen
|
||||
// as without it
|
||||
func TestAMissingNamedFileIsAUsageError(t *testing.T) {
|
||||
inv, err := parseCommandLine([]string{"-T", "-c", filepath.Join(t.TempDir(), "none.toml")})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if code, exit := composeOnScreen(&inv); code != 2 || !exit {
|
||||
t.Fatalf("exit %d, %v", code, exit)
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ Usage:
|
||||
lw -p|--preset SPEC [options] Run a preset's pipeline
|
||||
lw -t|--check [options] Build every pipeline and plugin, report, exit
|
||||
lw --dump [options] Print the effective configuration as TOML, exit
|
||||
lw -T|--tui [options] Compose pipelines on screen, then run them or
|
||||
print them as flags, variables or a file
|
||||
lw help | -h | --help
|
||||
lw -V | --version | --schema
|
||||
|
||||
@@ -31,6 +33,9 @@ after '='; short options do not combine. lw takes options only.
|
||||
else ./logwisp.toml)
|
||||
-t, --check Build every pipeline and plugin, report, exit
|
||||
--dump Print the effective configuration, exit
|
||||
-T, --tui Compose the pipelines on a full-screen
|
||||
terminal, starting from the ones lw would run
|
||||
or a preset; then run them, or print them
|
||||
-q, --quiet Silence lw's own log and notices; pipeline
|
||||
output still flows
|
||||
--color [WHEN] Level names in color on console sinks: auto
|
||||
|
||||
+54
-6
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/lixenwraith/logwisp/internal/compose"
|
||||
"github.com/lixenwraith/logwisp/internal/config"
|
||||
"github.com/lixenwraith/logwisp/internal/core"
|
||||
"github.com/lixenwraith/logwisp/internal/tui"
|
||||
"github.com/lixenwraith/logwisp/internal/version"
|
||||
|
||||
"github.com/lixenwraith/log"
|
||||
@@ -45,18 +46,19 @@ func main() {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if inv.on["tui"] {
|
||||
if code, exit := composeOnScreen(&inv); exit {
|
||||
os.Exit(code)
|
||||
}
|
||||
}
|
||||
|
||||
// --- 1. Initial setup ---
|
||||
// Emulates nohup
|
||||
signal.Ignore(syscall.SIGHUP)
|
||||
|
||||
manager, err := config.Load(inv.load)
|
||||
if err != nil {
|
||||
if errors.Is(err, config.ErrConfigNotFound) {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Error: Failed to load config: %v\n", err)
|
||||
os.Exit(1)
|
||||
os.Exit(loadFailed(err))
|
||||
}
|
||||
defer manager.Close()
|
||||
cfg, err := manager.Snapshot()
|
||||
@@ -216,3 +218,49 @@ func readsStdin(cfg *config.Config) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// loadFailed reports a configuration that did not load and returns lw's exit
|
||||
// code: a named file that is missing is a usage error
|
||||
func loadFailed(err error) int {
|
||||
if errors.Is(err, config.ErrConfigNotFound) {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
return 2
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Error: Failed to load config: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
// composeOnScreen is lw --tui: it starts from the pipelines lw would load, or
|
||||
// the preset menu in place of the built-in pipe, then prints a form and exits,
|
||||
// or leaves inv to run the pipelines composed in place of the loaded ones
|
||||
func composeOnScreen(inv *invocation) (code int, exit bool) {
|
||||
fail := func(err error) (int, bool) {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
return 1, true
|
||||
}
|
||||
manager, err := config.Load(inv.load)
|
||||
if err != nil {
|
||||
return loadFailed(err), true
|
||||
}
|
||||
cfg, err := manager.Snapshot()
|
||||
builtIn := manager.BuiltIn()
|
||||
manager.Close()
|
||||
start := &compose.Composition{}
|
||||
if err == nil && !builtIn {
|
||||
start, err = compose.FromConfig(cfg)
|
||||
}
|
||||
if err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
res, err := tui.Run(start, cfg.Color)
|
||||
switch {
|
||||
case err != nil:
|
||||
return fail(err)
|
||||
case res.Exit == tui.Print:
|
||||
fmt.Print(res.Output)
|
||||
case res.Exit == tui.Start:
|
||||
inv.load.Specs = config.PipelineSpecs(res.Pipelines)
|
||||
return 0, false
|
||||
}
|
||||
return 0, true
|
||||
}
|
||||
Reference in new issue
Block a user