Raw
 1package replica
 2
 3import (
 4	"context"
 5	"errors"
 6	"time"
 7
 8	"github.com/go-git/go-git/v5"
 9	"github.com/go-git/go-git/v5/plumbing"
10	"github.com/go-git/go-git/v5/plumbing/object"
11)
12
13const dailyInterval = 24 * time.Hour
14
15var ErrNoDigest = errors.New("replica: start-up needs a digest function for committed exports")
16
17type StartInput struct {
18	Repo        *git.Repository
19	Dir         string
20	Checkpoints Checkpoints
21	Primary     Remote
22	Digest      func([]byte) ([32]byte, error)
23	Current     [32]byte
24}
25
26type StartPlan struct {
27	StepNow, Pending     bool
28	CheckpointUnreadable bool
29	Committed            [32]byte
30	DailyDue             time.Time
31}
32
33func PlanStart(ctx context.Context, in StartInput) (StartPlan, error) {
34	if in.Digest == nil {
35		return StartPlan{}, ErrNoDigest
36	}
37	k, err := in.Checkpoints.ReadCheckpoint(ctx)
38	if err != nil {
39		return StartPlan{}, err
40	}
41	if err := ensureCheckpoint(ctx, in.Repo, in.Dir, in.Primary, k); err != nil {
42		return StartPlan{}, err
43	}
44	local, err := localHead(in.Repo)
45	if err != nil {
46		return StartPlan{}, err
47	}
48	if !k.Set {
49		if local.IsZero() {
50			return StartPlan{Pending: true}, nil
51		}
52		return StartPlan{StepNow: true}, nil
53	}
54	if local.String() != k.Value {
55		return StartPlan{StepNow: true}, nil
56	}
57	id := plumbing.NewHash(k.Value)
58	c, err := object.GetCommit(in.Repo.Storer, id)
59	if err != nil {
60		return StartPlan{}, err
61	}
62	blob, err := ReadFile(in.Repo.Storer, id)
63	if err != nil {
64		return StartPlan{}, err
65	}
66	dailyDue := c.Committer.When.UTC().Add(dailyInterval)
67	committed, err := in.Digest(blob)
68	if err != nil {
69		return StartPlan{StepNow: true, CheckpointUnreadable: true, DailyDue: dailyDue}, nil
70	}
71	return StartPlan{
72		Pending:   committed != in.Current,
73		Committed: committed,
74		DailyDue:  dailyDue,
75	}, nil
76}