Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add distinct type for cache paths #202

Merged
merged 2 commits into from
Jul 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ require (
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/jessevdk/go-flags v1.4.0 // indirect
github.com/klauspost/compress v1.15.0 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/klauspost/pgzip v1.2.4 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
Expand All @@ -96,6 +97,7 @@ require (
github.com/tonistiigi/fsutil v0.0.0-20220115021204-b19f7f9cb274 // indirect
github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f // indirect
github.com/vbatts/go-mtree v0.5.0 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0 // indirect
go.opentelemetry.io/otel v1.4.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,8 @@ github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U=
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A=
github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
Expand Down Expand Up @@ -1014,6 +1016,8 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
Expand Down
2 changes: 1 addition & 1 deletion nix/vendorSha256.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sha256-YDpyencMX3tg1slH3D3nhcazpF/oPfRJFgu/vsm9LD8=
sha256-ee675i1cCL78hHCQM6zQXy16rygOcco1lW7puvJdRSY=
137 changes: 137 additions & 0 deletions pkg/bass/cache_path.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package bass

import (
"context"
"encoding/base64"
"encoding/binary"
"fmt"
"path/filepath"
"strings"

"github.com/vito/bass/pkg/proto"
"github.com/zeebo/xxh3"
)

// CachePath is a Path within an ephemeral directory managed by the runtime.
type CachePath struct {
ID string
Path FileOrDirPath
}

var _ Value = CachePath{}

func NewCacheDir(id string) CachePath {
return NewCachePath(id, ParseFileOrDirPath("."))
}

func NewCachePath(id string, path FileOrDirPath) CachePath {
return CachePath{
ID: id,
Path: path,
}
}

func ParseCachePath(path string) CachePath {
return NewCachePath(
filepath.Dir(path),
ParseFileOrDirPath(filepath.Base(path)),
)
}

func (value CachePath) String() string {
return fmt.Sprintf("<cache: %s>/%s", value.ID, strings.TrimPrefix(value.Path.Slash(), "./"))
}

func (value CachePath) Hash() string {
var tmp [8]byte
binary.BigEndian.PutUint64(tmp[:], xxh3.HashString(value.ID))
return base64.URLEncoding.EncodeToString(tmp[:])
}

func (value CachePath) Equal(other Value) bool {
var o CachePath
return other.Decode(&o) == nil &&
value.ID == o.ID &&
value.Path.FilesystemPath().Equal(o.Path.FilesystemPath())
}

func (value CachePath) Decode(dest any) error {
switch x := dest.(type) {
case *CachePath:
*x = value
return nil
case *Path:
*x = value
return nil
case *Value:
*x = value
return nil
case *Applicative:
*x = value
return nil
case *Combiner:
*x = value
return nil
case Decodable:
return x.FromValue(value)
default:
return DecodeError{
Source: value,
Destination: dest,
}
}
}

func (path *CachePath) UnmarshalProto(msg proto.Message) error {
p, ok := msg.(*proto.CachePath)
if !ok {
return fmt.Errorf("unmarshal proto: %w", DecodeError{msg, path})
}

path.ID = p.Id

return path.Path.UnmarshalProto(p.Path)
}

// Eval returns the value.
func (value CachePath) Eval(_ context.Context, _ *Scope, cont Cont) ReadyCont {
return cont.Call(value, nil)
}

var _ Applicative = ThunkPath{}

func (app CachePath) Unwrap() Combiner {
if app.Path.File != nil {
return ThunkOperative{
Cmd: ThunkCmd{
Cache: &app,
},
}
} else {
return ExtendOperative{app}
}
}

var _ Combiner = CachePath{}

func (combiner CachePath) Call(ctx context.Context, val Value, scope *Scope, cont Cont) ReadyCont {
return Wrap(combiner.Unwrap()).Call(ctx, val, scope, cont)
}

var _ Path = CachePath{}

func (path CachePath) Name() string {
return path.Path.FilesystemPath().Name()
}

func (path CachePath) Extend(ext Path) (Path, error) {
extended := path

var err error
extended.Path, err = path.Path.Extend(ext)
if err != nil {
return nil, err
}

return extended, nil
}
5 changes: 5 additions & 0 deletions pkg/bass/ground.go
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,11 @@ func init() {
`=> (def file-thunk (from (linux/alpine) ($ sh -c "echo 42 > file")))`,
`=> (next (read file-thunk/file :json))`,
)

Ground.Set("cache-dir",
Func("cache-dir", "[id]", NewCacheDir),
`returns a cache directory corresponding to the string identifier`,
`Cache directories may be mounted to thunks. Their content persists across thunk runs.`)
}

type primPred struct {
Expand Down
7 changes: 5 additions & 2 deletions pkg/bass/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,11 @@ var validThunkMountSources = []bass.ThunkMountSource{
FSPath: bass.NewInMemoryFile("fs/mount-dir/file", "hello").Dir(),
},
{
Cache: &bass.FileOrDirPath{
Dir: &bass.DirPath{"cache/dir"},
Cache: &bass.CachePath{
ID: "some-cache",
Path: bass.FileOrDirPath{
Dir: &bass.DirPath{"cache/dir"},
},
},
},
{
Expand Down
15 changes: 15 additions & 0 deletions pkg/bass/proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,21 @@ func (value *FSPath) MarshalProto() (proto.Message, error) {
return lp, nil
}

func (value CachePath) MarshalProto() (proto.Message, error) {
pv := &proto.CachePath{
Id: value.ID,
}

pathp, err := value.Path.MarshalProto()
if err != nil {
return nil, err
}

pv.Path = pathp.(*proto.FilesystemPath)

return pv, nil
}

func (value Thunk) MarshalProto() (proto.Message, error) {
thunk := &proto.Thunk{
Insecure: value.Insecure,
Expand Down
Loading