mirror/merlin/sync/trace.go

175 lines
4.0 KiB
Go

package sync
import (
"os"
"path"
"strings"
"git.csclub.uwaterloo.ca/public/merlin/config"
)
func cscTraceArchLinux(repo *config.Repo, destPath string) []string {
args := []string{
"curl",
"-s", repo.TraceUrl,
"-o", destPath,
}
return args
}
// return false iff both files exist, are non-empty, and have the same contents
func cscTraceArchLinuxDiff(repo *config.Repo, destPath string) bool {
readFile := func(file string) string {
f, err := os.ReadFile(file)
if err != nil {
repo.Logger.Debug(err.Error())
return ""
}
return strings.TrimSpace(string(f))
}
file1 := readFile(destPath)
file2 := readFile(path.Join(buildDownloadDir(repo), "lastupdate"))
if file1 == "" || file2 == "" {
return true
}
return file1 != file2
}
func cscTraceArchLinuxUpdate(repo *config.Repo) (args []string) {
rsyncDir := repo.RsyncDir
localDir := repo.LocalDir
repo.RsyncDir = repo.RsyncDir + "/lastsync"
repo.LocalDir = repo.LocalDir + "/lastsync"
args = cscSyncArchLinux(repo)
repo.RsyncDir = rsyncDir
repo.LocalDir = localDir
return args
}
func cscTraceDebian(repo *config.Repo, destPath string) []string {
args := []string{
"nice", "rsync", "-tv", "-4",
"--address=" + config.Conf.IPv4Address,
"--quiet",
// "--log-file=" + repo.RepoLogFile,
repo.RsyncHost + "::" + path.Join(repo.RsyncDir, "project/trace", repo.TraceUrl),
destPath,
}
return args
}
// return false iff both files exist and were modified at the same time
func cscTraceDebianDiff(repo *config.Repo, destPath string) bool {
statFile := func(file string) int64 {
f, err := os.Stat(file)
if err != nil {
repo.Logger.Debug(err.Error())
return 0
}
return f.ModTime().Unix()
}
file1 := statFile(destPath)
file2 := statFile(path.Join(buildDownloadDir(repo), "project/trace", "lastupdate"))
if file1 == 0 || file2 == 0 {
return true
}
return file1 != file2
}
// some repos want us to check a last modification time file before performing a full sync
// returns a status to update the original sync's status along with if the sync should continue
func checkIfSyncNeeded(repo *config.Repo) (status int, continueSync bool) {
// default return values are the default status and to continue the sync
status = config.FAILURE
continueSync = true
// create a temp file
temp, err := os.CreateTemp("/tmp", ".tmp.merlin."+repo.Name+"-")
if err != nil {
repo.Logger.Error(err.Error())
return
}
temp.Close()
defer os.Remove(temp.Name())
// get the trace command
var args []string
switch repo.SyncType {
case "csc-sync-archlinux":
args = cscTraceArchLinux(repo, temp.Name())
case "csc-sync-debian":
args = cscTraceDebian(repo, temp.Name())
default:
repo.Logger.Error("Trace files are not implemented for sync type '" + repo.SyncType + "'")
return
}
ch := spawnProcess(repo, args)
if ch == nil {
// spawnSyncProcess will have already logged error
return
}
cmd := <-ch
if cmd.ProcessState.ExitCode() != 0 {
// if the process was terminated then don't continue to sync
if cmd.ProcessState.ExitCode() == -1 {
return config.TERMINATED, false
}
return
}
filesDiffer := true
switch repo.SyncType {
case "csc-sync-archlinux":
filesDiffer = cscTraceArchLinuxDiff(repo, temp.Name())
case "csc-sync-debian":
filesDiffer = cscTraceDebianDiff(repo, temp.Name())
}
// if the files are the same then don't continue to sync
if !filesDiffer {
repo.Logger.Debug("No changes found; no sync made")
// archlinux wants to sync a "lastsync" file even if lastupdate prevents sync
var args []string
switch repo.SyncType {
case "csc-sync-archlinux":
args = cscTraceArchLinuxUpdate(repo)
default:
return config.SUCCESS, false
}
ch := spawnProcess(repo, args)
if ch == nil {
// spawnSyncProcess will have already logged error
return
}
cmd := <-ch
if cmd.ProcessState.ExitCode() != 0 {
// if the process was terminated then don't continue to sync
if cmd.ProcessState.ExitCode() == -1 {
return config.TERMINATED, false
}
return
}
return config.SUCCESS, false
}
return
}