Allow manifests to be instantiated without providing packageSpecs. This allows manifests without packageSpecs to be introspected, but not serialized. The only reason we used to require packegaSpecs to be passed at instantiation time was to compute the kernelVer based on the kernelName and the NEVRAs in the package set. Now move this to be done at serialize time. This means that in order to serialize a manifest, you need to pass the packageSpecs at initialization time, but if you don't need to serialize, only to introspect it, then you don't need to pass it at all. In a future patch packageSpecs will be passed at serialization time to not have to make that commitment up front. The new logic is now that before a pipeline can be serialized, all the pipelines in the manifest must be "prepared" for serialization by calling serialize_start() on each of them, which does whatever would in the past have been done at initialization time which required the pacakgeSpecs. Once serialization has been finished serialize_end() must be called on each of the pipelines to undo any of the preparation, making sure we can serialize repeatedly, possibly while changing the fields of our pipeline in-between, and that serialization appears from the outside to not have any side-effects. In a future PR we may want to rework this logic to instead use a serialization context.
107 lines
3.3 KiB
Go
107 lines
3.3 KiB
Go
// Package manifest implements a standard set of osbuild pipelines. A pipeline
|
|
// conceptually represents a named filesystem tree, optionally generated
|
|
// in a provided build root (represented by another pipeline). All inputs
|
|
// to a pipeline must be explicitly specified, either in terms of other
|
|
// pipeline, in terms of content addressable inputs or in terms of static
|
|
// parameters to the inherited Pipeline structs.
|
|
package manifest
|
|
|
|
import (
|
|
"github.com/osbuild/osbuild-composer/internal/osbuild2"
|
|
"github.com/osbuild/osbuild-composer/internal/rpmmd"
|
|
)
|
|
|
|
type Pipeline interface {
|
|
Name() string
|
|
getBuildPackages() []string
|
|
getPackageSetChain() []rpmmd.PackageSet
|
|
serializeStart()
|
|
serializeEnd()
|
|
serialize() osbuild2.Pipeline
|
|
getPackageSpecs() []rpmmd.PackageSpec
|
|
getOSTreeCommits() []osTreeCommit
|
|
getInline() []string
|
|
}
|
|
|
|
// A BasePipeline represents the core functionality shared between each of the pipeline
|
|
// implementations, and the BasePipeline struct must be embedded in each of them.
|
|
type BasePipeline struct {
|
|
name string
|
|
runner string
|
|
build *BuildPipeline
|
|
}
|
|
|
|
// Name returns the name of the pipeline. The name must be unique for a given manifest.
|
|
// Pipeline names are used to refer to pipelines either as dependencies between pipelines
|
|
// or for exporting them.
|
|
func (p BasePipeline) Name() string {
|
|
return p.name
|
|
}
|
|
|
|
func (p BasePipeline) getBuildPackages() []string {
|
|
return []string{}
|
|
}
|
|
|
|
func (p BasePipeline) getPackageSetChain() []rpmmd.PackageSet {
|
|
return []rpmmd.PackageSet{}
|
|
}
|
|
|
|
func (p BasePipeline) getPackageSpecs() []rpmmd.PackageSpec {
|
|
return []rpmmd.PackageSpec{}
|
|
}
|
|
|
|
func (p BasePipeline) getOSTreeCommits() []osTreeCommit {
|
|
return []osTreeCommit{}
|
|
}
|
|
|
|
func (p BasePipeline) getInline() []string {
|
|
return []string{}
|
|
}
|
|
|
|
// NewBasePipeline returns a generic Pipeline object. The name is mandatory, immutable and must
|
|
// be unique among all the pipelines used in a manifest, which is currently not enforced.
|
|
// The build argument is a pipeline representing a build root in which the rest of the
|
|
// pipeline is built. In order to ensure reproducibility a build pipeline must always be
|
|
// provided, except for int he build pipeline itself. When a build pipeline is not provided
|
|
// the build host's filesystem is used as the build root, and in this case a runner must be
|
|
// specified which knows how to interpret the host filesystem as a build root.
|
|
func NewBasePipeline(name string, build *BuildPipeline, runner *string) BasePipeline {
|
|
p := BasePipeline{
|
|
name: name,
|
|
build: build,
|
|
}
|
|
if runner != nil {
|
|
if build != nil {
|
|
panic("both runner and build pipeline specified")
|
|
}
|
|
p.runner = *runner
|
|
} else if build == nil {
|
|
panic("neither build pipeline nor runner specified")
|
|
}
|
|
return p
|
|
}
|
|
|
|
// serializeStart must be called exactly once before each call
|
|
// to serialize().
|
|
func (p BasePipeline) serializeStart() {
|
|
}
|
|
|
|
// serializeEnd must be called exactly once after each call to
|
|
// serialize().
|
|
func (p BasePipeline) serializeEnd() {
|
|
}
|
|
|
|
// Serialize turns a given pipeline into an osbuild2.Pipeline object. This object is
|
|
// meant to be treated as opaque and not to be modified further outside of the pipeline
|
|
// package.
|
|
func (p BasePipeline) serialize() osbuild2.Pipeline {
|
|
var buildName string
|
|
if p.build != nil {
|
|
buildName = "name:" + p.build.Name()
|
|
}
|
|
return osbuild2.Pipeline{
|
|
Name: p.name,
|
|
Runner: p.runner,
|
|
Build: buildName,
|
|
}
|
|
}
|