simple.go 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package versioner
  7. import (
  8. "path/filepath"
  9. "sort"
  10. "strconv"
  11. "time"
  12. "github.com/syncthing/syncthing/lib/fs"
  13. "github.com/syncthing/syncthing/lib/util"
  14. )
  15. func init() {
  16. // Register the constructor for this type of versioner with the name "simple"
  17. Factories["simple"] = NewSimple
  18. }
  19. type Simple struct {
  20. keep int
  21. folderFs fs.Filesystem
  22. versionsFs fs.Filesystem
  23. }
  24. func NewSimple(folderID string, folderFs fs.Filesystem, params map[string]string) Versioner {
  25. keep, err := strconv.Atoi(params["keep"])
  26. if err != nil {
  27. keep = 5 // A reasonable default
  28. }
  29. s := Simple{
  30. keep: keep,
  31. folderFs: folderFs,
  32. versionsFs: fsFromParams(folderFs, params),
  33. }
  34. l.Debugf("instantiated %#v", s)
  35. return s
  36. }
  37. // Archive moves the named file away to a version archive. If this function
  38. // returns nil, the named file does not exist any more (has been archived).
  39. func (v Simple) Archive(filePath string) error {
  40. err := archiveFile(v.folderFs, v.versionsFs, filePath, TagFilename)
  41. if err != nil {
  42. return err
  43. }
  44. file := filepath.Base(filePath)
  45. dir := filepath.Dir(filePath)
  46. // Glob according to the new file~timestamp.ext pattern.
  47. pattern := filepath.Join(dir, TagFilename(file, TimeGlob))
  48. newVersions, err := v.versionsFs.Glob(pattern)
  49. if err != nil {
  50. l.Warnln("globbing:", err, "for", pattern)
  51. return nil
  52. }
  53. // Also according to the old file.ext~timestamp pattern.
  54. pattern = filepath.Join(dir, file+"~"+TimeGlob)
  55. oldVersions, err := v.versionsFs.Glob(pattern)
  56. if err != nil {
  57. l.Warnln("globbing:", err, "for", pattern)
  58. return nil
  59. }
  60. // Use all the found filenames. "~" sorts after "." so all old pattern
  61. // files will be deleted before any new, which is as it should be.
  62. versions := util.UniqueTrimmedStrings(append(oldVersions, newVersions...))
  63. sort.Strings(versions)
  64. if len(versions) > v.keep {
  65. for _, toRemove := range versions[:len(versions)-v.keep] {
  66. l.Debugln("cleaning out", toRemove)
  67. err = v.versionsFs.Remove(toRemove)
  68. if err != nil {
  69. l.Warnln("removing old version:", err)
  70. }
  71. }
  72. }
  73. return nil
  74. }
  75. func (v Simple) GetVersions() (map[string][]FileVersion, error) {
  76. return retrieveVersions(v.versionsFs)
  77. }
  78. func (v Simple) Restore(filepath string, versionTime time.Time) error {
  79. return restoreFile(v.versionsFs, v.folderFs, filepath, versionTime, TagFilename)
  80. }