simple.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Copyright (C) 2014 Jakob Borg and other contributors. All rights reserved.
  2. // Use of this source code is governed by an MIT-style license that can be
  3. // found in the LICENSE file.
  4. package versioner
  5. import (
  6. "os"
  7. "path/filepath"
  8. "sort"
  9. "strconv"
  10. "time"
  11. "github.com/calmh/syncthing/osutil"
  12. )
  13. func init() {
  14. // Register the constructor for this type of versioner with the name "simple"
  15. Factories["simple"] = NewSimple
  16. }
  17. // The type holds our configuration
  18. type Simple struct {
  19. keep int
  20. }
  21. // The constructor function takes a map of parameters and creates the type.
  22. func NewSimple(params map[string]string) Versioner {
  23. keep, err := strconv.Atoi(params["keep"])
  24. if err != nil {
  25. keep = 5 // A reasonable default
  26. }
  27. s := Simple{
  28. keep: keep,
  29. }
  30. if debug {
  31. l.Debugf("instantiated %#v", s)
  32. }
  33. return s
  34. }
  35. // Move away the named file to a version archive. If this function returns
  36. // nil, the named file does not exist any more (has been archived).
  37. func (v Simple) Archive(repoPath, filePath string) error {
  38. _, err := os.Stat(filePath)
  39. if err != nil && os.IsNotExist(err) {
  40. if debug {
  41. l.Debugln("not archiving nonexistent file", filePath)
  42. }
  43. return nil
  44. }
  45. versionsDir := filepath.Join(repoPath, ".stversions")
  46. _, err = os.Stat(versionsDir)
  47. if err != nil {
  48. if os.IsNotExist(err) {
  49. if debug {
  50. l.Debugln("creating versions dir", versionsDir)
  51. }
  52. os.MkdirAll(versionsDir, 0755)
  53. osutil.HideFile(versionsDir)
  54. } else {
  55. return err
  56. }
  57. }
  58. if debug {
  59. l.Debugln("archiving", filePath)
  60. }
  61. file := filepath.Base(filePath)
  62. inRepoPath, err := filepath.Rel(repoPath, filepath.Dir(filePath))
  63. if err != nil {
  64. return err
  65. }
  66. dir := filepath.Join(versionsDir, inRepoPath)
  67. err = os.MkdirAll(dir, 0755)
  68. if err != nil && !os.IsExist(err) {
  69. return err
  70. }
  71. ver := file + "~" + time.Now().Format("20060102-150405")
  72. dst := filepath.Join(dir, ver)
  73. if debug {
  74. l.Debugln("moving to", dst)
  75. }
  76. err = osutil.Rename(filePath, dst)
  77. if err != nil {
  78. return err
  79. }
  80. versions, err := filepath.Glob(filepath.Join(dir, file+"~*"))
  81. if err != nil {
  82. l.Warnln(err)
  83. return nil
  84. }
  85. if len(versions) > v.keep {
  86. sort.Strings(versions)
  87. for _, toRemove := range versions[:len(versions)-v.keep] {
  88. if debug {
  89. l.Debugln("cleaning out", toRemove)
  90. }
  91. err = os.Remove(toRemove)
  92. if err != nil {
  93. l.Warnln(err)
  94. }
  95. }
  96. }
  97. return nil
  98. }