package main import ( "fmt" "io" "os" "path/filepath" "regexp" "strings" "time" ccfg "git.wecise.com/wecise/common/matrix/cfg" clog "git.wecise.com/wecise/common/matrix/logger" "git.wecise.com/wecise/util/filewalker" ) var config = ccfg.MConfig() var logger = clog.New() // 同步指定文件夹中的内容 func PrintUsage() { println(`Usage: sync `) } var option = struct { Debug bool }{ Debug: false, } func main() { var frompath string = "" var topath string = "" for _, arg := range os.Args[1:] { if strings.HasPrefix(arg, "-") { switch arg { case "-debug": option.Debug = true } } else if arg != "" { if frompath == "" { frompath = arg } else if topath == "" { topath = arg } } } switch { case frompath != "" && topath != "": fmt.Println("sync from", frompath, "to", topath) for { err := sync(frompath, topath) if err != nil { println(err.Error()) os.Exit(1) } time.Sleep(5 * time.Second) } default: PrintUsage() os.Exit(1) } } func sync(frompath, topath string) (err error) { fw, e := filewalker.NewFileWalker([]string{frompath}, `^[^\.].*`) // orderby: dirfirst, filefirst, fullpath if e != nil { return e } count := 0 e = fw.List(func(basedir, fpath string) bool { if option.Debug { fmt.Println("basedir=", basedir, ", fpath=", fpath) } absbasedir, e := filepath.Abs(basedir) if e != nil { err = e return false } abstopath, e := filepath.Abs(topath) if e != nil { err = e return false } hiddenpath := fmt.Sprintf(`.*\%c\..*`, os.PathSeparator) if regexp.MustCompile(`^[^\.].*`).MatchString(fpath) && !regexp.MustCompile(hiddenpath).MatchString(fpath) { fromfile := filepath.Join(absbasedir, fpath) tofile := filepath.Join(abstopath, fpath) if option.Debug { fmt.Println(time.Now().Format("2006-01-02 15:04:05"), fromfile, " ==> ", tofile) } todir := filepath.Dir(tofile) e = os.MkdirAll(todir, os.ModePerm) if e != nil { err = fmt.Errorf("to dir %v", e) return false } fromfi, e := os.Stat(fromfile) if e != nil { err = fmt.Errorf("from file %v", e) return false } tofi, e := os.Stat(tofile) if e != nil && !os.IsNotExist(e) { err = fmt.Errorf("to file %v", e) return false } if tofi != nil && fromfi.Size() == tofi.Size() && fromfi.ModTime() == tofi.ModTime() { return true } fmt.Println(fromfile, " ==> ", tofile) frombs, e := ReadFile(fromfile) if e != nil { err = fmt.Errorf("from file %v", e) return false } e = os.WriteFile(tofile, frombs, os.ModePerm) if e != nil { err = fmt.Errorf("to file %v", e) return false } e = os.Chtimes(tofile, fromfi.ModTime(), fromfi.ModTime()) if e != nil { err = fmt.Errorf("to file %v", e) return false } count++ } return true }) if e != nil { return e } if err != nil { return } if count > 0 || option.Debug { fmt.Println(time.Now().Format("2006-01-02 15:04:05"), count, "files copied") } return } func ReadFile(name string) (data []byte, err error) { data = make([]byte, 0, 512) for { data, err = ReadFileContinue(name, data) if err == io.EOF { err = nil return } } } func ReadFileContinue(name string, data []byte) ([]byte, error) { f, err := os.Open(name) if err != nil { return data, err } defer f.Close() var size int if info, err := f.Stat(); err == nil { size64 := info.Size() if int64(int(size64)) == size64 { size = int(size64) } } size++ // one byte for final read at EOF // If a file claims a small size, read at least 512 bytes. // In particular, files in Linux's /proc claim size 0 but // then do not work right if read in small pieces, // so an initial read of 1 byte would not work correctly. offset := len(data) if size > cap(data) { ndata := make([]byte, len(data), size) copy(ndata, data) data = ndata } for { n, err := f.ReadAt(data[offset:cap(data)], int64(offset)) offset += n if err != nil { return data[:offset], err } if offset >= cap(data) { d := append(data[:cap(data)], 0) data = d[:offset] } } }