2017-08-03 22:24:02 +00:00
|
|
|
package local
|
|
|
|
|
|
|
|
import (
|
2018-01-16 22:30:10 +00:00
|
|
|
"context"
|
2017-12-04 22:58:00 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2017-08-03 22:24:02 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/moby/buildkit/cache"
|
|
|
|
"github.com/moby/buildkit/exporter"
|
|
|
|
"github.com/moby/buildkit/session"
|
|
|
|
"github.com/moby/buildkit/session/filesync"
|
|
|
|
"github.com/moby/buildkit/snapshot"
|
|
|
|
"github.com/moby/buildkit/util/progress"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"golang.org/x/time/rate"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Opt struct {
|
|
|
|
SessionManager *session.Manager
|
|
|
|
}
|
|
|
|
|
|
|
|
type localExporter struct {
|
|
|
|
opt Opt
|
|
|
|
// session manager
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(opt Opt) (exporter.Exporter, error) {
|
|
|
|
le := &localExporter{opt: opt}
|
|
|
|
return le, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) {
|
|
|
|
id := session.FromContext(ctx)
|
|
|
|
if id == "" {
|
|
|
|
return nil, errors.New("could not access local files without session")
|
|
|
|
}
|
|
|
|
|
|
|
|
timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
caller, err := e.opt.SessionManager.Get(timeoutCtx, id)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
li := &localExporterInstance{localExporter: e, caller: caller}
|
|
|
|
return li, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type localExporterInstance struct {
|
|
|
|
*localExporter
|
|
|
|
caller session.Caller
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *localExporterInstance) Name() string {
|
|
|
|
return "exporting to client"
|
|
|
|
}
|
|
|
|
|
2018-05-03 00:35:07 +00:00
|
|
|
func (e *localExporterInstance) Export(ctx context.Context, ref cache.ImmutableRef, opt map[string][]byte) (map[string]string, error) {
|
2017-12-04 22:58:00 +00:00
|
|
|
var src string
|
|
|
|
var err error
|
|
|
|
if ref == nil {
|
|
|
|
src, err = ioutil.TempDir("", "buildkit")
|
|
|
|
if err != nil {
|
2018-05-03 00:35:07 +00:00
|
|
|
return nil, err
|
2017-12-04 22:58:00 +00:00
|
|
|
}
|
|
|
|
defer os.RemoveAll(src)
|
|
|
|
} else {
|
|
|
|
mount, err := ref.Mount(ctx, true)
|
|
|
|
if err != nil {
|
2018-05-03 00:35:07 +00:00
|
|
|
return nil, err
|
2017-12-04 22:58:00 +00:00
|
|
|
}
|
2017-08-03 22:24:02 +00:00
|
|
|
|
2017-12-04 22:58:00 +00:00
|
|
|
lm := snapshot.LocalMounter(mount)
|
2017-08-03 22:24:02 +00:00
|
|
|
|
2017-12-04 22:58:00 +00:00
|
|
|
src, err = lm.Mount()
|
|
|
|
if err != nil {
|
2018-05-03 00:35:07 +00:00
|
|
|
return nil, err
|
2017-12-04 22:58:00 +00:00
|
|
|
}
|
|
|
|
defer lm.Unmount()
|
2017-08-03 22:24:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
progress := newProgressHandler(ctx, "copying files")
|
2018-05-03 00:35:07 +00:00
|
|
|
if err := filesync.CopyToCaller(ctx, src, e.caller, progress); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return nil, nil
|
2017-08-03 22:24:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func newProgressHandler(ctx context.Context, id string) func(int, bool) {
|
|
|
|
limiter := rate.NewLimiter(rate.Every(100*time.Millisecond), 1)
|
|
|
|
pw, _, _ := progress.FromContext(ctx)
|
|
|
|
now := time.Now()
|
|
|
|
st := progress.Status{
|
|
|
|
Started: &now,
|
|
|
|
Action: "transferring",
|
|
|
|
}
|
|
|
|
pw.Write(id, st)
|
|
|
|
return func(s int, last bool) {
|
|
|
|
if last || limiter.Allow() {
|
|
|
|
st.Current = s
|
|
|
|
if last {
|
|
|
|
now := time.Now()
|
|
|
|
st.Completed = &now
|
|
|
|
}
|
|
|
|
pw.Write(id, st)
|
|
|
|
if last {
|
|
|
|
pw.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|