teafolio/sync.go

111 lines
2.3 KiB
Go

package main
import (
"context"
"log"
"sort"
"time"
)
func (this *Application) sync(ctx context.Context) (bool, error) {
// List repositories on Gitea
repos, err := this.repos(ctx)
if err != nil {
return false, err
}
// Compare this list of repositories to our existing one
// If the repository is new, or if it's update-time has changed since we last
// saw it, then re-refresh its real git commit timestamps
// Otherwise copy them from the previous version
this.reposMut.RLock() // readonly
anyChanges := false
if len(repos) != len(this.reposCache) {
anyChanges = true
}
for i, rr := range repos {
if idx, ok := this.reposAlphabeticalOrder[rr.Name]; ok && this.reposCache[idx].GiteaUpdated == rr.GiteaUpdated {
// Already exists in cache with same Gitea update time
// Copy timestamps
repos[i] = this.reposCache[idx]
} else {
// New repo, or Gitea has updated timestamp
anyChanges = true
// Refresh timestamps
this.populateCommitInfo(ctx, &rr)
// Refresh topics
if t, err := this.topicsForRepo(ctx, rr.Name); err == nil {
rr.topics = t
}
// Save
repos[i] = rr
}
}
this.reposMut.RUnlock()
//
if !anyChanges {
return false, nil // nothing to do
}
// We have a final updated repos array
// Sort repos once alphabetically, to get alphabetical indexes...
sort.Slice(repos, func(i, j int) bool {
return repos[i].Name < repos[j].Name
})
alphabeticalOrderIndexes := make(map[string]int, len(repos))
for idx, repo := range repos {
alphabeticalOrderIndexes[repo.Name] = idx
}
// But then make sure the final sort is by most-recently-created
sort.Slice(repos, func(i, j int) bool {
return repos[i].oldestCommit.After(repos[j].oldestCommit)
})
// Commit our changes for the other threads to look at
this.reposMut.Lock()
this.reposCache = repos
this.reposAlphabeticalOrder = alphabeticalOrderIndexes
this.reposMut.Unlock()
// Done
return true, nil
}
func (this *Application) syncWorker(ctx context.Context) {
t := time.NewTicker(30 * time.Minute)
defer t.Stop()
for {
anyChanges, err := this.sync(ctx)
if err != nil {
// log and continue
log.Printf("Refreshing repositories: %s", err.Error())
}
if anyChanges {
log.Printf("Repositories updated")
}
select {
case <-t.C:
continue
case <-ctx.Done():
return
}
}
}