package gitpb // this is becoming a standard format // todo: autogenerate this from the .proto file? import ( "fmt" "os" "sort" sync "sync" "time" ) // bad global lock until I figure out some other plan var refslock sync.RWMutex type RefIterator struct { sync.RWMutex packs []*Ref index int } // NewRefIterator initializes a new iterator. func NewRefIterator(packs []*Ref) *RefIterator { return &RefIterator{packs: packs} } // Scan moves to the next element and returns false if there are no more packs. func (it *RefIterator) Scan() bool { if it.index >= len(it.packs) { return false } it.index++ return true } // Ref returns the current repo. func (it *RefIterator) Ref() *Ref { 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.Ref() // fmt.Println("Ref UUID:", d.Uuid) // } func (r *Repo) All() *RefIterator { repoPointers := r.selectAllRefs() iterator := NewRefIterator(repoPointers) return iterator } func (r *Repo) SortByName() *RefIterator { packs := r.selectAllRefs() sort.Sort(RefsByName(packs)) iterator := NewRefIterator(packs) return iterator } // enforces no duplicate package names func (repo *Repo) AppendRef(newP *Ref) bool { refslock.Lock() defer refslock.Unlock() for _, p := range repo.Refs { if p.RefName == newP.RefName { return false } } repo.Refs = append(repo.Refs, newP) return true } // returns time.Duration since last Update() func (r *Ref) Age(newP *Ref) time.Duration { t := time.Since(r.Ctime.AsTime()) return t } // find a package by name func (repo *Repo) FindRefByName(name string) *Ref { refslock.RLock() defer refslock.RUnlock() for _, p := range repo.Refs { if p.RefName == name { return p } } return nil } func (repo *Repo) LenRefs() int { refslock.RLock() defer refslock.RUnlock() return len(repo.Refs) } type RefsByName []*Ref func (a RefsByName) Len() int { return len(a) } func (a RefsByName) Less(i, j int) bool { return a[i].RefName < a[j].RefName } func (a RefsByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } // safely returns a slice of pointers to the Ref protobufs func (repo *Repo) selectAllRefs() []*Ref { refslock.RLock() defer refslock.RUnlock() // Create a new slice to hold pointers to each Ref var allRefs []*Ref allRefs = make([]*Ref, len(repo.Refs)) for i, p := range repo.Refs { allRefs[i] = p // Copy pointers for safe iteration } return allRefs } func (repo *Repo) DeleteByHash(hash string) *Ref { refslock.Lock() defer refslock.Unlock() for i, _ := range repo.Refs { if repo.Refs[i].Hash == hash { repo.Refs[i] = repo.Refs[len(repo.Refs)-1] repo.Refs = repo.Refs[:len(repo.Refs)-1] return nil } } return nil }