62 lines
1.6 KiB
Go
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))
|
|
}
|