diff --git a/README.md b/README.md index fdfa76ef..3857fc0e 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,9 @@ Flags: --progress string type of progress bar to use (e.g. verbose, term) --type string image type to build [qcow2, ami] (default "qcow2") --target-arch string architecture to build image for (default is the native architecture) + +Global Flags: + -v, --verbose Switch to verbose mode ``` ### Detailed description of optional flags @@ -143,6 +146,7 @@ Flags: | **--tls-verify** | Require HTTPS and verify certificates when contacting registries | `true` | | **--type** | [Image type](#-image-types) to build | `qcow2` | | **--target-arch** | [Target arch](#-target-architecture) to build | ❌ | +| **--verbose** | Switch output/progress to verbose mode | `false` | The `--type` parameter can be given multiple times and multiple outputs will be produced. diff --git a/bib/cmd/bootc-image-builder/main.go b/bib/cmd/bootc-image-builder/main.go index e88b549f..bc734f5c 100644 --- a/bib/cmd/bootc-image-builder/main.go +++ b/bib/cmd/bootc-image-builder/main.go @@ -546,72 +546,61 @@ func chownR(path string, chown string) error { var rootLogLevel string func rootPreRunE(cmd *cobra.Command, _ []string) error { - if rootLogLevel == "" { + verbose, _ := cmd.Flags().GetBool("verbose") + progress, _ := cmd.Flags().GetString("progress") + switch { + case rootLogLevel != "": + level, err := logrus.ParseLevel(rootLogLevel) + if err != nil { + return err + } + logrus.SetLevel(level) + case verbose: + logrus.SetLevel(logrus.InfoLevel) + default: logrus.SetLevel(logrus.ErrorLevel) - return nil } - - level, err := logrus.ParseLevel(rootLogLevel) - if err != nil { - return err + if verbose && progress == "auto" { + if err := cmd.Flags().Set("progress", "verbose"); err != nil { + return err + } } - logrus.SetLevel(level) - return nil } -func cmdVersion() (string, error) { +func versionFromBuildInfo() (string, error) { info, ok := debug.ReadBuildInfo() if !ok { return "", fmt.Errorf("cannot read build info") } - var gitRev string - var buildTime string var buildTainted bool - ret := []string{} + gitRev := "unknown" + buildTime := "unknown" for _, bs := range info.Settings { - if bs.Key == "vcs.revision" { - gitRev = bs.Value - continue - } - if bs.Key == "vcs.time" { + switch bs.Key { + case "vcs.revision": + gitRev = bs.Value[:7] + case "vcs.time": buildTime = bs.Value - continue - } - if bs.Key == "vcs.modified" { + case "vcs.modified": bT, err := strconv.ParseBool(bs.Value) if err != nil { logrus.Errorf("Error parsing 'vcs.modified': %v", err) bT = true } - buildTainted = bT - continue } } - if gitRev != "" { - ret = append(ret, fmt.Sprintf("build_revision: %s", gitRev[:7])) - } else { - ret = append(ret, "build_revision: unknown") - } - if buildTime != "" { - ret = append(ret, fmt.Sprintf("build_time: %s", buildTime)) - } - if buildTainted { - ret = append(ret, "build_status: tainted") - } else { - ret = append(ret, "build_status: ok") - } - // append final newline - ret = append(ret, "") - - return strings.Join(ret, "\n"), nil + return fmt.Sprintf(`build_revision: %s +build_time: %s +build_tainted: %v +`, gitRev, buildTime, buildTainted), nil } func buildCobraCmdline() (*cobra.Command, error) { - version, err := cmdVersion() + version, err := versionFromBuildInfo() if err != nil { return nil, err } @@ -626,6 +615,7 @@ func buildCobraCmdline() (*cobra.Command, error) { rootCmd.SetVersionTemplate(version) rootCmd.PersistentFlags().StringVar(&rootLogLevel, "log-level", "", "logging level (debug, info, error); default error") + rootCmd.PersistentFlags().BoolP("verbose", "v", false, `Switch to verbose mode`) buildCmd := &cobra.Command{ Use: "build IMAGE_NAME", @@ -639,7 +629,7 @@ func buildCobraCmdline() (*cobra.Command, error) { SilenceUsage: true, Example: rootCmd.Use + " build quay.io/centos-bootc/centos-bootc:stream9\n" + rootCmd.Use + " quay.io/centos-bootc/centos-bootc:stream9\n", - Version: rootCmd.Version, + Version: rootCmd.Version, } buildCmd.SetVersionTemplate(version) diff --git a/bib/cmd/bootc-image-builder/main_test.go b/bib/cmd/bootc-image-builder/main_test.go index bfc16601..5cb5d97b 100644 --- a/bib/cmd/bootc-image-builder/main_test.go +++ b/bib/cmd/bootc-image-builder/main_test.go @@ -8,6 +8,7 @@ import ( "strings" "testing" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/stretchr/testify/assert" @@ -573,3 +574,48 @@ func TestCobraCmdline(t *testing.T) { }) } } + +func TestCobraCmdlineVerbose(t *testing.T) { + for _, tc := range []struct { + cmdline []string + expectedProgress string + expectedLogrusLevel logrus.Level + }{ + { + []string{"quay.io..."}, + "auto", + logrus.ErrorLevel, + }, + { + []string{"-v", "quay.io..."}, + "verbose", + logrus.InfoLevel, + }, + } { + restore := mockOsArgs(tc.cmdline) + defer restore() + + rootCmd, err := main.BuildCobraCmdline() + assert.NoError(t, err) + + // collect progressFlag value + var progressFlag string + for _, cmd := range rootCmd.Commands() { + cmd.RunE = func(cmd *cobra.Command, args []string) error { + if progressFlag != "" { + t.Error("progressFlag set twice") + } + progressFlag, err = cmd.Flags().GetString("progress") + assert.NoError(t, err) + return nil + } + } + + t.Run(tc.expectedProgress, func(t *testing.T) { + err = rootCmd.Execute() + assert.NoError(t, err) + assert.Equal(t, tc.expectedProgress, progressFlag) + assert.Equal(t, tc.expectedLogrusLevel, logrus.GetLevel()) + }) + } +} diff --git a/test/test_opts.py b/test/test_opts.py index afb3d096..28641f13 100644 --- a/test/test_opts.py +++ b/test/test_opts.py @@ -148,7 +148,7 @@ def test_bib_errors_only_once(tmp_path, container_storage, build_fake_container) assert res.stderr.count(needle) == 1 -@pytest.mark.parametrize("version_argument", ["version", "--version", "-v"]) +@pytest.mark.parametrize("version_argument", ["version", "--version"]) def test_bib_version(tmp_path, container_storage, build_fake_container, version_argument): output_path = tmp_path / "output" output_path.mkdir(exist_ok=True) @@ -169,8 +169,11 @@ def test_bib_version(tmp_path, container_storage, build_fake_container, version_ capture_output=True, text=True, check=False) if git_res.returncode == 0: expected_rev = git_res.stdout.strip() - needle = f"revision: {expected_rev}" - assert needle in res.stdout + assert f"build_revision: {expected_rev}" in res.stdout + assert "build_time: " in res.stdout + assert "build_tainted: " in res.stdout + # we have a final newline + assert res.stdout[-1] == "\n" def test_bib_no_outside_container_warning_in_container(tmp_path, container_storage, build_fake_container):