Merge pull request #2401 from TomSweeneyRedHat/dev/tsweeney/buildah1.7

Vendor Buildah v1.7
This commit is contained in:
OpenShift Merge Robot
2019-02-22 23:56:06 +01:00
committed by GitHub
17 changed files with 333 additions and 181 deletions

View File

@ -179,7 +179,7 @@ func buildCmd(c *cliconfig.BuildValues) error {
} }
runtimeFlags := []string{} runtimeFlags := []string{}
for _, arg := range c.RuntimeOpts { for _, arg := range c.RuntimeFlags {
runtimeFlags = append(runtimeFlags, "--"+arg) runtimeFlags = append(runtimeFlags, "--"+arg)
} }
// end from buildah // end from buildah
@ -258,6 +258,7 @@ func buildCmd(c *cliconfig.BuildValues) error {
RuntimeArgs: runtimeFlags, RuntimeArgs: runtimeFlags,
SignaturePolicyPath: c.SignaturePolicy, SignaturePolicyPath: c.SignaturePolicy,
Squash: c.Squash, Squash: c.Squash,
Target: c.Target,
} }
return runtime.Build(getContext(), c, options, dockerfiles) return runtime.Build(getContext(), c, options, dockerfiles)
} }

View File

@ -362,6 +362,12 @@ Specifies the name which will be assigned to the resulting image if the build
process completes successfully. process completes successfully.
If _imageName_ does not include a registry name, the registry name *localhost* will be prepended to the image name. If _imageName_ does not include a registry name, the registry name *localhost* will be prepended to the image name.
**--target** *stageName*
Set the target build stage to build. When building a Dockerfile with multiple build stages, --target
can be used to specify an intermediate build stage by name as the final stage for the resulting image.
Commands after the target stage will be skipped.
**--tls-verify** *bool-value* **--tls-verify** *bool-value*
Require HTTPS and verify certificates when talking to container registries (defaults to true). Require HTTPS and verify certificates when talking to container registries (defaults to true).

View File

@ -162,7 +162,7 @@ func (c *Container) Commit(ctx context.Context, destImage string, options Contai
importBuilder.SetWorkDir(splitChange[1]) importBuilder.SetWorkDir(splitChange[1])
} }
} }
candidates, _, err := util.ResolveName(destImage, "", sc, c.runtime.store) candidates, _, _, err := util.ResolveName(destImage, "", sc, c.runtime.store)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "error resolving name %q", destImage) return nil, errors.Wrapf(err, "error resolving name %q", destImage)
} }

View File

@ -93,13 +93,13 @@ k8s.io/apimachinery kubernetes-1.10.13-beta.0 https://github.com/kubernetes/apim
k8s.io/client-go kubernetes-1.10.13-beta.0 https://github.com/kubernetes/client-go k8s.io/client-go kubernetes-1.10.13-beta.0 https://github.com/kubernetes/client-go
github.com/mrunalp/fileutils 7d4729fb36185a7c1719923406c9d40e54fb93c7 github.com/mrunalp/fileutils 7d4729fb36185a7c1719923406c9d40e54fb93c7
github.com/varlink/go 3ac79db6fd6aec70924193b090962f92985fe199 github.com/varlink/go 3ac79db6fd6aec70924193b090962f92985fe199
github.com/containers/buildah 973bb88ef1861a5b782c722c471dd79b6732852c github.com/containers/buildah v1.7
# TODO: Gotty has not been updated since 2012. Can we find replacement? # TODO: Gotty has not been updated since 2012. Can we find replacement?
github.com/Nvveen/Gotty cd527374f1e5bff4938207604a14f2e38a9cf512 github.com/Nvveen/Gotty cd527374f1e5bff4938207604a14f2e38a9cf512
# do not go beyond the below commit as the next one requires a more recent # do not go beyond the below commit as the next one requires a more recent
# docker which is in conflict with openshift/imagebuilder # docker which is in conflict with openshift/imagebuilder
github.com/fsouza/go-dockerclient 29c1814d12c072344bb91aac5d2ff719db39c523 github.com/fsouza/go-dockerclient 29c1814d12c072344bb91aac5d2ff719db39c523
github.com/openshift/imagebuilder 474d0f9df2cbabf006bd2b1c263a7b0789e228e0 github.com/openshift/imagebuilder 36823496a6868f72bc36282cc475eb8a070c0934
github.com/ulikunitz/xz v0.5.5 github.com/ulikunitz/xz v0.5.5
github.com/coreos/go-iptables v0.4.0 github.com/coreos/go-iptables v0.4.0
github.com/google/shlex c34317bd91bf98fab745d77b03933cf8769299fe github.com/google/shlex c34317bd91bf98fab745d77b03933cf8769299fe

View File

@ -26,7 +26,7 @@ const (
Package = "buildah" Package = "buildah"
// Version for the Package. Bump version in contrib/rpm/buildah.spec // Version for the Package. Bump version in contrib/rpm/buildah.spec
// too. // too.
Version = "1.7-dev" Version = "1.7"
// The value we use to identify what type of information, currently a // The value we use to identify what type of information, currently a
// serialized Builder structure, we are using as per-container state. // serialized Builder structure, we are using as per-container state.
// This should only be changed when we make incompatible changes to // This should only be changed when we make incompatible changes to
@ -336,11 +336,6 @@ type BuilderOptions struct {
// needs to be pulled and the image name alone can not be resolved to a // needs to be pulled and the image name alone can not be resolved to a
// reference to a source image. No separator is implicitly added. // reference to a source image. No separator is implicitly added.
Registry string Registry string
// Transport is a value which is prepended to the image's name, if it
// needs to be pulled and the image name alone, or the image name and
// the registry together, can not be resolved to a reference to a
// source image. No separator is implicitly added.
Transport string
// PullBlobDirectory is the name of a directory in which we'll attempt // PullBlobDirectory is the name of a directory in which we'll attempt
// to store copies of layer blobs that we pull down, if any. It should // to store copies of layer blobs that we pull down, if any. It should
// already exist. // already exist.

View File

@ -62,11 +62,6 @@ type BuildOptions struct {
// needs to be pulled and the image name alone can not be resolved to a // needs to be pulled and the image name alone can not be resolved to a
// reference to a source image. No separator is implicitly added. // reference to a source image. No separator is implicitly added.
Registry string Registry string
// Transport is a value which is prepended to the image's name, if it
// needs to be pulled and the image name alone, or the image name and
// the registry together, can not be resolved to a reference to a
// source image. No separator is implicitly added.
Transport string
// IgnoreUnrecognizedInstructions tells us to just log instructions we // IgnoreUnrecognizedInstructions tells us to just log instructions we
// don't recognize, and try to keep going. // don't recognize, and try to keep going.
IgnoreUnrecognizedInstructions bool IgnoreUnrecognizedInstructions bool
@ -171,6 +166,8 @@ type BuildOptions struct {
ForceRmIntermediateCtrs bool ForceRmIntermediateCtrs bool
// BlobDirectory is a directory which we'll use for caching layer blobs. // BlobDirectory is a directory which we'll use for caching layer blobs.
BlobDirectory string BlobDirectory string
// Target the targeted FROM in the Dockerfile to build
Target string
} }
// Executor is a buildah-based implementation of the imagebuilder.Executor // Executor is a buildah-based implementation of the imagebuilder.Executor
@ -184,7 +181,6 @@ type Executor struct {
builder *buildah.Builder builder *buildah.Builder
pullPolicy buildah.PullPolicy pullPolicy buildah.PullPolicy
registry string registry string
transport string
ignoreUnrecognizedInstructions bool ignoreUnrecognizedInstructions bool
quiet bool quiet bool
runtime string runtime string
@ -580,7 +576,6 @@ func NewExecutor(store storage.Store, options BuildOptions) (*Executor, error) {
contextDir: options.ContextDirectory, contextDir: options.ContextDirectory,
pullPolicy: options.PullPolicy, pullPolicy: options.PullPolicy,
registry: options.Registry, registry: options.Registry,
transport: options.Transport,
ignoreUnrecognizedInstructions: options.IgnoreUnrecognizedInstructions, ignoreUnrecognizedInstructions: options.IgnoreUnrecognizedInstructions,
quiet: options.Quiet, quiet: options.Quiet,
runtime: options.Runtime, runtime: options.Runtime,
@ -670,7 +665,6 @@ func (b *Executor) Prepare(ctx context.Context, stage imagebuilder.Stage, from s
FromImage: from, FromImage: from,
PullPolicy: b.pullPolicy, PullPolicy: b.pullPolicy,
Registry: b.registry, Registry: b.registry,
Transport: b.transport,
PullBlobDirectory: b.blobDirectory, PullBlobDirectory: b.blobDirectory,
SignaturePolicyPath: b.signaturePolicyPath, SignaturePolicyPath: b.signaturePolicyPath,
ReportWriter: b.reportWriter, ReportWriter: b.reportWriter,
@ -783,7 +777,7 @@ func (b *Executor) resolveNameToImageRef() (types.ImageReference, error) {
if b.output != "" { if b.output != "" {
imageRef, err = alltransports.ParseImageName(b.output) imageRef, err = alltransports.ParseImageName(b.output)
if err != nil { if err != nil {
candidates, _, err := util.ResolveName(b.output, "", b.systemContext, b.store) candidates, _, _, err := util.ResolveName(b.output, "", b.systemContext, b.store)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "error parsing target image name %q", b.output) return nil, errors.Wrapf(err, "error parsing target image name %q", b.output)
} }
@ -1441,6 +1435,13 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options BuildOpt
if err != nil { if err != nil {
return "", nil, errors.Wrap(err, "error reading multiple stages") return "", nil, errors.Wrap(err, "error reading multiple stages")
} }
if options.Target != "" {
stagesTargeted, ok := stages.ThroughTarget(options.Target)
if !ok {
return "", nil, errors.Errorf("The target %q was not found in the provided Dockerfile", options.Target)
}
stages = stagesTargeted
}
return exec.Build(ctx, stages) return exec.Build(ctx, stages)
} }

View File

@ -28,15 +28,14 @@ const (
minimumTruncatedIDLength = 3 minimumTruncatedIDLength = 3
) )
func pullAndFindImage(ctx context.Context, store storage.Store, imageName string, options BuilderOptions, sc *types.SystemContext) (*storage.Image, types.ImageReference, error) { func pullAndFindImage(ctx context.Context, store storage.Store, transport string, imageName string, options BuilderOptions, sc *types.SystemContext) (*storage.Image, types.ImageReference, error) {
pullOptions := PullOptions{ pullOptions := PullOptions{
ReportWriter: options.ReportWriter, ReportWriter: options.ReportWriter,
Store: store, Store: store,
SystemContext: options.SystemContext, SystemContext: options.SystemContext,
Transport: options.Transport,
BlobDirectory: options.PullBlobDirectory, BlobDirectory: options.PullBlobDirectory,
} }
ref, err := pullImage(ctx, store, imageName, pullOptions, sc) ref, err := pullImage(ctx, store, transport, imageName, pullOptions, sc)
if err != nil { if err != nil {
logrus.Debugf("error pulling image %q: %v", imageName, err) logrus.Debugf("error pulling image %q: %v", imageName, err)
return nil, nil, err return nil, nil, err
@ -101,16 +100,16 @@ func newContainerIDMappingOptions(idmapOptions *IDMappingOptions) storage.IDMapp
return options return options
} }
func resolveImage(ctx context.Context, systemContext *types.SystemContext, store storage.Store, options BuilderOptions) (types.ImageReference, *storage.Image, error) { func resolveImage(ctx context.Context, systemContext *types.SystemContext, store storage.Store, options BuilderOptions) (types.ImageReference, string, *storage.Image, error) {
type failure struct { type failure struct {
resolvedImageName string resolvedImageName string
err error err error
} }
candidates, transport, searchRegistriesWereUsedButEmpty, err := util.ResolveName(options.FromImage, options.Registry, systemContext, store)
candidates, searchRegistriesWereUsedButEmpty, err := util.ResolveName(options.FromImage, options.Registry, systemContext, store)
if err != nil { if err != nil {
return nil, nil, errors.Wrapf(err, "error parsing reference to image %q", options.FromImage) return nil, "", nil, errors.Wrapf(err, "error parsing reference to image %q", options.FromImage)
} }
failures := []failure{} failures := []failure{}
for _, image := range candidates { for _, image := range candidates {
var err error var err error
@ -118,25 +117,25 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store
if img, err := store.Image(image); err == nil && img != nil && strings.HasPrefix(img.ID, image) { if img, err := store.Image(image); err == nil && img != nil && strings.HasPrefix(img.ID, image) {
ref, err := is.Transport.ParseStoreReference(store, img.ID) ref, err := is.Transport.ParseStoreReference(store, img.ID)
if err != nil { if err != nil {
return nil, nil, errors.Wrapf(err, "error parsing reference to image %q", img.ID) return nil, "", nil, errors.Wrapf(err, "error parsing reference to image %q", img.ID)
} }
return ref, img, nil return ref, transport, img, nil
} }
} }
if options.PullPolicy == PullAlways { if options.PullPolicy == PullAlways {
pulledImg, pulledReference, err := pullAndFindImage(ctx, store, image, options, systemContext) pulledImg, pulledReference, err := pullAndFindImage(ctx, store, transport, image, options, systemContext)
if err != nil { if err != nil {
logrus.Debugf("unable to pull and read image %q: %v", image, err) logrus.Debugf("unable to pull and read image %q: %v", image, err)
failures = append(failures, failure{resolvedImageName: image, err: err}) failures = append(failures, failure{resolvedImageName: image, err: err})
continue continue
} }
return pulledReference, pulledImg, nil return pulledReference, transport, pulledImg, nil
} }
srcRef, err := alltransports.ParseImageName(image) srcRef, err := alltransports.ParseImageName(image)
if err != nil { if err != nil {
if options.Transport == "" { if transport == "" {
logrus.Debugf("error parsing image name %q: %v", image, err) logrus.Debugf("error parsing image name %q: %v", image, err)
failures = append(failures, failure{ failures = append(failures, failure{
resolvedImageName: image, resolvedImageName: image,
@ -144,12 +143,13 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store
}) })
continue continue
} }
logrus.Debugf("error parsing image name %q as given, trying with transport %q: %v", image, options.Transport, err) logrus.Debugf("error parsing image name %q as given, trying with transport %q: %v", image, transport, err)
transport := options.Transport
trans := transport
if transport != util.DefaultTransport { if transport != util.DefaultTransport {
transport = transport + ":" trans = trans + ":"
} }
srcRef2, err := alltransports.ParseImageName(transport + image) srcRef2, err := alltransports.ParseImageName(trans + image)
if err != nil { if err != nil {
logrus.Debugf("error parsing image name %q: %v", transport+image, err) logrus.Debugf("error parsing image name %q: %v", transport+image, err)
failures = append(failures, failure{ failures = append(failures, failure{
@ -163,19 +163,19 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store
destImage, err := localImageNameForReference(ctx, store, srcRef, options.FromImage) destImage, err := localImageNameForReference(ctx, store, srcRef, options.FromImage)
if err != nil { if err != nil {
return nil, nil, errors.Wrapf(err, "error computing local image name for %q", transports.ImageName(srcRef)) return nil, "", nil, errors.Wrapf(err, "error computing local image name for %q", transports.ImageName(srcRef))
} }
if destImage == "" { if destImage == "" {
return nil, nil, errors.Errorf("error computing local image name for %q", transports.ImageName(srcRef)) return nil, "", nil, errors.Errorf("error computing local image name for %q", transports.ImageName(srcRef))
} }
ref, err := is.Transport.ParseStoreReference(store, destImage) ref, err := is.Transport.ParseStoreReference(store, destImage)
if err != nil { if err != nil {
return nil, nil, errors.Wrapf(err, "error parsing reference to image %q", destImage) return nil, "", nil, errors.Wrapf(err, "error parsing reference to image %q", destImage)
} }
img, err := is.Transport.GetStoreImage(store, ref) img, err := is.Transport.GetStoreImage(store, ref)
if err == nil { if err == nil {
return ref, img, nil return ref, transport, img, nil
} }
if errors.Cause(err) == storage.ErrImageUnknown && options.PullPolicy != PullIfMissing { if errors.Cause(err) == storage.ErrImageUnknown && options.PullPolicy != PullIfMissing {
@ -187,26 +187,26 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store
continue continue
} }
pulledImg, pulledReference, err := pullAndFindImage(ctx, store, image, options, systemContext) pulledImg, pulledReference, err := pullAndFindImage(ctx, store, transport, image, options, systemContext)
if err != nil { if err != nil {
logrus.Debugf("unable to pull and read image %q: %v", image, err) logrus.Debugf("unable to pull and read image %q: %v", image, err)
failures = append(failures, failure{resolvedImageName: image, err: err}) failures = append(failures, failure{resolvedImageName: image, err: err})
continue continue
} }
return pulledReference, pulledImg, nil return pulledReference, transport, pulledImg, nil
} }
if len(failures) != len(candidates) { if len(failures) != len(candidates) {
return nil, nil, fmt.Errorf("internal error: %d candidates (%#v) vs. %d failures (%#v)", len(candidates), candidates, len(failures), failures) return nil, "", nil, fmt.Errorf("internal error: %d candidates (%#v) vs. %d failures (%#v)", len(candidates), candidates, len(failures), failures)
} }
registriesConfPath := sysregistries.RegistriesConfPath(systemContext) registriesConfPath := sysregistries.RegistriesConfPath(systemContext)
switch len(failures) { switch len(failures) {
case 0: case 0:
if searchRegistriesWereUsedButEmpty { if searchRegistriesWereUsedButEmpty {
return nil, nil, errors.Errorf("image name %q is a short name and no search registries are defined in %s.", options.FromImage, registriesConfPath) return nil, "", nil, errors.Errorf("image name %q is a short name and no search registries are defined in %s.", options.FromImage, registriesConfPath)
} }
return nil, nil, fmt.Errorf("internal error: no pull candidates were available for %q for an unknown reason", options.FromImage) return nil, "", nil, fmt.Errorf("internal error: no pull candidates were available for %q for an unknown reason", options.FromImage)
case 1: case 1:
err := failures[0].err err := failures[0].err
@ -216,7 +216,7 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store
if searchRegistriesWereUsedButEmpty { if searchRegistriesWereUsedButEmpty {
err = errors.Wrapf(err, "(image name %q is a short name and no search registries are defined in %s)", options.FromImage, registriesConfPath) err = errors.Wrapf(err, "(image name %q is a short name and no search registries are defined in %s)", options.FromImage, registriesConfPath)
} }
return nil, nil, err return nil, "", nil, err
default: default:
// NOTE: a multi-line error string: // NOTE: a multi-line error string:
@ -224,7 +224,7 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store
for _, f := range failures { for _, f := range failures {
e = e + fmt.Sprintf("\n* %q: %s", f.resolvedImageName, f.err.Error()) e = e + fmt.Sprintf("\n* %q: %s", f.resolvedImageName, f.err.Error())
} }
return nil, nil, errors.New(e) return nil, "", nil, errors.New(e)
} }
} }
@ -250,21 +250,19 @@ func findUnusedContainer(name string, containers []storage.Container) string {
} }
func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions) (*Builder, error) { func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions) (*Builder, error) {
var ref types.ImageReference var (
var img *storage.Image ref types.ImageReference
var err error img *storage.Image
err error
)
if options.FromImage == BaseImageFakeName { if options.FromImage == BaseImageFakeName {
options.FromImage = "" options.FromImage = ""
} }
if options.Transport == "" {
options.Transport = util.DefaultTransport
}
systemContext := getSystemContext(options.SystemContext, options.SignaturePolicyPath) systemContext := getSystemContext(options.SystemContext, options.SignaturePolicyPath)
if options.FromImage != "" && options.FromImage != "scratch" { if options.FromImage != "" && options.FromImage != "scratch" {
ref, img, err = resolveImage(ctx, systemContext, store, options) ref, _, img, err = resolveImage(ctx, systemContext, store, options)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -55,20 +55,21 @@ type BudResults struct {
File []string File []string
Format string Format string
Iidfile string Iidfile string
NoCache bool
Label []string Label []string
Logfile string Logfile string
Loglevel int Loglevel int
NoCache bool
Platform string Platform string
Pull bool Pull bool
PullAlways bool PullAlways bool
Quiet bool Quiet bool
Rm bool Rm bool
Runtime string Runtime string
RuntimeOpts []string RuntimeFlags []string
SignaturePolicy string SignaturePolicy string
Squash bool Squash bool
Tag []string Tag []string
Target string
TlsVerify bool TlsVerify bool
} }
@ -138,7 +139,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
fs.StringVar(&flags.CertDir, "cert-dir", "", "use certificates at the specified path to access the registry") fs.StringVar(&flags.CertDir, "cert-dir", "", "use certificates at the specified path to access the registry")
fs.BoolVar(&flags.Compress, "compress", false, "This is legacy option, which has no effect on the image") fs.BoolVar(&flags.Compress, "compress", false, "This is legacy option, which has no effect on the image")
fs.StringVar(&flags.Creds, "creds", "", "use `[username[:password]]` for accessing the registry") fs.StringVar(&flags.Creds, "creds", "", "use `[username[:password]]` for accessing the registry")
fs.BoolVarP(&flags.DisableCompression, "disable-compression", "D", false, "don't compress layers by default") fs.BoolVarP(&flags.DisableCompression, "disable-compression", "D", true, "don't compress layers by default")
fs.BoolVar(&flags.DisableContentTrust, "disable-content-trust", false, "This is a Docker specific option and is a NOOP") fs.BoolVar(&flags.DisableContentTrust, "disable-content-trust", false, "This is a Docker specific option and is a NOOP")
fs.StringSliceVarP(&flags.File, "file", "f", []string{}, "`pathname or URL` of a Dockerfile") fs.StringSliceVarP(&flags.File, "file", "f", []string{}, "`pathname or URL` of a Dockerfile")
fs.StringVar(&flags.Format, "format", DefaultFormat(), "`format` of the built image's manifest and metadata. Use BUILDAH_FORMAT environment variable to override.") fs.StringVar(&flags.Format, "format", DefaultFormat(), "`format` of the built image's manifest and metadata. Use BUILDAH_FORMAT environment variable to override.")
@ -153,10 +154,11 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
fs.BoolVarP(&flags.Quiet, "quiet", "q", false, "refrain from announcing build instructions and image read/write progress") fs.BoolVarP(&flags.Quiet, "quiet", "q", false, "refrain from announcing build instructions and image read/write progress")
fs.BoolVar(&flags.Rm, "rm", true, "Remove intermediate containers after a successful build (default true)") fs.BoolVar(&flags.Rm, "rm", true, "Remove intermediate containers after a successful build (default true)")
fs.StringVar(&flags.Runtime, "runtime", util.Runtime(), "`path` to an alternate runtime. Use BUILDAH_RUNTIME environment variable to override.") fs.StringVar(&flags.Runtime, "runtime", util.Runtime(), "`path` to an alternate runtime. Use BUILDAH_RUNTIME environment variable to override.")
fs.StringSliceVar(&flags.RuntimeOpts, "runtime-flag", []string{}, "add global flags for the container runtime") fs.StringSliceVar(&flags.RuntimeFlags, "runtime-flag", []string{}, "add global flags for the container runtime")
fs.StringVar(&flags.SignaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)") fs.StringVar(&flags.SignaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)")
fs.BoolVar(&flags.Squash, "squash", false, "Squash newly built layers into a single new layer. The build process does not currently support caching so this is a NOOP.") fs.BoolVar(&flags.Squash, "squash", false, "Squash newly built layers into a single new layer. The build process does not currently support caching so this is a NOOP.")
fs.StringSliceVarP(&flags.Tag, "tag", "t", []string{}, "tagged `name` to apply to the built image") fs.StringSliceVarP(&flags.Tag, "tag", "t", []string{}, "tagged `name` to apply to the built image")
fs.StringVar(&flags.Target, "target", "", "set the target build stage to build")
fs.BoolVar(&flags.TlsVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry") fs.BoolVar(&flags.TlsVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry")
return fs return fs
} }

View File

@ -251,9 +251,9 @@ func SystemContextFromOptions(c *cobra.Command) (*types.SystemContext, error) {
} }
tlsVerify, err := c.Flags().GetBool("tls-verify") tlsVerify, err := c.Flags().GetBool("tls-verify")
if err == nil && c.Flag("tls-verify").Changed { if err == nil && c.Flag("tls-verify").Changed {
ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(tlsVerify) ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!tlsVerify)
ctx.OCIInsecureSkipTLSVerify = tlsVerify ctx.OCIInsecureSkipTLSVerify = !tlsVerify
ctx.DockerDaemonInsecureSkipTLSVerify = tlsVerify ctx.DockerDaemonInsecureSkipTLSVerify = !tlsVerify
} }
creds, err := c.Flags().GetString("creds") creds, err := c.Flags().GetString("creds")
if err == nil && c.Flag("creds").Changed { if err == nil && c.Flag("creds").Changed {

View File

@ -9,10 +9,13 @@ import (
"github.com/containers/buildah/pkg/blobcache" "github.com/containers/buildah/pkg/blobcache"
"github.com/containers/buildah/util" "github.com/containers/buildah/util"
cp "github.com/containers/image/copy" cp "github.com/containers/image/copy"
"github.com/containers/image/directory"
"github.com/containers/image/docker" "github.com/containers/image/docker"
dockerarchive "github.com/containers/image/docker/archive"
"github.com/containers/image/docker/reference" "github.com/containers/image/docker/reference"
tarfile "github.com/containers/image/docker/tarfile" tarfile "github.com/containers/image/docker/tarfile"
ociarchive "github.com/containers/image/oci/archive" ociarchive "github.com/containers/image/oci/archive"
oci "github.com/containers/image/oci/layout"
"github.com/containers/image/signature" "github.com/containers/image/signature"
is "github.com/containers/image/storage" is "github.com/containers/image/storage"
"github.com/containers/image/transports" "github.com/containers/image/transports"
@ -40,10 +43,6 @@ type PullOptions struct {
// github.com/containers/image/types SystemContext to hold credentials // github.com/containers/image/types SystemContext to hold credentials
// and other authentication/authorization information. // and other authentication/authorization information.
SystemContext *types.SystemContext SystemContext *types.SystemContext
// Transport is a value which is prepended to the image's name, if the
// image name alone can not be resolved to a reference to a source
// image. No separator is implicitly added.
Transport string
// BlobDirectory is the name of a directory in which we'll attempt to // BlobDirectory is the name of a directory in which we'll attempt to
// store copies of layer blobs that we pull down, if any. It should // store copies of layer blobs that we pull down, if any. It should
// already exist. // already exist.
@ -51,10 +50,6 @@ type PullOptions struct {
// AllTags is a boolean value that determines if all tagged images // AllTags is a boolean value that determines if all tagged images
// will be downloaded from the repository. The default is false. // will be downloaded from the repository. The default is false.
AllTags bool AllTags bool
// Quiet is a boolean value that determines if minimal output to
// the user will be displayed, this is best used for logging.
// The default is false.
Quiet bool
} }
func localImageNameForReference(ctx context.Context, store storage.Store, srcRef types.ImageReference, spec string) (string, error) { func localImageNameForReference(ctx context.Context, store storage.Store, srcRef types.ImageReference, spec string) (string, error) {
@ -65,7 +60,7 @@ func localImageNameForReference(ctx context.Context, store storage.Store, srcRef
file := split[len(split)-1] file := split[len(split)-1]
var name string var name string
switch srcRef.Transport().Name() { switch srcRef.Transport().Name() {
case util.DockerArchive: case dockerarchive.Transport.Name():
tarSource, err := tarfile.NewSourceFromFile(file) tarSource, err := tarfile.NewSourceFromFile(file)
if err != nil { if err != nil {
return "", errors.Wrapf(err, "error opening tarfile %q as a source image", file) return "", errors.Wrapf(err, "error opening tarfile %q as a source image", file)
@ -92,7 +87,7 @@ func localImageNameForReference(ctx context.Context, store storage.Store, srcRef
} }
} }
} }
case util.OCIArchive: case ociarchive.Transport.Name():
// retrieve the manifest from index.json to access the image name // retrieve the manifest from index.json to access the image name
manifest, err := ociarchive.LoadManifestDescriptor(srcRef) manifest, err := ociarchive.LoadManifestDescriptor(srcRef)
if err != nil { if err != nil {
@ -107,7 +102,14 @@ func localImageNameForReference(ctx context.Context, store storage.Store, srcRef
} else { } else {
name = manifest.Annotations["org.opencontainers.image.ref.name"] name = manifest.Annotations["org.opencontainers.image.ref.name"]
} }
case util.DirTransport: case directory.Transport.Name():
// supports pull from a directory
name = split[1]
// remove leading "/"
if name[:1] == "/" {
name = name[1:]
}
case oci.Transport.Name():
// supports pull from a directory // supports pull from a directory
name = split[1] name = split[1]
// remove leading "/" // remove leading "/"
@ -152,50 +154,42 @@ func localImageNameForReference(ctx context.Context, store storage.Store, srcRef
// Pull copies the contents of the image from somewhere else to local storage. // Pull copies the contents of the image from somewhere else to local storage.
func Pull(ctx context.Context, imageName string, options PullOptions) error { func Pull(ctx context.Context, imageName string, options PullOptions) error {
spec := imageName
systemContext := getSystemContext(options.SystemContext, options.SignaturePolicyPath) systemContext := getSystemContext(options.SystemContext, options.SignaturePolicyPath)
srcRef, err := alltransports.ParseImageName(spec)
boptions := BuilderOptions{
FromImage: imageName,
SignaturePolicyPath: options.SignaturePolicyPath,
SystemContext: systemContext,
PullBlobDirectory: options.BlobDirectory,
ReportWriter: options.ReportWriter,
}
storageRef, transport, img, err := resolveImage(ctx, systemContext, options.Store, boptions)
if err != nil { if err != nil {
if options.Transport == "" { return err
options.Transport = util.DefaultTransport
} }
logrus.Debugf("error parsing image name %q, trying with transport %q: %v", spec, options.Transport, err)
transport := options.Transport var errs *multierror.Error
if transport != util.DefaultTransport {
transport = transport + ":"
}
spec = transport + spec
srcRef2, err2 := alltransports.ParseImageName(spec)
if err2 != nil {
return errors.Wrapf(err2, "error parsing image name %q", imageName)
}
srcRef = srcRef2
}
if options.Quiet {
options.ReportWriter = nil // Turns off logging output
}
var names []string
if options.AllTags { if options.AllTags {
if srcRef.DockerReference() == nil { if transport != util.DefaultTransport {
return errors.New("Non-docker transport is currently not supported") return errors.New("Non-docker transport is not supported, for --all-tags pulling")
} }
tags, err := docker.GetRepositoryTags(ctx, systemContext, srcRef)
spec := transport + storageRef.DockerReference().Name()
storageRef, err = alltransports.ParseImageName(spec)
if err != nil {
return errors.Wrapf(err, "error getting repository tags")
}
tags, err := docker.GetRepositoryTags(ctx, systemContext, storageRef)
if err != nil { if err != nil {
return errors.Wrapf(err, "error getting repository tags") return errors.Wrapf(err, "error getting repository tags")
} }
for _, tag := range tags { for _, tag := range tags {
name := spec + ":" + tag name := spec + ":" + tag
names = append(names, name)
}
} else {
names = append(names, spec)
}
var errs *multierror.Error
for _, name := range names {
if options.ReportWriter != nil { if options.ReportWriter != nil {
options.ReportWriter.Write([]byte("Pulling " + name + "\n")) options.ReportWriter.Write([]byte("Pulling " + name + "\n"))
} }
ref, err := pullImage(ctx, options.Store, name, options, systemContext) ref, err := pullImage(ctx, options.Store, transport, name, options, systemContext)
if err != nil { if err != nil {
errs = multierror.Append(errs, err) errs = multierror.Append(errs, err)
continue continue
@ -207,22 +201,25 @@ func Pull(ctx context.Context, imageName string, options PullOptions) error {
} }
fmt.Printf("%s\n", img.ID) fmt.Printf("%s\n", img.ID)
} }
} else {
fmt.Printf("%s\n", img.ID)
}
return errs.ErrorOrNil() return errs.ErrorOrNil()
} }
func pullImage(ctx context.Context, store storage.Store, imageName string, options PullOptions, sc *types.SystemContext) (types.ImageReference, error) { func pullImage(ctx context.Context, store storage.Store, transport string, imageName string, options PullOptions, sc *types.SystemContext) (types.ImageReference, error) {
spec := imageName spec := imageName
srcRef, err := alltransports.ParseImageName(spec) srcRef, err := alltransports.ParseImageName(spec)
if err != nil { if err != nil {
if options.Transport == "" { logrus.Debugf("error parsing image name %q, trying with transport %q: %v", spec, transport, err)
options.Transport = util.DefaultTransport if transport == "" {
} transport = util.DefaultTransport
logrus.Debugf("error parsing image name %q, trying with transport %q: %v", spec, options.Transport, err) } else {
transport := options.Transport
if transport != util.DefaultTransport { if transport != util.DefaultTransport {
transport = transport + ":" transport = transport + ":"
} }
}
spec = transport + spec spec = transport + spec
srcRef2, err2 := alltransports.ParseImageName(spec) srcRef2, err2 := alltransports.ParseImageName(spec)
if err2 != nil { if err2 != nil {

View File

@ -2,6 +2,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/syscall.h>
#include <linux/memfd.h>
#include <fcntl.h> #include <fcntl.h>
#include <grp.h> #include <grp.h>
#include <sched.h> #include <sched.h>
@ -12,6 +14,28 @@
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#ifndef F_LINUX_SPECIFIC_BASE
#define F_LINUX_SPECIFIC_BASE 1024
#endif
#ifndef F_ADD_SEALS
#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
#endif
#ifndef F_SEAL_SEAL
#define F_SEAL_SEAL 0x0001LU
#endif
#ifndef F_SEAL_SHRINK
#define F_SEAL_SHRINK 0x0002LU
#endif
#ifndef F_SEAL_GROW
#define F_SEAL_GROW 0x0004LU
#endif
#ifndef F_SEAL_WRITE
#define F_SEAL_WRITE 0x0008LU
#endif
#define BUFSTEP 1024
static const char *_max_user_namespaces = "/proc/sys/user/max_user_namespaces"; static const char *_max_user_namespaces = "/proc/sys/user/max_user_namespaces";
static const char *_unprivileged_user_namespaces = "/proc/sys/kernel/unprivileged_userns_clone"; static const char *_unprivileged_user_namespaces = "/proc/sys/kernel/unprivileged_userns_clone";
@ -59,6 +83,119 @@ static void _check_proc_sys_file(const char *path)
} }
} }
static char **parse_proc_stringlist(const char *list) {
int fd, n, i, n_strings;
char *buf, *new_buf, **ret;
size_t size, new_size, used;
fd = open(list, O_RDONLY);
if (fd == -1) {
return NULL;
}
buf = NULL;
size = 0;
used = 0;
for (;;) {
new_size = used + BUFSTEP;
new_buf = realloc(buf, new_size);
if (new_buf == NULL) {
free(buf);
fprintf(stderr, "realloc(%ld): out of memory\n", (long)(size + BUFSTEP));
return NULL;
}
buf = new_buf;
size = new_size;
memset(buf + used, '\0', size - used);
n = read(fd, buf + used, size - used - 1);
if (n < 0) {
fprintf(stderr, "read(): %m\n");
return NULL;
}
if (n == 0) {
break;
}
used += n;
}
close(fd);
n_strings = 0;
for (n = 0; n < used; n++) {
if ((n == 0) || (buf[n-1] == '\0')) {
n_strings++;
}
}
ret = calloc(n_strings + 1, sizeof(char *));
if (ret == NULL) {
fprintf(stderr, "calloc(): out of memory\n");
return NULL;
}
i = 0;
for (n = 0; n < used; n++) {
if ((n == 0) || (buf[n-1] == '\0')) {
ret[i++] = &buf[n];
}
}
ret[i] = NULL;
return ret;
}
static int buildah_reexec(void) {
char **argv, *exename;
int fd, mmfd, n_read, n_written;
struct stat st;
char buf[2048];
argv = parse_proc_stringlist("/proc/self/cmdline");
if (argv == NULL) {
return -1;
}
fd = open("/proc/self/exe", O_RDONLY | O_CLOEXEC);
if (fd == -1) {
fprintf(stderr, "open(\"/proc/self/exe\"): %m\n");
return -1;
}
if (fstat(fd, &st) == -1) {
fprintf(stderr, "fstat(\"/proc/self/exe\"): %m\n");
return -1;
}
exename = basename(argv[0]);
mmfd = syscall(SYS_memfd_create, exename, (long) MFD_ALLOW_SEALING | MFD_CLOEXEC);
if (mmfd == -1) {
fprintf(stderr, "memfd_create(): %m\n");
return -1;
}
for (;;) {
n_read = read(fd, buf, sizeof(buf));
if (n_read < 0) {
fprintf(stderr, "read(\"/proc/self/exe\"): %m\n");
return -1;
}
if (n_read == 0) {
break;
}
n_written = write(mmfd, buf, n_read);
if (n_written < 0) {
fprintf(stderr, "write(anonfd): %m\n");
return -1;
}
if (n_written != n_read) {
fprintf(stderr, "write(anonfd): short write (%d != %d)\n", n_written, n_read);
return -1;
}
}
close(fd);
if (fcntl(mmfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) == -1) {
close(mmfd);
fprintf(stderr, "Error sealing memfd copy: %m\n");
return -1;
}
if (fexecve(mmfd, argv, environ) == -1) {
close(mmfd);
fprintf(stderr, "Error during reexec(...): %m\n");
return -1;
}
return 0;
}
void _buildah_unshare(void) void _buildah_unshare(void)
{ {
int flags, pidfd, continuefd, n, pgrp, sid, ctty; int flags, pidfd, continuefd, n, pgrp, sid, ctty;
@ -132,5 +269,8 @@ void _buildah_unshare(void)
_exit(1); _exit(1);
} }
} }
if (buildah_reexec() != 0) {
_exit(1);
}
return; return;
} }

View File

@ -56,8 +56,10 @@ func (c *Cmd) Start() error {
c.Env = append(c.Env, fmt.Sprintf("_Buildah-unshare=%d", c.UnshareFlags)) c.Env = append(c.Env, fmt.Sprintf("_Buildah-unshare=%d", c.UnshareFlags))
// Please the libpod "rootless" package to find the expected env variables. // Please the libpod "rootless" package to find the expected env variables.
if os.Geteuid() != 0 {
c.Env = append(c.Env, "_LIBPOD_USERNS_CONFIGURED=done") c.Env = append(c.Env, "_LIBPOD_USERNS_CONFIGURED=done")
c.Env = append(c.Env, fmt.Sprintf("_LIBPOD_ROOTLESS_UID=%d", os.Geteuid())) c.Env = append(c.Env, fmt.Sprintf("_LIBPOD_ROOTLESS_UID=%d", os.Geteuid()))
}
// Create the pipe for reading the child's PID. // Create the pipe for reading the child's PID.
pidRead, pidWrite, err := os.Pipe() pidRead, pidWrite, err := os.Pipe()

View File

@ -11,14 +11,11 @@ import (
"strings" "strings"
"syscall" "syscall"
"github.com/containers/image/directory"
dockerarchive "github.com/containers/image/docker/archive"
"github.com/containers/image/docker/reference" "github.com/containers/image/docker/reference"
ociarchive "github.com/containers/image/oci/archive"
"github.com/containers/image/pkg/sysregistriesv2" "github.com/containers/image/pkg/sysregistriesv2"
"github.com/containers/image/signature" "github.com/containers/image/signature"
is "github.com/containers/image/storage" is "github.com/containers/image/storage"
"github.com/containers/image/tarball" "github.com/containers/image/transports"
"github.com/containers/image/types" "github.com/containers/image/types"
"github.com/containers/storage" "github.com/containers/storage"
"github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/idtools"
@ -43,36 +40,18 @@ var (
"index.docker.io": "library", "index.docker.io": "library",
"docker.io": "library", "docker.io": "library",
} }
// Transports contains the possible transports used for images
Transports = map[string]string{
dockerarchive.Transport.Name(): "",
ociarchive.Transport.Name(): "",
directory.Transport.Name(): "",
tarball.Transport.Name(): "",
}
// DockerArchive is the transport we prepend to an image name
// when saving to docker-archive
DockerArchive = dockerarchive.Transport.Name()
// OCIArchive is the transport we prepend to an image name
// when saving to oci-archive
OCIArchive = ociarchive.Transport.Name()
// DirTransport is the transport for pushing and pulling
// images to and from a directory
DirTransport = directory.Transport.Name()
// TarballTransport is the transport for importing a tar archive
// and creating a filesystem image
TarballTransport = tarball.Transport.Name()
) )
// ResolveName checks if name is a valid image name, and if that name doesn't // ResolveName checks if name is a valid image name, and if that name doesn't
// include a domain portion, returns a list of the names which it might // include a domain portion, returns a list of the names which it might
// correspond to in the set of configured registries, // correspond to in the set of configured registries, the transport used to
// and a boolean which is true iff 1) the list of search registries was used, and 2) it was empty. // pull the image, and a boolean which is true iff
// 1) the list of search registries was used, and 2) it was empty.
// NOTE: The "list of search registries is empty" check does not count blocked registries, // NOTE: The "list of search registries is empty" check does not count blocked registries,
// and neither the implied "localhost" nor a possible firstRegistry are counted // and neither the implied "localhost" nor a possible firstRegistry are counted
func ResolveName(name string, firstRegistry string, sc *types.SystemContext, store storage.Store) ([]string, bool, error) { func ResolveName(name string, firstRegistry string, sc *types.SystemContext, store storage.Store) ([]string, string, bool, error) {
if name == "" { if name == "" {
return nil, false, nil return nil, "", false, nil
} }
// Maybe it's a truncated image ID. Don't prepend a registry name, then. // Maybe it's a truncated image ID. Don't prepend a registry name, then.
@ -80,27 +59,28 @@ func ResolveName(name string, firstRegistry string, sc *types.SystemContext, sto
if img, err := store.Image(name); err == nil && img != nil && strings.HasPrefix(img.ID, name) { if img, err := store.Image(name); err == nil && img != nil && strings.HasPrefix(img.ID, name) {
// It's a truncated version of the ID of an image that's present in local storage; // It's a truncated version of the ID of an image that's present in local storage;
// we need only expand the ID. // we need only expand the ID.
return []string{img.ID}, false, nil return []string{img.ID}, "", false, nil
} }
} }
// If the image includes a transport's name as a prefix, use it as-is. // If the image includes a transport's name as a prefix, use it as-is.
if strings.HasPrefix(name, DefaultTransport) {
return []string{strings.TrimPrefix(name, DefaultTransport)}, DefaultTransport, false, nil
}
split := strings.SplitN(name, ":", 2) split := strings.SplitN(name, ":", 2)
if len(split) == 2 { if len(split) == 2 {
if _, ok := Transports[split[0]]; ok { if trans := transports.Get(split[0]); trans != nil {
return []string{split[1]}, false, nil return []string{split[1]}, trans.Name(), false, nil
} }
} }
name = strings.TrimPrefix(name, DefaultTransport)
// If the image name already included a domain component, we're done. // If the image name already included a domain component, we're done.
named, err := reference.ParseNormalizedNamed(name) named, err := reference.ParseNormalizedNamed(name)
if err != nil { if err != nil {
return nil, false, errors.Wrapf(err, "error parsing image name %q", name) return nil, "", false, errors.Wrapf(err, "error parsing image name %q", name)
} }
if named.String() == name { if named.String() == name {
// Parsing produced the same result, so there was a domain name in there to begin with. // Parsing produced the same result, so there was a domain name in there to begin with.
return []string{name}, false, nil return []string{name}, DefaultTransport, false, nil
} }
if reference.Domain(named) != "" && RegistryDefaultPathPrefix[reference.Domain(named)] != "" { if reference.Domain(named) != "" && RegistryDefaultPathPrefix[reference.Domain(named)] != "" {
// If this domain can cause us to insert something in the middle, check if that happened. // If this domain can cause us to insert something in the middle, check if that happened.
@ -117,7 +97,7 @@ func ResolveName(name string, firstRegistry string, sc *types.SystemContext, sto
defaultPrefix := RegistryDefaultPathPrefix[reference.Domain(named)] + "/" defaultPrefix := RegistryDefaultPathPrefix[reference.Domain(named)] + "/"
if strings.HasPrefix(repoPath, defaultPrefix) && path.Join(domain, repoPath[len(defaultPrefix):])+tag+digest == name { if strings.HasPrefix(repoPath, defaultPrefix) && path.Join(domain, repoPath[len(defaultPrefix):])+tag+digest == name {
// Yup, parsing just inserted a bit in the middle, so there was a domain name there to begin with. // Yup, parsing just inserted a bit in the middle, so there was a domain name there to begin with.
return []string{name}, false, nil return []string{name}, DefaultTransport, false, nil
} }
} }
@ -153,7 +133,7 @@ func ResolveName(name string, firstRegistry string, sc *types.SystemContext, sto
candidate := path.Join(registry, middle, name) candidate := path.Join(registry, middle, name)
candidates = append(candidates, candidate) candidates = append(candidates, candidate)
} }
return candidates, searchRegistriesAreEmpty, nil return candidates, DefaultTransport, searchRegistriesAreEmpty, nil
} }
// ExpandNames takes unqualified names, parses them as image names, and returns // ExpandNames takes unqualified names, parses them as image names, and returns
@ -164,7 +144,7 @@ func ExpandNames(names []string, firstRegistry string, systemContext *types.Syst
expanded := make([]string, 0, len(names)) expanded := make([]string, 0, len(names))
for _, n := range names { for _, n := range names {
var name reference.Named var name reference.Named
nameList, _, err := ResolveName(n, firstRegistry, systemContext, store) nameList, _, _, err := ResolveName(n, firstRegistry, systemContext, store)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "error parsing name %q", n) return nil, errors.Wrapf(err, "error parsing name %q", n)
} }
@ -200,7 +180,7 @@ func FindImage(store storage.Store, firstRegistry string, systemContext *types.S
var ref types.ImageReference var ref types.ImageReference
var img *storage.Image var img *storage.Image
var err error var err error
names, _, err := ResolveName(image, firstRegistry, systemContext, store) names, _, _, err := ResolveName(image, firstRegistry, systemContext, store)
if err != nil { if err != nil {
return nil, nil, errors.Wrapf(err, "error parsing name %q", image) return nil, nil, errors.Wrapf(err, "error parsing name %q", image)
} }

View File

@ -3,10 +3,13 @@ github.com/blang/semver v3.5.0
github.com/BurntSushi/toml v0.2.0 github.com/BurntSushi/toml v0.2.0
github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d
github.com/containernetworking/cni v0.7.0-alpha1 github.com/containernetworking/cni v0.7.0-alpha1
github.com/containers/image v1.3 github.com/containers/image v1.4
github.com/vbauerster/mpb v3.3.4
github.com/mattn/go-isatty v0.0.4
github.com/VividCortex/ewma v1.1.1
github.com/boltdb/bolt v1.3.1 github.com/boltdb/bolt v1.3.1
github.com/containers/libpod v1.0 github.com/containers/libpod v1.0
github.com/containers/storage v1.9 github.com/containers/storage v1.10
github.com/docker/distribution 5f6282db7d65e6d72ad7c2cc66310724a57be716 github.com/docker/distribution 5f6282db7d65e6d72ad7c2cc66310724a57be716
github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00 github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00
github.com/docker/docker-credential-helpers v0.6.1 github.com/docker/docker-credential-helpers v0.6.1
@ -21,7 +24,6 @@ github.com/gorilla/mux v1.6.2
github.com/hashicorp/errwrap v1.0.0 github.com/hashicorp/errwrap v1.0.0
github.com/hashicorp/go-multierror v1.0.0 github.com/hashicorp/go-multierror v1.0.0
github.com/imdario/mergo v0.3.6 github.com/imdario/mergo v0.3.6
github.com/mattn/go-runewidth v0.0.4
github.com/mattn/go-shellwords v1.0.3 github.com/mattn/go-shellwords v1.0.3
github.com/Microsoft/go-winio v0.4.11 github.com/Microsoft/go-winio v0.4.11
github.com/Microsoft/hcsshim v0.8.3 github.com/Microsoft/hcsshim v0.8.3
@ -36,7 +38,7 @@ github.com/opencontainers/runc v1.0.0-rc6
github.com/opencontainers/runtime-spec v1.0.0 github.com/opencontainers/runtime-spec v1.0.0
github.com/opencontainers/runtime-tools v0.8.0 github.com/opencontainers/runtime-tools v0.8.0
github.com/opencontainers/selinux v1.1 github.com/opencontainers/selinux v1.1
github.com/openshift/imagebuilder a4122153148e3b34161191f868565d8dffe65a69 github.com/openshift/imagebuilder 36823496a6868f72bc36282cc475eb8a070c0934
github.com/ostreedev/ostree-go 9ab99253d365aac3a330d1f7281cf29f3d22820b github.com/ostreedev/ostree-go 9ab99253d365aac3a330d1f7281cf29f3d22820b
github.com/pkg/errors v0.8.1 github.com/pkg/errors v0.8.1
github.com/pquerna/ffjson d49c2bc1aa135aad0c6f4fc2056623ec78f5d5ac github.com/pquerna/ffjson d49c2bc1aa135aad0c6f4fc2056623ec78f5d5ac
@ -55,7 +57,6 @@ golang.org/x/net 45ffb0cd1ba084b73e26dee67e667e1be5acce83 https://github.com/gol
golang.org/x/sync 37e7f081c4d4c64e13b10787722085407fe5d15f https://github.com/golang/sync golang.org/x/sync 37e7f081c4d4c64e13b10787722085407fe5d15f https://github.com/golang/sync
golang.org/x/sys 7fbe1cd0fcc20051e1fcb87fbabec4a1bacaaeba https://github.com/golang/sys golang.org/x/sys 7fbe1cd0fcc20051e1fcb87fbabec4a1bacaaeba https://github.com/golang/sys
golang.org/x/text e6919f6577db79269a6443b9dc46d18f2238fb5d https://github.com/golang/text golang.org/x/text e6919f6577db79269a6443b9dc46d18f2238fb5d https://github.com/golang/text
gopkg.in/cheggaaa/pb.v1 v1.0.27
gopkg.in/yaml.v2 v2.2.2 gopkg.in/yaml.v2 v2.2.2
k8s.io/client-go kubernetes-1.10.13-beta.0 https://github.com/kubernetes/client-go k8s.io/client-go kubernetes-1.10.13-beta.0 https://github.com/kubernetes/client-go
github.com/klauspost/pgzip v1.2.1 github.com/klauspost/pgzip v1.2.1
@ -63,17 +64,4 @@ github.com/klauspost/compress v1.4.1
github.com/klauspost/cpuid v1.2.0 github.com/klauspost/cpuid v1.2.0
github.com/onsi/gomega v1.4.3 github.com/onsi/gomega v1.4.3
github.com/spf13/cobra v0.0.3 github.com/spf13/cobra v0.0.3
github.com/cpuguy83/go-md2man v1.0.8
github.com/spf13/pflag v1.0.3 github.com/spf13/pflag v1.0.3
github.com/inconshreveable/mousetrap v1.0.0
github.com/russross/blackfriday v2.0.1
github.com/mitchellh/go-homedir v1.0.0
github.com/spf13/viper v1.3.1
github.com/fsnotify/fsnotify v1.4.7
github.com/hashicorp/hcl v1.0.0
github.com/magiconair/properties v1.8.0
github.com/mitchellh/mapstructure v1.1.2
github.com/pelletier/go-toml v1.2.0
github.com/spf13/afero v1.2.0
github.com/spf13/cast v1.3.0
github.com/spf13/jwalterweatherman v1.0.0

View File

@ -70,7 +70,7 @@ is ignored.
## Code Example ## Code Example
``` ```go
f, err := os.Open("path/to/Dockerfile") f, err := os.Open("path/to/Dockerfile")
if err != nil { if err != nil {
return err return err

View File

@ -40,6 +40,7 @@ type Run struct {
type Executor interface { type Executor interface {
Preserve(path string) error Preserve(path string) error
EnsureContainerPath(path string) error
Copy(excludes []string, copies ...Copy) error Copy(excludes []string, copies ...Copy) error
Run(run Run, config docker.Config) error Run(run Run, config docker.Config) error
UnrecognizedInstruction(step *Step) error UnrecognizedInstruction(step *Step) error
@ -52,6 +53,11 @@ func (logExecutor) Preserve(path string) error {
return nil return nil
} }
func (logExecutor) EnsureContainerPath(path string) error {
log.Printf("ENSURE %s", path)
return nil
}
func (logExecutor) Copy(excludes []string, copies ...Copy) error { func (logExecutor) Copy(excludes []string, copies ...Copy) error {
for _, c := range copies { for _, c := range copies {
log.Printf("COPY %v -> %s (from:%s download:%t), chown: %s", c.Src, c.Dest, c.From, c.Download, c.Chown) log.Printf("COPY %v -> %s (from:%s download:%t), chown: %s", c.Src, c.Dest, c.From, c.Download, c.Chown)
@ -75,6 +81,10 @@ func (noopExecutor) Preserve(path string) error {
return nil return nil
} }
func (noopExecutor) EnsureContainerPath(path string) error {
return nil
}
func (noopExecutor) Copy(excludes []string, copies ...Copy) error { func (noopExecutor) Copy(excludes []string, copies ...Copy) error {
return nil return nil
} }
@ -153,6 +163,7 @@ func (stages Stages) ByName(name string) (Stage, bool) {
return Stage{}, false return Stage{}, false
} }
// Get just the target stage.
func (stages Stages) ByTarget(target string) (Stages, bool) { func (stages Stages) ByTarget(target string) (Stages, bool) {
if len(target) == 0 { if len(target) == 0 {
return stages, true return stages, true
@ -165,6 +176,19 @@ func (stages Stages) ByTarget(target string) (Stages, bool) {
return nil, false return nil, false
} }
// Get all the stages up to and including the target.
func (stages Stages) ThroughTarget(target string) (Stages, bool) {
if len(target) == 0 {
return stages, true
}
for i, stage := range stages {
if stage.Name == target {
return stages[0 : i+1], true
}
}
return nil, false
}
type Stage struct { type Stage struct {
Position int Position int
Name string Name string
@ -319,6 +343,13 @@ func (b *Builder) Run(step *Step, exec Executor, noRunsRemaining bool) error {
if err := exec.Copy(b.Excludes, copies...); err != nil { if err := exec.Copy(b.Excludes, copies...); err != nil {
return err return err
} }
if len(b.RunConfig.WorkingDir) > 0 {
if err := exec.EnsureContainerPath(b.RunConfig.WorkingDir); err != nil {
return err
}
}
for _, run := range runs { for _, run := range runs {
config := b.Config() config := b.Config()
config.Env = step.Env config.Env = step.Env

View File

@ -128,9 +128,20 @@ func add(b *Builder, args []string, attributes map[string]bool, flagArgs []strin
if len(args) < 2 { if len(args) < 2 {
return errAtLeastOneArgument("ADD") return errAtLeastOneArgument("ADD")
} }
var chown string
last := len(args) - 1 last := len(args) - 1
dest := makeAbsolute(args[last], b.RunConfig.WorkingDir) dest := makeAbsolute(args[last], b.RunConfig.WorkingDir)
b.PendingCopies = append(b.PendingCopies, Copy{Src: args[0:last], Dest: dest, Download: true}) if len(flagArgs) > 0 {
for _, arg := range flagArgs {
switch {
case strings.HasPrefix(arg, "--chown="):
chown = strings.TrimPrefix(arg, "--chown=")
default:
return fmt.Errorf("ADD only supports the --chown=<uid:gid> flag")
}
}
}
b.PendingCopies = append(b.PendingCopies, Copy{Src: args[0:last], Dest: dest, Download: true, Chown: chown})
return nil return nil
} }