diff --git a/docs/reference/europa/dagger/engine/README.md b/docs/reference/europa/dagger/engine/README.md index f2ecc560..d3965862 100644 --- a/docs/reference/europa/dagger/engine/README.md +++ b/docs/reference/europa/dagger/engine/README.md @@ -99,3 +99,13 @@ _No input._ ### engine.#Service Outputs _No output._ + +## engine.#WriteFile + +### engine.#WriteFile Inputs + +_No input._ + +### engine.#WriteFile Outputs + +_No output._ diff --git a/plan/task/writefile.go b/plan/task/writefile.go new file mode 100644 index 00000000..f92fb8b2 --- /dev/null +++ b/plan/task/writefile.go @@ -0,0 +1,89 @@ +package task + +import ( + "context" + "fmt" + "io/fs" + + "cuelang.org/go/cue" + "github.com/moby/buildkit/client/llb" + "go.dagger.io/dagger/compiler" + "go.dagger.io/dagger/plancontext" + "go.dagger.io/dagger/solver" +) + +func init() { + Register("WriteFile", func() Task { return &writeFileTask{} }) +} + +type writeFileTask struct { +} + +func (t *writeFileTask) Run(ctx context.Context, pctx *plancontext.Context, s solver.Solver, v *compiler.Value) (*compiler.Value, error) { + var contents []byte + var err error + + path, err := v.Lookup("path").String() + if err != nil { + return nil, err + } + + switch kind := v.Lookup("contents").Kind(); kind { + // TODO: support bytes? + // case cue.BytesKind: + // contents, err = v.Lookup("contents").Bytes() + case cue.StringKind: + var str string + str, err = v.Lookup("contents").String() + if err == nil { + contents = []byte(str) + } + case cue.BottomKind: + err = fmt.Errorf("%s: WriteFile contents is not set", path) + default: + err = fmt.Errorf("%s: unhandled data type in WriteFile: %s", path, kind) + } + + if err != nil { + return nil, err + } + + mode, err := v.Lookup("mode").Int64() + + if err != nil { + return nil, err + } + + input, err := pctx.FS.FromValue(v.Lookup("input")) + + if err != nil { + return nil, err + } + + inputState, err := input.Result().ToState() + + if err != nil { + return nil, err + } + + outputState := inputState.File( + llb.Mkfile(path, fs.FileMode(mode), contents), + withCustomName(v, "WriteFile %s", path), + ) + + result, err := s.Solve(ctx, outputState, pctx.Platform.Get()) + + if err != nil { + return nil, err + } + + fs := pctx.FS.New(result) + + output := compiler.NewValue() + + if err := output.FillPath(cue.ParsePath("output"), fs.MarshalCUE()); err != nil { + return nil, err + } + + return output, nil +} diff --git a/stdlib/europa/dagger/engine/fs.cue b/stdlib/europa/dagger/engine/fs.cue index 7632d6be..bb8f1209 100644 --- a/stdlib/europa/dagger/engine/fs.cue +++ b/stdlib/europa/dagger/engine/fs.cue @@ -8,3 +8,13 @@ package engine contents: string output: #FS } + +#WriteFile: { + _type: "WriteFile" + + input: #FS + path: string + contents: string + mode: int + output: #FS +} diff --git a/tests/tasks.bats b/tests/tasks.bats index 8036dffd..5c111b2e 100644 --- a/tests/tasks.bats +++ b/tests/tasks.bats @@ -12,4 +12,15 @@ setup() { @test "task: #ReadFile" { cd "$TESTDIR"/tasks/readfile dagger --europa up +} + +@test "task: #WriteFile" { + cd "$TESTDIR"/tasks/writefile + dagger --europa up ./writefile.cue +} + +@test "task: #WriteFile failure: different contents" { + cd "$TESTDIR"/tasks/writefile + run dagger --europa up ./writefile_failure_diff_contents.cue + assert_failure } \ No newline at end of file diff --git a/tests/tasks/writefile/cue.mod/module.cue b/tests/tasks/writefile/cue.mod/module.cue new file mode 100644 index 00000000..f8af9cef --- /dev/null +++ b/tests/tasks/writefile/cue.mod/module.cue @@ -0,0 +1 @@ +module: "" diff --git a/tests/tasks/writefile/cue.mod/pkg/.gitignore b/tests/tasks/writefile/cue.mod/pkg/.gitignore new file mode 100644 index 00000000..2d4dc1ae --- /dev/null +++ b/tests/tasks/writefile/cue.mod/pkg/.gitignore @@ -0,0 +1,3 @@ +# generated by dagger +alpha.dagger.io +dagger.lock diff --git a/tests/tasks/writefile/writefile.cue b/tests/tasks/writefile/writefile.cue new file mode 100644 index 00000000..4f84b9b9 --- /dev/null +++ b/tests/tasks/writefile/writefile.cue @@ -0,0 +1,26 @@ +package main + +import ( + "alpha.dagger.io/europa/dagger/engine" +) + +engine.#Plan & { + actions: { + pull: engine.#Pull & { + source: "alpine:3.15.0@sha256:e7d88de73db3d3fd9b2d63aa7f447a10fd0220b7cbf39803c803f2af9ba256b3" + } + write: engine.#WriteFile & { + input: pull.output + path: "/testing" + contents: "1,2,3" + mode: 700 + } + readfile: engine.#ReadFile & { + input: write.output + path: "/testing" + } & { + // assert result + contents: "1,2,3" + } + } +} diff --git a/tests/tasks/writefile/writefile_failure_diff_contents.cue b/tests/tasks/writefile/writefile_failure_diff_contents.cue new file mode 100644 index 00000000..3e4fb3c8 --- /dev/null +++ b/tests/tasks/writefile/writefile_failure_diff_contents.cue @@ -0,0 +1,26 @@ +package main + +import ( + "alpha.dagger.io/europa/dagger/engine" +) + +engine.#Plan & { + actions: { + pull: engine.#Pull & { + source: "alpine:3.15.0@sha256:e7d88de73db3d3fd9b2d63aa7f447a10fd0220b7cbf39803c803f2af9ba256b3" + } + write: engine.#WriteFile & { + input: pull.output + path: "/testing" + contents: "1,2,3,4" + mode: 700 + } + readfile: engine.#ReadFile & { + input: write.output + path: "/testing" + } & { + // assert result + contents: "1,2,3" + } + } +}