mirror of https://github.com/rclone/rclone.git
166 lines
4.2 KiB
Go
166 lines
4.2 KiB
Go
package bilib
|
|
|
|
import (
|
|
"bytes"
|
|
"os"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Names comprises a set of file names
|
|
type Names map[string]interface{}
|
|
|
|
// ToNames converts string slice to a set of names
|
|
func ToNames(list []string) Names {
|
|
ns := Names{}
|
|
for _, f := range list {
|
|
ns.Add(f)
|
|
}
|
|
return ns
|
|
}
|
|
|
|
// Add adds new file name to the set
|
|
func (ns Names) Add(name string) {
|
|
ns[name] = nil
|
|
}
|
|
|
|
// Has checks whether given name is present in the set
|
|
func (ns Names) Has(name string) bool {
|
|
_, ok := ns[name]
|
|
return ok
|
|
}
|
|
|
|
// NotEmpty checks whether set is not empty
|
|
func (ns Names) NotEmpty() bool {
|
|
return len(ns) > 0
|
|
}
|
|
|
|
// ToList converts name set to string slice
|
|
func (ns Names) ToList() []string {
|
|
list := []string{}
|
|
for file := range ns {
|
|
list = append(list, file)
|
|
}
|
|
sort.Strings(list)
|
|
return list
|
|
}
|
|
|
|
// Save saves name set in a text file
|
|
func (ns Names) Save(path string) error {
|
|
return SaveList(ns.ToList(), path)
|
|
}
|
|
|
|
// SaveList saves file name list in a text file
|
|
func SaveList(list []string, path string) error {
|
|
buf := &bytes.Buffer{}
|
|
for _, s := range list {
|
|
_, _ = buf.WriteString(strconv.Quote(s))
|
|
_ = buf.WriteByte('\n')
|
|
}
|
|
return os.WriteFile(path, buf.Bytes(), PermSecure)
|
|
}
|
|
|
|
// AliasMap comprises a pair of names that are not equal but treated as equal for comparison purposes
|
|
// For example, when normalizing unicode and casing
|
|
// This helps reduce repeated normalization functions, which really slow things down
|
|
type AliasMap map[string]string
|
|
|
|
// Add adds new pair to the set, in both directions
|
|
func (am AliasMap) Add(name1, name2 string) {
|
|
if name1 != name2 {
|
|
am[name1] = name2
|
|
am[name2] = name1
|
|
}
|
|
}
|
|
|
|
// Alias returns the alternate version, if any, else the original.
|
|
func (am AliasMap) Alias(name1 string) string {
|
|
// note: we don't need to check normalization settings, because we already did it in March.
|
|
// the AliasMap will only exist if March paired up two unequal filenames.
|
|
name2, ok := am[name1]
|
|
if ok {
|
|
return name2
|
|
}
|
|
return name1
|
|
}
|
|
|
|
// ParseGlobs determines whether a string contains {brackets}
|
|
// and returns the substring (including both brackets) for replacing
|
|
// substring is first opening bracket to last closing bracket --
|
|
// good for {{this}} but not {this}{this}
|
|
func ParseGlobs(s string) (hasGlobs bool, substring string) {
|
|
open := strings.Index(s, "{")
|
|
close := strings.LastIndex(s, "}")
|
|
if open >= 0 && close > open {
|
|
return true, s[open : close+1]
|
|
}
|
|
return false, ""
|
|
}
|
|
|
|
// TrimBrackets converts {{this}} to this
|
|
func TrimBrackets(s string) string {
|
|
return strings.Trim(s, "{}")
|
|
}
|
|
|
|
// TimeFormat converts a user-supplied string to a Go time constant, if possible
|
|
func TimeFormat(timeFormat string) string {
|
|
switch timeFormat {
|
|
case "Layout":
|
|
timeFormat = time.Layout
|
|
case "ANSIC":
|
|
timeFormat = time.ANSIC
|
|
case "UnixDate":
|
|
timeFormat = time.UnixDate
|
|
case "RubyDate":
|
|
timeFormat = time.RubyDate
|
|
case "RFC822":
|
|
timeFormat = time.RFC822
|
|
case "RFC822Z":
|
|
timeFormat = time.RFC822Z
|
|
case "RFC850":
|
|
timeFormat = time.RFC850
|
|
case "RFC1123":
|
|
timeFormat = time.RFC1123
|
|
case "RFC1123Z":
|
|
timeFormat = time.RFC1123Z
|
|
case "RFC3339":
|
|
timeFormat = time.RFC3339
|
|
case "RFC3339Nano":
|
|
timeFormat = time.RFC3339Nano
|
|
case "Kitchen":
|
|
timeFormat = time.Kitchen
|
|
case "Stamp":
|
|
timeFormat = time.Stamp
|
|
case "StampMilli":
|
|
timeFormat = time.StampMilli
|
|
case "StampMicro":
|
|
timeFormat = time.StampMicro
|
|
case "StampNano":
|
|
timeFormat = time.StampNano
|
|
case "DateTime":
|
|
// timeFormat = time.DateTime // missing in go1.19
|
|
timeFormat = "2006-01-02 15:04:05"
|
|
case "DateOnly":
|
|
// timeFormat = time.DateOnly // missing in go1.19
|
|
timeFormat = "2006-01-02"
|
|
case "TimeOnly":
|
|
// timeFormat = time.TimeOnly // missing in go1.19
|
|
timeFormat = "15:04:05"
|
|
case "MacFriendlyTime", "macfriendlytime", "mac":
|
|
timeFormat = "2006-01-02 0304PM" // not actually a Go constant -- but useful as macOS filenames can't have colons
|
|
}
|
|
return timeFormat
|
|
}
|
|
|
|
// AppyTimeGlobs converts "myfile-{DateOnly}.txt" to "myfile-2006-01-02.txt"
|
|
func AppyTimeGlobs(s string, t time.Time) string {
|
|
hasGlobs, substring := ParseGlobs(s)
|
|
if !hasGlobs {
|
|
return s
|
|
}
|
|
timeString := t.Local().Format(TimeFormat(TrimBrackets(substring)))
|
|
return strings.ReplaceAll(s, substring, timeString)
|
|
}
|