Skip to content

Commit 813a476

Browse files
committed
Add outputs.files task to plan
Signed-off-by: Helder Correia <[email protected]>
1 parent 025ce14 commit 813a476

File tree

8 files changed

+169
-12
lines changed

8 files changed

+169
-12
lines changed

pkg/dagger.io/dagger/engine/plan.cue

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ package engine
1717

1818
// Send outputs to the client
1919
outputs: {
20-
@dagger(notimplemented)
20+
// Export an #FS to the client
2121
directories: [name=string]: _#outputDirectory
22+
// Export a string to a file
23+
files: [name=string]: _#outputFile
2224
}
2325

2426
// Forward network services to and from the client
@@ -110,6 +112,19 @@ _#outputDirectory: {
110112
dest: string
111113
}
112114

115+
_#outputFile: {
116+
$dagger: task: _name: "OutputFile"
117+
118+
// File contents to export
119+
contents: string
120+
121+
// Export to this path ON THE CLIENT MACHINE
122+
dest: string
123+
124+
// Permissions of the file (defaults to 0o644)
125+
permissions?: int
126+
}
127+
113128
// Forward a network endpoint to and from the client
114129
_#proxyEndpoint: {
115130
$dagger: task: _name: "ProxyEndpoint"

plan/task/outputfile.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package task
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io/fs"
7+
"os"
8+
9+
"cuelang.org/go/cue"
10+
"go.dagger.io/dagger/compiler"
11+
"go.dagger.io/dagger/plancontext"
12+
"go.dagger.io/dagger/solver"
13+
)
14+
15+
func init() {
16+
Register("OutputFile", func() Task { return &outputFileTask{} })
17+
}
18+
19+
type outputFileTask struct {
20+
}
21+
22+
func (c outputFileTask) Run(ctx context.Context, pctx *plancontext.Context, s solver.Solver, v *compiler.Value) (*compiler.Value, error) {
23+
var contents []byte
24+
var err error
25+
26+
switch kind := v.Lookup("contents").Kind(); kind {
27+
case cue.StringKind:
28+
var str string
29+
str, err = v.Lookup("contents").String()
30+
if err == nil {
31+
contents = []byte(str)
32+
}
33+
case cue.BottomKind:
34+
err = fmt.Errorf("contents is not set")
35+
default:
36+
err = fmt.Errorf("unhandled data type in contents: %s", kind)
37+
}
38+
39+
if err != nil {
40+
return nil, err
41+
}
42+
43+
dest, err := v.Lookup("dest").AbsPath()
44+
if err != nil {
45+
return nil, err
46+
}
47+
48+
perm := fs.FileMode(0644) // default permission
49+
if v.Lookup("permissions").Exists() {
50+
permissions, err := v.Lookup("permissions").Int64()
51+
if err != nil {
52+
return nil, err
53+
}
54+
perm = fs.FileMode(permissions)
55+
}
56+
57+
err = os.WriteFile(dest, contents, perm)
58+
if err != nil {
59+
return nil, err
60+
}
61+
62+
return compiler.NewValue(), nil
63+
}

tests/plan.bats

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ setup() {
6969
cd "$TESTDIR"
7070
"$DAGGER" --europa up ./plan/inputs/secrets/exec.cue
7171
"$DAGGER" --europa up ./plan/inputs/secrets/exec_relative.cue
72-
72+
7373
run "$DAGGER" --europa up ./plan/inputs/secrets/invalid_command.cue
7474
assert_failure
7575
assert_output --partial 'failed: exec: "rtyet": executable file not found'
76-
76+
7777
run "$DAGGER" --europa up ./plan/inputs/secrets/invalid_command_options.cue
7878
assert_failure
7979
assert_output --partial 'option'
@@ -83,30 +83,74 @@ setup() {
8383
cd "$TESTDIR"
8484
"$DAGGER" --europa up --with 'inputs: params: foo:"bar"' ./plan/with/params.cue
8585
"$DAGGER" --europa up --with 'actions: verify: env: FOO: "bar"' ./plan/with/actions.cue
86-
86+
8787
run "$DAGGER" --europa up --with 'inputs: params: foo:1' ./plan/with/params.cue
8888
assert_failure
8989
assert_output --partial "conflicting values string and 1"
90-
90+
9191
run "$DAGGER" --europa up ./plan/with/params.cue
9292
assert_failure
9393
assert_output --partial "actions.verify.env.FOO: non-concrete value string"
9494
}
9595

96-
@test "plan/outputs" {
97-
cd "$TESTDIR"/plan/outputs
96+
@test "plan/outputs/directories" {
97+
cd "$TESTDIR"/plan/outputs/directories
9898

9999
rm -f "./out/test"
100100
"$DAGGER" --europa up ./outputs.cue
101101
assert [ -f "./out/test" ]
102102
}
103103

104-
@test "plan/outputs relative paths" {
104+
@test "plan/outputs/directories relative paths" {
105+
cd "$TESTDIR"/plan
106+
107+
rm -f "./outputs/directories/out/test"
108+
"$DAGGER" --europa up ./outputs/directories/outputs.cue
109+
assert [ -f "./outputs/directories/out/test" ]
110+
}
111+
112+
@test "plan/outputs/files normal usage" {
113+
cd "$TESTDIR"/plan/outputs/files
114+
115+
"$DAGGER" --europa up ./usage.cue
116+
117+
run ./test.sh
118+
assert_output "Hello World!"
119+
120+
run ls -l "./test.sh"
121+
assert_output --partial "-rwxr-x---"
122+
123+
rm -f "./test.sh"
124+
}
125+
126+
@test "plan/outputs/files relative path" {
105127
cd "$TESTDIR"/plan
106128

107-
rm -f "./outputs/out/test"
108-
"$DAGGER" --europa up ./outputs/outputs.cue
109-
assert [ -f "./outputs/out/test" ]
129+
"$DAGGER" --europa up ./outputs/files/usage.cue
130+
assert [ -f "./outputs/files/test.sh" ]
131+
132+
rm -f "./outputs/files/test.sh"
133+
}
134+
135+
@test "plan/outputs/files default permissions" {
136+
cd "$TESTDIR"/plan/outputs/files
137+
138+
"$DAGGER" --europa up ./default_permissions.cue
139+
140+
run ls -l "./test"
141+
assert_output --partial "-rw-r--r--"
142+
143+
rm -f "./test"
144+
}
145+
146+
@test "plan/outputs/files no contents" {
147+
cd "$TESTDIR"/plan/outputs/files
148+
149+
run "$DAGGER" --europa up ./no_contents.cue
150+
assert_failure
151+
assert_output --partial "contents is not set"
152+
153+
assert [ ! -f "./test" ]
110154
}
111155

112156
@test "plan/platform" {
@@ -121,4 +165,4 @@ setup() {
121165
# Run with invalid platform
122166
run "$DAGGER" --europa up ./plan/platform/config_platform_failure_invalid_platform.cue
123167
assert_failure
124-
}
168+
}
File renamed without changes.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
import "dagger.io/dagger"
4+
5+
dagger.#Plan & {
6+
outputs: files: test: {
7+
contents: "foobar"
8+
dest: "./test"
9+
}
10+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package main
2+
3+
import "dagger.io/dagger"
4+
5+
dagger.#Plan & {
6+
outputs: files: test: dest: "./test"
7+
}

tests/plan/outputs/files/usage.cue

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package main
2+
3+
import "dagger.io/dagger"
4+
5+
dagger.#Plan & {
6+
outputs: files: {
7+
[path=string]: dest: path
8+
"test.sh": {
9+
contents: """
10+
#!/bin/bash
11+
set -euo pipefail
12+
echo "Hello World!"
13+
14+
"""
15+
permissions: 0o750
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)