package tools import ( "errors" "io" "io/fs" "os" "os/exec" "path/filepath" "strconv" "strings" "time" "velvettear/gosync/log" "velvettear/gosync/settings" ) var sourceFiles map[string]int64 // unexported function(s) func getSourceFiles() map[string]int64 { timestamp := time.Now() sourceFiles = map[string]int64{} if settings.SourceIsRemote() { log.Info("getting the list of remote source files...") error := fillRemoteSourceFiles() if error != nil { log.Fatal("encountered an error getting the list of remote source files", error.Error()) } } else { source, _ := strings.CutSuffix(settings.Source, "/*") stats, error := os.Stat(source) if error != nil { log.Fatal("encountered an error getting stats for source", error.Error()) } if stats.IsDir() { log.Info("scanning source...", source) filepath.WalkDir(source, fillSourceFiles) } else { sourceFiles[settings.Source] = stats.Size() } } log.InfoTimed("found "+strconv.Itoa(len(sourceFiles))+" source files", timestamp.UnixMilli()) return sourceFiles } func fillRemoteSourceFiles() error { var arguments []string if len(settings.Password) > 0 { arguments = append(arguments, "-p", settings.Password) } arguments = append(arguments, "ssh") remote, path, _ := strings.Cut(settings.Source, ":") path, _ = strings.CutSuffix(path, "/*") if len(settings.User) > 0 { remote = settings.User + "@" + remote } arguments = append(arguments, remote, "find", "\""+path+"\"", "-type", "f", "-exec", "du", "-b", "{}", "\\;") cmd := exec.Command("sshpass", arguments...) stdout, stdoutError := cmd.StdoutPipe() stderr, stderrError := cmd.StderrPipe() cmd.Start() if stdoutError != nil { return stdoutError } if stderrError != nil { return stderrError } outBytes, stdoutError := io.ReadAll(stdout) if stdoutError != nil { return stdoutError } errorBytes, stderrError := io.ReadAll(stderr) if stderrError != nil { return stderrError } cmd.Wait() error := strings.TrimSpace(string(errorBytes)) if len(error) > 0 { return errors.New(error) } for _, line := range strings.Split(string(outBytes), "\n") { if !strings.Contains(line, "\t") { continue } parts := strings.Split(line, "\t") size, error := strconv.ParseInt(parts[0], 10, 64) if error != nil { log.Warning("encountered an error getting the file size for file '"+path+"'", error.Error()) } sourceFiles[parts[1]] = size } return nil } func fillSourceFiles(path string, dir fs.DirEntry, err error) error { if err != nil { return err } if dir.IsDir() { return nil } stats, error := os.Stat(path) if error != nil { log.Fatal("encountered an error getting stats for file", error.Error()) return nil } sourceFiles[path] = stats.Size() return nil } func getSourceFileSize() int64 { var total int64 for _, size := range sourceFiles { total += size } return total }