mirror/merlin/sync/pre.go

166 lines
4.2 KiB
Go

package sync
import (
"os"
"path/filepath"
"git.csclub.uwaterloo.ca/public/merlin/config"
)
// jobs to complete before repo sync command should be run
// when done is false: status can be ignored and sync command should continue
// when done is true: sync should exit with status
func preRepoSync(repo *config.Repo) (status int, done bool) {
status = config.SUCCESS
done = false
// clear the rsync log file
if repo.RsyncLogFile != "" {
err := os.Truncate(repo.RsyncLogFile, 0)
if err != nil {
status = config.FAILURE
repo.Logger.Error("Error while trying to clear logfile: " + repo.RepoLogFile)
}
}
if repo.TraceHost != "" {
if status, done = checkIfRepoSyncNeeded(repo); done {
// run alternative jobs if a full sync will not be done
if exit := noRepoSyncNeeded(repo); exit != config.SUCCESS {
status = exit
}
return
}
}
return
}
// check if the repo should be synced by comparing their trace file with our own
// returns the exit status of the command used to retrieve the repo's trace file
// returns true for done if and only if no errors occur and it is confirmed that
// the trace files are the same or that a termination signal was given
// (csc-sync-debian will always sync so done in its case will always be false)
func checkIfRepoSyncNeeded(repo *config.Repo) (status int, done bool) {
status = config.FAILURE
done = false
if repo.DryRun {
repo.Logger.Debug("dry running so assuming that trace file was changed")
return config.SUCCESS, false
}
repo.Logger.Debug("Retrieving the repo's trace file")
temp, err := os.CreateTemp("/tmp", "merlin-"+repo.Name+"-trace-*")
if err != nil {
repo.Logger.Error(err.Error())
return
}
temp.Close()
defer os.Remove(temp.Name())
// get the trace command to copy the last update file
var cmd []string
switch repo.SyncType {
case "csc-sync-archlinux":
cmd = cscTraceArchLinux(repo, temp.Name())
case "csc-sync-debian":
cmd = cscTraceDebian(repo, temp.Name())
default:
repo.Logger.Error("Trace files are not implemented for sync type '" + repo.SyncType + "'")
return
}
status = spawnProcessAndWait(repo, cmd)
if status != config.SUCCESS {
if status == config.TERMINATED {
done = true
}
return
}
repo.Logger.Debug("Comparing the repo's trace file with our own")
// diff returns true if files are the same (if files are the same then sync is done)
switch repo.SyncType {
case "csc-sync-archlinux":
done = cscTraceArchLinuxDiff(repo, temp.Name())
case "csc-sync-debian":
done = cscTraceDebianDiff(repo, temp.Name())
}
if done {
repo.Logger.Info("trace file for " + repo.RsyncHost + " unchanged")
// debian syncs even when trace file is unchanged
if repo.SyncType == "csc-sync-debian" {
done = false
}
return
}
repo.Logger.Debug("trace file changes found; will attempt to sync")
return
}
// jobs to do when a full sync will not be run
func noRepoSyncNeeded(repo *config.Repo) (status int) {
status = config.SUCCESS
var args []string
switch repo.SyncType {
case "csc-sync-archlinux":
args = cscTraceArchLinuxUpdate(repo)
}
status = spawnProcessAndWait(repo, args)
return
}
func cscTraceArchLinux(repo *config.Repo, newTime string) []string {
args := []string{
"curl",
"--interface", config.Conf.IPv4Address,
"-s", repo.TraceHost,
"-o", newTime,
}
return args
}
func cscTraceDebian(repo *config.Repo, newTime string) []string {
args := []string{
"nice", "rsync", "-tv", "--quiet",
"-4", "--address=" + config.Conf.IPv4Address,
repo.RsyncHost + "::" + filepath.Join(repo.RsyncDir, "project/trace", repo.TraceHost),
newTime,
}
return args
}
func cscTraceArchLinuxDiff(repo *config.Repo, newTime string) bool {
return diffFileContent(repo, newTime, filepath.Join(buildDownloadDir(repo), "lastupdate"))
}
func cscTraceDebianDiff(repo *config.Repo, newTime string) bool {
return diffFileTime(repo, newTime, filepath.Join(buildDownloadDir(repo), "project/trace", repo.TraceHost))
}
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
}