Files
gonic/fileutil/fileutil.go
2023-12-29 19:20:31 +00:00

62 lines
1.6 KiB
Go

// TODO: this package shouldn't really exist. we can usually just attempt our normal filesystem operations
// and handle errors atomically. eg.
// - Safe could instead be try create file, handle error
// - Unique could be try create file, on err create file (1), etc
package fileutil
import (
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
)
var nonAlphaNumExpr = regexp.MustCompile("[^a-zA-Z0-9_.]+")
func Safe(filename string) string {
filename = nonAlphaNumExpr.ReplaceAllString(filename, "")
return filename
}
// try to find a unqiue file (or dir) name. incrementing like "example (1)"
func Unique(base, filename string) (string, error) {
return unique(base, filename, 0)
}
func unique(base, filename string, count uint) (string, error) {
var suffix string
if count > 0 {
suffix = fmt.Sprintf(" (%d)", count)
}
path := base + suffix
if filename != "" {
noExt := strings.TrimSuffix(filename, filepath.Ext(filename))
path = filepath.Join(base, noExt+suffix+filepath.Ext(filename))
}
_, err := os.Stat(path)
if os.IsNotExist(err) {
return path, nil
}
if err != nil {
return "", err
}
return unique(base, filename, count+1)
}
func First(path ...string) (string, error) {
var err error
for _, p := range path {
_, err = os.Stat(p)
if err == nil {
return p, nil
}
}
return "", err
}
// HasPrefix checks a path has a prefix, making sure to respect path boundaries. So that /aa & /a does not match, but /a/a & /a does.
func HasPrefix(p, prefix string) bool {
return p == prefix || strings.HasPrefix(p, filepath.Clean(prefix)+string(filepath.Separator))
}