cuelang.org/go@v0.10.1/pkg/tool/file/file.go (about) 1 // Copyright 2019 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package file 16 17 import ( 18 "os" 19 "path/filepath" 20 "runtime" 21 22 "cuelang.org/go/cue" 23 "cuelang.org/go/cue/errors" 24 "cuelang.org/go/internal/task" 25 pkgpath "cuelang.org/go/pkg/path" 26 ) 27 28 func init() { 29 task.Register("tool/file.Read", newReadCmd) 30 task.Register("tool/file.Append", newAppendCmd) 31 task.Register("tool/file.Create", newCreateCmd) 32 task.Register("tool/file.Glob", newGlobCmd) 33 task.Register("tool/file.Mkdir", newMkdirCmd) 34 task.Register("tool/file.MkdirTemp", newMkdirTempCmd) 35 task.Register("tool/file.RemoveAll", newRemoveAllCmd) 36 } 37 38 func newReadCmd(v cue.Value) (task.Runner, error) { return &cmdRead{}, nil } 39 func newAppendCmd(v cue.Value) (task.Runner, error) { return &cmdAppend{}, nil } 40 func newCreateCmd(v cue.Value) (task.Runner, error) { return &cmdCreate{}, nil } 41 func newGlobCmd(v cue.Value) (task.Runner, error) { return &cmdGlob{}, nil } 42 func newMkdirCmd(v cue.Value) (task.Runner, error) { return &cmdMkdir{}, nil } 43 func newMkdirTempCmd(v cue.Value) (task.Runner, error) { return &cmdMkdirTemp{}, nil } 44 func newRemoveAllCmd(v cue.Value) (task.Runner, error) { return &cmdRemoveAll{}, nil } 45 46 type cmdRead struct{} 47 type cmdAppend struct{} 48 type cmdCreate struct{} 49 type cmdGlob struct{} 50 type cmdMkdir struct{} 51 type cmdMkdirTemp struct{} 52 type cmdRemoveAll struct{} 53 54 func (c *cmdRead) Run(ctx *task.Context) (res interface{}, err error) { 55 filename := ctx.String("filename") 56 if ctx.Err != nil { 57 return nil, ctx.Err 58 } 59 60 b, err := os.ReadFile(filename) 61 if err != nil { 62 return nil, err 63 } 64 update := map[string]interface{}{"contents": b} 65 66 switch v := ctx.Lookup("contents"); v.IncompleteKind() { 67 case cue.BytesKind: 68 // already set above 69 case cue.StringKind: 70 update["contents"] = string(b) 71 } 72 return update, nil 73 } 74 75 func (c *cmdAppend) Run(ctx *task.Context) (res interface{}, err error) { 76 var ( 77 filename = filepath.FromSlash(ctx.String("filename")) 78 mode = ctx.Int64("permissions") 79 b = ctx.Bytes("contents") 80 ) 81 if ctx.Err != nil { 82 return nil, ctx.Err 83 } 84 85 f, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.FileMode(mode)) 86 if err != nil { 87 return nil, err 88 } 89 defer f.Close() 90 91 if _, err := f.Write(b); err != nil { 92 return nil, err 93 } 94 return nil, nil 95 } 96 97 func (c *cmdCreate) Run(ctx *task.Context) (res interface{}, err error) { 98 var ( 99 filename = filepath.FromSlash(ctx.String("filename")) 100 mode = ctx.Int64("permissions") 101 b = ctx.Bytes("contents") 102 ) 103 if ctx.Err != nil { 104 return nil, ctx.Err 105 } 106 107 return nil, os.WriteFile(filename, b, os.FileMode(mode)) 108 } 109 110 func (c *cmdGlob) Run(ctx *task.Context) (res interface{}, err error) { 111 glob := ctx.String("glob") 112 if ctx.Err != nil { 113 return nil, ctx.Err 114 } 115 // Validate that the glob pattern is valid per [pkgpath.Match]. 116 // Note that we use the current OS to match the semantics of [filepath.Glob], 117 // and since the APIs in this package are meant to support native paths. 118 os := pkgpath.Unix 119 if runtime.GOOS == "windows" { 120 os = pkgpath.Windows 121 } 122 if _, err := pkgpath.Match(glob, "", os); err != nil { 123 return nil, err 124 } 125 m, err := filepath.Glob(glob) 126 for i, s := range m { 127 m[i] = filepath.ToSlash(s) 128 } 129 files := map[string]interface{}{"files": m} 130 return files, err 131 } 132 133 func (c *cmdMkdir) Run(ctx *task.Context) (res interface{}, err error) { 134 path := ctx.String("path") 135 mode := ctx.Int64("permissions") 136 createParents, _ := ctx.Lookup("createParents").Bool() 137 138 if ctx.Err != nil { 139 return nil, ctx.Err 140 } 141 142 if createParents { 143 if err := os.MkdirAll(path, os.FileMode(mode)); err != nil { 144 return nil, errors.Wrapf(err, ctx.Obj.Pos(), "failed to create directory") 145 } 146 } else { 147 dir, err := os.Stat(path) 148 if err == nil && dir.IsDir() { 149 return nil, nil 150 } 151 if err := os.Mkdir(path, os.FileMode(mode)); err != nil { 152 return nil, errors.Wrapf(err, ctx.Obj.Pos(), "failed to create directory") 153 } 154 } 155 156 return nil, nil 157 } 158 159 func (c *cmdMkdirTemp) Run(ctx *task.Context) (res interface{}, err error) { 160 dir := ctx.String("dir") 161 pattern := ctx.String("pattern") 162 163 if ctx.Err != nil { 164 return nil, ctx.Err 165 } 166 167 path, err := os.MkdirTemp(dir, pattern) 168 if err != nil { 169 return nil, errors.Wrapf(err, ctx.Obj.Pos(), "failed to create temporary directory") 170 } 171 172 return map[string]interface{}{"path": path}, nil 173 } 174 175 func (c *cmdRemoveAll) Run(ctx *task.Context) (res interface{}, err error) { 176 path := ctx.String("path") 177 178 if ctx.Err != nil { 179 return nil, ctx.Err 180 } 181 182 if _, err := os.Stat(path); err != nil { 183 return map[string]interface{}{"success": false}, nil 184 } 185 186 if err := os.RemoveAll(path); err != nil { 187 return nil, errors.Wrapf(err, ctx.Obj.Pos(), "failed to remove path") 188 } 189 190 return map[string]interface{}{"success": true}, nil 191 }