mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
builder: add support for separate upload-request
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
parent
f3ef8c93d6
commit
a25846a675
2 changed files with 119 additions and 6 deletions
|
@ -63,6 +63,10 @@ func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if build == nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
var imageID = build.ImageID
|
var imageID = build.ImageID
|
||||||
if options.Squash {
|
if options.Squash {
|
||||||
if imageID, err = squashBuild(build, b.imageComponent); err != nil {
|
if imageID, err = squashBuild(build, b.imageComponent); err != nil {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containerd/containerd/content"
|
"github.com/containerd/containerd/content"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
@ -34,7 +35,7 @@ type Builder struct {
|
||||||
reqBodyHandler *reqBodyHandler
|
reqBodyHandler *reqBodyHandler
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
jobs map[string]func()
|
jobs map[string]*buildJob
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(opt Opt) (*Builder, error) {
|
func New(opt Opt) (*Builder, error) {
|
||||||
|
@ -47,15 +48,15 @@ func New(opt Opt) (*Builder, error) {
|
||||||
b := &Builder{
|
b := &Builder{
|
||||||
controller: c,
|
controller: c,
|
||||||
reqBodyHandler: reqHandler,
|
reqBodyHandler: reqHandler,
|
||||||
jobs: map[string]func(){},
|
jobs: map[string]*buildJob{},
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) Cancel(ctx context.Context, id string) error {
|
func (b *Builder) Cancel(ctx context.Context, id string) error {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
if cancel, ok := b.jobs[id]; ok {
|
if j, ok := b.jobs[id]; ok && j.cancel != nil {
|
||||||
cancel()
|
j.cancel()
|
||||||
}
|
}
|
||||||
b.mu.Unlock()
|
b.mu.Unlock()
|
||||||
return nil
|
return nil
|
||||||
|
@ -114,10 +115,43 @@ func (b *Builder) Prune(ctx context.Context) (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.Result, error) {
|
func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.Result, error) {
|
||||||
|
var rc = opt.Source
|
||||||
|
|
||||||
if buildID := opt.Options.BuildID; buildID != "" {
|
if buildID := opt.Options.BuildID; buildID != "" {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
ctx, b.jobs[buildID] = context.WithCancel(ctx)
|
|
||||||
|
upload := false
|
||||||
|
if strings.HasPrefix(buildID, "upload-request:") {
|
||||||
|
upload = true
|
||||||
|
buildID = strings.TrimPrefix(buildID, "upload-request:")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := b.jobs[buildID]; !ok {
|
||||||
|
b.jobs[buildID] = newBuildJob()
|
||||||
|
}
|
||||||
|
j := b.jobs[buildID]
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
j.cancel = cancel
|
||||||
b.mu.Unlock()
|
b.mu.Unlock()
|
||||||
|
|
||||||
|
if upload {
|
||||||
|
ctx2, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
err := j.SetUpload(ctx2, rc)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if remoteContext := opt.Options.RemoteContext; remoteContext == "upload-request" {
|
||||||
|
ctx2, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
var err error
|
||||||
|
rc, err = j.WaitUpload(ctx2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
opt.Options.RemoteContext = ""
|
||||||
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
delete(b.jobs, buildID)
|
delete(b.jobs, buildID)
|
||||||
}()
|
}()
|
||||||
|
@ -142,7 +176,7 @@ func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.
|
||||||
frontendAttrs["context"] = opt.Options.RemoteContext
|
frontendAttrs["context"] = opt.Options.RemoteContext
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
url, cancel := b.reqBodyHandler.newRequest(opt.Source)
|
url, cancel := b.reqBodyHandler.newRequest(rc)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
frontendAttrs["context"] = url
|
frontendAttrs["context"] = url
|
||||||
}
|
}
|
||||||
|
@ -295,3 +329,78 @@ type contentStoreNoLabels struct {
|
||||||
func (c *contentStoreNoLabels) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
|
func (c *contentStoreNoLabels) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
|
||||||
return content.Info{}, nil
|
return content.Info{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type wrapRC struct {
|
||||||
|
io.ReadCloser
|
||||||
|
once sync.Once
|
||||||
|
err error
|
||||||
|
waitCh chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapRC) Read(b []byte) (int, error) {
|
||||||
|
n, err := w.ReadCloser.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
e := err
|
||||||
|
if e == io.EOF {
|
||||||
|
e = nil
|
||||||
|
}
|
||||||
|
w.close(e)
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapRC) Close() error {
|
||||||
|
err := w.ReadCloser.Close()
|
||||||
|
w.close(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapRC) close(err error) {
|
||||||
|
w.once.Do(func() {
|
||||||
|
w.err = err
|
||||||
|
close(w.waitCh)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrapRC) wait() error {
|
||||||
|
<-w.waitCh
|
||||||
|
return w.err
|
||||||
|
}
|
||||||
|
|
||||||
|
type buildJob struct {
|
||||||
|
cancel func()
|
||||||
|
waitCh chan func(io.ReadCloser) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBuildJob() *buildJob {
|
||||||
|
return &buildJob{waitCh: make(chan func(io.ReadCloser) error)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *buildJob) WaitUpload(ctx context.Context) (io.ReadCloser, error) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
|
||||||
|
var upload io.ReadCloser
|
||||||
|
fn := func(rc io.ReadCloser) error {
|
||||||
|
w := &wrapRC{ReadCloser: rc, waitCh: make(chan struct{})}
|
||||||
|
upload = w
|
||||||
|
close(done)
|
||||||
|
return w.wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case j.waitCh <- fn:
|
||||||
|
<-done
|
||||||
|
return upload, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *buildJob) SetUpload(ctx context.Context, rc io.ReadCloser) error {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case fn := <-j.waitCh:
|
||||||
|
return fn(rc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue