diff --git a/cmd/build/main.go b/cmd/build/main.go index eedeb348e..b64cef3ec 100644 --- a/cmd/build/main.go +++ b/cmd/build/main.go @@ -144,6 +144,9 @@ func depsolve(cacheDir string, packageSets map[string][]rpmmd.PackageSet, d dist } func save(ms manifest.OSBuildManifest, fpath string) error { + if err := os.MkdirAll(filepath.Dir(fpath), 0777); err != nil { + return fmt.Errorf("cannot save manifest: %w", err) + } b, err := json.MarshalIndent(ms, "", " ") if err != nil { return fmt.Errorf("failed to marshal data for %q: %s\n", fpath, err.Error()) @@ -183,24 +186,28 @@ func filterRepos(repos []rpmmd.RepoConfig, typeName string) []rpmmd.RepoConfig { func run() error { // common args - var outputDir, osbuildStore, rpmCacheRoot string + var outputDir, osbuildStore, rpmCacheRoot, manifestPath string + var manifestOnly bool flag.StringVar(&outputDir, "output", ".", "artifact output directory") flag.StringVar(&osbuildStore, "store", ".osbuild", "osbuild store for intermediate pipeline trees") flag.StringVar(&rpmCacheRoot, "rpmmd", "/tmp/rpmmd", "rpm metadata cache directory") + flag.BoolVar(&manifestOnly, "manifest-only", false, "only build the manifest, do not run osbuild") + flag.StringVar(&manifestPath, "manifest-path", "", "write manifest to the give path") // osbuild checkpoint arg var checkpoints cmdutil.MultiValue flag.Var(&checkpoints, "checkpoints", "comma-separated list of pipeline names to checkpoint (passed to osbuild --checkpoint)") // image selection args - var distroName, imgTypeName, configFile string + var distroName, imgTypeName, configFile, targetArch string flag.StringVar(&distroName, "distro", "", "distribution (required)") flag.StringVar(&imgTypeName, "type", "", "image type name (required)") - flag.StringVar(&configFile, "config", "", "build config file (required)") + flag.StringVar(&configFile, "config", "", "build config file") + flag.StringVar(&targetArch, "target-arch", "", "target architecture to use, mostly for -manifest-only") flag.Parse() - if distroName == "" || imgTypeName == "" || configFile == "" { + if distroName == "" || imgTypeName == "" { flag.Usage() os.Exit(1) } @@ -211,13 +218,14 @@ func run() error { } distroFac := distrofactory.NewDefault() - config, err := buildconfig.New(configFile) - if err != nil { - return err - } - - if err := os.MkdirAll(outputDir, 0777); err != nil { - return fmt.Errorf("failed to create target directory: %s", err.Error()) + var config *buildconfig.BuildConfig + if configFile != "" { + config, err = buildconfig.New(configFile) + if err != nil { + return err + } + } else { + config = &buildconfig.BuildConfig{} } distribution := distroFac.GetDistro(distroName) @@ -225,18 +233,17 @@ func run() error { return fmt.Errorf("invalid or unsupported distribution: %q", distroName) } - archName := arch.Current().String() + var archName string + if targetArch != "" { + archName = targetArch + } else { + archName = arch.Current().String() + } arch, err := distribution.GetArch(archName) if err != nil { return fmt.Errorf("invalid arch name %q for distro %q: %s\n", archName, distroName, err.Error()) } - buildName := fmt.Sprintf("%s-%s-%s-%s", u(distroName), u(archName), u(imgTypeName), u(config.Name)) - buildDir := filepath.Join(outputDir, buildName) - if err := os.MkdirAll(buildDir, 0777); err != nil { - return fmt.Errorf("failed to create target directory: %s", err.Error()) - } - imgType, err := arch.GetImageType(imgTypeName) if err != nil { return fmt.Errorf("invalid image type %q for distro %q and arch %q: %s\n", imgTypeName, distroName, archName, err.Error()) @@ -252,21 +259,36 @@ func run() error { return fmt.Errorf("no repositories defined for %s/%s\n", distroName, archName) } - fmt.Printf("Generating manifest for %s: ", config.Name) + fmt.Printf("Generating manifest for %s", config.Name) mf, err := makeManifest(config, imgType, distribution, repos, archName, rpmCacheRoot) if err != nil { return err } fmt.Print("DONE\n") - manifestPath := filepath.Join(buildDir, "manifest.json") + buildName := fmt.Sprintf("%s-%s-%s-%s", u(distroName), u(archName), u(imgTypeName), u(config.Name)) + if manifestPath == "" { + buildDir := filepath.Join(outputDir, buildName) + manifestPath = filepath.Join(buildDir, "manifest.json") + } if err := save(mf, manifestPath); err != nil { return err } + if manifestOnly { + return nil + } fmt.Printf("Building manifest: %s\n", manifestPath) jobOutput := filepath.Join(outputDir, buildName) + if err := os.MkdirAll(jobOutput, 0777); err != nil { + return fmt.Errorf("failed to create output directory: %w", err) + } + buildDir := filepath.Join(outputDir, buildName) + if err := os.MkdirAll(buildDir, 0777); err != nil { + return fmt.Errorf("failed to create target directory: %w", err) + } + _, err = osbuild.RunOSBuild(mf, osbuildStore, jobOutput, imgType.Exports(), checkpoints, nil, false, os.Stderr) if err != nil { return err