Skip to content

Commit

Permalink
main,osbuildprogress: add --progress=term,plain,debug support
Browse files Browse the repository at this point in the history
This adds a new `progress` flag that makes use of the
osbuild jsonseq progress information to show progress and
hide the low-level details from the user.
  • Loading branch information
mvo5 committed Dec 12, 2024
1 parent 238b22a commit 48e9a07
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 15 deletions.
50 changes: 38 additions & 12 deletions bib/cmd/bootc-image-builder/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ import (
"github.com/osbuild/images/pkg/container"
"github.com/osbuild/images/pkg/dnfjson"
"github.com/osbuild/images/pkg/manifest"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/rpmmd"

"github.com/osbuild/bootc-image-builder/bib/internal/buildconfig"
podman_container "github.com/osbuild/bootc-image-builder/bib/internal/container"
"github.com/osbuild/bootc-image-builder/bib/internal/imagetypes"
"github.com/osbuild/bootc-image-builder/bib/internal/progress"
"github.com/osbuild/bootc-image-builder/bib/internal/setup"
"github.com/osbuild/bootc-image-builder/bib/internal/source"
"github.com/osbuild/bootc-image-builder/bib/internal/util"
Expand Down Expand Up @@ -171,7 +171,16 @@ func saveManifest(ms manifest.OSBuildManifest, fpath string) error {
return nil
}

func manifestFromCobra(cmd *cobra.Command, args []string) ([]byte, *mTLSConfig, error) {
func manifestFromCobra(cmd *cobra.Command, args []string, pbar progress.ProgressBar) ([]byte, *mTLSConfig, error) {
if pbar == nil {
var err error
pbar, err = progress.New("plain")
// this should never happen
if err != nil {
return nil, nil, err
}
}

cntArch := arch.Current()

imgref := args[0]
Expand Down Expand Up @@ -234,6 +243,11 @@ func manifestFromCobra(cmd *cobra.Command, args []string) ([]byte, *mTLSConfig,
logrus.Debug("Using local container")
}

pbar.SetPulseMsgf("Manifest generation step")
if err := pbar.Start(); err != nil {
return nil, nil, fmt.Errorf("cannot start progress: %v", err)
}

if err := setup.ValidateHasContainerTags(imgref); err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -320,7 +334,7 @@ func manifestFromCobra(cmd *cobra.Command, args []string) ([]byte, *mTLSConfig,
}

func cmdManifest(cmd *cobra.Command, args []string) error {
mf, _, err := manifestFromCobra(cmd, args)
mf, _, err := manifestFromCobra(cmd, args, nil)
if err != nil {
return fmt.Errorf("cannot generate manifest: %w", err)
}
Expand Down Expand Up @@ -383,6 +397,7 @@ func cmdBuild(cmd *cobra.Command, args []string) error {
osbuildStore, _ := cmd.Flags().GetString("store")
outputDir, _ := cmd.Flags().GetString("output")
targetArch, _ := cmd.Flags().GetString("target-arch")
progressType, _ := cmd.Flags().GetString("progress")

logrus.Debug("Validating environment")
if err := setup.Validate(targetArch); err != nil {
Expand Down Expand Up @@ -415,13 +430,23 @@ func cmdBuild(cmd *cobra.Command, args []string) error {
return fmt.Errorf("chowning is not allowed in output directory")
}

pbar, err := progress.New(progressType)
if err != nil {
return fmt.Errorf("cannto create progress bar: %w", err)
}
defer func() {
if err := pbar.Stop(); err != nil {
logrus.Warnf("progressbar stopping failed: %v", err)
}
}()

manifest_fname := fmt.Sprintf("manifest-%s.json", strings.Join(imgTypes, "-"))
fmt.Printf("Generating manifest %s\n", manifest_fname)
mf, mTLS, err := manifestFromCobra(cmd, args)
pbar.SetMessagef("Generating manifest %s", manifest_fname)
mf, mTLS, err := manifestFromCobra(cmd, args, pbar)
if err != nil {
return fmt.Errorf("cannot build manifest: %w", err)
}
fmt.Print("DONE\n")
pbar.SetMessagef("Done generating manifest")

// collect pipeline exports for each image type
imageTypes, err := imagetypes.New(imgTypes...)
Expand All @@ -434,7 +459,8 @@ func cmdBuild(cmd *cobra.Command, args []string) error {
return fmt.Errorf("cannot save manifest: %w", err)
}

fmt.Printf("Building %s\n", manifest_fname)
pbar.SetPulseMsgf("Image building step")
pbar.SetMessagef("Building %s", manifest_fname)

var osbuildEnv []string
if !canChown {
Expand All @@ -453,12 +479,11 @@ func cmdBuild(cmd *cobra.Command, args []string) error {
osbuildEnv = append(osbuildEnv, envVars...)
}

_, err = osbuild.RunOSBuild(mf, osbuildStore, outputDir, exports, nil, osbuildEnv, false, os.Stderr)
if err != nil {
if err = progress.RunOSBuild(pbar, mf, osbuildStore, outputDir, exports, osbuildEnv); err != nil {
return fmt.Errorf("cannot run osbuild: %w", err)
}

fmt.Println("Build complete!")
pbar.SetMessagef("Build complete!")
if upload {
for idx, imgType := range imgTypes {
switch imgType {
Expand All @@ -472,7 +497,7 @@ func cmdBuild(cmd *cobra.Command, args []string) error {
}
}
} else {
fmt.Printf("Results saved in\n%s\n", outputDir)
pbar.SetMessagef("Results saved in %s", outputDir)
}

if err := chownR(outputDir, chown); err != nil {
Expand Down Expand Up @@ -607,8 +632,9 @@ func buildCobraCmdline() (*cobra.Command, error) {
buildCmd.Flags().String("aws-region", "", "target region for AWS uploads (only for type=ami)")
buildCmd.Flags().String("chown", "", "chown the ouput directory to match the specified UID:GID")
buildCmd.Flags().String("output", ".", "artifact output directory")
buildCmd.Flags().String("progress", "text", "type of progress bar to use")
buildCmd.Flags().String("store", "/store", "osbuild store for intermediate pipeline trees")
//TODO: add json progress for higher level tools like "podman bootc"
buildCmd.Flags().String("progress", "", "type of progress bar to use")
// flag rules
for _, dname := range []string{"output", "store", "rpmmd"} {
if err := buildCmd.MarkFlagDirname(dname); err != nil {
Expand Down
5 changes: 2 additions & 3 deletions test/containerbuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,15 @@ def build_fake_container_fixture(tmpdir_factory, build_container):

fake_osbuild_path = tmp_path / "fake-osbuild"
fake_osbuild_path.write_text(textwrap.dedent("""\
#!/bin/sh -e
#!/bin/bash -e
# injest generated manifest from the images library, if we do not
# do this images may fail with "broken" pipe errors
cat -
cat - >/dev/null
mkdir -p /output/qcow2
echo "fake-disk.qcow2" > /output/qcow2/disk.qcow2
echo "Done"
"""), encoding="utf8")

cntf_path = tmp_path / "Containerfile"
Expand Down
33 changes: 33 additions & 0 deletions test/test_progress.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import subprocess

# pylint: disable=unused-import
from test_opts import container_storage_fixture
from containerbuild import build_container_fixture, build_fake_container_fixture


def bib_cmd(container_storage, output_path, build_fake_container):
return [
"podman", "run", "--rm",
"--privileged",
"--security-opt", "label=type:unconfined_t",
"-v", f"{container_storage}:/var/lib/containers/storage",
"-v", f"{output_path}:/output",
build_fake_container,
"build",
"quay.io/centos-bootc/centos-bootc:stream9",
]


def test_progress_debug(tmp_path, container_storage, build_fake_container):
output_path = tmp_path / "output"
output_path.mkdir(exist_ok=True)

cmdline = bib_cmd(container_storage, output_path, build_fake_container)
cmdline.append("--progress=debug")
res = subprocess.run(cmdline, capture_output=True, check=True, text=True)
assert res.stderr.count("Start progressbar") == 1
assert res.stderr.count("Manifest generation step") == 1
assert res.stderr.count("Image generation step") == 1
assert res.stderr.count("Build complete") == 1
assert res.stderr.count("Stop progressbar") == 1
assert res.stdout.strip() == ""

0 comments on commit 48e9a07

Please sign in to comment.