mirror of https://github.com/docker/cli.git
build: Add support for using context from stdin with buildkit
Signed-off-by: Tibor Vass <tibor@docker.com>
This commit is contained in:
parent
8cf213bd0c
commit
e0b3921a03
|
@ -81,59 +81,81 @@ func ValidateContextDirectory(srcPath string, excludes []string) error {
|
|||
})
|
||||
}
|
||||
|
||||
// GetContextFromReader will read the contents of the given reader as either a
|
||||
// Dockerfile or tar archive. Returns a tar archive used as a context and a
|
||||
// path to the Dockerfile inside the tar.
|
||||
func GetContextFromReader(r io.ReadCloser, dockerfileName string) (out io.ReadCloser, relDockerfile string, err error) {
|
||||
buf := bufio.NewReader(r)
|
||||
// DetectArchiveReader detects whether the input stream is an archive or a
|
||||
// Dockerfile and returns a buffered version of input, safe to consume in lieu
|
||||
// of input. If an archive is detected, isArchive is set to true, and to false
|
||||
// otherwise, in which case it is safe to assume input represents the contents
|
||||
// of a Dockerfile.
|
||||
func DetectArchiveReader(input io.ReadCloser) (rc io.ReadCloser, isArchive bool, err error) {
|
||||
buf := bufio.NewReader(input)
|
||||
|
||||
magic, err := buf.Peek(archiveHeaderSize)
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, "", errors.Errorf("failed to peek context header from STDIN: %v", err)
|
||||
return nil, false, errors.Errorf("failed to peek context header from STDIN: %v", err)
|
||||
}
|
||||
|
||||
if IsArchive(magic) {
|
||||
return ioutils.NewReadCloserWrapper(buf, func() error { return r.Close() }), dockerfileName, nil
|
||||
return ioutils.NewReadCloserWrapper(buf, func() error { return input.Close() }), IsArchive(magic), nil
|
||||
}
|
||||
|
||||
|
||||
// WriteTempDockerfile writes a Dockerfile stream to a temporary file with a
|
||||
// name specified by DefaultDockerfileName and returns the path to the
|
||||
// temporary directory containing the Dockerfile.
|
||||
func WriteTempDockerfile(rc io.ReadCloser) (string, error) {
|
||||
dockerfileDir, err := ioutil.TempDir("", "docker-build-tempdockerfile-")
|
||||
if err != nil {
|
||||
return "", errors.Errorf("unable to create temporary context directory: %v", err)
|
||||
}
|
||||
|
||||
f, err := os.Create(filepath.Join(dockerfileDir, DefaultDockerfileName))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, err = io.Copy(f, rc)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return "", err
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return dockerfileDir, rc.Close()
|
||||
}
|
||||
|
||||
// GetContextFromReader will read the contents of the given reader as either a
|
||||
// Dockerfile or tar archive. Returns a tar archive used as a context and a
|
||||
// path to the Dockerfile inside the tar.
|
||||
func GetContextFromReader(rc io.ReadCloser, dockerfileName string) (out io.ReadCloser, relDockerfile string, err error) {
|
||||
rc, isArchive, err := DetectArchiveReader(rc)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if isArchive {
|
||||
return rc, dockerfileName, nil
|
||||
}
|
||||
|
||||
// Input should be read as a Dockerfile.
|
||||
|
||||
if dockerfileName == "-" {
|
||||
return nil, "", errors.New("build context is not an archive")
|
||||
}
|
||||
|
||||
// Input should be read as a Dockerfile.
|
||||
tmpDir, err := ioutil.TempDir("", "docker-build-context-")
|
||||
if err != nil {
|
||||
return nil, "", errors.Errorf("unable to create temporary context directory: %v", err)
|
||||
}
|
||||
|
||||
f, err := os.Create(filepath.Join(tmpDir, DefaultDockerfileName))
|
||||
dockerfileDir, err := WriteTempDockerfile(rc)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
_, err = io.Copy(f, buf)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if err := f.Close(); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if err := r.Close(); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
tar, err := archive.Tar(tmpDir, archive.Uncompressed)
|
||||
tar, err := archive.Tar(dockerfileDir, archive.Uncompressed)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return ioutils.NewReadCloserWrapper(tar, func() error {
|
||||
err := tar.Close()
|
||||
os.RemoveAll(tmpDir)
|
||||
os.RemoveAll(dockerfileDir)
|
||||
return err
|
||||
}), DefaultDockerfileName, nil
|
||||
|
||||
}
|
||||
|
||||
// IsArchive checks for the magic bytes of a tar or any supported compression
|
||||
|
|
|
@ -4,12 +4,14 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/image/build"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
@ -46,9 +48,45 @@ func runBuildBuildKit(dockerCli command.Cli, options buildOptions) error {
|
|||
var body io.Reader
|
||||
switch {
|
||||
case options.contextFromStdin():
|
||||
body = os.Stdin
|
||||
remote = uploadRequestRemote
|
||||
rc, isArchive, err := build.DetectArchiveReader(os.Stdin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isArchive {
|
||||
body = rc
|
||||
remote = uploadRequestRemote
|
||||
} else {
|
||||
dockerfileDir, err := build.WriteTempDockerfile(rc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(dockerfileDir)
|
||||
emptyDir, _ := ioutil.TempDir("", "stupid-empty-dir")
|
||||
defer os.RemoveAll(emptyDir)
|
||||
s.Allow(filesync.NewFSSyncProvider([]filesync.SyncedDir{
|
||||
{
|
||||
Name: "context",
|
||||
Dir: emptyDir,
|
||||
},
|
||||
{
|
||||
Name: "dockerfile",
|
||||
Dir: string(dockerfileDir),
|
||||
},
|
||||
}))
|
||||
remote = clientSessionRemote
|
||||
}
|
||||
case isLocalDir(options.context):
|
||||
s.Allow(filesync.NewFSSyncProvider([]filesync.SyncedDir{
|
||||
{
|
||||
Name: "context",
|
||||
Dir: options.context,
|
||||
Map: resetUIDAndGID,
|
||||
},
|
||||
{
|
||||
Name: "dockerfile",
|
||||
Dir: filepath.Dir(options.dockerfileName),
|
||||
},
|
||||
}))
|
||||
remote = clientSessionRemote
|
||||
case urlutil.IsGitURL(options.context):
|
||||
remote = options.context
|
||||
|
@ -65,20 +103,6 @@ func runBuildBuildKit(dockerCli command.Cli, options buildOptions) error {
|
|||
// statusContext = opentracing.ContextWithSpan(statusContext, span)
|
||||
// }
|
||||
|
||||
if remote == clientSessionRemote {
|
||||
s.Allow(filesync.NewFSSyncProvider([]filesync.SyncedDir{
|
||||
{
|
||||
Name: "context",
|
||||
Dir: options.context,
|
||||
Map: resetUIDAndGID,
|
||||
},
|
||||
{
|
||||
Name: "dockerfile",
|
||||
Dir: filepath.Dir(options.dockerfileName),
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
s.Allow(authprovider.NewDockerAuthProvider())
|
||||
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
|
|
Loading…
Reference in New Issue