diff --git a/go/libraries/doltcore/doltdb/doltdb.go b/go/libraries/doltcore/doltdb/doltdb.go index 133d74ea7da..0c33644eeb7 100644 --- a/go/libraries/doltcore/doltdb/doltdb.go +++ b/go/libraries/doltcore/doltdb/doltdb.go @@ -594,6 +594,54 @@ func (ddb *DoltDB) ResolveTag(ctx context.Context, tagRef ref.TagRef) (*Tag, err return NewTag(ctx, tagRef.GetPath(), ds, ddb.vrw, ddb.ns) } +// TagResolver is used to late bind tag resolution +type TagResolver struct { + ddb *DoltDB + ref ref.TagRef + h hash.Hash +} + +func (tr *TagResolver) Addr() hash.Hash { + return tr.h +} + +// Resolve resolves the tag reference to a *Tag +func (tr *TagResolver) Resolve(ctx context.Context) (*Tag, error) { + return tr.ddb.ResolveTag(ctx, tr.ref) +} + +// ResolveTags takes a slice of TagRefs and returns the corresponding Tag objects. +func (ddb *DoltDB) ResolveTags(ctx context.Context, tagRefs []ref.DoltRef) ([]TagResolver, error) { + datasets, err := ddb.db.Datasets(ctx) + if err != nil { + return nil, err + } + + tagMap := make(map[string]ref.TagRef) + for _, tagRef := range tagRefs { + if tr, ok := tagRef.(ref.TagRef); ok { + tagMap[tagRef.String()] = tr + } else { + panic(fmt.Sprintf("runtime error: expected TagRef, got %T", tagRef)) + } + } + + results := make([]TagResolver, 0, len(tagRefs)) + + err = datasets.IterAll(ctx, func(id string, addr hash.Hash) error { + if val, ok := tagMap[id]; ok { + tr := TagResolver{ddb: ddb, ref: val, h: addr} + results = append(results, tr) + } + return nil // NM4 - is it an error if we don't find it???? Probably need to delete it on --prune. + }) + if err != nil { + return nil, err + } + + return results, nil +} + // ResolveWorkingSet takes a WorkingSetRef and returns the corresponding WorkingSet object. func (ddb *DoltDB) ResolveWorkingSet(ctx context.Context, workingSetRef ref.WorkingSetRef) (*WorkingSet, error) { ds, err := ddb.db.GetDataset(ctx, workingSetRef.String()) diff --git a/go/libraries/doltcore/doltdb/tag.go b/go/libraries/doltcore/doltdb/tag.go index 2186e8bd91c..6275bf74f2a 100644 --- a/go/libraries/doltcore/doltdb/tag.go +++ b/go/libraries/doltcore/doltdb/tag.go @@ -57,7 +57,7 @@ func NewTag(ctx context.Context, name string, ds datas.Dataset, vrw types.ValueR return &Tag{ Name: name, vrw: vrw, - addr: addr, + addr: addr, // NM4 - object address which is what we actually care about. Meta: meta, Commit: commit, }, nil diff --git a/go/libraries/doltcore/env/actions/remotes.go b/go/libraries/doltcore/env/actions/remotes.go index 7f1472bc8e8..f00b8a89885 100644 --- a/go/libraries/doltcore/env/actions/remotes.go +++ b/go/libraries/doltcore/env/actions/remotes.go @@ -338,11 +338,8 @@ func Clone(ctx context.Context, srcDB, destDB *doltdb.DoltDB, eventCh chan<- pul // been fetched into the destination DB. // todo: potentially too expensive to iterate over all srcDB tags func FetchFollowTags(ctx context.Context, tempTableDir string, srcDB, destDB *doltdb.DoltDB, progStarter ProgStarter, progStopper ProgStopper) error { - err := IterResolvedTags(ctx, srcDB, func(tag *doltdb.Tag) (stop bool, err error) { - tagHash, err := tag.GetAddr() - if err != nil { - return true, err - } + err := IterResolvedTags(ctx, srcDB, func(tag *doltdb.TagResolver) (stop bool, err error) { + tagHash := tag.Addr() has, err := destDB.Has(ctx, tagHash) if err != nil { @@ -353,7 +350,12 @@ func FetchFollowTags(ctx context.Context, tempTableDir string, srcDB, destDB *do return false, nil } - cmHash, err := tag.Commit.HashOf() + t, err := tag.Resolve(ctx) + if err != nil { + return true, err + } + + cmHash, err := t.Commit.HashOf() if err != nil { return true, err } @@ -378,7 +380,7 @@ func FetchFollowTags(ctx context.Context, tempTableDir string, srcDB, destDB *do newCtx, cancelFunc := context.WithCancel(ctx) wg, statsCh := progStarter(newCtx) - err = FetchTag(ctx, tempTableDir, srcDB, destDB, tag, statsCh) + err = FetchTag(ctx, tempTableDir, srcDB, destDB, t, statsCh) progStopper(cancelFunc, wg, statsCh) if err == nil { cli.Println() @@ -390,7 +392,7 @@ func FetchFollowTags(ctx context.Context, tempTableDir string, srcDB, destDB *do return true, err } - err = destDB.SetHead(ctx, tag.GetDoltRef(), tagHash) + err = destDB.SetHead(ctx, t.GetDoltRef(), tagHash) return false, err }) diff --git a/go/libraries/doltcore/env/actions/tag.go b/go/libraries/doltcore/env/actions/tag.go index 3dc7b40ab2a..dfed6a3235c 100644 --- a/go/libraries/doltcore/env/actions/tag.go +++ b/go/libraries/doltcore/env/actions/tag.go @@ -16,8 +16,6 @@ package actions import ( "context" - "fmt" - "sort" "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" "github.com/dolthub/dolt/go/libraries/doltcore/env" @@ -98,36 +96,21 @@ func DeleteTagsOnDB(ctx context.Context, ddb *doltdb.DoltDB, tagNames ...string) } // IterResolvedTags iterates over tags in dEnv.DoltDB from newest to oldest, resolving the tag to a commit and calling cb(). -func IterResolvedTags(ctx context.Context, ddb *doltdb.DoltDB, cb func(tag *doltdb.Tag) (stop bool, err error)) error { +func IterResolvedTags(ctx context.Context, ddb *doltdb.DoltDB, cb func(tag *doltdb.TagResolver) (stop bool, err error)) error { tagRefs, err := ddb.GetTags(ctx) if err != nil { return err } - var resolved []*doltdb.Tag - for _, r := range tagRefs { - tr, ok := r.(ref.TagRef) - if !ok { - return fmt.Errorf("DoltDB.GetTags() returned non-tag DoltRef") - } - - tag, err := ddb.ResolveTag(ctx, tr) - if err != nil { - return err - } - - resolved = append(resolved, tag) + tagResolvers, err := ddb.ResolveTags(ctx, tagRefs) + _ = tagResolvers + if err != nil { + return err } - // iterate newest to oldest - sort.Slice(resolved, func(i, j int) bool { - return resolved[i].Meta.Timestamp > resolved[j].Meta.Timestamp - }) - - for _, tag := range resolved { - stop, err := cb(tag) - + for _, tagResolver := range tagResolvers { + stop, err := cb(&tagResolver) if err != nil { return err } @@ -135,6 +118,5 @@ func IterResolvedTags(ctx context.Context, ddb *doltdb.DoltDB, cb func(tag *dolt break } } - return nil }