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 services via thunk addrs #225

Merged
merged 6 commits into from
Aug 8, 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
18 changes: 18 additions & 0 deletions demos/addrs.bass
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
; a simple server that returns a static index
(defn http-server [port index]
(from (linux/python)
(-> ($ python -m http.server (str port))
(with-mount (mkfile ./index.html index) ./index.html)
(with-port :http port))))

(defn main []
; construct a couple of server thunks (doesn't start them)
(let [hello (http-server 1111 "hello,")
world (http-server 2222 "world!")]
; curl both thunk addrs
;
; starts the two servers, waits for the ports to be ready, and resolves to
; a string using the given template
(run (from (linux/nixery.dev/shell/curl)
($ curl -s (addr hello :http "http://$host:$port"))
($ curl -s (addr world :http "http://$host:$port"))))))
4 changes: 4 additions & 0 deletions docs/go/bass.go
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,10 @@ func (plugin *Plugin) bindingDocs(ns string, scope *bass.Scope, sym bass.Symbol,
endLine = booklit.String(strconv.Itoa(end))
}

if loc.File == nil {
return nil, fmt.Errorf("binding has no file location: %s", sym)
}

var path string
var fsp *bass.FSPath
if err := loc.File.Decode(&fsp); err == nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/bass/cache_path.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (value CachePath) String() string {

// Hash returns a non-cryptographic hash of the cache path's ID.
func (value CachePath) Hash() string {
return b64(xxh3.HashString(value.ID))
return b32(xxh3.HashString(value.ID))
}

func (value CachePath) Equal(other Value) bool {
Expand Down
98 changes: 74 additions & 24 deletions pkg/bass/json_test.go → pkg/bass/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,33 +122,60 @@ var validThiccThunk = bass.Thunk{
},
Env: stableEnv,
Labels: stableLabels,
Ports: []bass.ThunkPort{
{"http", 80},
{"ssh", 22},
},
}

var validThunkImages = []bass.ThunkImage{
{
Thunk: &validBasicThunk,
},
}

var validThunkImageRefs = []bass.ThunkImageRef{
var validThunkImageRefs = []bass.ImageRef{
{
Platform: bass.Platform{
OS: "os",
Arch: "arch",
},
Repository: bass.ImageRepository{
Static: "repo",
},
Tag: "tag",
Digest: "digest",
},
{
Platform: bass.Platform{
OS: "os",
Arch: "arch",
},
Repository: "repo",
Tag: "tag",
Repository: bass.ImageRepository{
Static: "repo",
},
Tag: "tag",
// no digest
},
{
Platform: bass.Platform{
OS: "os",
// no arch
},
Repository: "repo",
Tag: "tag",
Repository: bass.ImageRepository{
Static: "repo",
},
Tag: "tag",
// no digest
},
{
Platform: bass.Platform{
OS: "os",
// no arch
},
Repository: "repo",
Repository: bass.ImageRepository{
Static: "repo",
},
// no tag
// no digest
},
Expand All @@ -157,39 +184,55 @@ var validThunkImageRefs = []bass.ThunkImageRef{
OS: "os",
Arch: "arch",
},
Repository: "repo",
Tag: "tag",
Digest: "digest",
Repository: bass.ImageRepository{
Addr: &bass.ThunkAddr{
Thunk: validBasicThunk,
Port: "http",
Format: "$host:$port/repo",
},
},
Tag: "tag",
Digest: "digest",
},
{
Platform: bass.Platform{
OS: "os",
Arch: "arch",
OS: "os",
// no arch
},
File: &bass.ThunkPath{
Thunk: validBasicThunk,
Path: bass.ParseFileOrDirPath("image.tar"),
Repository: bass.ImageRepository{
Addr: &bass.ThunkAddr{
Thunk: validBasicThunk,
Port: "http",
Format: "$host:$port/repo",
},
},
Tag: "tag",
// no tag
// no digest
},
}

var validThunkImageArchives = []bass.ImageArchive{
{
File: bass.ThunkPath{
Thunk: validBasicThunk,
Path: bass.ParseFileOrDirPath("image.tar"),
},
Platform: bass.Platform{
OS: "os",
Arch: "arch",
},
File: &bass.ThunkPath{
Tag: "tag",
},
{
File: bass.ThunkPath{
Thunk: validBasicThunk,
Path: bass.ParseFileOrDirPath("image.tar"),
},
Tag: "tag",
Digest: "digest",
},
}

var validThunkImages = []bass.ThunkImage{
{
Thunk: &validBasicThunk,
Platform: bass.Platform{
OS: "os",
Arch: "arch",
},
// no tag
},
}

Expand All @@ -201,6 +244,13 @@ func init() {
})
}

for _, ref := range validThunkImageArchives {
cp := ref
validThunkImages = append(validThunkImages, bass.ThunkImage{
Archive: &cp,
})
}

for _, img := range validThunkImages {
thunk := validBasicThunk
cp := img
Expand Down
4 changes: 2 additions & 2 deletions pkg/bass/fake_runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ type ExportPath struct {
FS fstest.MapFS
}

func (fake *FakeRuntime) Resolve(context.Context, bass.ThunkImageRef) (bass.ThunkImageRef, error) {
return bass.ThunkImageRef{}, fmt.Errorf("Resolve unimplemented")
func (fake *FakeRuntime) Resolve(context.Context, bass.ImageRef) (bass.ImageRef, error) {
return bass.ImageRef{}, fmt.Errorf("Resolve unimplemented")
}

func (fake *FakeRuntime) Run(context.Context, bass.Thunk) error {
Expand Down
42 changes: 21 additions & 21 deletions pkg/bass/filesystem_path.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,27 @@ func (path FileOrDirPath) ToValue() Value {
}
}

// FromValue decodes val into a FilePath or a DirPath, setting whichever worked
// as the internal value.
func (path *FileOrDirPath) FromValue(val Value) error {
var file FilePath
if err := val.Decode(&file); err == nil {
path.File = &file
return nil
}

var dir DirPath
if err := val.Decode(&dir); err == nil {
path.Dir = &dir
return nil
}

return DecodeError{
Source: val,
Destination: path,
}
}

func (path *FileOrDirPath) UnmarshalProto(msg proto.Message) error {
p, ok := msg.(*proto.FilesystemPath)
if !ok {
Expand Down Expand Up @@ -158,24 +179,3 @@ func (value *FileOrDirPath) UnmarshalJSON(b []byte) error {

return value.UnmarshalProto(msg)
}

// FromValue decodes val into a FilePath or a DirPath, setting whichever worked
// as the internal value.
func (path *FileOrDirPath) FromValue(val Value) error {
var file FilePath
if err := val.Decode(&file); err == nil {
path.File = &file
return nil
}

var dir DirPath
if err := val.Decode(&dir); err == nil {
path.Dir = &dir
return nil
}

return DecodeError{
Source: val,
Destination: path,
}
}
24 changes: 22 additions & 2 deletions pkg/bass/ground.go
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,11 @@ func init() {
`Labels are typically used to control caching. Two thunks that differ only in labels will evaluate separately and produce independent results.`,
`=> (with-label ($ sleep 10) :at (now 10))`)

Ground.Set("with-port",
Func("with-port", "[thunk sym int]", (Thunk).WithPort),
`returns thunk with a named port appended to its ports`,
`=> (with-port ($ godoc -http=:6060) :godoc 6060)`)

Ground.Set("with-mount",
Func("with-mount", "[thunk source target]", (Thunk).WithMount),
`returns thunk with a mount from source to the target path`,
Expand Down Expand Up @@ -720,10 +725,10 @@ func init() {
`=> (load (.strings))`)

Ground.Set("resolve",
Func("resolve", "[platform ref]", func(ctx context.Context, ref ThunkImageRef) (ThunkImageRef, error) {
Func("resolve", "[platform ref]", func(ctx context.Context, ref ImageRef) (ImageRef, error) {
runtime, err := RuntimeFromContext(ctx, ref.Platform)
if err != nil {
return ThunkImageRef{}, err
return ImageRef{}, err
}

return runtime.Resolve(ctx, ref)
Expand All @@ -745,6 +750,21 @@ func init() {
`=> ((start (from (linux/alpine) ($ banana)) raiser))`,
`=> ((start (from (linux/alpine) ($ echo)) raiser))`)

Ground.Set("addr", Func("addr", "[thunk port & fmt]", (Thunk).Addr),
`returns an address for a port provided by the thunk`,
`Takes an optional format argument which defaults to "$host:$port".`,
`=> (def thunk (-> ($ python -m http.server) (with-port :http 8080)))`,
`=> (addr thunk :http)`)

Ground.Set("wait",
Func("wait", "[]", func(ctx context.Context) error {
return RunsFromContext(ctx).Wait()
}),
`waits for all started thunks to finish`,
`Returns an error if any of the thunk handlers error.`,
`=> (defn echo-server [msg] (start (from (linux/alpine) ($ sleep 1 $msg)) null?))`,
`=> (wait)`)

Ground.Set("read",
Func("read", "[thunk-or-file protocol]", func(ctx context.Context, read Readable, proto Symbol) (*Source, error) {
sink := NewInMemorySink()
Expand Down
2 changes: 1 addition & 1 deletion pkg/bass/host_path.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (value HostPath) String() string {

// Hash returns a non-cryptographic hash of the host path's context dir.
func (value HostPath) Hash() string {
return b64(xxh3.HashString(value.ContextDir))
return b32(xxh3.HashString(value.ContextDir))
}

func (value HostPath) Equal(other Value) bool {
Expand Down
2 changes: 1 addition & 1 deletion pkg/bass/memo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func uniq(thunk bass.Thunk) bass.Thunk {
func TestOpenMemosThunkPath(t *testing.T) {
baseThunk := bass.Thunk{
Image: &bass.ThunkImage{
Ref: &bass.ThunkImageRef{
Ref: &bass.ImageRef{
Platform: fakePlatform,
},
},
Expand Down
7 changes: 7 additions & 0 deletions pkg/bass/proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,13 @@ func (value Thunk) MarshalProto() (proto.Message, error) {
}
}

for _, port := range value.Ports {
thunk.Ports = append(thunk.Ports, &proto.ThunkPort{
Name: port.Name,
Port: int32(port.Port),
})
}

return thunk, nil
}

Expand Down
28 changes: 27 additions & 1 deletion pkg/bass/runs.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,49 @@ import (
type Runs struct {
wg sync.WaitGroup

stops []func()
stopsL sync.Mutex

errs error
errsL sync.Mutex
}

func (runs *Runs) Go(f func() error) {
func (runs *Runs) Go(stop func(), f func() error) {
runs.wg.Add(1)
go func() {
defer runs.wg.Done()
runs.record(f())
}()

runs.stopsL.Lock()
runs.stops = append(runs.stops, stop)
runs.stopsL.Unlock()
}

func (runs *Runs) Stop() {
runs.stopsL.Lock()
for _, stop := range runs.stops {
stop()
}
runs.stopsL.Unlock()
}

func (runs *Runs) Wait() error {
runs.wg.Wait()
return runs.errs
}

func (runs *Runs) StopAndWait() error {
runs.Stop()
return runs.Wait()
}

func (runs *Runs) Err() error {
runs.errsL.Lock()
defer runs.errsL.Unlock()
return runs.errs
}

func (runs *Runs) record(err error) {
runs.errsL.Lock()
if runs.errs != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/bass/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type RuntimePool interface {
}

type Runtime interface {
Resolve(context.Context, ThunkImageRef) (ThunkImageRef, error)
Resolve(context.Context, ImageRef) (ImageRef, error)
Run(context.Context, Thunk) error
Read(context.Context, io.Writer, Thunk) error
Export(context.Context, io.Writer, Thunk) error
Expand Down
Loading