sync.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "path/filepath"
  7. "regexp"
  8. "strings"
  9. "time"
  10. ccfg "git.wecise.com/wecise/common/matrix/cfg"
  11. clog "git.wecise.com/wecise/common/matrix/logger"
  12. "git.wecise.com/wecise/util/filewalker"
  13. )
  14. var config = ccfg.MConfig()
  15. var logger = clog.New()
  16. // 同步指定文件夹中的内容
  17. func PrintUsage() {
  18. println(`Usage:
  19. sync <frompath> <topath>
  20. `)
  21. }
  22. var option = struct {
  23. Debug bool
  24. }{
  25. Debug: false,
  26. }
  27. func main() {
  28. var frompath string = ""
  29. var topath string = ""
  30. for _, arg := range os.Args[1:] {
  31. if strings.HasPrefix(arg, "-") {
  32. switch arg {
  33. case "-debug":
  34. option.Debug = true
  35. }
  36. } else if arg != "" {
  37. if frompath == "" {
  38. frompath = arg
  39. } else if topath == "" {
  40. topath = arg
  41. }
  42. }
  43. }
  44. switch {
  45. case frompath != "" && topath != "":
  46. fmt.Println("sync from", frompath, "to", topath)
  47. for {
  48. err := sync(frompath, topath)
  49. if err != nil {
  50. println(err.Error())
  51. os.Exit(1)
  52. }
  53. time.Sleep(5 * time.Second)
  54. }
  55. default:
  56. PrintUsage()
  57. os.Exit(1)
  58. }
  59. }
  60. func sync(frompath, topath string) (err error) {
  61. fw, e := filewalker.NewFileWalker([]string{frompath}, `^[^\.].*`) // orderby: dirfirst, filefirst, fullpath
  62. if e != nil {
  63. return e
  64. }
  65. count := 0
  66. e = fw.List(func(basedir, fpath string) bool {
  67. if option.Debug {
  68. fmt.Println("basedir=", basedir, ", fpath=", fpath)
  69. }
  70. absbasedir, e := filepath.Abs(basedir)
  71. if e != nil {
  72. err = e
  73. return false
  74. }
  75. abstopath, e := filepath.Abs(topath)
  76. if e != nil {
  77. err = e
  78. return false
  79. }
  80. hiddenpath := fmt.Sprintf(`.*\%c\..*`, os.PathSeparator)
  81. if regexp.MustCompile(`^[^\.].*`).MatchString(fpath) && !regexp.MustCompile(hiddenpath).MatchString(fpath) {
  82. fromfile := filepath.Join(absbasedir, fpath)
  83. tofile := filepath.Join(abstopath, fpath)
  84. if option.Debug {
  85. fmt.Println(time.Now().Format("2006-01-02 15:04:05"), fromfile, " ==> ", tofile)
  86. }
  87. todir := filepath.Dir(tofile)
  88. e = os.MkdirAll(todir, os.ModePerm)
  89. if e != nil {
  90. err = fmt.Errorf("to dir %v", e)
  91. return false
  92. }
  93. fromfi, e := os.Stat(fromfile)
  94. if e != nil {
  95. err = fmt.Errorf("from file %v", e)
  96. return false
  97. }
  98. tofi, e := os.Stat(tofile)
  99. if e != nil && !os.IsNotExist(e) {
  100. err = fmt.Errorf("to file %v", e)
  101. return false
  102. }
  103. if tofi != nil && fromfi.Size() == tofi.Size() && fromfi.ModTime() == tofi.ModTime() {
  104. return true
  105. }
  106. fmt.Println(fromfile, " ==> ", tofile)
  107. frombs, e := ReadFile(fromfile)
  108. if e != nil {
  109. err = fmt.Errorf("from file %v", e)
  110. return false
  111. }
  112. e = os.WriteFile(tofile, frombs, os.ModePerm)
  113. if e != nil {
  114. err = fmt.Errorf("to file %v", e)
  115. return false
  116. }
  117. e = os.Chtimes(tofile, fromfi.ModTime(), fromfi.ModTime())
  118. if e != nil {
  119. err = fmt.Errorf("to file %v", e)
  120. return false
  121. }
  122. count++
  123. }
  124. return true
  125. })
  126. if e != nil {
  127. return e
  128. }
  129. if err != nil {
  130. return
  131. }
  132. if count > 0 || option.Debug {
  133. fmt.Println(time.Now().Format("2006-01-02 15:04:05"), count, "files copied")
  134. }
  135. return
  136. }
  137. func ReadFile(name string) (data []byte, err error) {
  138. data = make([]byte, 0, 512)
  139. for {
  140. data, err = ReadFileContinue(name, data)
  141. if err == io.EOF {
  142. err = nil
  143. return
  144. }
  145. }
  146. }
  147. func ReadFileContinue(name string, data []byte) ([]byte, error) {
  148. f, err := os.Open(name)
  149. if err != nil {
  150. return data, err
  151. }
  152. defer f.Close()
  153. var size int
  154. if info, err := f.Stat(); err == nil {
  155. size64 := info.Size()
  156. if int64(int(size64)) == size64 {
  157. size = int(size64)
  158. }
  159. }
  160. size++ // one byte for final read at EOF
  161. // If a file claims a small size, read at least 512 bytes.
  162. // In particular, files in Linux's /proc claim size 0 but
  163. // then do not work right if read in small pieces,
  164. // so an initial read of 1 byte would not work correctly.
  165. offset := len(data)
  166. if size > cap(data) {
  167. ndata := make([]byte, len(data), size)
  168. copy(ndata, data)
  169. data = ndata
  170. }
  171. for {
  172. n, err := f.ReadAt(data[offset:cap(data)], int64(offset))
  173. offset += n
  174. if err != nil {
  175. return data[:offset], err
  176. }
  177. if offset >= cap(data) {
  178. d := append(data[:cap(data)], 0)
  179. data = d[:offset]
  180. }
  181. }
  182. }