mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-10 13:37:08 +08:00
build: allow dockerfile from URL
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
@ -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,21 +746,22 @@ 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()
|
||||||
target.FrontendAttrs["context"] = up.Add(buf)
|
target.FrontendAttrs["context"] = up.Add(buf)
|
||||||
target.Session = append(target.Session, up)
|
target.Session = append(target.Session, up)
|
||||||
} else {
|
} else {
|
||||||
if inp.DockerfilePath != "" {
|
if inp.DockerfilePath != "" {
|
||||||
return nil, errDockerfileConflict
|
return nil, errDockerfileConflict
|
||||||
|
}
|
||||||
|
// stdin is dockerfile
|
||||||
|
dockerfileReader = buf
|
||||||
|
inp.ContextPath, _ = ioutil.TempDir("", "empty-dir")
|
||||||
|
toRemove = append(toRemove, inp.ContextPath)
|
||||||
|
target.LocalDirs["context"] = inp.ContextPath
|
||||||
}
|
}
|
||||||
// stdin is dockerfile
|
|
||||||
dockerfileReader = buf
|
|
||||||
inp.ContextPath, _ = ioutil.TempDir("", "empty-dir")
|
|
||||||
toRemove = append(toRemove, inp.ContextPath)
|
|
||||||
target.LocalDirs["context"] = inp.ContextPath
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case isLocalDir(inp.ContextPath):
|
case isLocalDir(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 == "" {
|
||||||
|
69
build/url.go
Normal file
69
build/url.go
Normal file
@ -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
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user