|
Packit Service |
15f37d |
package osbuild2
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
import (
|
|
Packit Service |
15f37d |
"bytes"
|
|
Packit Service |
15f37d |
"encoding/json"
|
|
Packit Service |
15f37d |
"fmt"
|
|
Packit Service |
15f37d |
"regexp"
|
|
Packit Service |
15f37d |
"sort"
|
|
Packit Service |
15f37d |
)
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
type OCIArchiveStageOptions struct {
|
|
Packit Service |
15f37d |
// The CPU architecture of the image
|
|
Packit Service |
15f37d |
Architecture string `json:"architecture"`
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
// Resulting image filename
|
|
Packit Service |
15f37d |
Filename string `json:"filename"`
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
// The execution parameters
|
|
Packit Service |
15f37d |
Config *OCIArchiveConfig `json:"config,omitempty"`
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
type OCIArchiveConfig struct {
|
|
Packit Service |
15f37d |
Cmd []string `json:"Cmd,omitempty"`
|
|
Packit Service |
15f37d |
Env []string `json:"Env,omitempty"`
|
|
Packit Service |
15f37d |
ExposedPorts []string `json:"ExposedPorts,omitempty"`
|
|
Packit Service |
15f37d |
User string `json:"User,omitempty"`
|
|
Packit Service |
15f37d |
Labels map[string]string `json:"Labels,omitempty"`
|
|
Packit Service |
15f37d |
StopSignal string `json:"StopSignal,omitempty"`
|
|
Packit Service |
15f37d |
Volumes []string `json:"Volumes,omitempty"`
|
|
Packit Service |
15f37d |
WorkingDir string `json:"WorkingDir,omitempty"`
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
func (OCIArchiveStageOptions) isStageOptions() {}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
type OCIArchiveStageInputs struct {
|
|
Packit Service |
15f37d |
// Base layer for the container
|
|
Packit Service |
15f37d |
Base *OCIArchiveStageInput `json:"base"`
|
|
Packit Service |
15f37d |
// Additional layers in ascending order
|
|
Packit Service |
15f37d |
Layers []OCIArchiveStageInput `json:",omitempty"`
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
func (OCIArchiveStageInputs) isStageInputs() {}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
type OCIArchiveStageInput struct {
|
|
Packit Service |
15f37d |
inputCommon
|
|
Packit Service |
15f37d |
References OCIArchiveStageReferences `json:"references"`
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
func (OCIArchiveStageInput) isStageInput() {}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
type OCIArchiveStageReferences []string
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
func (OCIArchiveStageReferences) isReferences() {}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
// A new OCIArchiveStage to to assemble an OCI image archive
|
|
Packit Service |
15f37d |
func NewOCIArchiveStage(options *OCIArchiveStageOptions, inputs *OCIArchiveStageInputs) *Stage {
|
|
Packit Service |
15f37d |
return &Stage{
|
|
Packit Service |
15f37d |
Type: "org.osbuild.oci-archive",
|
|
Packit Service |
15f37d |
Options: options,
|
|
Packit Service |
15f37d |
Inputs: inputs,
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
// Custom marshaller for OCIArchiveStageInputs, needed to generate keys of the
|
|
Packit Service |
15f37d |
// form "layer.N", (where N = 1, 2, ...) for the Layers property
|
|
Packit Service |
15f37d |
func (inputs *OCIArchiveStageInputs) MarshalJSON() ([]byte, error) {
|
|
Packit Service |
15f37d |
if inputs == nil {
|
|
Packit Service |
15f37d |
return json.Marshal(inputs)
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
layers := inputs.Layers
|
|
Packit Service |
15f37d |
inputsMap := make(map[string]OCIArchiveStageInput, len(layers)+1)
|
|
Packit Service |
15f37d |
if inputs.Base != nil {
|
|
Packit Service |
15f37d |
inputsMap["base"] = *inputs.Base
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
for idx, input := range layers {
|
|
Packit Service |
15f37d |
key := fmt.Sprintf("layer.%d", idx+1)
|
|
Packit Service |
15f37d |
inputsMap[key] = input
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
return json.Marshal(inputsMap)
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
// Get the sorted keys that match the pattern "layer.N" (for N > 0)
|
|
Packit Service |
15f37d |
func layerKeys(layers map[string]OCIArchiveStageInput) ([]string, error) {
|
|
Packit Service |
15f37d |
keys := make([]string, 0, len(layers))
|
|
Packit Service |
15f37d |
for key := range layers {
|
|
Packit Service |
15f37d |
re := regexp.MustCompile(`layer\.[1-9]\d*`)
|
|
Packit Service |
15f37d |
if key == "base" {
|
|
Packit Service |
15f37d |
continue
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
if !re.MatchString(key) {
|
|
Packit Service |
15f37d |
return nil, fmt.Errorf("invalid key: %q", key)
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
keys = append(keys, key)
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
sort.Strings(keys)
|
|
Packit Service |
15f37d |
return keys, nil
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
// Custom unmarshaller for OCIArchiveStageInputs, needed to handle keys of the
|
|
Packit Service |
15f37d |
// form "layer.N", (where N = 1, 2, ...) for the Layers property
|
|
Packit Service |
15f37d |
func (inputs *OCIArchiveStageInputs) UnmarshalJSON(data []byte) error {
|
|
Packit Service |
15f37d |
if len(data) == 0 {
|
|
Packit Service |
15f37d |
return nil
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
if inputs == nil {
|
|
Packit Service |
15f37d |
inputs = new(OCIArchiveStageInputs)
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
inputsMap := make(map[string]OCIArchiveStageInput)
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
dec := json.NewDecoder(bytes.NewReader(data))
|
|
Packit Service |
15f37d |
dec.DisallowUnknownFields()
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
if err := dec.Decode(&inputsMap); err != nil {
|
|
Packit Service |
15f37d |
return err
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
// "base" layer is required
|
|
Packit Service |
15f37d |
base, ok := inputsMap["base"]
|
|
Packit Service |
15f37d |
if !ok {
|
|
Packit Service |
15f37d |
return fmt.Errorf("missing required key \"base\"")
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
inputs.Base = &base
|
|
Packit Service |
15f37d |
keys, err := layerKeys(inputsMap)
|
|
Packit Service |
15f37d |
if err != nil {
|
|
Packit Service |
15f37d |
return err
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
inputs.Layers = make([]OCIArchiveStageInput, len(inputsMap)-1)
|
|
Packit Service |
15f37d |
for idx, key := range keys {
|
|
Packit Service |
15f37d |
inputs.Layers[idx] = inputsMap[key]
|
|
Packit Service |
15f37d |
}
|
|
Packit Service |
15f37d |
|
|
Packit Service |
15f37d |
return nil
|
|
Packit Service |
15f37d |
}
|