Skip to content

Commit

Permalink
fileop: llbsolver implementation
Browse files Browse the repository at this point in the history
Signed-off-by: Tonis Tiigi <[email protected]>
  • Loading branch information
tonistiigi committed Mar 15, 2019
1 parent b2b0e3d commit 2be999b
Show file tree
Hide file tree
Showing 2 changed files with 246 additions and 0 deletions.
179 changes: 179 additions & 0 deletions solver/llbsolver/file/backend.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package file

import (
"context"
"io/ioutil"
"os"
"path/filepath"

"github.com/containerd/continuity/fs"
"github.com/moby/buildkit/snapshot"
"github.com/moby/buildkit/solver/llbsolver/ops/fileoptypes"
"github.com/moby/buildkit/solver/pb"
"github.com/pkg/errors"
copy "github.com/tonistiigi/fsutil/copy"
"golang.org/x/sys/unix"
)

func mkdir(ctx context.Context, d string, action pb.FileActionMkDir) error {
p, err := fs.RootPath(d, filepath.Join(filepath.Join("/", action.Path)))
if err != nil {
return err
}

if action.MakeParents {
if err := os.MkdirAll(p, os.FileMode(action.Mode&0777)); err != nil {
return err
}
} else {
if err := os.Mkdir(p, os.FileMode(action.Mode&0777)); err != nil {
return err
}
}

if action.Timestamp != -1 {
st := unix.Timespec{Sec: action.Timestamp / 1e9, Nsec: action.Timestamp % 1e9}
timespec := []unix.Timespec{st, st}
if err := unix.UtimesNanoAt(unix.AT_FDCWD, p, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil {
return errors.Wrapf(err, "failed to utime %s", p)
}
}
return nil
}

func mkfile(ctx context.Context, d string, action pb.FileActionMkFile) error {
p, err := fs.RootPath(d, filepath.Join(filepath.Join("/", action.Path)))
if err != nil {
return err
}

if err := ioutil.WriteFile(p, action.Data, os.FileMode(action.Mode)|0777); err != nil {
return err
}

if action.Timestamp != -1 {
st := unix.Timespec{Sec: action.Timestamp / 1e9, Nsec: action.Timestamp % 1e9}
timespec := []unix.Timespec{st, st}
if err := unix.UtimesNanoAt(unix.AT_FDCWD, p, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil {
return errors.Wrapf(err, "failed to utime %s", p)
}
}
return nil
}

func rm(ctx context.Context, d string, action pb.FileActionRm) error {
p, err := fs.RootPath(d, filepath.Join(filepath.Join("/", action.Path)))
if err != nil {
return err
}

if err := os.RemoveAll(p); err != nil {
if os.IsNotExist(errors.Cause(err)) && action.AllowNotFound {
return nil
}
return err
}

return nil
}

func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy) error {
// // src is the source path
// Src string `protobuf:"bytes,1,opt,name=src,proto3" json:"src,omitempty"`
// // dest path
// Dest string `protobuf:"bytes,2,opt,name=dest,proto3" json:"dest,omitempty"`
// // optional owner override
// Owner *ChownOpt `protobuf:"bytes,4,opt,name=owner" json:"owner,omitempty"`
// // optional permission bits override
// Mode int32 `protobuf:"varint,5,opt,name=mode,proto3" json:"mode,omitempty"`
// // followSymlink resolves symlinks in src
// FollowSymlink bool `protobuf:"varint,6,opt,name=followSymlink,proto3" json:"followSymlink,omitempty"`
// // dirCopyContents only copies contents if src is a directory
// DirCopyContents bool `protobuf:"varint,7,opt,name=dirCopyContents,proto3" json:"dirCopyContents,omitempty"`
// // attemptUnpackDockerCompatibility detects if src is an archive to unpack it instead
// AttemptUnpackDockerCompatibility bool `protobuf:"varint,8,opt,name=attemptUnpackDockerCompatibility,proto3" json:"attemptUnpackDockerCompatibility,omitempty"`
// // createDestPath creates dest path directories if needed
// CreateDestPath bool `protobuf:"varint,9,opt,name=createDestPath,proto3" json:"createDestPath,omitempty"`
// // allowWildcard allows filepath.Match wildcards in src path
// AllowWildcard bool `protobuf:"varint,10,opt,name=allowWildcard,proto3" json:"allowWildcard,omitempty"`
// // allowEmptyWildcard doesn't fail the whole copy if wildcard doesn't resolve to files
// AllowEmptyWildcard bool `protobuf:"varint,11,opt,name=allowEmptyWildcard,proto3" json:"allowEmptyWildcard,omitempty"`
// // optional created time override
// Timestamp int64 `protobuf:"varint,12,opt,name=timestamp,proto3" json:"timestamp,omitempty"`

srcp, err := fs.RootPath(src, filepath.Join(filepath.Join("/", action.Src)))
if err != nil {
return err
}

destp, err := fs.RootPath(dest, filepath.Join(filepath.Join("/", action.Dest)))
if err != nil {
return err
}

if err := copy.Copy(ctx, srcp, destp); err != nil {
return err
}

return nil
}

type FileBackend struct {
}

func (fb *FileBackend) Mkdir(ctx context.Context, m fileoptypes.Mount, action pb.FileActionMkDir) error {
mnt, ok := m.(*Mount)
if !ok {
return errors.Errorf("invalid mount type %T", m)
}

lm := snapshot.LocalMounter(mnt.m)
dir, err := lm.Mount()
if err != nil {
return err
}
defer lm.Unmount()

return mkdir(ctx, dir, action)
}

func (fb *FileBackend) Mkfile(ctx context.Context, m fileoptypes.Mount, action pb.FileActionMkFile) error {
mnt, ok := m.(*Mount)
if !ok {
return errors.Errorf("invalid mount type %T", m)
}

_ = mnt

return errors.Errorf("mkfile not implemented")
}
func (fb *FileBackend) Rm(ctx context.Context, m fileoptypes.Mount, action pb.FileActionRm) error {
mnt, ok := m.(*Mount)
if !ok {
return errors.Errorf("invalid mount type %T", m)
}
_ = mnt

return errors.Errorf("rm not implemented")
}
func (fb *FileBackend) Copy(ctx context.Context, m1 fileoptypes.Mount, m2 fileoptypes.Mount, action pb.FileActionCopy) error {
mnt1, ok := m1.(*Mount)
if !ok {
return errors.Errorf("invalid mount type %T", m1)
}
mnt2, ok := m2.(*Mount)
if !ok {
return errors.Errorf("invalid mount type %T", m2)
}

_ = mnt1
_ = mnt2
return errors.Errorf("copy not implemented")
}

// type Backend interface {
// Mkdir(context.Context, Mount, pb.FileActionMkDir) error
// Mkfile(context.Context, Mount, pb.FileActionMkFile) error
// Rm(context.Context, Mount, pb.FileActionRm) error
// Copy(context.Context, Mount, Mount, pb.FileActionCopy) error
// }
67 changes: 67 additions & 0 deletions solver/llbsolver/file/refmanager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package file

import (
"context"

"github.com/moby/buildkit/cache"
"github.com/moby/buildkit/snapshot"
"github.com/moby/buildkit/solver/llbsolver/ops/fileoptypes"
"github.com/pkg/errors"
)

type RefManager struct {
cm cache.Manager
}

func (rm *RefManager) Prepare(ctx context.Context, ref fileoptypes.Ref, readonly bool) (fileoptypes.Mount, error) {
ir, ok := ref.(cache.ImmutableRef)
if !ok {
return nil, errors.Errorf("invalid ref type: %T", ref)
}

if ir != nil && readonly {
m, err := ir.Mount(ctx, readonly)
if err != nil {
return nil, err
}
return &Mount{m: m}, nil
}

mr, err := rm.cm.New(ctx, ir, cache.WithDescription("fileop target"))
if err != nil {
return nil, err
}
m, err := mr.Mount(ctx, readonly)
if err != nil {
return nil, err
}
return &Mount{m: m, mr: mr}, nil
}

func (rm *RefManager) Commit(ctx context.Context, mount fileoptypes.Mount) (fileoptypes.Ref, error) {
m, ok := mount.(*Mount)
if !ok {
return nil, errors.Errorf("invalid mount type %T", mount)
}
if err := m.Release(context.TODO()); err != nil {
return nil, err
}
if m.mr == nil {
return nil, errors.Errorf("invalid mount without active ref for commit")
}
return m.mr.Commit(ctx)
}

type Mount struct {
m snapshot.Mountable
mr cache.MutableRef
}

func (m *Mount) Release(ctx context.Context) error {
m.m.Release()
if m.mr != nil {
return m.mr.Release(ctx)
}
return nil
}
func (m *Mount) IsFileOpMount() {}

0 comments on commit 2be999b

Please sign in to comment.