From 30df06d9dc760f7adf8ce51f2443dedc773f1350 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Mon, 5 Apr 2021 09:35:37 +0200 Subject: [PATCH] safcm: add -q (quiet) command line option --- cmd/safcm/config/config.go | 1 + cmd/safcm/sync.go | 3 + cmd/safcm/sync_changes.go | 30 ++++++++- cmd/safcm/sync_changes_test.go | 111 +++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 1 deletion(-) diff --git a/cmd/safcm/config/config.go b/cmd/safcm/config/config.go index 6dae4a1..bae137f 100644 --- a/cmd/safcm/config/config.go +++ b/cmd/safcm/config/config.go @@ -28,6 +28,7 @@ import ( type Config struct { DryRun bool `yaml:"-"` // set via command line + Quiet bool `yaml:"-"` // set via command line LogLevel safcm.LogLevel `yaml:"-"` // set via command line DetectGroups []string `yaml:"detect_groups"` diff --git a/cmd/safcm/sync.go b/cmd/safcm/sync.go index 7f1e090..e8f6431 100644 --- a/cmd/safcm/sync.go +++ b/cmd/safcm/sync.go @@ -71,6 +71,8 @@ func MainSync(args []string) error { optionDryRun := flag.Bool("n", false, "dry-run, show diff but don't perform any changes") + optionQuiet := flag.Bool("q", false, + "hide successful, non-trigger commands with no output from host changes listing") optionLog := flag.String("log", "info", "set log `level`; "+ "levels: error, info, verbose, debug, debug2, debug3") @@ -105,6 +107,7 @@ func MainSync(args []string) error { return err } cfg.DryRun = *optionDryRun + cfg.Quiet = *optionQuiet cfg.LogLevel = level toSync, err := hostsToSync(names, allHosts, allGroups) diff --git a/cmd/safcm/sync_changes.go b/cmd/safcm/sync_changes.go index 14d73c2..4634911 100644 --- a/cmd/safcm/sync_changes.go +++ b/cmd/safcm/sync_changes.go @@ -145,13 +145,41 @@ func (s *Sync) formatServiceChanges(changes []safcm.ServiceChange) string { func (s *Sync) formatCommandChanges(changes []safcm.CommandChange) string { const indent = " > " + // Quiet hides all successful, non-trigger commands which produce no + // output. This is useful as many commands will be used to enforce a + // certain state (e.g. file not-present, `ainsl`, etc.) and are run on + // each sync. Displaying them provides not much useful information. + // Instead, quiet shows them only when they produce output (e.g. + // `ainsl`, `rm -v`) and thus modify the host's state. + var noOutput int + if s.config.Quiet && !s.config.DryRun { + for _, x := range changes { + if x.Trigger == "" && + x.Error == "" && + x.Output == "" { + noOutput++ + } + } + } + var buf strings.Builder - fmt.Fprintf(&buf, "executed %d command(s):", len(changes)) + fmt.Fprintf(&buf, "executed %d command(s)", len(changes)) + if noOutput > 0 { + fmt.Fprintf(&buf, ", %d with no output", noOutput) + } + if noOutput != len(changes) { + fmt.Fprintf(&buf, ":") + } if s.config.DryRun { fmt.Fprintf(&buf, " (dry-run)") } fmt.Fprintf(&buf, "\n") for _, x := range changes { + if noOutput > 0 && + x.Trigger == "" && x.Error == "" && x.Output == "" { + continue + } + fmt.Fprintf(&buf, "%s", s.formatTarget(x.Command)) if x.Trigger != "" { fmt.Fprintf(&buf, ", trigger for %q", x.Trigger) diff --git a/cmd/safcm/sync_changes_test.go b/cmd/safcm/sync_changes_test.go index 76a0168..f48d441 100644 --- a/cmd/safcm/sync_changes_test.go +++ b/cmd/safcm/sync_changes_test.go @@ -465,6 +465,7 @@ func TestFormatCommandChanges(t *testing.T) { tests := []struct { name string dryRun bool + quiet bool changes []safcm.CommandChange exp string }{ @@ -472,6 +473,7 @@ func TestFormatCommandChanges(t *testing.T) { { "regular", false, + false, []safcm.CommandChange{ { Command: "fake command", @@ -514,6 +516,7 @@ func TestFormatCommandChanges(t *testing.T) { { "dry-run", true, + false, []safcm.CommandChange{ { Command: "fake command", @@ -527,9 +530,116 @@ func TestFormatCommandChanges(t *testing.T) { `, }, + { + "quiet", + false, + true, + []safcm.CommandChange{ + { + Command: "fake command", + Output: "fake output", + }, + { + Command: "fake command with no output", + }, + { + Command: "fake command with newline", + Output: "fake output\n", + }, + { + Command: "fake command with more output", + Output: "fake out\nfake put\nfake\n", + }, + { + Command: "fake failed command", + Output: "fake output", + Error: "fake error", + }, + }, + `executed 5 command(s), 1 with no output: +"fake command": + > fake output + > \ No newline at end of file +"fake command with newline": + > fake output +"fake command with more output": + > fake out + > fake put + > fake +"fake failed command", failed: "fake error": + > fake output + > \ No newline at end of file +`, + }, + + { + "quiet (only quiet commands)", + false, + true, + []safcm.CommandChange{ + { + Command: "fake command with no output", + }, + { + Command: "fake command with no output", + }, + }, + `executed 2 command(s), 2 with no output +`, + }, + + { + "quiet (quiet with errors)", + false, + true, + []safcm.CommandChange{ + { + Command: "fake command with no output but error", + Error: "fake error", + }, + { + Command: "fake command with no output", + }, + }, + `executed 2 command(s), 1 with no output: +"fake command with no output but error", failed: "fake error" +`, + }, + + { + "quiet & dry-run", + true, + true, + []safcm.CommandChange{ + { + Command: "fake command", + }, + { + Command: "fake command with no output", + }, + { + Command: "fake command with newline", + }, + { + Command: "fake command with more output", + }, + { + Command: "fake failed command", + }, + }, + `executed 5 command(s): (dry-run) +"fake command" +"fake command with no output" +"fake command with newline" +"fake command with more output" +"fake failed command" +`, + }, + { "escaping", false, + false, []safcm.CommandChange{ { Command: "\x00", @@ -550,6 +660,7 @@ func TestFormatCommandChanges(t *testing.T) { s := &Sync{ config: &config.Config{ DryRun: tc.dryRun, + Quiet: tc.quiet, }, } -- 2.44.1