github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/lib/version/version.go (about)

     1  // Package version provides machinery for versioning file names
     2  // with a timestamp-based version string
     3  package version
     4  
     5  import (
     6  	"path"
     7  	"regexp"
     8  	"strings"
     9  	"time"
    10  )
    11  
    12  const versionFormat = "-v2006-01-02-150405.000"
    13  
    14  var versionRegexp = regexp.MustCompile(`-v\d{4}-\d{2}-\d{2}-\d{6}-\d{3}`)
    15  
    16  // Split fileName into base and extension so that base + ext == fileName
    17  func splitExt(fileName string) (base, ext string) {
    18  	ext = path.Ext(fileName)
    19  	base = fileName[:len(fileName)-len(ext)]
    20  	// .file splits to base == "", ext == ".file"
    21  	// so swap ext and base in this case
    22  	if ext != "" && base == "" {
    23  		base, ext = ext, base
    24  	}
    25  	return base, ext
    26  }
    27  
    28  // Add returns fileName modified to include t as the version
    29  func Add(fileName string, t time.Time) string {
    30  	base, ext := splitExt(fileName)
    31  	s := t.Format(versionFormat)
    32  	// Replace the '.' with a '-'
    33  	s = strings.ReplaceAll(s, ".", "-")
    34  	return base + s + ext
    35  }
    36  
    37  // Remove returns a modified fileName without the version string and the time it represented
    38  // If the fileName did not have a version then time.Time{} is returned along with an unmodified fileName
    39  func Remove(fileName string) (t time.Time, fileNameWithoutVersion string) {
    40  	fileNameWithoutVersion = fileName
    41  	base, ext := splitExt(fileName)
    42  	if len(base) < len(versionFormat) {
    43  		return
    44  	}
    45  	versionStart := len(base) - len(versionFormat)
    46  	// Check it ends in -xxx
    47  	if base[len(base)-4] != '-' {
    48  		return
    49  	}
    50  	// Replace with .xxx for parsing
    51  	base = base[:len(base)-4] + "." + base[len(base)-3:]
    52  	newT, err := time.Parse(versionFormat, base[versionStart:])
    53  	if err != nil {
    54  		return
    55  	}
    56  	return newT, base[:versionStart] + ext
    57  }
    58  
    59  // Match returns true if the fileName has a version string
    60  func Match(fileName string) bool {
    61  	return versionRegexp.MatchString(fileName)
    62  }