build: allow dockerfile from URL

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
pull/398/head
Tonis Tiigi 4 years ago
parent 0360668cc1
commit 290e25917c

@ -285,7 +285,7 @@ func isDefaultMobyDriver(d driver.Driver) bool {
return ok return ok
} }
func toSolveOpt(d driver.Driver, multiDriver bool, opt Options, dl dockerLoadCallback) (solveOpt *client.SolveOpt, release func(), err error) { func toSolveOpt(ctx context.Context, d driver.Driver, multiDriver bool, opt Options, pw progress.Writer, dl dockerLoadCallback) (solveOpt *client.SolveOpt, release func(), err error) {
defers := make([]func(), 0, 2) defers := make([]func(), 0, 2)
releaseF := func() { releaseF := func() {
for _, f := range defers { for _, f := range defers {
@ -425,7 +425,7 @@ func toSolveOpt(d driver.Driver, multiDriver bool, opt Options, dl dockerLoadCal
so.Exports = opt.Exports so.Exports = opt.Exports
so.Session = opt.Session so.Session = opt.Session
releaseLoad, err := LoadInputs(opt.Inputs, &so) releaseLoad, err := LoadInputs(ctx, d, opt.Inputs, pw, &so)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -530,7 +530,7 @@ func Build(ctx context.Context, drivers []DriverInfo, opt map[string]Options, do
for i, dp := range m[k] { for i, dp := range m[k] {
d := drivers[dp.driverIndex].Driver d := drivers[dp.driverIndex].Driver
opt.Platforms = dp.platforms opt.Platforms = dp.platforms
so, release, err := toSolveOpt(d, multiDriver, opt, func(name string) (io.WriteCloser, func(), error) { so, release, err := toSolveOpt(ctx, d, multiDriver, opt, pw, func(name string) (io.WriteCloser, func(), error) {
return newDockerLoader(ctx, docker, name, mw) return newDockerLoader(ctx, docker, name, mw)
}) })
if err != nil { if err != nil {
@ -720,7 +720,7 @@ func createTempDockerfile(r io.Reader) (string, error) {
return dir, err return dir, err
} }
func LoadInputs(inp Inputs, target *client.SolveOpt) (func(), error) { func LoadInputs(ctx context.Context, d driver.Driver, inp Inputs, pw progress.Writer, target *client.SolveOpt) (func(), error) {
if inp.ContextPath == "" { if inp.ContextPath == "" {
return nil, errors.New("please specify build context (e.g. \".\" for the current directory)") return nil, errors.New("please specify build context (e.g. \".\" for the current directory)")
} }
@ -746,7 +746,7 @@ func LoadInputs(inp Inputs, target *client.SolveOpt) (func(), error) {
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
return nil, errors.Wrap(err, "failed to peek context header from STDIN") return nil, errors.Wrap(err, "failed to peek context header from STDIN")
} }
if !(err == io.EOF && len(magic) == 0) {
if isArchive(magic) { if isArchive(magic) {
// stdin is context // stdin is context
up := uploadprovider.New() up := uploadprovider.New()
@ -762,6 +762,7 @@ func LoadInputs(inp Inputs, target *client.SolveOpt) (func(), error) {
toRemove = append(toRemove, inp.ContextPath) toRemove = append(toRemove, inp.ContextPath)
target.LocalDirs["context"] = inp.ContextPath target.LocalDirs["context"] = inp.ContextPath
} }
}
case isLocalDir(inp.ContextPath): case isLocalDir(inp.ContextPath):
target.LocalDirs["context"] = inp.ContextPath target.LocalDirs["context"] = inp.ContextPath
@ -791,6 +792,16 @@ func LoadInputs(inp Inputs, target *client.SolveOpt) (func(), error) {
} }
toRemove = append(toRemove, dockerfileDir) toRemove = append(toRemove, dockerfileDir)
dockerfileName = "Dockerfile" dockerfileName = "Dockerfile"
target.FrontendAttrs["dockerfilekey"] = "dockerfile"
}
if urlutil.IsURL(inp.DockerfilePath) {
dockerfileDir, err = createTempDockerfileFromURL(ctx, d, inp.DockerfilePath, pw)
if err != nil {
return nil, err
}
toRemove = append(toRemove, dockerfileDir)
dockerfileName = "Dockerfile"
target.FrontendAttrs["dockerfilekey"] = "dockerfile"
} }
if dockerfileName == "" { if dockerfileName == "" {

@ -0,0 +1,69 @@
package build
import (
"context"
"io/ioutil"
"path/filepath"
"github.com/docker/buildx/driver"
"github.com/docker/buildx/util/progress"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb"
gwclient "github.com/moby/buildkit/frontend/gateway/client"
"github.com/pkg/errors"
)
func createTempDockerfileFromURL(ctx context.Context, d driver.Driver, url string, pw progress.Writer) (string, error) {
c, err := d.Client(ctx)
if err != nil {
return "", err
}
var out string
_, err = c.Build(ctx, client.SolveOpt{}, "buildx", func(ctx context.Context, c gwclient.Client) (*gwclient.Result, error) {
def, err := llb.HTTP(url, llb.Filename("Dockerfile"), llb.WithCustomNamef("[internal] load %s", url)).Marshal(ctx)
if err != nil {
return nil, err
}
res, err := c.Solve(ctx, gwclient.SolveRequest{
Definition: def.ToPB(),
})
if err != nil {
return nil, err
}
ref, err := res.SingleRef()
if err != nil {
return nil, err
}
stat, err := ref.StatFile(ctx, gwclient.StatRequest{
Path: "Dockerfile",
})
if err != nil {
return nil, err
}
if stat.Size() > 512*1024 {
return nil, errors.Errorf("Dockerfile %s bigger than allowed max size", url)
}
dt, err := ref.ReadFile(ctx, gwclient.ReadRequest{
Filename: "Dockerfile",
})
if err != nil {
return nil, err
}
dir, err := ioutil.TempDir("", "buildx")
if err != nil {
return nil, err
}
if err := ioutil.WriteFile(filepath.Join(dir, "Dockerfile"), dt, 0600); err != nil {
return nil, err
}
out = dir
return nil, nil
}, pw.Status())
if err != nil {
return "", err
}
return out, nil
}

@ -5,10 +5,12 @@ import (
"io/ioutil" "io/ioutil"
"sort" "sort"
"strings" "strings"
"sync"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
dockerclient "github.com/docker/docker/client" dockerclient "github.com/docker/docker/client"
"github.com/moby/buildkit/client"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -117,9 +119,27 @@ func GetDriver(ctx context.Context, name string, f Factory, api dockerclient.API
return nil, err return nil, err
} }
} }
return f.New(ctx, ic) d, err := f.New(ctx, ic)
if err != nil {
return nil, err
}
return &cachedDriver{Driver: d}, nil
} }
func GetFactories() map[string]Factory { func GetFactories() map[string]Factory {
return drivers return drivers
} }
type cachedDriver struct {
Driver
client *client.Client
err error
once sync.Once
}
func (d *cachedDriver) Client(ctx context.Context) (*client.Client, error) {
d.once.Do(func() {
d.client, d.err = d.Driver.Client(ctx)
})
return d.client, d.err
}

Loading…
Cancel
Save