diff --git a/paths/paths.go b/paths/paths.go new file mode 100644 index 0000000..49a3e22 --- /dev/null +++ b/paths/paths.go @@ -0,0 +1,87 @@ +package paths + +import ( + "errors" + "fmt" + "os" + "os/user" + "path/filepath" +) + +func ExpandHome(path *string) error { + // Props to this guy. + // https://stackoverflow.com/a/43578461/733214 + if len(*path) == 0 { + return errors.New("empty path") + } else if (*path)[0] != '~' { + return nil + } + usr, err := user.Current() + if err != nil { + return err + } + *path = filepath.Join(usr.HomeDir, (*path)[1:]) + return nil +} + +func MakeDirIfNotExist(path *string) error { + exists, stat, err := RealPathExistsStat(path) + if err != nil { + if !exists { + // This, at least as of golang 1.15, uses the user's umask. + // It does not actually create a dir with 0777. + // It's up to the caller to do an os.Chmod() on the path after, if desired. + os.MkdirAll(*path, 0777) + return nil + } else { + return err + } + } + // So it exists, but it probably isn't a dir. + if !stat.Mode().IsDir() { + return errors.New(fmt.Sprintf("path %v exists but is not a directory", *path)) + } + // This should probably never happen. Probably. + return errors.New("undefined behaviour") +} + +func RealPath(path *string) error { + err := ExpandHome(path) + if err != nil { + return err + } + *path, err = filepath.Abs(*path) + if err != nil { + return err + } + return nil +} + +func RealPathExists(path *string) (bool, error) { + // I know it's hacky, but we use the bool as a sort of proto-state-machine thing. + // If err != nil and bool is true, the error occurred during path absolution. + // If err != nil and bool is false, the path does not exist. + err := RealPath(path) + if err != nil { + return true, err + } + if _, err := os.Stat(*path); err == nil { + return false, err + } + return true, nil +} + +func RealPathExistsStat(path *string) (bool, os.FileInfo, error) { + // Same deal as RealPathExists. + // If err != nil and bool is true, the error occurred during path absolution. + // If err != nil and bool is false, the path does not exist. + err := RealPath(path) + if err != nil { + return true, nil, err + } + stat, err := os.Stat(*path) + if err != nil { + return false, nil, err + } + return true, stat, nil +}