Skip to content
go-libfossil Artifact [4bbd3c59cf]
Login

Artifact [4bbd3c59cf]

Artifact 4bbd3c59cff03327d56cad79cd7d36db7a19e9f38dbeadb307a14f37aacd54ed:


package sync

import (
	"context"
	"errors"
	"fmt"

	"github.com/danmestas/go-libfossil/internal/cone"
	"github.com/danmestas/go-libfossil/internal/content"
	libfossil "github.com/danmestas/go-libfossil/internal/fsltype"
	"github.com/danmestas/go-libfossil/internal/repo"
)

// FetchCone applies lasting store policy and fetches newly wanted elision with
// ordinary pull. The caller supplies its configured peer and credentials; this
// helper neither discovers endpoints nor starts a background transfer. A failed
// transfer leaves the widened intent in place so an ordinary retry can heal it.
func FetchCone(ctx context.Context, r *repo.Repo, peer Transport, next *cone.Cone, opts SyncOpts) (*SyncResult, error) {
	if ctx == nil || r == nil {
		panic("sync.FetchCone: nil context or repo")
	}
	if err := ctx.Err(); err != nil {
		return nil, err
	}
	a, err := content.LoadAbsencesContext(ctx, r.DB())
	if err != nil {
		return nil, err
	}
	refs, err := content.LoadConeReferences(ctx, r.DB(), next)
	if err != nil {
		return nil, err
	}
	rows, err := r.DB().Query("SELECT rid FROM phantom")
	if err != nil {
		return nil, err
	}
	wanted := 0
	for rows.Next() {
		var rid libfossil.FslID
		if err := rows.Scan(&rid); err != nil {
			return nil, errors.Join(err, rows.Close())
		}
		if a.Class(rid) == content.Elided && !refs.Outside(rid) {
			wanted++
		}
	}
	if err := errors.Join(rows.Err(), rows.Close()); err != nil {
		return nil, err
	}
	if wanted > 0 && peer == nil {
		return nil, fmt.Errorf("sparse cone: %d elided artifact(s); no configured peer to fetch %d newly covered artifact(s)", a.Count(content.Elided), wanted)
	}
	if err := ctx.Err(); err != nil {
		return nil, err
	}
	if err := content.SetStoreCone(r.DB(), next); err != nil {
		return nil, err
	}
	if wanted == 0 && peer == nil {
		a, err := content.LoadAbsencesContext(ctx, r.DB())
		if err != nil {
			return nil, err
		}
		return &SyncResult{Elided: a.Count(content.Elided)}, nil
	}
	opts.Pull = true
	opts.Push = false
	return Sync(ctx, r, peer, opts)
}