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