grokify/mogo

View on GitHub
os/osutil/filepath.go

Summary

Maintainability
A
1 hr
Test Coverage
package osutil

import (
    "fmt"
    "go/build"
    "os"
    "path/filepath"
    "regexp"
    "sort"
    "strings"
)

func IsDir(name string) (bool, error) {
    if fi, err := os.Stat(name); err != nil {
        return false, err
    } else if !fi.Mode().IsDir() {
        return false, nil
    } else {
        return true, nil
    }
}

// IsFile verifies a path exists and is a file. It will optionally
// check if a file is not empty. An os file not exists check can be
// done with os.IsNotExist(err) which acts on error from os.Stat().
func IsFile(name string, sizeGtZero bool) (bool, error) {
    if fi, err := os.Stat(name); err != nil {
        return false, err
    } else if !fi.Mode().IsRegular() {
        return false, nil
    } else if sizeGtZero && fi.Size() <= 0 {
        return false, nil
    }
    return true, nil
}

// Exists checks whether the named filepath exists or not for a file or directory.
func Exists(name string) (bool, error) {
    _, err := os.Stat(name)
    if os.IsNotExist(err) {
        return false, nil
    } else if err != nil {
        return false, err
    }
    return true, nil
}

func MustUserHomeDir(subdirs ...string) string {
    if userhomedir, err := os.UserHomeDir(); err != nil {
        panic(err)
    } else if len(subdirs) > 0 {
        return filepath.Join(userhomedir, filepath.Join(subdirs...))
    } else {
        return userhomedir
    }
}

func GoPath(parts ...string) string {
    partsPath := ""
    if len(parts) > 0 {
        if strings.TrimSpace(parts[0]) == "." {
            parts = parts[1:]
        }
        partsPath = filepath.Join(parts...)
        if strings.TrimSpace(partsPath) == "." {
            partsPath = ""
        }
    }
    gopath := os.Getenv("GOPATH")
    if gopath != "" {
        if len(partsPath) > 0 {
            return filepath.Join(gopath, partsPath)
        }
        return gopath
    }
    gopath = build.Default.GOPATH
    if len(partsPath) > 0 {
        return filepath.Join(gopath, partsPath)
    }
    return gopath
}

/*
func GoPathSrc(pkgparts ...string) string {
    if len(pkgparts) > 0 {
        packagePath := filepath.Join(pkgparts...)
        if len(packagePath) > 0 && packagePath != "." {
            return filepath.Join(GoPath(), "src", packagePath)
        }
    }
    return filepath.Join(GoPath(), "src")
}
*/

// Filenames returns a list of filenames for files only (no directories). If a directory
// is provided it will return a list of filenames in that directory. If a `Regexp` or
// `inclEmptyFiles` params are provided, those will be use to filter the output.
func Filenames(name string, rx *regexp.Regexp, inclEmptyFiles, absPath bool) ([]string, error) {
    isFile, err := IsFile(name, !inclEmptyFiles)
    if err != nil {
        return []string{}, err
    }
    if isFile {
        if rx == nil || rx.MatchString(name) {
            if absPath {
                nameAbs, err := AbsFilepath(name)
                if err != nil {
                    return []string{}, err
                }
                name = nameAbs
            }
            return []string{name}, nil
        } else {
            return []string{}, nil
        }
    }
    var filenames []string
    entries, err := ReadDirMore(name, rx, false, true, inclEmptyFiles)
    if err != nil {
        return []string{}, nil
    }
    for _, entry := range entries {
        filename := filepath.Join(name, entry.Name())
        if absPath {
            filenameAbs, err := AbsFilepath(filename)
            if err != nil {
                return []string{}, err
            }
            filename = filenameAbs
        }
        filenames = append(filenames, filename)
    }
    sort.Strings(filenames)
    return filenames, nil
}

func FilenamesFilterSizeGTZero(filepaths ...string) []string {
    var filepathsExist []string

    for _, envPathVal := range filepaths {
        envPathVals := strings.Split(envPathVal, ",")
        for _, envPath := range envPathVals {
            envPath = strings.TrimSpace(envPath)

            if isFile, err := IsFile(envPath, true); isFile && err == nil {
                filepathsExist = append(filepathsExist, envPath)
            }
        }
    }
    return filepathsExist
}

func SplitBetter(path string) (dir, file string) {
    isDir, err := IsDir(path)
    if err != nil && isDir {
        return dir, ""
    }
    return filepath.Split(path)
}

func SplitBest(path string) (dir, file string, err error) {
    isDir, err := IsDir(path)
    if err != nil {
        return "", "", err
    } else if isDir {
        return path, "", nil
    }
    isFile, err := IsFile(path, false)
    if err != nil {
        return "", "", err
    } else if isFile {
        dir, file := filepath.Split(path)
        return dir, file, nil
    }
    return "", "", fmt.Errorf("path is valid but not file or directory: [%v]", path)
}

// ReadDirSplit returnsa slides of `os.FileInfo` for directories and files.
// Note: this isn't as necessary any more since `os.ReadDir()` returns a slice of
// `os.DirEntry{}` which has a `IsDir()` func.
func ReadDirSplit(dirname string, inclDotDirs bool) ([]os.FileInfo, []os.FileInfo, error) {
    allDEs, err := os.ReadDir(dirname)
    if err != nil {
        return []os.FileInfo{}, []os.FileInfo{}, err
    }
    // allFIs, err := DirEntriesToFileInfos(allDEs)
    allDEs2 := DirEntries(allDEs)
    allFIs, err := allDEs2.Infos()
    if err != nil {
        return []os.FileInfo{}, []os.FileInfo{}, err
    }
    subdirs, regular := FileInfosSplit(allFIs, inclDotDirs)
    return subdirs, regular, nil
}

func FileInfosSplit(all []os.FileInfo, inclDotDirs bool) ([]os.FileInfo, []os.FileInfo) {
    var subdirs []os.FileInfo
    var regular []os.FileInfo
    for _, f := range all {
        if f.Mode().IsDir() {
            if f.Name() == "." && f.Name() == ".." {
                if inclDotDirs {
                    subdirs = append(subdirs, f)
                }
            } else {
                subdirs = append(subdirs, f)
            }
        } else {
            regular = append(regular, f)
        }
    }
    return subdirs, regular
}

func DirFromPath(path string) (string, error) {
    path = strings.TrimRight(path, "/\\")
    f, err := os.Open(path)
    if err != nil {
        return "", err
    }
    defer f.Close()
    fi, err := f.Stat()
    if err != nil {
        return "", err
    }
    isFile := false
    switch mode := fi.Mode(); {
    case mode.IsDir():
        return path, nil
    case mode.IsRegular():
        isFile = true
    }
    if !isFile {
        return "", nil
    }
    rx1 := regexp.MustCompile(`^(.+)[/\\][^/\\]+`)
    rs1 := rx1.FindStringSubmatch(path)
    dir := ""
    if len(rs1) > 1 {
        dir = rs1[1]
    }
    return dir, nil
}