package main import ( "encoding/json" "flag" "fmt" "io" "io/ioutil" "os" "path" "github.com/osbuild/osbuild-composer/internal/distro/fedora32" "github.com/osbuild/osbuild-composer/internal/distro/fedora33" "github.com/osbuild/osbuild-composer/internal/distro/rhel8" "github.com/osbuild/osbuild-composer/internal/distro/rhel84" "github.com/osbuild/osbuild-composer/internal/blueprint" "github.com/osbuild/osbuild-composer/internal/distro" "github.com/osbuild/osbuild-composer/internal/rpmmd" ) type repository struct { BaseURL string `json:"baseurl,omitempty"` Metalink string `json:"metalink,omitempty"` MirrorList string `json:"mirrorlist,omitempty"` GPGKey string `json:"gpgkey,omitempty"` CheckGPG bool `json:"check_gpg,omitempty"` } type composeRequest struct { Distro string `json:"distro"` Arch string `json:"arch"` ImageType string `json:"image-type"` Blueprint blueprint.Blueprint `json:"blueprint"` Repositories []repository `json:"repositories"` } func main() { var rpmmdArg bool flag.BoolVar(&rpmmdArg, "rpmmd", false, "output rpmmd struct instead of pipeline manifest") var seedArg int64 flag.Int64Var(&seedArg, "seed", 0, "seed for generating manifests (default: 0)") flag.Parse() // Path to composeRequet or '-' for stdin composeRequestArg := flag.Arg(0) composeRequest := &composeRequest{} if composeRequestArg != "" { var reader io.Reader if composeRequestArg == "-" { reader = os.Stdin } else { var err error reader, err = os.Open(composeRequestArg) if err != nil { panic("Could not open compose request: " + err.Error()) } } file, err := ioutil.ReadAll(reader) if err != nil { panic("Could not read compose request: " + err.Error()) } err = json.Unmarshal(file, &composeRequest) if err != nil { panic("Could not parse blueprint: " + err.Error()) } } distros, err := distro.NewRegistry(fedora32.New(), fedora33.New(), rhel8.New(), rhel84.New(), rhel84.NewCentos()) if err != nil { panic(err) } d := distros.GetDistro(composeRequest.Distro) if d == nil { _, _ = fmt.Fprintf(os.Stderr, "The provided distribution '%s' is not supported. Use one of these:\n", composeRequest.Distro) for _, d := range distros.List() { _, _ = fmt.Fprintln(os.Stderr, " *", d) } return } arch, err := d.GetArch(composeRequest.Arch) if err != nil { fmt.Fprintf(os.Stderr, "The provided architecture '%s' is not supported by %s. Use one of these:\n", composeRequest.Arch, d.Name()) for _, a := range d.ListArches() { _, _ = fmt.Fprintln(os.Stderr, " *", a) } return } imageType, err := arch.GetImageType(composeRequest.ImageType) if err != nil { fmt.Fprintf(os.Stderr, "The provided image type '%s' is not supported by %s for %s. Use one of these:\n", composeRequest.ImageType, d.Name(), arch.Name()) for _, t := range arch.ListImageTypes() { _, _ = fmt.Fprintln(os.Stderr, " *", t) } return } repos := make([]rpmmd.RepoConfig, len(composeRequest.Repositories)) for i, repo := range composeRequest.Repositories { repos[i] = rpmmd.RepoConfig{ Name: fmt.Sprintf("repo-%d", i), BaseURL: repo.BaseURL, Metalink: repo.Metalink, MirrorList: repo.MirrorList, GPGKey: repo.GPGKey, CheckGPG: repo.CheckGPG, } } packageSets := imageType.PackageSets(composeRequest.Blueprint) home, err := os.UserHomeDir() if err != nil { panic("os.UserHomeDir(): " + err.Error()) } rpm_md := rpmmd.NewRPMMD(path.Join(home, ".cache/osbuild-composer/rpmmd"), "/usr/libexec/osbuild-composer/dnf-json") packageSpecSets := make(map[string][]rpmmd.PackageSpec) for name, packages := range packageSets { packageSpecs, _, err := rpm_md.Depsolve(packages, repos, d.ModulePlatformID(), arch.Name()) if err != nil { panic("Could not depsolve: " + err.Error()) } packageSpecSets[name] = packageSpecs } var bytes []byte if rpmmdArg { bytes, err = json.Marshal(packageSpecSets) if err != nil { panic(err) } } else { manifest, err := imageType.Manifest(composeRequest.Blueprint.Customizations, distro.ImageOptions{ Size: imageType.Size(0), OSTree: distro.OSTreeImageOptions{ Ref: imageType.OSTreeRef(), // use default OSTreeRef for image type }, }, repos, packageSpecSets, seedArg) if err != nil { panic(err.Error()) } bytes, err = json.Marshal(manifest) if err != nil { panic(err) } } os.Stdout.Write(bytes) }