main: add build --with-buildlog
This commit adds a new `--with-buildlog` option that will automatically create a buildlog in the output directory.
This commit is contained in:
parent
55d3b4916a
commit
2e741a70ad
3 changed files with 116 additions and 19 deletions
|
|
@ -14,6 +14,7 @@ type buildOptions struct {
|
||||||
StoreDir string
|
StoreDir string
|
||||||
|
|
||||||
WriteManifest bool
|
WriteManifest bool
|
||||||
|
WriteBuildlog bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildImage(pbar progress.ProgressBar, res *imagefilter.Result, osbuildManifest []byte, opts *buildOptions) error {
|
func buildImage(pbar progress.ProgressBar, res *imagefilter.Result, osbuildManifest []byte, opts *buildOptions) error {
|
||||||
|
|
@ -31,5 +32,19 @@ func buildImage(pbar progress.ProgressBar, res *imagefilter.Result, osbuildManif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return progress.RunOSBuild(pbar, osbuildManifest, opts.StoreDir, opts.OutputDir, res.ImgType.Exports(), nil)
|
osbuildOpts := &progress.OSBuildOptions{
|
||||||
|
StoreDir: opts.StoreDir,
|
||||||
|
OutputDir: opts.OutputDir,
|
||||||
|
}
|
||||||
|
if opts.WriteBuildlog {
|
||||||
|
p := filepath.Join(opts.OutputDir, fmt.Sprintf("%s.buildlog", outputNameFor(res)))
|
||||||
|
f, err := os.Create(p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
osbuildOpts.BuildLog = f
|
||||||
|
}
|
||||||
|
return progress.RunOSBuild(pbar, osbuildManifest, res.ImgType.Exports(), osbuildOpts)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,11 @@ func cmdBuild(cmd *cobra.Command, args []string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
withBuildlog, err := cmd.Flags().GetBool("with-buildlog")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
pbar, err := progressFromCmd(cmd)
|
pbar, err := progressFromCmd(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -257,6 +262,7 @@ func cmdBuild(cmd *cobra.Command, args []string) error {
|
||||||
OutputDir: outputDir,
|
OutputDir: outputDir,
|
||||||
StoreDir: cacheDir,
|
StoreDir: cacheDir,
|
||||||
WriteManifest: withManifest,
|
WriteManifest: withManifest,
|
||||||
|
WriteBuildlog: withBuildlog,
|
||||||
}
|
}
|
||||||
pbar.SetPulseMsgf("Image building step")
|
pbar.SetPulseMsgf("Image building step")
|
||||||
if err := buildImage(pbar, res, mf.Bytes(), buildOpts); err != nil {
|
if err := buildImage(pbar, res, mf.Bytes(), buildOpts); err != nil {
|
||||||
|
|
@ -379,6 +385,7 @@ operating systems like Fedora, CentOS and RHEL with easy customizations support.
|
||||||
}
|
}
|
||||||
buildCmd.Flags().AddFlagSet(manifestCmd.Flags())
|
buildCmd.Flags().AddFlagSet(manifestCmd.Flags())
|
||||||
buildCmd.Flags().Bool("with-manifest", false, `export osbuild manifest`)
|
buildCmd.Flags().Bool("with-manifest", false, `export osbuild manifest`)
|
||||||
|
buildCmd.Flags().Bool("with-buildlog", false, `export osbuild buildlog`)
|
||||||
// XXX: add --rpmmd cache too and put under /var/cache/image-builder/dnf
|
// XXX: add --rpmmd cache too and put under /var/cache/image-builder/dnf
|
||||||
buildCmd.Flags().String("cache", "/var/cache/image-builder/store", `osbuild directory to cache intermediate build artifacts"`)
|
buildCmd.Flags().String("cache", "/var/cache/image-builder/store", `osbuild directory to cache intermediate build artifacts"`)
|
||||||
// XXX: add "--verbose" here, similar to how bib is doing this
|
// XXX: add "--verbose" here, similar to how bib is doing this
|
||||||
|
|
|
||||||
|
|
@ -384,6 +384,9 @@ func TestBuildIntegrationArgs(t *testing.T) {
|
||||||
}, {
|
}, {
|
||||||
[]string{"--with-manifest"},
|
[]string{"--with-manifest"},
|
||||||
[]string{"centos-9-qcow2-x86_64.osbuild-manifest.json"},
|
[]string{"centos-9-qcow2-x86_64.osbuild-manifest.json"},
|
||||||
|
}, {
|
||||||
|
[]string{"--with-buildlog"},
|
||||||
|
[]string{"centos-9-qcow2-x86_64.buildlog"},
|
||||||
}, {
|
}, {
|
||||||
[]string{"--with-sbom"},
|
[]string{"--with-sbom"},
|
||||||
[]string{"centos-9-qcow2-x86_64.buildroot-build.spdx.json",
|
[]string{"centos-9-qcow2-x86_64.buildroot-build.spdx.json",
|
||||||
|
|
@ -416,7 +419,7 @@ func TestBuildIntegrationArgs(t *testing.T) {
|
||||||
defer fakeOsbuildCmd.Restore()
|
defer fakeOsbuildCmd.Restore()
|
||||||
|
|
||||||
err := main.Run()
|
err := main.Run()
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// ensure output dir override works
|
// ensure output dir override works
|
||||||
osbuildCall := fakeOsbuildCmd.Calls()[0]
|
osbuildCall := fakeOsbuildCmd.Calls()[0]
|
||||||
|
|
@ -441,6 +444,7 @@ cat - > "$0".stdin
|
||||||
echo "error on stdout"
|
echo "error on stdout"
|
||||||
>&2 echo "error on stderr"
|
>&2 echo "error on stderr"
|
||||||
|
|
||||||
|
sleep 0.1
|
||||||
>&3 echo '{"message": "osbuild-stage-output"}'
|
>&3 echo '{"message": "osbuild-stage-output"}'
|
||||||
exit 1
|
exit 1
|
||||||
`
|
`
|
||||||
|
|
@ -471,12 +475,61 @@ func TestBuildIntegrationErrorsProgressVerbose(t *testing.T) {
|
||||||
stdout, stderr := testutil.CaptureStdio(t, func() {
|
stdout, stderr := testutil.CaptureStdio(t, func() {
|
||||||
err = main.Run()
|
err = main.Run()
|
||||||
})
|
})
|
||||||
assert.EqualError(t, err, "running osbuild failed: exit status 1")
|
assert.EqualError(t, err, "error running osbuild: exit status 1")
|
||||||
|
|
||||||
assert.Contains(t, stdout, "error on stdout\n")
|
assert.Contains(t, stdout, "error on stdout\n")
|
||||||
assert.Contains(t, stderr, "error on stderr\n")
|
assert.Contains(t, stderr, "error on stderr\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuildIntegrationErrorsProgressVerboseWithBuildlog(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("manifest generation takes a while")
|
||||||
|
}
|
||||||
|
if !hasDepsolveDnf() {
|
||||||
|
t.Skip("no osbuild-depsolve-dnf binary found")
|
||||||
|
}
|
||||||
|
|
||||||
|
restore := main.MockNewRepoRegistry(testrepos.New)
|
||||||
|
defer restore()
|
||||||
|
|
||||||
|
outputDir := t.TempDir()
|
||||||
|
restore = main.MockOsArgs([]string{
|
||||||
|
"build",
|
||||||
|
"qcow2",
|
||||||
|
"--distro", "centos-9",
|
||||||
|
"--progress=verbose",
|
||||||
|
"--with-buildlog",
|
||||||
|
"--output-dir", outputDir,
|
||||||
|
})
|
||||||
|
defer restore()
|
||||||
|
|
||||||
|
failingOsbuild := `#!/bin/sh
|
||||||
|
cat - > "$0".stdin
|
||||||
|
echo "error on stdout"
|
||||||
|
>&2 echo "error on stderr"
|
||||||
|
exit 1
|
||||||
|
`
|
||||||
|
fakeOsbuildCmd := testutil.MockCommand(t, "osbuild", failingOsbuild)
|
||||||
|
defer fakeOsbuildCmd.Restore()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
stdout, _ := testutil.CaptureStdio(t, func() {
|
||||||
|
err = main.Run()
|
||||||
|
})
|
||||||
|
assert.EqualError(t, err, "error running osbuild: exit status 1")
|
||||||
|
|
||||||
|
// when the buildlog is used we do not get the direct output of
|
||||||
|
// osbuild on stderr, to avoid races everything goes via stdout
|
||||||
|
assert.Contains(t, stdout, "error on stdout\n")
|
||||||
|
assert.Contains(t, stdout, "error on stderr\n")
|
||||||
|
|
||||||
|
buildLog, err := os.ReadFile(filepath.Join(outputDir, "centos-9-qcow2-x86_64.buildlog"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, string(buildLog), `error on stdout
|
||||||
|
error on stderr
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
func TestBuildIntegrationErrorsProgressTerm(t *testing.T) {
|
func TestBuildIntegrationErrorsProgressTerm(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("manifest generation takes a while")
|
t.Skip("manifest generation takes a while")
|
||||||
|
|
@ -488,30 +541,52 @@ func TestBuildIntegrationErrorsProgressTerm(t *testing.T) {
|
||||||
restore := main.MockNewRepoRegistry(testrepos.New)
|
restore := main.MockNewRepoRegistry(testrepos.New)
|
||||||
defer restore()
|
defer restore()
|
||||||
|
|
||||||
restore = main.MockOsArgs([]string{
|
for _, withBuildlog := range []bool{false, true} {
|
||||||
"build",
|
t.Run(fmt.Sprintf("with buildlog %v", withBuildlog), func(t *testing.T) {
|
||||||
"qcow2",
|
outputDir := t.TempDir()
|
||||||
"--distro", "centos-9",
|
cmd := []string{
|
||||||
"--progress=term",
|
"build",
|
||||||
})
|
"qcow2",
|
||||||
defer restore()
|
"--distro", "centos-9",
|
||||||
|
"--progress=term",
|
||||||
|
"--output-dir", outputDir,
|
||||||
|
}
|
||||||
|
if withBuildlog {
|
||||||
|
cmd = append(cmd, "--with-buildlog")
|
||||||
|
}
|
||||||
|
restore = main.MockOsArgs(cmd)
|
||||||
|
defer restore()
|
||||||
|
|
||||||
fakeOsbuildCmd := testutil.MockCommand(t, "osbuild", failingOsbuild)
|
fakeOsbuildCmd := testutil.MockCommand(t, "osbuild", failingOsbuild)
|
||||||
defer fakeOsbuildCmd.Restore()
|
defer fakeOsbuildCmd.Restore()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
stdout, stderr := testutil.CaptureStdio(t, func() {
|
stdout, stderr := testutil.CaptureStdio(t, func() {
|
||||||
err = main.Run()
|
err = main.Run()
|
||||||
})
|
})
|
||||||
assert.EqualError(t, err, `error running osbuild: exit status 1
|
assert.EqualError(t, err, `error running osbuild: exit status 1
|
||||||
BuildLog:
|
BuildLog:
|
||||||
osbuild-stage-output
|
osbuild-stage-output
|
||||||
Output:
|
Output:
|
||||||
error on stdout
|
error on stdout
|
||||||
error on stderr
|
error on stderr
|
||||||
`)
|
`)
|
||||||
assert.NotContains(t, stdout, "error on stdout")
|
assert.NotContains(t, stdout, "error on stdout")
|
||||||
assert.NotContains(t, stderr, "error on stderr")
|
assert.NotContains(t, stderr, "error on stderr")
|
||||||
|
|
||||||
|
if withBuildlog {
|
||||||
|
buildLog, err := os.ReadFile(filepath.Join(outputDir, "centos-9-qcow2-x86_64.buildlog"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, string(buildLog), `error on stdout
|
||||||
|
error on stderr
|
||||||
|
osbuild-stage-output
|
||||||
|
`)
|
||||||
|
} else {
|
||||||
|
_, err := os.Stat(filepath.Join(outputDir, "centos-9-qcow2-x86_64.buildlog"))
|
||||||
|
assert.True(t, os.IsNotExist(err))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestManifestIntegrationWithSBOMWithOutputDir(t *testing.T) {
|
func TestManifestIntegrationWithSBOMWithOutputDir(t *testing.T) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue