summaryrefslogtreecommitdiffstats
path: root/config.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 17:12:05 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 17:12:05 +0000
commit9ec46d47bedefa10bdaaa8a587ddb1851ef396ec (patch)
treeba7545ee99b384a6fc3e5ea028ae4c643648d683 /config.go
parentInitial commit. (diff)
downloadgolang-github-containers-buildah-9ec46d47bedefa10bdaaa8a587ddb1851ef396ec.tar.xz
golang-github-containers-buildah-9ec46d47bedefa10bdaaa8a587ddb1851ef396ec.zip
Adding upstream version 1.33.5+ds1.upstream/1.33.5+ds1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'config.go')
-rw-r--r--config.go747
1 files changed, 747 insertions, 0 deletions
diff --git a/config.go b/config.go
new file mode 100644
index 0000000..3a287c7
--- /dev/null
+++ b/config.go
@@ -0,0 +1,747 @@
+package buildah
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "os"
+ "runtime"
+ "strings"
+ "time"
+
+ "github.com/containers/buildah/define"
+ "github.com/containers/buildah/docker"
+ internalUtil "github.com/containers/buildah/internal/util"
+ "github.com/containers/common/pkg/util"
+ "github.com/containers/image/v5/manifest"
+ "github.com/containers/image/v5/pkg/compression"
+ "github.com/containers/image/v5/transports"
+ "github.com/containers/image/v5/types"
+ "github.com/containers/storage/pkg/stringid"
+ ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/sirupsen/logrus"
+)
+
+// unmarshalConvertedConfig obtains the config blob of img valid for the wantedManifestMIMEType format
+// (either as it exists, or converting the image if necessary), and unmarshals it into dest.
+// NOTE: The MIME type is of the _manifest_, not of the _config_ that is returned.
+func unmarshalConvertedConfig(ctx context.Context, dest interface{}, img types.Image, wantedManifestMIMEType string) error {
+ _, actualManifestMIMEType, err := img.Manifest(ctx)
+ if err != nil {
+ return fmt.Errorf("getting manifest MIME type for %q: %w", transports.ImageName(img.Reference()), err)
+ }
+ if wantedManifestMIMEType != actualManifestMIMEType {
+ layerInfos := img.LayerInfos()
+ for i := range layerInfos { // force the "compression" to gzip, which is supported by all of the formats we care about
+ layerInfos[i].CompressionOperation = types.Compress
+ layerInfos[i].CompressionAlgorithm = &compression.Gzip
+ }
+ updatedImg, err := img.UpdatedImage(ctx, types.ManifestUpdateOptions{
+ LayerInfos: layerInfos,
+ })
+ if err != nil {
+ return fmt.Errorf("resetting recorded compression for %q: %w", transports.ImageName(img.Reference()), err)
+ }
+ secondUpdatedImg, err := updatedImg.UpdatedImage(ctx, types.ManifestUpdateOptions{
+ ManifestMIMEType: wantedManifestMIMEType,
+ })
+ if err != nil {
+ return fmt.Errorf("converting image %q from %q to %q: %w", transports.ImageName(img.Reference()), actualManifestMIMEType, wantedManifestMIMEType, err)
+ }
+ img = secondUpdatedImg
+ }
+ config, err := img.ConfigBlob(ctx)
+ if err != nil {
+ return fmt.Errorf("reading %s config from %q: %w", wantedManifestMIMEType, transports.ImageName(img.Reference()), err)
+ }
+ if err := json.Unmarshal(config, dest); err != nil {
+ return fmt.Errorf("parsing %s configuration %q from %q: %w", wantedManifestMIMEType, string(config), transports.ImageName(img.Reference()), err)
+ }
+ return nil
+}
+
+func (b *Builder) initConfig(ctx context.Context, img types.Image, sys *types.SystemContext) error {
+ if img != nil { // A pre-existing image, as opposed to a "FROM scratch" new one.
+ rawManifest, manifestMIMEType, err := img.Manifest(ctx)
+ if err != nil {
+ return fmt.Errorf("reading image manifest for %q: %w", transports.ImageName(img.Reference()), err)
+ }
+ rawConfig, err := img.ConfigBlob(ctx)
+ if err != nil {
+ return fmt.Errorf("reading image configuration for %q: %w", transports.ImageName(img.Reference()), err)
+ }
+ b.Manifest = rawManifest
+ b.Config = rawConfig
+
+ dimage := docker.V2Image{}
+ if err := unmarshalConvertedConfig(ctx, &dimage, img, manifest.DockerV2Schema2MediaType); err != nil {
+ return err
+ }
+ b.Docker = dimage
+
+ oimage := ociv1.Image{}
+ if err := unmarshalConvertedConfig(ctx, &oimage, img, ociv1.MediaTypeImageManifest); err != nil {
+ return err
+ }
+ b.OCIv1 = oimage
+
+ if manifestMIMEType == ociv1.MediaTypeImageManifest {
+ // Attempt to recover format-specific data from the manifest.
+ v1Manifest := ociv1.Manifest{}
+ if err := json.Unmarshal(b.Manifest, &v1Manifest); err != nil {
+ return fmt.Errorf("parsing OCI manifest %q: %w", string(b.Manifest), err)
+ }
+ for k, v := range v1Manifest.Annotations {
+ b.ImageAnnotations[k] = v
+ }
+ }
+ }
+
+ b.setupLogger()
+ b.fixupConfig(sys)
+ return nil
+}
+
+func (b *Builder) fixupConfig(sys *types.SystemContext) {
+ if b.Docker.Config != nil {
+ // Prefer image-level settings over those from the container it was built from.
+ b.Docker.ContainerConfig = *b.Docker.Config
+ }
+ b.Docker.Config = &b.Docker.ContainerConfig
+ b.Docker.DockerVersion = ""
+ now := time.Now().UTC()
+ if b.Docker.Created.IsZero() {
+ b.Docker.Created = now
+ }
+ if b.OCIv1.Created == nil || b.OCIv1.Created.IsZero() {
+ b.OCIv1.Created = &now
+ }
+ if b.OS() == "" {
+ if sys != nil && sys.OSChoice != "" {
+ b.SetOS(sys.OSChoice)
+ } else {
+ b.SetOS(runtime.GOOS)
+ }
+ }
+ if b.Architecture() == "" {
+ if sys != nil && sys.ArchitectureChoice != "" {
+ b.SetArchitecture(sys.ArchitectureChoice)
+ } else {
+ b.SetArchitecture(runtime.GOARCH)
+ }
+ // in case the arch string we started with was shorthand for a known arch+variant pair, normalize it
+ ps := internalUtil.NormalizePlatform(ociv1.Platform{OS: b.OS(), Architecture: b.Architecture(), Variant: b.Variant()})
+ b.SetArchitecture(ps.Architecture)
+ b.SetVariant(ps.Variant)
+ }
+ if b.Variant() == "" {
+ if sys != nil && sys.VariantChoice != "" {
+ b.SetVariant(sys.VariantChoice)
+ }
+ // in case the arch string we started with was shorthand for a known arch+variant pair, normalize it
+ ps := internalUtil.NormalizePlatform(ociv1.Platform{OS: b.OS(), Architecture: b.Architecture(), Variant: b.Variant()})
+ b.SetArchitecture(ps.Architecture)
+ b.SetVariant(ps.Variant)
+ }
+ if b.Format == define.Dockerv2ImageManifest && b.Hostname() == "" {
+ b.SetHostname(stringid.TruncateID(stringid.GenerateRandomID()))
+ }
+}
+
+func (b *Builder) setupLogger() {
+ if b.Logger == nil {
+ b.Logger = logrus.New()
+ b.Logger.SetOutput(os.Stderr)
+ b.Logger.SetLevel(logrus.GetLevel())
+ }
+}
+
+// Annotations returns a set of key-value pairs from the image's manifest.
+func (b *Builder) Annotations() map[string]string {
+ return copyStringStringMap(b.ImageAnnotations)
+}
+
+// SetAnnotation adds or overwrites a key's value from the image's manifest.
+// Note: this setting is not present in the Docker v2 image format, so it is
+// discarded when writing images using Docker v2 formats.
+func (b *Builder) SetAnnotation(key, value string) {
+ if b.ImageAnnotations == nil {
+ b.ImageAnnotations = map[string]string{}
+ }
+ b.ImageAnnotations[key] = value
+}
+
+// UnsetAnnotation removes a key and its value from the image's manifest, if
+// it's present.
+func (b *Builder) UnsetAnnotation(key string) {
+ delete(b.ImageAnnotations, key)
+}
+
+// ClearAnnotations removes all keys and their values from the image's
+// manifest.
+func (b *Builder) ClearAnnotations() {
+ b.ImageAnnotations = map[string]string{}
+}
+
+// CreatedBy returns a description of how this image was built.
+func (b *Builder) CreatedBy() string {
+ return b.ImageCreatedBy
+}
+
+// SetCreatedBy sets the description of how this image was built.
+func (b *Builder) SetCreatedBy(how string) {
+ b.ImageCreatedBy = how
+}
+
+// OS returns a name of the OS on which the container, or a container built
+// using an image built from this container, is intended to be run.
+func (b *Builder) OS() string {
+ return b.OCIv1.OS
+}
+
+// SetOS sets the name of the OS on which the container, or a container built
+// using an image built from this container, is intended to be run.
+func (b *Builder) SetOS(os string) {
+ b.OCIv1.OS = os
+ b.Docker.OS = os
+}
+
+// OSVersion returns a version of the OS on which the container, or a container
+// built using an image built from this container, is intended to be run.
+func (b *Builder) OSVersion() string {
+ return b.OCIv1.OSVersion
+}
+
+// SetOSVersion sets the version of the OS on which the container, or a
+// container built using an image built from this container, is intended to be
+// run.
+func (b *Builder) SetOSVersion(version string) {
+ b.OCIv1.OSVersion = version
+ b.Docker.OSVersion = version
+}
+
+// OSFeatures returns a list of OS features which the container, or a container
+// built using an image built from this container, depends on the OS supplying.
+func (b *Builder) OSFeatures() []string {
+ return copyStringSlice(b.OCIv1.OSFeatures)
+}
+
+// SetOSFeature adds a feature of the OS which the container, or a container
+// built using an image built from this container, depends on the OS supplying.
+func (b *Builder) SetOSFeature(feature string) {
+ if !util.StringInSlice(feature, b.OCIv1.OSFeatures) {
+ b.OCIv1.OSFeatures = append(b.OCIv1.OSFeatures, feature)
+ }
+ if !util.StringInSlice(feature, b.Docker.OSFeatures) {
+ b.Docker.OSFeatures = append(b.Docker.OSFeatures, feature)
+ }
+}
+
+// UnsetOSFeature removes a feature of the OS which the container, or a
+// container built using an image built from this container, depends on the OS
+// supplying.
+func (b *Builder) UnsetOSFeature(feature string) {
+ if util.StringInSlice(feature, b.OCIv1.OSFeatures) {
+ features := make([]string, 0, len(b.OCIv1.OSFeatures))
+ for _, f := range b.OCIv1.OSFeatures {
+ if f != feature {
+ features = append(features, f)
+ }
+ }
+ b.OCIv1.OSFeatures = features
+ }
+ if util.StringInSlice(feature, b.Docker.OSFeatures) {
+ features := make([]string, 0, len(b.Docker.OSFeatures))
+ for _, f := range b.Docker.OSFeatures {
+ if f != feature {
+ features = append(features, f)
+ }
+ }
+ b.Docker.OSFeatures = features
+ }
+}
+
+// ClearOSFeatures clears the list of features of the OS which the container,
+// or a container built using an image built from this container, depends on
+// the OS supplying.
+func (b *Builder) ClearOSFeatures() {
+ b.OCIv1.OSFeatures = []string{}
+ b.Docker.OSFeatures = []string{}
+}
+
+// Architecture returns a name of the architecture on which the container, or a
+// container built using an image built from this container, is intended to be
+// run.
+func (b *Builder) Architecture() string {
+ return b.OCIv1.Architecture
+}
+
+// SetArchitecture sets the name of the architecture on which the container, or
+// a container built using an image built from this container, is intended to
+// be run.
+func (b *Builder) SetArchitecture(arch string) {
+ b.OCIv1.Architecture = arch
+ b.Docker.Architecture = arch
+}
+
+// Variant returns a name of the architecture variant on which the container,
+// or a container built using an image built from this container, is intended
+// to be run.
+func (b *Builder) Variant() string {
+ return b.OCIv1.Variant
+}
+
+// SetVariant sets the name of the architecture variant on which the container,
+// or a container built using an image built from this container, is intended
+// to be run.
+func (b *Builder) SetVariant(variant string) {
+ b.Docker.Variant = variant
+ b.OCIv1.Variant = variant
+}
+
+// Maintainer returns contact information for the person who built the image.
+func (b *Builder) Maintainer() string {
+ return b.OCIv1.Author
+}
+
+// SetMaintainer sets contact information for the person who built the image.
+func (b *Builder) SetMaintainer(who string) {
+ b.OCIv1.Author = who
+ b.Docker.Author = who
+}
+
+// User returns information about the user as whom the container, or a
+// container built using an image built from this container, should be run.
+func (b *Builder) User() string {
+ return b.OCIv1.Config.User
+}
+
+// SetUser sets information about the user as whom the container, or a
+// container built using an image built from this container, should be run.
+// Acceptable forms are a user name or ID, optionally followed by a colon and a
+// group name or ID.
+func (b *Builder) SetUser(spec string) {
+ b.OCIv1.Config.User = spec
+ b.Docker.Config.User = spec
+}
+
+// OnBuild returns the OnBuild value from the container.
+func (b *Builder) OnBuild() []string {
+ return copyStringSlice(b.Docker.Config.OnBuild)
+}
+
+// ClearOnBuild removes all values from the OnBuild structure
+func (b *Builder) ClearOnBuild() {
+ b.Docker.Config.OnBuild = []string{}
+}
+
+// SetOnBuild sets a trigger instruction to be executed when the image is used
+// as the base of another image.
+// Note: this setting is not present in the OCIv1 image format, so it is
+// discarded when writing images using OCIv1 formats.
+func (b *Builder) SetOnBuild(onBuild string) {
+ if onBuild != "" && b.Format != define.Dockerv2ImageManifest {
+ b.Logger.Warnf("ONBUILD is not supported for OCI image format, %s will be ignored. Must use `docker` format", onBuild)
+ }
+ b.Docker.Config.OnBuild = append(b.Docker.Config.OnBuild, onBuild)
+}
+
+// WorkDir returns the default working directory for running commands in the
+// container, or in a container built using an image built from this container.
+func (b *Builder) WorkDir() string {
+ return b.OCIv1.Config.WorkingDir
+}
+
+// SetWorkDir sets the location of the default working directory for running
+// commands in the container, or in a container built using an image built from
+// this container.
+func (b *Builder) SetWorkDir(there string) {
+ b.OCIv1.Config.WorkingDir = there
+ b.Docker.Config.WorkingDir = there
+}
+
+// Shell returns the default shell for running commands in the
+// container, or in a container built using an image built from this container.
+func (b *Builder) Shell() []string {
+ return copyStringSlice(b.Docker.Config.Shell)
+}
+
+// SetShell sets the default shell for running
+// commands in the container, or in a container built using an image built from
+// this container.
+// Note: this setting is not present in the OCIv1 image format, so it is
+// discarded when writing images using OCIv1 formats.
+func (b *Builder) SetShell(shell []string) {
+ if len(shell) > 0 && b.Format != define.Dockerv2ImageManifest {
+ b.Logger.Warnf("SHELL is not supported for OCI image format, %s will be ignored. Must use `docker` format", shell)
+ }
+
+ b.Docker.Config.Shell = copyStringSlice(shell)
+}
+
+// Env returns a list of key-value pairs to be set when running commands in the
+// container, or in a container built using an image built from this container.
+func (b *Builder) Env() []string {
+ return copyStringSlice(b.OCIv1.Config.Env)
+}
+
+// SetEnv adds or overwrites a value to the set of environment strings which
+// should be set when running commands in the container, or in a container
+// built using an image built from this container.
+func (b *Builder) SetEnv(k string, v string) {
+ reset := func(s *[]string) {
+ n := []string{}
+ for i := range *s {
+ if !strings.HasPrefix((*s)[i], k+"=") {
+ n = append(n, (*s)[i])
+ }
+ }
+ n = append(n, k+"="+v)
+ *s = n
+ }
+ reset(&b.OCIv1.Config.Env)
+ reset(&b.Docker.Config.Env)
+}
+
+// UnsetEnv removes a value from the set of environment strings which should be
+// set when running commands in this container, or in a container built using
+// an image built from this container.
+func (b *Builder) UnsetEnv(k string) {
+ unset := func(s *[]string) {
+ n := []string{}
+ for i := range *s {
+ if !strings.HasPrefix((*s)[i], k+"=") {
+ n = append(n, (*s)[i])
+ }
+ }
+ *s = n
+ }
+ unset(&b.OCIv1.Config.Env)
+ unset(&b.Docker.Config.Env)
+}
+
+// ClearEnv removes all values from the set of environment strings which should
+// be set when running commands in this container, or in a container built
+// using an image built from this container.
+func (b *Builder) ClearEnv() {
+ b.OCIv1.Config.Env = []string{}
+ b.Docker.Config.Env = []string{}
+}
+
+// Cmd returns the default command, or command parameters if an Entrypoint is
+// set, to use when running a container built from an image built from this
+// container.
+func (b *Builder) Cmd() []string {
+ return copyStringSlice(b.OCIv1.Config.Cmd)
+}
+
+// SetCmd sets the default command, or command parameters if an Entrypoint is
+// set, to use when running a container built from an image built from this
+// container.
+func (b *Builder) SetCmd(cmd []string) {
+ b.OCIv1.Config.Cmd = copyStringSlice(cmd)
+ b.Docker.Config.Cmd = copyStringSlice(cmd)
+}
+
+// Entrypoint returns the command to be run for containers built from images
+// built from this container.
+func (b *Builder) Entrypoint() []string {
+ if len(b.OCIv1.Config.Entrypoint) > 0 {
+ return copyStringSlice(b.OCIv1.Config.Entrypoint)
+ }
+ return nil
+}
+
+// SetEntrypoint sets the command to be run for in containers built from images
+// built from this container.
+func (b *Builder) SetEntrypoint(ep []string) {
+ b.OCIv1.Config.Entrypoint = copyStringSlice(ep)
+ b.Docker.Config.Entrypoint = copyStringSlice(ep)
+}
+
+// Labels returns a set of key-value pairs from the image's runtime
+// configuration.
+func (b *Builder) Labels() map[string]string {
+ return copyStringStringMap(b.OCIv1.Config.Labels)
+}
+
+// SetLabel adds or overwrites a key's value from the image's runtime
+// configuration.
+func (b *Builder) SetLabel(k string, v string) {
+ if b.OCIv1.Config.Labels == nil {
+ b.OCIv1.Config.Labels = map[string]string{}
+ }
+ b.OCIv1.Config.Labels[k] = v
+ if b.Docker.Config.Labels == nil {
+ b.Docker.Config.Labels = map[string]string{}
+ }
+ b.Docker.Config.Labels[k] = v
+}
+
+// UnsetLabel removes a key and its value from the image's runtime
+// configuration, if it's present.
+func (b *Builder) UnsetLabel(k string) {
+ delete(b.OCIv1.Config.Labels, k)
+ delete(b.Docker.Config.Labels, k)
+}
+
+// ClearLabels removes all keys and their values from the image's runtime
+// configuration.
+func (b *Builder) ClearLabels() {
+ b.OCIv1.Config.Labels = map[string]string{}
+ b.Docker.Config.Labels = map[string]string{}
+}
+
+// Ports returns the set of ports which should be exposed when a container
+// based on an image built from this container is run.
+func (b *Builder) Ports() []string {
+ p := []string{}
+ for k := range b.OCIv1.Config.ExposedPorts {
+ p = append(p, k)
+ }
+ return p
+}
+
+// SetPort adds or overwrites an exported port in the set of ports which should
+// be exposed when a container based on an image built from this container is
+// run.
+func (b *Builder) SetPort(p string) {
+ if b.OCIv1.Config.ExposedPorts == nil {
+ b.OCIv1.Config.ExposedPorts = map[string]struct{}{}
+ }
+ b.OCIv1.Config.ExposedPorts[p] = struct{}{}
+ if b.Docker.Config.ExposedPorts == nil {
+ b.Docker.Config.ExposedPorts = make(docker.PortSet)
+ }
+ b.Docker.Config.ExposedPorts[docker.Port(p)] = struct{}{}
+}
+
+// UnsetPort removes an exposed port from the set of ports which should be
+// exposed when a container based on an image built from this container is run.
+func (b *Builder) UnsetPort(p string) {
+ delete(b.OCIv1.Config.ExposedPorts, p)
+ delete(b.Docker.Config.ExposedPorts, docker.Port(p))
+}
+
+// ClearPorts empties the set of ports which should be exposed when a container
+// based on an image built from this container is run.
+func (b *Builder) ClearPorts() {
+ b.OCIv1.Config.ExposedPorts = map[string]struct{}{}
+ b.Docker.Config.ExposedPorts = docker.PortSet{}
+}
+
+// Volumes returns a list of filesystem locations which should be mounted from
+// outside of the container when a container built from an image built from
+// this container is run.
+func (b *Builder) Volumes() []string {
+ v := []string{}
+ for k := range b.OCIv1.Config.Volumes {
+ v = append(v, k)
+ }
+ if len(v) > 0 {
+ return v
+ }
+ return nil
+}
+
+// CheckVolume returns True if the location exists in the image's list of locations
+// which should be mounted from outside of the container when a container
+// based on an image built from this container is run
+
+func (b *Builder) CheckVolume(v string) bool {
+ _, OCIv1Volume := b.OCIv1.Config.Volumes[v]
+ _, DockerVolume := b.Docker.Config.Volumes[v]
+ return OCIv1Volume || DockerVolume
+}
+
+// AddVolume adds a location to the image's list of locations which should be
+// mounted from outside of the container when a container based on an image
+// built from this container is run.
+func (b *Builder) AddVolume(v string) {
+ if b.OCIv1.Config.Volumes == nil {
+ b.OCIv1.Config.Volumes = map[string]struct{}{}
+ }
+ b.OCIv1.Config.Volumes[v] = struct{}{}
+ if b.Docker.Config.Volumes == nil {
+ b.Docker.Config.Volumes = map[string]struct{}{}
+ }
+ b.Docker.Config.Volumes[v] = struct{}{}
+}
+
+// RemoveVolume removes a location from the list of locations which should be
+// mounted from outside of the container when a container based on an image
+// built from this container is run.
+func (b *Builder) RemoveVolume(v string) {
+ delete(b.OCIv1.Config.Volumes, v)
+ delete(b.Docker.Config.Volumes, v)
+}
+
+// ClearVolumes removes all locations from the image's list of locations which
+// should be mounted from outside of the container when a container based on an
+// image built from this container is run.
+func (b *Builder) ClearVolumes() {
+ b.OCIv1.Config.Volumes = map[string]struct{}{}
+ b.Docker.Config.Volumes = map[string]struct{}{}
+}
+
+// Hostname returns the hostname which will be set in the container and in
+// containers built using images built from the container.
+func (b *Builder) Hostname() string {
+ return b.Docker.Config.Hostname
+}
+
+// SetHostname sets the hostname which will be set in the container and in
+// containers built using images built from the container.
+// Note: this setting is not present in the OCIv1 image format, so it is
+// discarded when writing images using OCIv1 formats.
+func (b *Builder) SetHostname(name string) {
+ b.Docker.Config.Hostname = name
+}
+
+// Domainname returns the domainname which will be set in the container and in
+// containers built using images built from the container.
+func (b *Builder) Domainname() string {
+ return b.Docker.Config.Domainname
+}
+
+// SetDomainname sets the domainname which will be set in the container and in
+// containers built using images built from the container.
+// Note: this setting is not present in the OCIv1 image format, so it is
+// discarded when writing images using OCIv1 formats.
+func (b *Builder) SetDomainname(name string) {
+ if name != "" && b.Format != define.Dockerv2ImageManifest {
+ b.Logger.Warnf("DOMAINNAME is not supported for OCI image format, domainname %s will be ignored. Must use `docker` format", name)
+ }
+ b.Docker.Config.Domainname = name
+}
+
+// SetDefaultMountsFilePath sets the mounts file path for testing purposes
+func (b *Builder) SetDefaultMountsFilePath(path string) {
+ b.DefaultMountsFilePath = path
+}
+
+// Comment returns the comment which will be set in the container and in
+// containers built using images built from the container
+func (b *Builder) Comment() string {
+ return b.Docker.Comment
+}
+
+// SetComment sets the comment which will be set in the container and in
+// containers built using images built from the container.
+// Note: this setting is not present in the OCIv1 image format, so it is
+// discarded when writing images using OCIv1 formats.
+func (b *Builder) SetComment(comment string) {
+ if comment != "" && b.Format != define.Dockerv2ImageManifest {
+ logrus.Warnf("COMMENT is not supported for OCI image format, comment %s will be ignored. Must use `docker` format", comment)
+ }
+ b.Docker.Comment = comment
+}
+
+// HistoryComment returns the comment which will be used in the history item
+// which will describe the latest layer when we commit an image.
+func (b *Builder) HistoryComment() string {
+ return b.ImageHistoryComment
+}
+
+// SetHistoryComment sets the comment which will be used in the history item
+// which will describe the latest layer when we commit an image.
+func (b *Builder) SetHistoryComment(comment string) {
+ b.ImageHistoryComment = comment
+}
+
+// StopSignal returns the signal which will be set in the container and in
+// containers built using images built from the container
+func (b *Builder) StopSignal() string {
+ return b.Docker.Config.StopSignal
+}
+
+// SetStopSignal sets the signal which will be set in the container and in
+// containers built using images built from the container.
+func (b *Builder) SetStopSignal(stopSignal string) {
+ b.OCIv1.Config.StopSignal = stopSignal
+ b.Docker.Config.StopSignal = stopSignal
+}
+
+// Healthcheck returns information that recommends how a container engine
+// should check if a running container is "healthy".
+func (b *Builder) Healthcheck() *docker.HealthConfig {
+ if b.Docker.Config.Healthcheck == nil {
+ return nil
+ }
+ return &docker.HealthConfig{
+ Test: copyStringSlice(b.Docker.Config.Healthcheck.Test),
+ Interval: b.Docker.Config.Healthcheck.Interval,
+ Timeout: b.Docker.Config.Healthcheck.Timeout,
+ StartPeriod: b.Docker.Config.Healthcheck.StartPeriod,
+ Retries: b.Docker.Config.Healthcheck.Retries,
+ }
+}
+
+// SetHealthcheck sets recommended commands to run in order to verify that a
+// running container based on this image is "healthy", along with information
+// specifying how often that test should be run, and how many times the test
+// should fail before the container should be considered unhealthy.
+// Note: this setting is not present in the OCIv1 image format, so it is
+// discarded when writing images using OCIv1 formats.
+func (b *Builder) SetHealthcheck(config *docker.HealthConfig) {
+ b.Docker.Config.Healthcheck = nil
+ if config != nil {
+ if b.Format != define.Dockerv2ImageManifest {
+ b.Logger.Warnf("HEALTHCHECK is not supported for OCI image format and will be ignored. Must use `docker` format")
+ }
+ b.Docker.Config.Healthcheck = &docker.HealthConfig{
+ Test: copyStringSlice(config.Test),
+ Interval: config.Interval,
+ Timeout: config.Timeout,
+ StartPeriod: config.StartPeriod,
+ Retries: config.Retries,
+ }
+ }
+}
+
+// AddPrependedEmptyLayer adds an item to the history that we'll create when
+// committing the image, after any history we inherit from the base image, but
+// before the history item that we'll use to describe the new layer that we're
+// adding.
+func (b *Builder) AddPrependedEmptyLayer(created *time.Time, createdBy, author, comment string) {
+ if created != nil {
+ copiedTimestamp := *created
+ created = &copiedTimestamp
+ }
+ b.PrependedEmptyLayers = append(b.PrependedEmptyLayers, ociv1.History{
+ Created: created,
+ CreatedBy: createdBy,
+ Author: author,
+ Comment: comment,
+ EmptyLayer: true,
+ })
+}
+
+// ClearPrependedEmptyLayers clears the list of history entries that we'll add
+// to the committed image before the entry for the layer that we're adding.
+func (b *Builder) ClearPrependedEmptyLayers() {
+ b.PrependedEmptyLayers = nil
+}
+
+// AddAppendedEmptyLayer adds an item to the history that we'll create when
+// committing the image, after the history item that we'll use to describe the
+// new layer that we're adding.
+func (b *Builder) AddAppendedEmptyLayer(created *time.Time, createdBy, author, comment string) {
+ if created != nil {
+ copiedTimestamp := *created
+ created = &copiedTimestamp
+ }
+ b.AppendedEmptyLayers = append(b.AppendedEmptyLayers, ociv1.History{
+ Created: created,
+ CreatedBy: createdBy,
+ Author: author,
+ Comment: comment,
+ EmptyLayer: true,
+ })
+}
+
+// ClearAppendedEmptyLayers clears the list of history entries that we'll add
+// to the committed image after the entry for the layer that we're adding.
+func (b *Builder) ClearAppendedEmptyLayers() {
+ b.AppendedEmptyLayers = nil
+}