2017-07-11 17:12:12 +00:00
|
|
|
package local
|
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
|
2017-07-14 18:59:31 +00:00
|
|
|
"github.com/Sirupsen/logrus"
|
|
|
|
"github.com/boltdb/bolt"
|
2017-07-11 17:12:12 +00:00
|
|
|
"github.com/moby/buildkit/cache"
|
2017-07-14 18:59:31 +00:00
|
|
|
"github.com/moby/buildkit/cache/metadata"
|
2017-07-11 17:12:12 +00:00
|
|
|
"github.com/moby/buildkit/session"
|
|
|
|
"github.com/moby/buildkit/session/filesync"
|
|
|
|
"github.com/moby/buildkit/snapshot"
|
|
|
|
"github.com/moby/buildkit/source"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"golang.org/x/net/context"
|
|
|
|
)
|
|
|
|
|
2017-07-14 18:59:31 +00:00
|
|
|
const keySharedKey = "local.sharedKey"
|
|
|
|
|
2017-07-11 17:12:12 +00:00
|
|
|
type Opt struct {
|
|
|
|
SessionManager *session.Manager
|
|
|
|
CacheAccessor cache.Accessor
|
2017-07-14 18:59:31 +00:00
|
|
|
MetadataStore *metadata.Store
|
2017-07-11 17:12:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewSource(opt Opt) (source.Source, error) {
|
|
|
|
ls := &localSource{
|
|
|
|
sm: opt.SessionManager,
|
|
|
|
cm: opt.CacheAccessor,
|
2017-07-14 18:59:31 +00:00
|
|
|
md: opt.MetadataStore,
|
2017-07-11 17:12:12 +00:00
|
|
|
}
|
|
|
|
return ls, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type localSource struct {
|
|
|
|
sm *session.Manager
|
|
|
|
cm cache.Accessor
|
2017-07-14 18:59:31 +00:00
|
|
|
md *metadata.Store
|
2017-07-11 17:12:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ls *localSource) ID() string {
|
|
|
|
return source.LocalScheme
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ls *localSource) Resolve(ctx context.Context, id source.Identifier) (source.SourceInstance, error) {
|
|
|
|
localIdentifier, ok := id.(*source.LocalIdentifier)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.Errorf("invalid local identifier %v", id)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &localSourceHandler{
|
|
|
|
src: *localIdentifier,
|
|
|
|
localSource: ls,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type localSourceHandler struct {
|
|
|
|
src source.LocalIdentifier
|
|
|
|
*localSource
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ls *localSourceHandler) CacheKey(ctx context.Context) (string, error) {
|
|
|
|
sessionID := ls.src.SessionID
|
|
|
|
|
|
|
|
if sessionID == "" {
|
2017-07-14 18:05:54 +00:00
|
|
|
id := session.FromContext(ctx)
|
|
|
|
if id == "" {
|
2017-07-11 17:12:12 +00:00
|
|
|
return "", errors.New("could not access local files without session")
|
|
|
|
}
|
2017-07-14 18:05:54 +00:00
|
|
|
sessionID = id
|
2017-07-11 17:12:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return "session:" + ls.src.Name + ":" + sessionID, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ls *localSourceHandler) Snapshot(ctx context.Context) (out cache.ImmutableRef, retErr error) {
|
|
|
|
|
2017-07-14 18:05:54 +00:00
|
|
|
id := session.FromContext(ctx)
|
|
|
|
if id == "" {
|
2017-07-11 17:12:12 +00:00
|
|
|
return nil, errors.New("could not access local files without session")
|
|
|
|
}
|
|
|
|
|
|
|
|
timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
2017-07-14 18:05:54 +00:00
|
|
|
caller, err := ls.sm.Get(timeoutCtx, id)
|
2017-07-11 17:12:12 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-07-14 18:59:31 +00:00
|
|
|
sharedKey := keySharedKey + ":" + ls.src.Name + ":" + caller.SharedKey()
|
|
|
|
|
|
|
|
var mutable cache.MutableRef
|
|
|
|
sis, err := ls.md.Search(sharedKey)
|
2017-07-11 17:12:12 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-07-14 18:59:31 +00:00
|
|
|
for _, si := range sis {
|
|
|
|
if m, err := ls.cm.GetMutable(ctx, si.ID()); err == nil {
|
|
|
|
logrus.Debugf("reusing ref for local: %s", m.ID())
|
|
|
|
mutable = m
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if mutable == nil {
|
|
|
|
m, err := ls.cm.New(ctx, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
mutable = m
|
|
|
|
logrus.Debugf("new ref for local: %s", mutable.ID())
|
|
|
|
}
|
2017-07-11 17:12:12 +00:00
|
|
|
|
|
|
|
defer func() {
|
|
|
|
if retErr != nil && mutable != nil {
|
2017-07-14 18:59:31 +00:00
|
|
|
go mutable.Release(context.TODO())
|
2017-07-11 17:12:12 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
mount, err := mutable.Mount(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
lm := snapshot.LocalMounter(mount)
|
|
|
|
|
|
|
|
dest, err := lm.Mount()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
if retErr != nil && lm != nil {
|
|
|
|
lm.Unmount()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
opt := filesync.FSSendRequestOpt{
|
|
|
|
IncludePatterns: nil,
|
|
|
|
OverrideExcludes: false,
|
|
|
|
DestDir: dest,
|
|
|
|
CacheUpdater: nil,
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := filesync.FSSync(ctx, caller, opt); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := lm.Unmount(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
lm = nil
|
|
|
|
|
2017-07-14 18:59:31 +00:00
|
|
|
skipStoreSharedKey := false
|
|
|
|
si, _ := ls.md.Get(mutable.ID())
|
|
|
|
if v := si.Get(keySharedKey); v != nil {
|
|
|
|
var str string
|
|
|
|
if err := v.Unmarshal(&str); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
skipStoreSharedKey = str == sharedKey
|
|
|
|
}
|
|
|
|
if !skipStoreSharedKey {
|
|
|
|
v, err := metadata.NewValue(sharedKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
v.Index = sharedKey
|
|
|
|
if err := si.Update(func(b *bolt.Bucket) error {
|
|
|
|
return si.SetValue(b, sharedKey, v)
|
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
logrus.Debugf("saved %s as %s", mutable.ID(), sharedKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
snap, err := mutable.Commit(ctx)
|
2017-07-11 17:12:12 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
mutable = nil
|
|
|
|
|
2017-07-14 18:59:31 +00:00
|
|
|
return snap, nil
|
2017-07-11 17:12:12 +00:00
|
|
|
}
|