diff --git a/cmd/image-builder/export_test.go b/cmd/image-builder/export_test.go index c361adba..22c36b5b 100644 --- a/cmd/image-builder/export_test.go +++ b/cmd/image-builder/export_test.go @@ -5,11 +5,13 @@ import ( "io" "os" + "github.com/osbuild/images/pkg/distrofactory" "github.com/osbuild/images/pkg/reporegistry" ) var ( GetOneImage = getOneImage + Run = run ) func MockOsArgs(new []string) (restore func()) { @@ -49,6 +51,10 @@ func MockNewRepoRegistry(f func() (*reporegistry.RepoRegistry, error)) (restore } } -var ( - Run = run -) +func MockDistrofactoryNew(f func() *distrofactory.Factory) (restore func()) { + saved := distrofactoryNew + distrofactoryNew = f + return func() { + distrofactoryNew = saved + } +} diff --git a/cmd/image-builder/filters.go b/cmd/image-builder/filters.go index 58a89aaf..ff96253b 100644 --- a/cmd/image-builder/filters.go +++ b/cmd/image-builder/filters.go @@ -10,12 +10,15 @@ import ( "github.com/osbuild/images/pkg/imagefilter" ) +var distrofactoryNew = distrofactory.NewDefault + func newImageFilterDefault(dataDir string) (*imagefilter.ImageFilter, error) { - fac := distrofactory.NewDefault() + fac := distrofactoryNew() repos, err := newRepoRegistry(dataDir) if err != nil { return nil, err } + return imagefilter.New(fac, repos) } diff --git a/cmd/image-builder/list.go b/cmd/image-builder/list.go index 81e357ee..9bf06d94 100644 --- a/cmd/image-builder/list.go +++ b/cmd/image-builder/list.go @@ -4,8 +4,8 @@ import ( "github.com/osbuild/images/pkg/imagefilter" ) -func listImages(output string, filterExprs []string, opts *cmdlineOpts) error { - imageFilter, err := newImageFilterDefault(opts.dataDir) +func listImages(dataDir, output string, filterExprs []string) error { + imageFilter, err := newImageFilterDefault(dataDir) if err != nil { return err } @@ -19,7 +19,7 @@ func listImages(output string, filterExprs []string, opts *cmdlineOpts) error { if err != nil { return err } - if err := fmter.Output(opts.out, filteredResult); err != nil { + if err := fmter.Output(osStdout, filteredResult); err != nil { return err } diff --git a/cmd/image-builder/main.go b/cmd/image-builder/main.go index 96fe0f98..03f93eda 100644 --- a/cmd/image-builder/main.go +++ b/cmd/image-builder/main.go @@ -7,6 +7,11 @@ import ( "github.com/sirupsen/logrus" "github.com/spf13/cobra" + + "github.com/osbuild/images/pkg/arch" + "github.com/osbuild/images/pkg/blueprint" + + "github.com/osbuild/image-builder-cli/internal/manifestgen" ) var ( @@ -14,11 +19,6 @@ var ( osStderr io.Writer = os.Stderr ) -type cmdlineOpts struct { - dataDir string - out io.Writer -} - func cmdListImages(cmd *cobra.Command, args []string) error { filter, err := cmd.Flags().GetStringArray("filter") if err != nil { @@ -33,11 +33,46 @@ func cmdListImages(cmd *cobra.Command, args []string) error { return err } - opts := &cmdlineOpts{ - out: osStdout, - dataDir: dataDir, + return listImages(dataDir, output, filter) +} + +func cmdManifest(cmd *cobra.Command, args []string) error { + dataDir, err := cmd.Flags().GetString("datadir") + if err != nil { + return err + } + + distroStr := args[0] + imgTypeStr := args[1] + var archStr string + if len(args) > 2 { + archStr = args[2] + } else { + archStr = arch.Current().String() } - return listImages(output, filter, opts) + // XXX: this is not symetric, ideally we would only pass + // either a single reporegistry from a datadir everywhere + // or we would pass datadir everywhere but with just + // datadir we cannot create test distros as they cannot be + // defined outside of code so manifestgen needs to take a + // reporegistry instead of just a datadir + res, err := getOneImage(dataDir, distroStr, imgTypeStr, archStr) + if err != nil { + return err + } + repos, err := newRepoRegistry(dataDir) + if err != nil { + return err + } + // XXX: add --rpmmd/cachedir option like bib + mg, err := manifestgen.New(repos, &manifestgen.Options{ + Output: osStdout, + }) + if err != nil { + return err + } + var bp blueprint.Blueprint + return mg.Generate(&bp, res.Distro, res.ImgType, res.Arch, nil) } func run() error { @@ -69,6 +104,17 @@ operating sytsems like centos and RHEL with easy customizations support.`, listImagesCmd.Flags().String("output", "", "Output in a specific format (text, json)") rootCmd.AddCommand(listImagesCmd) + manifestCmd := &cobra.Command{ + Use: "manifest []", + Short: "Build manifest for the given distro/image-type, e.g. centos-9 qcow2", + RunE: cmdManifest, + SilenceUsage: true, + Args: cobra.MinimumNArgs(2), + Hidden: true, + } + // XXX: add blueprint switch + rootCmd.AddCommand(manifestCmd) + return rootCmd.Execute() } diff --git a/cmd/image-builder/main_test.go b/cmd/image-builder/main_test.go index 2d949e4d..4405d852 100644 --- a/cmd/image-builder/main_test.go +++ b/cmd/image-builder/main_test.go @@ -3,6 +3,7 @@ package main_test import ( "bytes" "encoding/json" + "os" "testing" "github.com/sirupsen/logrus" @@ -11,6 +12,7 @@ import ( testrepos "github.com/osbuild/images/test/data/repositories" "github.com/osbuild/image-builder-cli/cmd/image-builder" + "github.com/osbuild/image-builder-cli/internal/manifesttest" ) func init() { @@ -108,3 +110,38 @@ func TestListImagesOverrideDatadir(t *testing.T) { err := main.Run() assert.EqualError(t, err, `no repositories found in the given paths: [/this/path/does/not/exist]`) } + +func hasDepsolveDnf() bool { + // XXX: expose images/pkg/depsolve:findDepsolveDnf() + _, err := os.Stat("/usr/libexec/osbuild-depsolve-dnf") + return err == nil +} + +// XXX: move to pytest like bib maybe? +func TestManifestIntegrationSmoke(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() + + restore = main.MockOsArgs([]string{ + "manifest", "centos-9", "qcow2"}, + ) + defer restore() + + var fakeStdout bytes.Buffer + restore = main.MockOsStdout(&fakeStdout) + defer restore() + + err := main.Run() + assert.NoError(t, err) + + pipelineNames, err := manifesttest.PipelineNamesFrom(fakeStdout.Bytes()) + assert.NoError(t, err) + assert.Contains(t, pipelineNames, "qcow2") +}