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 *Refs) All() *RefIterator { repoPointers := r.selectAllRefs() iterator := NewRefIterator(repoPointers) return iterator } func (r *Refs) SortByName() *RefIterator { packs := r.selectAllRefs() sort.Sort(ByName(packs)) iterator := NewRefIterator(packs) return iterator } // enforces no duplicate package names func (r *Refs) Append(newP *Ref) bool { refslock.Lock() defer refslock.Unlock() for _, p := range r.Refs { if p.RefName == newP.RefName { return false } } r.Refs = append(r.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 (r *Refs) FindByName(name string) *Ref { refslock.RLock() defer refslock.RUnlock() for _, p := range r.Refs { if p.RefName == name { return p } } return nil } func (r *Refs) Len() int { refslock.RLock() defer refslock.RUnlock() return len(r.Refs) } type ByName []*Ref func (a ByName) Len() int { return len(a) } func (a ByName) Less(i, j int) bool { return a[i].RefName < a[j].RefName } func (a ByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } // safely returns a slice of pointers to the Ref protobufs func (r *Refs) selectAllRefs() []*Ref { refslock.RLock() defer refslock.RUnlock() // Create a new slice to hold pointers to each Ref var allPacks []*Ref allPacks = make([]*Ref, len(r.Refs)) for i, p := range r.Refs { allPacks[i] = p // Copy pointers for safe iteration } return allPacks } func (all *Refs) DeleteByHash(hash string) *Ref { refslock.Lock() defer refslock.Unlock() for i, _ := range all.Refs { if all.Refs[i].Hash == hash { all.Refs[i] = all.Refs[len(all.Refs)-1] all.Refs = all.Refs[:len(all.Refs)-1] return nil } } return nil } /* func (r *Refs) UnmergedRefRepos() *RefRepoIterator { repoPointers := r.selectUnmergedRefRepos() sort.Sort(ByName(repoPointers)) iterator := NewRefRepoIterator(repoPointers) return iterator } */ /* // this sort doesn't really work. I think it forgets to sort the last two // todo: sort this out. literally // SelectRefPointers safely returns a slice of pointers to Ref records. func (r *Refs) selectUnmergedRefs() []*RefRow { r.RLock() defer r.RUnlock() // Create a new slice to hold pointers to each Ref // repoPointers := make([]*Ref, len(c.E.Refs)) var repoPointers []*RefRow for _, repo := range me.allrepos { repoPointers = append(repoPointers, repo) // Copy pointers for safe iteration } return repoPointers } */