package forgepb // TODO: autogen this? (probably not feasible. need go-arglike tricks in proto) import ( "fmt" "os" "sort" sync "sync" "time" ) // bad global lock until I figure out some other plan var reposLock sync.RWMutex type RepoIterator struct { sync.RWMutex packs []*Repo index int } // NewRepoIterator initializes a new iterator. func NewRepoIterator(packs []*Repo) *RepoIterator { return &RepoIterator{packs: packs} } // Scan moves to the next element and returns false if there are no more packs. func (it *RepoIterator) Scan() bool { if it.index >= len(it.packs) { return false } it.index++ return true } // Repo returns the current repo. func (it *RepoIterator) Repo() *Repo { if it.packs[it.index-1] == nil { for i, d := range it.packs { fmt.Println("i =", i, d) } fmt.Println("len =", len(it.packs)) fmt.Println("repo == nil", it.index, it.index-1) os.Exit(-1) } return it.packs[it.index-1] } // Use Scan() in a loop, similar to a while loop // // for iterator.Scan() { // d := iterator.Repo() // fmt.Println("Repo UUID:", d.Uuid) // } func (r *Repos) All() *RepoIterator { repoPointers := r.selectAllRepos() iterator := NewRepoIterator(repoPointers) return iterator } func (r *Repos) SortByPath() *RepoIterator { packs := r.selectAllRepos() sort.Sort(ByRepoPath(packs)) iterator := NewRepoIterator(packs) return iterator } // enforces no duplicate repo paths func (r *Repos) Append(newP *Repo) bool { reposLock.Lock() defer reposLock.Unlock() for _, p := range r.Repos { if p.GoPath == newP.GoPath { return false } } r.Repos = append(r.Repos, newP) return true } // returns time.Duration since last Update() func (r *Repo) Age(newP *Repo) time.Duration { t := time.Since(r.Verstamp.AsTime()) return t } // find a repo by path func (r *Repos) FindByPath(gopath string) *Repo { reposLock.RLock() defer reposLock.RUnlock() for _, p := range r.Repos { if p.GoPath == gopath { return p } } return nil } func (r *Repos) Len() int { reposLock.RLock() defer reposLock.RUnlock() return len(r.Repos) } type ByRepoPath []*Repo func (a ByRepoPath) Len() int { return len(a) } func (a ByRepoPath) Less(i, j int) bool { return a[i].GoPath < a[j].GoPath } func (a ByRepoPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (all *Repos) DeleteByPath(gopath string) *Repo { reposLock.Lock() defer reposLock.Unlock() var newr Repo for i, _ := range all.Repos { if all.Repos[i].GoPath == gopath { newr = *all.Repos[i] all.Repos[i] = all.Repos[len(all.Repos)-1] all.Repos = all.Repos[:len(all.Repos)-1] return &newr } } return nil } // safely returns a slice of pointers to the Repo protobufs func (r *Repos) selectAllRepos() []*Repo { reposLock.RLock() defer reposLock.RUnlock() // Create a new slice to hold pointers to each Repo var allPacks []*Repo allPacks = make([]*Repo, len(r.Repos)) for i, p := range r.Repos { allPacks[i] = p // Copy pointers for safe iteration } return allPacks }