github.com/AlpineAIO/wails/v2@v2.0.0-beta.32.0.20240505041856-1047a8fa5fef/internal/s/s.go (about) 1 package s 2 3 import ( 4 "crypto/md5" 5 "encoding/hex" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "strings" 12 13 "github.com/bitfield/script" 14 ) 15 16 var ( 17 Output io.Writer = io.Discard 18 IndentSize int 19 originalOutput io.Writer 20 currentIndent int 21 ) 22 23 func checkError(err error) { 24 if err != nil { 25 println("\nERROR:", err.Error()) 26 os.Exit(1) 27 } 28 } 29 30 func mute() { 31 originalOutput = Output 32 Output = ioutil.Discard 33 } 34 35 func unmute() { 36 Output = originalOutput 37 } 38 39 func indent() { 40 currentIndent += IndentSize 41 } 42 43 func unindent() { 44 currentIndent -= IndentSize 45 } 46 47 func log(message string, args ...interface{}) { 48 indent := strings.Repeat(" ", currentIndent) 49 _, err := fmt.Fprintf(Output, indent+message+"\n", args...) 50 checkError(err) 51 } 52 53 // RENAME a file or directory 54 func RENAME(source string, target string) { 55 log("RENAME %s -> %s", source, target) 56 err := os.Rename(source, target) 57 checkError(err) 58 } 59 60 // MUSTDELETE a file. 61 func MUSTDELETE(filename string) { 62 log("DELETE %s", filename) 63 err := os.Remove(filepath.Join(CWD(), filename)) 64 checkError(err) 65 } 66 67 // DELETE a file. 68 func DELETE(filename string) { 69 log("DELETE %s", filename) 70 _ = os.Remove(filepath.Join(CWD(), filename)) 71 } 72 73 func CD(dir string) { 74 err := os.Chdir(dir) 75 checkError(err) 76 log("CD %s [%s]", dir, CWD()) 77 } 78 79 func MKDIR(path string, mode ...os.FileMode) { 80 var perms os.FileMode 81 perms = 0o755 82 if len(mode) == 1 { 83 perms = mode[0] 84 } 85 log("MKDIR %s (perms: %v)", path, perms) 86 err := os.MkdirAll(path, perms) 87 checkError(err) 88 } 89 90 // ENDIR ensures that the path gets created if it doesn't exist 91 func ENDIR(path string, mode ...os.FileMode) { 92 var perms os.FileMode 93 perms = 0o755 94 if len(mode) == 1 { 95 perms = mode[0] 96 } 97 _ = os.MkdirAll(path, perms) 98 } 99 100 // COPYDIR recursively copies a directory tree, attempting to preserve permissions. 101 // Source directory must exist, destination directory must *not* exist. 102 // Symlinks are ignored and skipped. 103 // Credit: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04 104 func COPYDIR(src string, dst string) { 105 log("COPYDIR %s -> %s", src, dst) 106 src = filepath.Clean(src) 107 dst = filepath.Clean(dst) 108 109 si, err := os.Stat(src) 110 checkError(err) 111 if !si.IsDir() { 112 checkError(fmt.Errorf("source is not a directory")) 113 } 114 115 _, err = os.Stat(dst) 116 if err != nil && !os.IsNotExist(err) { 117 checkError(err) 118 } 119 if err == nil { 120 checkError(fmt.Errorf("destination already exists")) 121 } 122 123 indent() 124 MKDIR(dst) 125 126 entries, err := os.ReadDir(src) 127 checkError(err) 128 129 for _, entry := range entries { 130 srcPath := filepath.Join(src, entry.Name()) 131 dstPath := filepath.Join(dst, entry.Name()) 132 133 if entry.IsDir() { 134 COPYDIR(srcPath, dstPath) 135 } else { 136 // Skip symlinks. 137 if entry.Type()&os.ModeSymlink != 0 { 138 continue 139 } 140 141 COPY(srcPath, dstPath) 142 } 143 } 144 unindent() 145 } 146 147 // COPY file from source to target 148 func COPY(source string, target string) { 149 log("COPY %s -> %s", source, target) 150 src, err := os.Open(source) 151 checkError(err) 152 defer closefile(src) 153 d, err := os.Create(target) 154 checkError(err) 155 _, err = io.Copy(d, src) 156 checkError(err) 157 } 158 159 func CWD() string { 160 result, err := os.Getwd() 161 checkError(err) 162 log("CWD [%s]", result) 163 return result 164 } 165 166 func RMDIR(target string) { 167 log("RMDIR %s", target) 168 err := os.RemoveAll(target) 169 checkError(err) 170 } 171 172 func RM(target string) { 173 log("RM %s", target) 174 err := os.Remove(target) 175 checkError(err) 176 } 177 178 func ECHO(message string) { 179 println(message) 180 } 181 182 func TOUCH(filepath string) { 183 log("TOUCH %s", filepath) 184 f, err := os.Create(filepath) 185 checkError(err) 186 closefile(f) 187 } 188 189 func EXEC(command string) { 190 log("EXEC %s", command) 191 gen := script.Exec(command) 192 gen.Wait() 193 checkError(gen.Error()) 194 } 195 196 // EXISTS - Returns true if the given path exists 197 func EXISTS(path string) bool { 198 _, err := os.Lstat(path) 199 log("EXISTS %s (%T)", path, err == nil) 200 return err == nil 201 } 202 203 // ISDIR returns true if the given directory exists 204 func ISDIR(path string) bool { 205 fi, err := os.Lstat(path) 206 if err != nil { 207 return false 208 } 209 210 return fi.Mode().IsDir() 211 } 212 213 // ISDIREMPTY returns true if the given directory is empty 214 func ISDIREMPTY(dir string) bool { 215 // CREDIT: https://stackoverflow.com/a/30708914/8325411 216 f, err := os.Open(dir) 217 checkError(err) 218 defer closefile(f) 219 220 _, err = f.Readdirnames(1) // Or f.Readdir(1) 221 return err == io.EOF 222 } 223 224 // ISFILE returns true if the given file exists 225 func ISFILE(path string) bool { 226 fi, err := os.Lstat(path) 227 if err != nil { 228 return false 229 } 230 231 return fi.Mode().IsRegular() 232 } 233 234 // SUBDIRS returns a list of subdirectories for the given directory 235 func SUBDIRS(rootDir string) []string { 236 var result []string 237 238 // Iterate root dir 239 err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error { 240 checkError(err) 241 // If we have a directory, save it 242 if info.IsDir() { 243 result = append(result, path) 244 } 245 return nil 246 }) 247 checkError(err) 248 return result 249 } 250 251 // SAVESTRING will create a file with the given string 252 func SAVESTRING(filename string, data string) { 253 log("SAVESTRING %s", filename) 254 mute() 255 SAVEBYTES(filename, []byte(data)) 256 unmute() 257 } 258 259 // LOADSTRING returns the contents of the given filename as a string 260 func LOADSTRING(filename string) string { 261 log("LOADSTRING %s", filename) 262 mute() 263 data := LOADBYTES(filename) 264 unmute() 265 return string(data) 266 } 267 268 // SAVEBYTES will create a file with the given string 269 func SAVEBYTES(filename string, data []byte) { 270 log("SAVEBYTES %s", filename) 271 err := os.WriteFile(filename, data, 0o755) 272 checkError(err) 273 } 274 275 // LOADBYTES returns the contents of the given filename as a string 276 func LOADBYTES(filename string) []byte { 277 log("LOADBYTES %s", filename) 278 data, err := os.ReadFile(filename) 279 checkError(err) 280 return data 281 } 282 283 func closefile(f *os.File) { 284 err := f.Close() 285 checkError(err) 286 } 287 288 // MD5FILE returns the md5sum of the given file 289 func MD5FILE(filename string) string { 290 f, err := os.Open(filename) 291 checkError(err) 292 defer closefile(f) 293 294 h := md5.New() 295 _, err = io.Copy(h, f) 296 checkError(err) 297 298 return hex.EncodeToString(h.Sum(nil)) 299 } 300 301 // Sub is the substitution type 302 type Sub map[string]string 303 304 // REPLACEALL replaces all substitution keys with associated values in the given file 305 func REPLACEALL(filename string, substitutions Sub) { 306 log("REPLACEALL %s (%v)", filename, substitutions) 307 data := LOADSTRING(filename) 308 for old, newText := range substitutions { 309 data = strings.ReplaceAll(data, old, newText) 310 } 311 SAVESTRING(filename, data) 312 }