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  }