Merge pull request #235 from dagger/cli-query
Implemented cli query command
This commit is contained in:
commit
e0afc6304d
@ -65,9 +65,12 @@ func DeploymentUp(ctx context.Context, deployment *dagger.Deployment) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Fatal().Err(err).Msg("unable to create client")
|
lg.Fatal().Err(err).Msg("unable to create client")
|
||||||
}
|
}
|
||||||
output, err := c.Up(ctx, deployment)
|
output, err := c.Do(ctx, deployment, func(ctx context.Context, deployment *dagger.Deployment, s dagger.Solver) error {
|
||||||
|
log.Ctx(ctx).Debug().Msg("bringing deployment up")
|
||||||
|
return deployment.Up(ctx, s, nil)
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Fatal().Err(err).Msg("failed to compute")
|
lg.Fatal().Err(err).Msg("failed to up deployment")
|
||||||
}
|
}
|
||||||
fmt.Println(output.JSON())
|
fmt.Println(output.JSON())
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,20 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"cuelang.org/go/cue"
|
||||||
"dagger.io/go/cmd/dagger/cmd/common"
|
"dagger.io/go/cmd/dagger/cmd/common"
|
||||||
"dagger.io/go/cmd/dagger/logger"
|
"dagger.io/go/cmd/dagger/logger"
|
||||||
"dagger.io/go/dagger"
|
"dagger.io/go/dagger"
|
||||||
|
"dagger.io/go/dagger/compiler"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
var queryCmd = &cobra.Command{
|
var queryCmd = &cobra.Command{
|
||||||
Use: "query [EXPR] [flags]",
|
Use: "query [TARGET] [flags]",
|
||||||
Short: "Query the contents of a deployment",
|
Short: "Query the contents of a deployment",
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.MaximumNArgs(1),
|
||||||
PreRun: func(cmd *cobra.Command, args []string) {
|
PreRun: func(cmd *cobra.Command, args []string) {
|
||||||
// Fix Viper bug for duplicate flags:
|
// Fix Viper bug for duplicate flags:
|
||||||
// https://github.com/spf13/viper/issues/233
|
// https://github.com/spf13/viper/issues/233
|
||||||
@ -26,6 +28,8 @@ var queryCmd = &cobra.Command{
|
|||||||
lg := logger.New()
|
lg := logger.New()
|
||||||
ctx := lg.WithContext(cmd.Context())
|
ctx := lg.WithContext(cmd.Context())
|
||||||
|
|
||||||
|
cueOpts := parseQueryFlags()
|
||||||
|
|
||||||
store, err := dagger.DefaultStore()
|
store, err := dagger.DefaultStore()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Fatal().Err(err).Msg("failed to load store")
|
lg.Fatal().Err(err).Msg("failed to load store")
|
||||||
@ -33,31 +37,73 @@ var queryCmd = &cobra.Command{
|
|||||||
|
|
||||||
deployment := common.GetCurrentDeployment(ctx, store)
|
deployment := common.GetCurrentDeployment(ctx, store)
|
||||||
|
|
||||||
expr := args[0]
|
lg = lg.With().
|
||||||
|
Str("deploymentName", deployment.Name()).
|
||||||
|
Str("deploymentId", deployment.ID()).
|
||||||
|
Logger()
|
||||||
|
|
||||||
out, err := deployment.Query(ctx, expr, nil)
|
cuePath := cue.MakePath()
|
||||||
if err != nil {
|
if len(args) > 0 {
|
||||||
lg.
|
cuePath = cue.ParsePath(args[0])
|
||||||
Fatal().
|
|
||||||
Err(err).
|
|
||||||
Str("deploymentName", deployment.Name()).
|
|
||||||
Str("deploymentId", deployment.ID()).
|
|
||||||
Msg("failed to query deployment")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(out)
|
c, err := dagger.NewClient(ctx, "")
|
||||||
// TODO: Implement options: --no-*, --format, --revision
|
if err != nil {
|
||||||
|
lg.Fatal().Err(err).Msg("unable to create client")
|
||||||
|
}
|
||||||
|
output, err := c.Do(ctx, deployment, nil)
|
||||||
|
if err != nil {
|
||||||
|
lg.Fatal().Err(err).Msg("failed to query deployment")
|
||||||
|
}
|
||||||
|
|
||||||
|
cueVal := output.LookupPath(cuePath)
|
||||||
|
|
||||||
|
if viper.GetBool("concrete") {
|
||||||
|
if err := cueVal.IsConcreteR(); err != nil {
|
||||||
|
lg.Fatal().Err(compiler.Err(err)).Msg("not concrete")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := cueVal.Source(cueOpts...)
|
||||||
|
if err != nil {
|
||||||
|
lg.Fatal().Err(err).Msg("failed to lookup source")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(out))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func parseQueryFlags() []cue.Option {
|
||||||
queryCmd.Flags().String("revision", "latest", "Query a specific version of the deployment")
|
opts := []cue.Option{
|
||||||
queryCmd.Flags().StringP("format", "f", "", "Output format (json|yaml|cue|text|env)")
|
cue.Definitions(true),
|
||||||
|
}
|
||||||
|
|
||||||
queryCmd.Flags().BoolP("--no-input", "I", false, "Exclude inputs from query")
|
if viper.GetBool("concrete") {
|
||||||
queryCmd.Flags().BoolP("--no-output", "O", false, "Exclude outputs from query")
|
opts = append(opts, cue.Concrete(true))
|
||||||
queryCmd.Flags().BoolP("--no-plan", "P", false, "Exclude outputs from query")
|
}
|
||||||
|
|
||||||
|
if viper.GetBool("show-optional") {
|
||||||
|
opts = append(opts, cue.Optional(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
if viper.GetBool("show-attributes") {
|
||||||
|
opts = append(opts, cue.Attributes(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
queryCmd.Flags().BoolP("concrete", "c", false, "Require the evaluation to be concrete")
|
||||||
|
queryCmd.Flags().BoolP("show-optional", "O", false, "Display optional fields")
|
||||||
|
queryCmd.Flags().BoolP("show-attributes", "A", false, "Display field attributes")
|
||||||
|
|
||||||
|
// FIXME: implement the flags below
|
||||||
|
// queryCmd.Flags().String("revision", "latest", "Query a specific version of the deployment")
|
||||||
|
// queryCmd.Flags().StringP("format", "f", "", "Output format (json|yaml|cue|text|env)")
|
||||||
|
// queryCmd.Flags().BoolP("no-input", "I", false, "Exclude inputs from query")
|
||||||
|
// queryCmd.Flags().BoolP("no-output", "O", false, "Exclude outputs from query")
|
||||||
|
// queryCmd.Flags().BoolP("no-plan", "P", false, "Exclude outputs from query")
|
||||||
|
|
||||||
if err := viper.BindPFlags(queryCmd.Flags()); err != nil {
|
if err := viper.BindPFlags(queryCmd.Flags()); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -61,8 +61,10 @@ func NewClient(ctx context.Context, host string) (*Client, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ClientDoFunc func(context.Context, *Deployment, Solver) error
|
||||||
|
|
||||||
// FIXME: return completed *Route, instead of *compiler.Value
|
// FIXME: return completed *Route, instead of *compiler.Value
|
||||||
func (c *Client) Up(ctx context.Context, deployment *Deployment) (*compiler.Value, error) {
|
func (c *Client) Do(ctx context.Context, deployment *Deployment, fn ClientDoFunc) (*compiler.Value, error) {
|
||||||
lg := log.Ctx(ctx)
|
lg := log.Ctx(ctx)
|
||||||
eg, gctx := errgroup.WithContext(ctx)
|
eg, gctx := errgroup.WithContext(ctx)
|
||||||
|
|
||||||
@ -79,7 +81,7 @@ func (c *Client) Up(ctx context.Context, deployment *Deployment) (*compiler.Valu
|
|||||||
outr, outw := io.Pipe()
|
outr, outw := io.Pipe()
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
defer outw.Close()
|
defer outw.Close()
|
||||||
return c.buildfn(gctx, deployment, events, outw)
|
return c.buildfn(gctx, deployment, fn, events, outw)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Spawn output retriever
|
// Spawn output retriever
|
||||||
@ -96,7 +98,7 @@ func (c *Client) Up(ctx context.Context, deployment *Deployment) (*compiler.Valu
|
|||||||
return out, eg.Wait()
|
return out, eg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) buildfn(ctx context.Context, deployment *Deployment, ch chan *bk.SolveStatus, w io.WriteCloser) error {
|
func (c *Client) buildfn(ctx context.Context, deployment *Deployment, fn ClientDoFunc, ch chan *bk.SolveStatus, w io.WriteCloser) error {
|
||||||
lg := log.Ctx(ctx)
|
lg := log.Ctx(ctx)
|
||||||
|
|
||||||
// Scan local dirs to grant access
|
// Scan local dirs to grant access
|
||||||
@ -138,9 +140,10 @@ func (c *Client) buildfn(ctx context.Context, deployment *Deployment, ch chan *b
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute output overlay
|
// Compute output overlay
|
||||||
lg.Debug().Msg("computing deployment")
|
if fn != nil {
|
||||||
if err := deployment.Up(ctx, s, nil); err != nil {
|
if err := fn(ctx, deployment, s); err != nil {
|
||||||
return nil, compiler.Err(err)
|
return nil, compiler.Err(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export deployment to a cue directory
|
// Export deployment to a cue directory
|
||||||
@ -149,9 +152,14 @@ func (c *Client) buildfn(ctx context.Context, deployment *Deployment, ch chan *b
|
|||||||
span, _ := opentracing.StartSpanFromContext(ctx, "Deployment.Export")
|
span, _ := opentracing.StartSpanFromContext(ctx, "Deployment.Export")
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
|
stateSource, err := deployment.State().Source()
|
||||||
|
if err != nil {
|
||||||
|
return nil, compiler.Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
st := llb.Scratch().File(
|
st := llb.Scratch().File(
|
||||||
llb.Mkfile("state.cue", 0600, deployment.State().JSON()),
|
llb.Mkfile("state.cue", 0600, stateSource),
|
||||||
llb.WithCustomName("[internal] serializing state to JSON"),
|
llb.WithCustomName("[internal] serializing state to CUE"),
|
||||||
)
|
)
|
||||||
ref, err := s.Solve(ctx, st)
|
ref, err := s.Solve(ctx, st)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -204,11 +204,11 @@ func (v *Value) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return cue source for this value
|
// Return cue source for this value
|
||||||
func (v *Value) Source() ([]byte, error) {
|
func (v *Value) Source(opts ...cue.Option) ([]byte, error) {
|
||||||
v.cc.rlock()
|
v.cc.rlock()
|
||||||
defer v.cc.runlock()
|
defer v.cc.runlock()
|
||||||
|
|
||||||
return cueformat.Node(v.val.Eval().Syntax())
|
return cueformat.Node(v.val.Eval().Syntax(opts...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Value) IsEmptyStruct() bool {
|
func (v *Value) IsEmptyStruct() bool {
|
||||||
|
@ -308,10 +308,6 @@ func (d *Deployment) Down(ctx context.Context, _ *DownOpts) error {
|
|||||||
panic("NOT IMPLEMENTED")
|
panic("NOT IMPLEMENTED")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Deployment) Query(ctx context.Context, expr interface{}, o *QueryOpts) (*compiler.Value, error) {
|
|
||||||
panic("NOT IMPLEMENTED")
|
|
||||||
}
|
|
||||||
|
|
||||||
type QueryOpts struct{}
|
type QueryOpts struct{}
|
||||||
|
|
||||||
func newTaskFunc(inst *cue.Instance, runner cueflow.RunnerFunc) cueflow.TaskFunc {
|
func newTaskFunc(inst *cue.Instance, runner cueflow.RunnerFunc) cueflow.TaskFunc {
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
package test
|
package test
|
||||||
|
|
||||||
import "dagger.io/dagger"
|
import (
|
||||||
|
"dagger.io/dagger"
|
||||||
|
"dagger.io/llb"
|
||||||
|
)
|
||||||
|
|
||||||
// Set to `--input-dir=./tests/dockerbuild/testdata`
|
// Set to `--input-dir=./tests/dockerbuild/testdata`
|
||||||
TestData: dagger.#Artifact
|
TestData: dagger.#Artifact
|
||||||
|
|
||||||
TestInlinedDockerfile: #compute: [
|
TestInlinedDockerfile: #compute: [
|
||||||
dagger.#DockerBuild & {
|
llb.#DockerBuild & {
|
||||||
dockerfile: """
|
dockerfile: """
|
||||||
FROM alpine:latest@sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
|
FROM alpine:latest@sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
|
||||||
RUN echo hello world
|
RUN echo hello world
|
||||||
@ -15,51 +18,51 @@ TestInlinedDockerfile: #compute: [
|
|||||||
]
|
]
|
||||||
|
|
||||||
TestOpChaining: #compute: [
|
TestOpChaining: #compute: [
|
||||||
dagger.#DockerBuild & {
|
llb.#DockerBuild & {
|
||||||
dockerfile: """
|
dockerfile: """
|
||||||
FROM alpine:latest@sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
|
FROM alpine:latest@sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
|
||||||
RUN echo foobar > /output
|
RUN echo foobar > /output
|
||||||
"""
|
"""
|
||||||
},
|
},
|
||||||
dagger.#Exec & {
|
llb.#Exec & {
|
||||||
args: ["sh", "-c", "test $(cat /output) = foobar"]
|
args: ["sh", "-c", "test $(cat /output) = foobar"]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
TestBuildContext: #compute: [
|
TestBuildContext: #compute: [
|
||||||
dagger.#DockerBuild & {
|
llb.#DockerBuild & {
|
||||||
context: TestData
|
context: TestData
|
||||||
},
|
},
|
||||||
dagger.#Exec & {
|
llb.#Exec & {
|
||||||
args: ["sh", "-c", "test $(cat /dir/foo) = foobar"]
|
args: ["sh", "-c", "test $(cat /dir/foo) = foobar"]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
TestBuildContextAndDockerfile: #compute: [
|
TestBuildContextAndDockerfile: #compute: [
|
||||||
dagger.#DockerBuild & {
|
llb.#DockerBuild & {
|
||||||
context: TestData
|
context: TestData
|
||||||
dockerfile: """
|
dockerfile: """
|
||||||
FROM alpine:latest@sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
|
FROM alpine:latest@sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
|
||||||
COPY foo /override
|
COPY foo /override
|
||||||
"""
|
"""
|
||||||
},
|
},
|
||||||
dagger.#Exec & {
|
llb.#Exec & {
|
||||||
args: ["sh", "-c", "test $(cat /override) = foobar"]
|
args: ["sh", "-c", "test $(cat /override) = foobar"]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
TestDockerfilePath: #compute: [
|
TestDockerfilePath: #compute: [
|
||||||
dagger.#DockerBuild & {
|
llb.#DockerBuild & {
|
||||||
context: TestData
|
context: TestData
|
||||||
dockerfilePath: "./dockerfilepath/Dockerfile.custom"
|
dockerfilePath: "./dockerfilepath/Dockerfile.custom"
|
||||||
},
|
},
|
||||||
dagger.#Exec & {
|
llb.#Exec & {
|
||||||
args: ["sh", "-c", "test $(cat /test) = dockerfilePath"]
|
args: ["sh", "-c", "test $(cat /test) = dockerfilePath"]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
TestBuildArgs: #compute: [
|
TestBuildArgs: #compute: [
|
||||||
dagger.#DockerBuild & {
|
llb.#DockerBuild & {
|
||||||
dockerfile: """
|
dockerfile: """
|
||||||
FROM alpine:latest@sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
|
FROM alpine:latest@sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
|
||||||
ARG TEST=foo
|
ARG TEST=foo
|
||||||
@ -71,7 +74,7 @@ TestBuildArgs: #compute: [
|
|||||||
|
|
||||||
// FIXME: this doesn't test anything beside not crashing
|
// FIXME: this doesn't test anything beside not crashing
|
||||||
TestBuildLabels: #compute: [
|
TestBuildLabels: #compute: [
|
||||||
dagger.#DockerBuild & {
|
llb.#DockerBuild & {
|
||||||
dockerfile: """
|
dockerfile: """
|
||||||
FROM alpine:latest@sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
|
FROM alpine:latest@sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
|
||||||
"""
|
"""
|
||||||
@ -81,7 +84,7 @@ TestBuildLabels: #compute: [
|
|||||||
|
|
||||||
// FIXME: this doesn't test anything beside not crashing
|
// FIXME: this doesn't test anything beside not crashing
|
||||||
TestBuildPlatform: #compute: [
|
TestBuildPlatform: #compute: [
|
||||||
dagger.#DockerBuild & {
|
llb.#DockerBuild & {
|
||||||
dockerfile: """
|
dockerfile: """
|
||||||
FROM alpine:latest@sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
|
FROM alpine:latest@sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
|
||||||
"""
|
"""
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"dagger.io/dagger"
|
"dagger.io/llb"
|
||||||
"dagger.io/alpine"
|
"dagger.io/alpine"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -10,11 +10,11 @@ TestPushContainer: {
|
|||||||
random: {
|
random: {
|
||||||
string
|
string
|
||||||
#compute: [
|
#compute: [
|
||||||
dagger.#Load & {from: alpine.#Image},
|
llb.#Load & {from: alpine.#Image},
|
||||||
dagger.#Exec & {
|
llb.#Exec & {
|
||||||
args: ["sh", "-c", "echo -n $RANDOM > /rand"]
|
args: ["sh", "-c", "echo -n $RANDOM > /rand"]
|
||||||
},
|
},
|
||||||
dagger.#Export & {
|
llb.#Export & {
|
||||||
source: "/rand"
|
source: "/rand"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -24,11 +24,11 @@ TestPushContainer: {
|
|||||||
push: {
|
push: {
|
||||||
ref: "daggerio/ci-test:\(random)"
|
ref: "daggerio/ci-test:\(random)"
|
||||||
#compute: [
|
#compute: [
|
||||||
dagger.#WriteFile & {
|
llb.#WriteFile & {
|
||||||
content: random
|
content: random
|
||||||
dest: "/rand"
|
dest: "/rand"
|
||||||
},
|
},
|
||||||
dagger.#PushContainer & {
|
llb.#PushContainer & {
|
||||||
"ref": ref
|
"ref": ref
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -36,15 +36,15 @@ TestPushContainer: {
|
|||||||
|
|
||||||
// Pull the image back
|
// Pull the image back
|
||||||
pull: #compute: [
|
pull: #compute: [
|
||||||
dagger.#FetchContainer & {
|
llb.#FetchContainer & {
|
||||||
ref: push.ref
|
ref: push.ref
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
// Check the content
|
// Check the content
|
||||||
check: #compute: [
|
check: #compute: [
|
||||||
dagger.#Load & {from: alpine.#Image},
|
llb.#Load & {from: alpine.#Image},
|
||||||
dagger.#Exec & {
|
llb.#Exec & {
|
||||||
args: [
|
args: [
|
||||||
"sh", "-c", #"""
|
"sh", "-c", #"""
|
||||||
test "$(cat /src/rand)" = "\#(random)"
|
test "$(cat /src/rand)" = "\#(random)"
|
||||||
|
Reference in New Issue
Block a user