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  }