mirror of
https://github.com/holos-run/holos.git
synced 2026-03-20 01:04:59 +00:00
This sub-command renders the web app form from CUE code and updates the form using the `holos.platform.v1alpha1.PlatformService/UpdatePlatform` rpc method. Example use case, starting fresh: ``` rm -rf ~/holos mkdir ~/holos cd ~/holos ``` Step 1: Login ```sh holos login ``` ```txt 9:53AM INF login.go:40 logged in as jeff@ois.run version=0.79.0 name="Jeff McCune" exp="2024-05-17 21:16:07 -0700 PDT" email=jeff@ois.run ``` Step 2: Register to create server side resources. ```sh holos register user ``` ``` 9:52AM INF register.go:68 user version=0.79.0 email=jeff@ois.run user_id=018f826d-85a8-751d-81ee-64d0f2775b3f org_id=018f826d-85a8-751e-98dd-a6cddd9dd8f0 ``` Step 3: Generate the bare platform in the local filesystem. ```sh holos generate platform bare ``` ```txt 9:52AM INF generate.go:79 wrote platform.metadata.json version=0.79.0 platform_id=018f826d-85a8-751f-96d0-0d2bf70df909 path=/home/jeff/holos/platform.metadata.json 9:52AM INF generate.go:91 generated platform bare version=0.79.0 platform_id=018f826d-85a8-751f-96d0-0d2bf70df909 path=/home/jeff/holos ``` Step 4: Push the platform form to the `holos server` web app. ```sh holos push platform form . ``` ```txt 9:52AM INF client.go:67 updated platform version=0.79.0 platform_id=018f826d-85a8-751f-96d0-0d2bf70df909 duration=73.62995ms ``` At this point the platform form is published and functions as expected when visiting the platform web interface.
92 lines
2.2 KiB
Go
92 lines
2.2 KiB
Go
package push
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"cuelang.org/go/cue/cuecontext"
|
|
"cuelang.org/go/cue/load"
|
|
"github.com/holos-run/holos"
|
|
"github.com/holos-run/holos/internal/errors"
|
|
)
|
|
|
|
func NewInstance(name string) (*Instance, error) {
|
|
absPath, err := filepath.Abs(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
path := holos.InstancePath(absPath)
|
|
mod, err := FindCueMod(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Instance{path: path, mod: mod}, nil
|
|
}
|
|
|
|
// Instance represents a CUE instance.
|
|
type Instance struct {
|
|
path holos.InstancePath
|
|
mod holos.PathCueMod
|
|
}
|
|
|
|
// Export builds the cue instance into a JSON byte slice. Equivalent of cue
|
|
// export.
|
|
func (i *Instance) Export(ctx context.Context) ([]byte, error) {
|
|
// CUE Loader
|
|
cfg := load.Config{Dir: string(i.mod)}
|
|
|
|
// Make target relative to the module directory
|
|
relPath, err := filepath.Rel(string(i.mod), string(i.path))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
relPath = "./" + relPath
|
|
|
|
instances := load.Instances([]string{relPath}, &cfg)
|
|
if len(instances) != 1 {
|
|
return nil, errors.Wrap(errors.New("exactly one instance is required"))
|
|
}
|
|
instance := instances[0]
|
|
|
|
if err := instance.Err; err != nil {
|
|
return nil, errors.Wrap(fmt.Errorf("could not load: %w", err))
|
|
}
|
|
|
|
cueCtx := cuecontext.New()
|
|
|
|
value := cueCtx.BuildInstance(instance)
|
|
if err := value.Err(); err != nil {
|
|
return nil, errors.Wrap(fmt.Errorf("could not build %s: %w", instance.Dir, err))
|
|
}
|
|
if err := value.Validate(); err != nil {
|
|
return nil, errors.Wrap(fmt.Errorf("could not validate: %w", err))
|
|
}
|
|
|
|
b, err := value.MarshalJSON()
|
|
if err != nil {
|
|
return nil, errors.Wrap(fmt.Errorf("could not marshal cue instance %s: %w", instance.Dir, err))
|
|
}
|
|
|
|
return b, nil
|
|
}
|
|
|
|
func FindCueMod(name holos.InstancePath) (dir holos.PathCueMod, err error) {
|
|
path := holos.PathCueMod(name)
|
|
for {
|
|
if _, err := os.Stat(filepath.Join(string(path), "cue.mod")); err == nil {
|
|
dir = path
|
|
break
|
|
} else if !os.IsNotExist(err) {
|
|
return "", err
|
|
}
|
|
parentPath := holos.PathCueMod(filepath.Dir(string(path)))
|
|
if parentPath == path {
|
|
return "", fmt.Errorf("no cue.mod from root to leaf: %v", name)
|
|
}
|
|
path = parentPath
|
|
}
|
|
return dir, nil
|
|
}
|