Migrate dagger.#Secret and dagger.#Stream to new format

- Refactored to keep every transformation of built-in types (e.g. FS,
  Secret, etc) to/from CUE in the same place (plancontext)
- dagger.#Service and dagger.#Secret are now following the new FS-like format
  (e.g. `_service: id: string`)
- Backward compatibility
- dagger.#Stream is now an alias for dagger.#Service

Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
This commit is contained in:
Andrea Luzzardi
2021-11-30 17:51:28 -08:00
parent 5ab3c47dac
commit 5b7b1cab79
27 changed files with 284 additions and 217 deletions

View File

@@ -2,18 +2,10 @@ package plancontext
import (
"crypto/sha256"
"encoding/json"
"fmt"
)
type ContextKey string
// Context holds the execution context for a plan.
//
// Usage:
// ctx := plancontext.New()
// id := ctx.Secrets.Register("mysecret")
// secret := ctx.Secrets.Get(id)
type Context struct {
Platform *platformContext
FS *fsContext
@@ -28,25 +20,26 @@ func New() *Context {
platform: defaultPlatform,
},
FS: &fsContext{
store: make(map[ContextKey]*FS),
store: make(map[string]*FS),
},
LocalDirs: &localDirContext{
store: make(map[ContextKey]*LocalDir),
store: []string{},
},
Secrets: &secretContext{
store: make(map[ContextKey]*Secret),
store: make(map[string]*Secret),
},
Services: &serviceContext{
store: make(map[ContextKey]*Service),
store: make(map[string]*Service),
},
}
}
func hashID(v interface{}) ContextKey {
data, err := json.Marshal(v)
if err != nil {
panic(err)
func hashID(values ...string) string {
hash := sha256.New()
for _, v := range values {
if _, err := hash.Write([]byte(v)); err != nil {
panic(err)
}
}
hash := sha256.Sum256(data)
return ContextKey(fmt.Sprintf("%x", hash))
return fmt.Sprintf("%x", hash)
}

View File

@@ -9,10 +9,8 @@ import (
func TestContext(t *testing.T) {
ctx := New()
id := ctx.Secrets.Register(&Secret{
PlainText: "test",
})
secret := ctx.Secrets.Get(id)
require.NotNil(t, secret)
require.Equal(t, "test", secret.PlainText)
secret := ctx.Secrets.New("test")
get, err := ctx.Secrets.FromValue(secret.Value())
require.NoError(t, err)
require.Equal(t, "test", get.PlainText())
}

View File

@@ -1,32 +1,71 @@
package plancontext
import (
"fmt"
"sync"
"cuelang.org/go/cue"
"github.com/google/uuid"
bkgw "github.com/moby/buildkit/frontend/gateway/client"
"go.dagger.io/dagger/compiler"
)
var (
fsIDPath = cue.MakePath(
cue.Hid("_fs", "alpha.dagger.io/dagger"),
cue.Str("id"),
)
)
type FS struct {
Result bkgw.Reference
id string
result bkgw.Reference
}
func (fs *FS) Result() bkgw.Reference {
return fs.result
}
func (fs *FS) Value() *compiler.Value {
v := compiler.NewValue()
if err := v.FillPath(fsIDPath, fs.id); err != nil {
panic(err)
}
return v
}
type fsContext struct {
l sync.RWMutex
store map[ContextKey]*FS
store map[string]*FS
}
func (c *fsContext) Register(fs *FS) ContextKey {
func (c *fsContext) New(result bkgw.Reference) *FS {
c.l.Lock()
defer c.l.Unlock()
id := hashID(fs)
c.store[id] = fs
return id
fs := &FS{
// FIXME: get a hash from result instead
id: uuid.New().String(),
result: result,
}
c.store[fs.id] = fs
return fs
}
func (c *fsContext) Get(id ContextKey) *FS {
func (c *fsContext) FromValue(v *compiler.Value) (*FS, error) {
c.l.RLock()
defer c.l.RUnlock()
return c.store[id]
id, err := v.LookupPath(fsIDPath).String()
if err != nil {
return nil, fmt.Errorf("invalid FS %q: %w", v.Path(), err)
}
fs, ok := c.store[id]
if !ok {
return nil, fmt.Errorf("fs %q not found", id)
}
return fs, nil
}

View File

@@ -5,41 +5,16 @@ import (
"sync"
)
type LocalDir struct {
Path string
}
type localDirContext struct {
l sync.RWMutex
store map[ContextKey]*LocalDir
store []string
}
func (c *localDirContext) Register(directory *LocalDir) ContextKey {
func (c *localDirContext) Add(dir string) {
c.l.Lock()
defer c.l.Unlock()
id := hashID(directory)
c.store[id] = directory
return id
}
func (c *localDirContext) Get(id ContextKey) *LocalDir {
c.l.RLock()
defer c.l.RUnlock()
return c.store[id]
}
func (c *localDirContext) List() []*LocalDir {
c.l.RLock()
defer c.l.RUnlock()
directories := make([]*LocalDir, 0, len(c.store))
for _, d := range c.store {
directories = append(directories, d)
}
return directories
c.store = append(c.store, dir)
}
func (c *localDirContext) Paths() (map[string]string, error) {
@@ -48,12 +23,12 @@ func (c *localDirContext) Paths() (map[string]string, error) {
directories := make(map[string]string)
for _, d := range c.store {
abs, err := filepath.Abs(d.Path)
abs, err := filepath.Abs(d)
if err != nil {
return nil, err
}
directories[d.Path] = abs
directories[d] = abs
}
return directories, nil

View File

@@ -1,26 +1,77 @@
package plancontext
import "sync"
import (
"fmt"
"sync"
"cuelang.org/go/cue"
"go.dagger.io/dagger/compiler"
)
var (
secretIDPath = cue.MakePath(
cue.Hid("_secret", "alpha.dagger.io/dagger"),
cue.Str("id"),
)
)
type Secret struct {
id string
plainText string
}
func (s *Secret) ID() string {
return s.id
}
func (s *Secret) PlainText() string {
return s.plainText
}
func (s *Secret) Value() *compiler.Value {
v := compiler.NewValue()
if err := v.FillPath(secretIDPath, s.id); err != nil {
panic(err)
}
return v
}
type secretContext struct {
l sync.RWMutex
store map[ContextKey]*Secret
store map[string]*Secret
}
type Secret struct {
PlainText string
}
func (c *secretContext) New(plaintext string) *Secret {
secret := &Secret{
id: hashID(plaintext),
plainText: plaintext,
}
func (c *secretContext) Register(secret *Secret) ContextKey {
c.l.Lock()
defer c.l.Unlock()
id := hashID(secret.PlainText)
c.store[id] = secret
return id
c.store[secret.id] = secret
return secret
}
func (c *secretContext) Get(id ContextKey) *Secret {
func (c *secretContext) FromValue(v *compiler.Value) (*Secret, error) {
c.l.RLock()
defer c.l.RUnlock()
id, err := v.LookupPath(secretIDPath).String()
if err != nil {
return nil, fmt.Errorf("invalid secret %q: %w", v.Path(), err)
}
secret, ok := c.store[id]
if !ok {
return nil, fmt.Errorf("secret %q not found", id)
}
return secret, nil
}
func (c *secretContext) Get(id string) *Secret {
c.l.RLock()
defer c.l.RUnlock()

View File

@@ -1,27 +1,84 @@
package plancontext
import "sync"
import (
"fmt"
"sync"
"cuelang.org/go/cue"
"go.dagger.io/dagger/compiler"
)
var (
serviceIDPath = cue.MakePath(
cue.Hid("_service", "alpha.dagger.io/dagger"),
cue.Str("id"),
)
)
type Service struct {
id string
unix string
npipe string
}
func (s *Service) ID() string {
return s.id
}
func (s *Service) Unix() string {
return s.unix
}
func (s *Service) NPipe() string {
return s.npipe
}
func (s *Service) Value() *compiler.Value {
v := compiler.NewValue()
if err := v.FillPath(serviceIDPath, s.id); err != nil {
panic(err)
}
return v
}
type serviceContext struct {
l sync.RWMutex
store map[ContextKey]*Service
store map[string]*Service
}
type Service struct {
Unix string
Npipe string
}
func (c *serviceContext) Register(service *Service) ContextKey {
func (c *serviceContext) New(unix, npipe string) *Service {
c.l.Lock()
defer c.l.Unlock()
id := hashID(service)
c.store[id] = service
return id
s := &Service{
id: hashID(unix, npipe),
unix: unix,
npipe: npipe,
}
c.store[s.id] = s
return s
}
func (c *serviceContext) Get(id ContextKey) *Service {
func (c *serviceContext) FromValue(v *compiler.Value) (*Service, error) {
c.l.RLock()
defer c.l.RUnlock()
id, err := v.LookupPath(serviceIDPath).String()
if err != nil {
return nil, fmt.Errorf("invalid service %q: %w", v.Path(), err)
}
s, ok := c.store[id]
if !ok {
return nil, fmt.Errorf("service %q not found", id)
}
return s, nil
}
func (c *serviceContext) Get(id string) *Service {
c.l.RLock()
defer c.l.RUnlock()