github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/utils/filesys/fs.go (about) 1 // Copyright 2019 Dolthub, Inc. 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 filesys 16 17 import ( 18 "encoding/json" 19 "errors" 20 "io" 21 "os" 22 "time" 23 ) 24 25 var ErrIsDir = errors.New("operation not valid on a directory") 26 var ErrIsFile = errors.New("operation not valid on a file") 27 var ErrDirNotExist = errors.New("directory does not exist") 28 29 // ReadableFS is an interface providing read access to objs in a filesystem 30 type ReadableFS interface { 31 32 // OpenForRead opens a file for reading 33 OpenForRead(fp string) (io.ReadCloser, error) 34 35 // ReadFile reads the entire contents of a file 36 ReadFile(fp string) ([]byte, error) 37 38 // Exists will tell you if a file or directory with a given path already exists, and if it does is it a directory 39 Exists(path string) (exists bool, isDir bool) 40 41 // converts a path to an absolute path. If it's already an absolute path the input path will be returned unaltered 42 Abs(path string) (string, error) 43 44 // LastModified gets the last modified timestamp for a file or directory at a given path 45 LastModified(path string) (t time.Time, exists bool) 46 } 47 48 // WritableFS is an interface providing write access to objs in a filesystem 49 type WritableFS interface { 50 // OpenForWrite opens a file for writing. The file will be created if it does not exist, and if it does exist 51 // it will be overwritten. 52 OpenForWrite(fp string, perm os.FileMode) (io.WriteCloser, error) 53 54 // OpenForWriteAppend opens a file for writing. The file will be created if it does not exist, and it will 55 // append only to that new file. If file exists, it will append to existing file. 56 OpenForWriteAppend(fp string, perm os.FileMode) (io.WriteCloser, error) 57 58 // WriteFileWithPerms writes the entire data buffer to a given file. The file will be created if it does not exist, 59 // and if it does exist it will be overwritten. WriteFile attempts to write the file atomically and durably. 60 WriteFile(fp string, data []byte, perm os.FileMode) error 61 62 // MkDirs creates a folder and all the parent folders that are necessary to create it. 63 MkDirs(path string) error 64 65 // DeleteFile will delete a file at the given path 66 DeleteFile(path string) error 67 68 // Delete will delete an empty directory, or a file. If trying delete a directory that is not empty you can set force to 69 // true in order to delete the dir and all of it's contents 70 Delete(path string, force bool) error 71 72 // MoveFile will move a file from the srcPath in the filesystem to the destPath 73 MoveFile(srcPath, destPath string) error 74 75 // MoveDir will move a directory from the srcPath in the filesystem to the destPath. For example, 76 // MoveDir("foo", "bar/baz") will move the "foo" directory to "bar/baz", meaning the contents of "foo" are now 77 // directly under the "baz" directory. All subdirectories on |destPath| must already exist before MoveDir is called. 78 MoveDir(srcPath, destPath string) error 79 80 // TempDir returns the path of a new temporary directory. 81 TempDir() string 82 } 83 84 // FSIterCB specifies the signature of the function that will be called for every item found while iterating. 85 type FSIterCB func(path string, size int64, isDir bool) (stop bool) 86 87 // WalkableFS is an interface for walking the files and subdirectories of a directory 88 type WalkableFS interface { 89 90 // Iter iterates over the files and subdirectories within a given directory (Optionally recursively). There 91 // are no guarantees about the ordering of results. Two calls to iterate the same directory may yield 92 // differently ordered results. 93 Iter(directory string, recursive bool, cb FSIterCB) error 94 } 95 96 // ReadWriteFS is an interface whose implementors will provide read, and write implementations but may not allow 97 // for files to be listed. 98 type ReadWriteFS interface { 99 ReadableFS 100 WritableFS 101 } 102 103 // Filesys is an interface whose implementors will provide read, write, and list mechanisms 104 type Filesys interface { 105 ReadableFS 106 WritableFS 107 WalkableFS 108 109 // WithWorkingDir returns a copy of this Filesys with the given working directory 110 WithWorkingDir(path string) (Filesys, error) 111 } 112 113 func UnmarshalJSONFile(fs ReadableFS, path string, dest interface{}) error { 114 data, err := fs.ReadFile(path) 115 116 if err != nil { 117 return err 118 } 119 120 return json.Unmarshal(data, dest) 121 } 122 123 func CopyFile(srcPath, destPath string, srcFS, destFS Filesys) (err error) { 124 rd, err := srcFS.OpenForRead(srcPath) 125 if err != nil { 126 return err 127 } 128 defer func() { 129 cerr := rd.Close() 130 if err == nil { 131 err = cerr 132 } 133 }() 134 135 wr, err := destFS.OpenForWrite(destPath, os.ModePerm) 136 if err != nil { 137 return err 138 } 139 defer func() { 140 cerr := wr.Close() 141 if err == nil { 142 err = cerr 143 } 144 }() 145 146 _, err = io.Copy(wr, rd) 147 return 148 }