Skip to content

Commit 23cc102

Browse files
eonpataponmyitcv
authored andcommitted
pkg/tool/file: add Mkdir, MkdirAll
Closes #420 Change-Id: Iff8d66e9151f3a76f8c3986cab0eb26a9ff33126 Signed-off-by: Jean-Philippe Braun <eon@patapon.info> Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/530736 Reviewed-by: Paul Jolly <paul@myitcv.io>
1 parent 0aaf4c6 commit 23cc102

File tree

5 files changed

+152
-0
lines changed

5 files changed

+152
-0
lines changed

pkg/tool/file/doc.go

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/tool/file/file.cue

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,27 @@ Glob: {
7575
glob: !=""
7676
files: [...string]
7777
}
78+
79+
// Mkdir creates a directory at the specified path.
80+
Mkdir: {
81+
$id: "tool/file.Mkdir"
82+
83+
// The directory path to create.
84+
// If path is already a directory, Mkdir does nothing.
85+
// If path already exists and is not a directory, Mkdir will return an error.
86+
path: string
87+
88+
// When true any necessary parents are created as well.
89+
createParents: bool | *false
90+
91+
// Directory mode and permission bits.
92+
permissions: int | *0o755
93+
}
94+
95+
// MkdirAll creates a directory at the specified path along with any necessary
96+
// parents.
97+
// If path is already a directory, MkdirAll does nothing.
98+
// If path already exists and is not a directory, MkdirAll will return an error.
99+
MkdirAll: Mkdir & {
100+
createParents: true
101+
}

pkg/tool/file/file.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"path/filepath"
2424

2525
"cuelang.org/go/cue"
26+
"cuelang.org/go/cue/errors"
2627
"cuelang.org/go/internal/task"
2728
)
2829

@@ -31,17 +32,20 @@ func init() {
3132
task.Register("tool/file.Append", newAppendCmd)
3233
task.Register("tool/file.Create", newCreateCmd)
3334
task.Register("tool/file.Glob", newGlobCmd)
35+
task.Register("tool/file.Mkdir", newMkdirCmd)
3436
}
3537

3638
func newReadCmd(v cue.Value) (task.Runner, error) { return &cmdRead{}, nil }
3739
func newAppendCmd(v cue.Value) (task.Runner, error) { return &cmdAppend{}, nil }
3840
func newCreateCmd(v cue.Value) (task.Runner, error) { return &cmdCreate{}, nil }
3941
func newGlobCmd(v cue.Value) (task.Runner, error) { return &cmdGlob{}, nil }
42+
func newMkdirCmd(v cue.Value) (task.Runner, error) { return &cmdMkdir{}, nil }
4043

4144
type cmdRead struct{}
4245
type cmdAppend struct{}
4346
type cmdCreate struct{}
4447
type cmdGlob struct{}
48+
type cmdMkdir struct{}
4549

4650
func (c *cmdRead) Run(ctx *task.Context) (res interface{}, err error) {
4751
filename := ctx.String("filename")
@@ -111,3 +115,29 @@ func (c *cmdGlob) Run(ctx *task.Context) (res interface{}, err error) {
111115
files := map[string]interface{}{"files": m}
112116
return files, err
113117
}
118+
119+
func (c *cmdMkdir) Run(ctx *task.Context) (res interface{}, err error) {
120+
path := ctx.String("path")
121+
mode := ctx.Int64("permissions")
122+
createParents, _ := ctx.Lookup("createParents").Bool()
123+
124+
if ctx.Err != nil {
125+
return nil, ctx.Err
126+
}
127+
128+
if createParents {
129+
if err := os.MkdirAll(path, os.FileMode(mode)); err != nil {
130+
return nil, errors.Wrapf(err, ctx.Obj.Pos(), "failed to create directory")
131+
}
132+
} else {
133+
dir, err := os.Stat(path)
134+
if err == nil && dir.IsDir() {
135+
return nil, nil
136+
}
137+
if err := os.Mkdir(path, os.FileMode(mode)); err != nil {
138+
return nil, errors.Wrapf(err, ctx.Obj.Pos(), "failed to create directory")
139+
}
140+
}
141+
142+
return nil, nil
143+
}

pkg/tool/file/file_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,68 @@ func TestGlob(t *testing.T) {
137137
t.Errorf("got %v; want %v", got, want)
138138
}
139139
}
140+
141+
func TestMkdir(t *testing.T) {
142+
baseDir, err := os.MkdirTemp("", "")
143+
if err != nil {
144+
t.Fatal(err)
145+
}
146+
defer os.RemoveAll(baseDir)
147+
148+
// simple dir creation
149+
d1 := filepath.Join(baseDir, "foo")
150+
v := parse(t, "tool/file.Mkdir", fmt.Sprintf(`{path: "%s"}`, d1))
151+
_, err = (*cmdMkdir).Run(nil, &task.Context{Obj: v})
152+
if err != nil {
153+
t.Fatal(err)
154+
}
155+
fi1, err := os.Stat(d1)
156+
if err != nil {
157+
t.Fatal(err)
158+
}
159+
if !fi1.IsDir() {
160+
t.Fatal("not a directory")
161+
}
162+
expectedMode1 := os.ModeDir | 0755
163+
if int(fi1.Mode()) != int(expectedMode1) {
164+
t.Fatal("wrong permissions", fi1.Mode())
165+
}
166+
167+
// dir already exists
168+
v = parse(t, "tool/file.Mkdir", fmt.Sprintf(`{path: "%s"}`, d1))
169+
_, err = (*cmdMkdir).Run(nil, &task.Context{Obj: v})
170+
if err != nil {
171+
t.Fatal(err)
172+
}
173+
174+
// create parents
175+
// set permissions
176+
d2 := filepath.Join(baseDir, "bar/x")
177+
v = parse(t, "tool/file.MkdirAll", fmt.Sprintf(`{path: "%s", permissions: 0o700}`, d2))
178+
_, err = (*cmdMkdir).Run(nil, &task.Context{Obj: v})
179+
if err != nil {
180+
t.Fatal(err)
181+
}
182+
fi2, err := os.Stat(d2)
183+
if err != nil {
184+
t.Fatal(err)
185+
}
186+
if !fi2.IsDir() {
187+
t.Fatal("not a directory")
188+
}
189+
expectedMode2 := os.ModeDir | 0700
190+
if int(fi2.Mode()) != int(expectedMode2) {
191+
t.Fatal("wrong permissions", fi2.Mode())
192+
}
193+
194+
// file at same path
195+
f, err := ioutil.TempFile(baseDir, "")
196+
if err != nil {
197+
t.Fatal(err)
198+
}
199+
v = parse(t, "tool/file.Mkdir", fmt.Sprintf(`{path: "%s"}`, f.Name()))
200+
_, err = (*cmdMkdir).Run(nil, &task.Context{Obj: v})
201+
if err == nil {
202+
t.Fatal("should not create directory at existing filepath")
203+
}
204+
}

pkg/tool/file/pkg.go

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)