github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/mods/file/file.go (about) 1 package file 2 3 import ( 4 "math/big" 5 "os" 6 "strconv" 7 8 "github.com/markusbkk/elvish/pkg/eval" 9 "github.com/markusbkk/elvish/pkg/eval/errs" 10 "github.com/markusbkk/elvish/pkg/eval/vals" 11 ) 12 13 var Ns = eval.BuildNsNamed("file"). 14 AddGoFns(map[string]interface{}{ 15 "close": close, 16 "open": open, 17 "pipe": pipe, 18 "truncate": truncate, 19 }).Ns() 20 21 //elvdoc:fn open 22 // 23 // ```elvish 24 // file:open $filename 25 // ``` 26 // 27 // Opens a file. Currently, `open` only supports opening a file for reading. 28 // File must be closed with `close` explicitly. Example: 29 // 30 // ```elvish-transcript 31 // ~> cat a.txt 32 // This is 33 // a file. 34 // ~> use file 35 // ~> var f = (file:open a.txt) 36 // ~> cat < $f 37 // This is 38 // a file. 39 // ~> close $f 40 // ``` 41 // 42 // @cf file:close 43 44 func open(name string) (vals.File, error) { 45 return os.Open(name) 46 } 47 48 //elvdoc:fn close 49 // 50 // ```elvish 51 // file:close $file 52 // ``` 53 // 54 // Closes a file opened with `open`. 55 // 56 // @cf file:open 57 58 func close(f vals.File) error { 59 return f.Close() 60 } 61 62 //elvdoc:fn pipe 63 // 64 // ```elvish 65 // file:pipe 66 // ``` 67 // 68 // Create a new pipe that can be used in redirections. A pipe contains a read-end and write-end. 69 // Each pipe object is a [pseudo-map](language.html#pseudo-map) with fields `r` (the read-end [file 70 // object](./language.html#file)) and `w` (the write-end). 71 // 72 // When redirecting command input from a pipe with `<`, the read-end is used. When redirecting 73 // command output to a pipe with `>`, the write-end is used. Redirecting both input and output with 74 // `<>` to a pipe is not supported. 75 // 76 // Pipes have an OS-dependent buffer, so writing to a pipe without an active reader 77 // does not necessarily block. Pipes **must** be explicitly closed with `file:close`. 78 // 79 // Putting values into pipes will cause those values to be discarded. 80 // 81 // Examples (assuming the pipe has a large enough buffer): 82 // 83 // ```elvish-transcript 84 // ~> var p = (file:pipe) 85 // ~> echo 'lorem ipsum' > $p 86 // ~> head -n1 < $p 87 // lorem ipsum 88 // ~> put 'lorem ipsum' > $p 89 // ~> file:close $p[w] # close the write-end 90 // ~> head -n1 < $p # blocks unless the write-end is closed 91 // ~> file:close $p[r] # close the read-end 92 // ``` 93 // 94 // @cf file:close 95 96 func pipe() (vals.Pipe, error) { 97 r, w, err := os.Pipe() 98 return vals.NewPipe(r, w), err 99 } 100 101 //elvdoc:fn truncate 102 // 103 // ```elvish 104 // file:truncate $filename $size 105 // ``` 106 // 107 // changes the size of the named file. If the file is a symbolic link, it 108 // changes the size of the link's target. The size must be an integer between 0 109 // and 2^64-1. 110 111 func truncate(name string, rawSize vals.Num) error { 112 var size int64 113 switch rawSize := rawSize.(type) { 114 case int: 115 size = int64(rawSize) 116 case *big.Int: 117 if rawSize.IsInt64() { 118 size = rawSize.Int64() 119 } else { 120 return truncateSizeOutOfRange(rawSize.String()) 121 } 122 default: 123 return errs.BadValue{ 124 What: "size argument to file:truncate", 125 Valid: "integer", Actual: "non-integer", 126 } 127 } 128 if size < 0 { 129 return truncateSizeOutOfRange(strconv.FormatInt(size, 10)) 130 } 131 return os.Truncate(name, size) 132 } 133 134 func truncateSizeOutOfRange(size string) error { 135 return errs.OutOfRange{ 136 What: "size argument to file:truncate", 137 ValidLow: "0", 138 ValidHigh: "2^64-1", 139 Actual: size, 140 } 141 }