Skip to content
go-libfossil Artifact [2e2cf8fe49]
Login

Artifact [2e2cf8fe49]

Artifact 2e2cf8fe4940755ee29ff504e67bf94a60e50471c205a9de2df262c10b612bed:


package libfossil

import (
	"context"
	"fmt"

	"github.com/danmestas/go-libfossil/internal/checkout"
	"github.com/danmestas/go-libfossil/internal/fsltype"
)

// UpdateContext recovers necessary structure and selected update payloads from
// an explicit peer before checkout mutation. An implicit target is resolved once;
// after recovery the local update replans against fresh working files.
func (c *Checkout) UpdateContext(
	ctx context.Context, opts UpdateOpts, required RequiredContentOpts,
) (UpdateResult, error) {
	if err := required.validate(ctx); err != nil {
		return UpdateResult{}, err
	}
	_, before, err := c.requiredState()
	if err != nil {
		return UpdateResult{}, err
	}
	target, files, readiness := c.inner.UpdateRequiredFiles(ctx, checkout.UpdateOpts{
		TargetRID: fsltype.FslID(opts.TargetRID),
	})
	if err := c.checkRequiredState(before); err != nil {
		return UpdateResult{}, err
	}
	if target == 0 {
		return UpdateResult{}, readiness
	}
	state, err := c.updateRequiredState(target)
	if err != nil {
		return UpdateResult{}, err
	}
	if readiness != nil {
		if err := required.recover(ctx, c.inner.Repo(), readiness); err != nil {
			return UpdateResult{}, err
		}
		if err := c.checkUpdateRequiredState(target, state); err != nil {
			return UpdateResult{}, err
		}
		resolved, fresh, err := c.inner.UpdateRequiredFiles(ctx, checkout.UpdateOpts{TargetRID: target})
		if err != nil {
			return UpdateResult{}, err
		}
		if resolved != target {
			return UpdateResult{}, fmt.Errorf("libfossil: update recovery target changed")
		}
		files = fresh
	}
	names, err := requiredFileNames(ctx, c.inner.Repo(), files, func(string) bool { return true })
	if err != nil {
		return UpdateResult{}, err
	}
	if err := required.recoverFiles(ctx, c.inner.Repo(), names); err != nil {
		return UpdateResult{}, err
	}
	if err := c.checkUpdateRequiredState(target, state); err != nil {
		return UpdateResult{}, err
	}
	return c.update(ctx, UpdateOpts{TargetRID: int64(target)})
}

func (c *Checkout) updateRequiredState(target fsltype.FslID) (string, error) {
	_, state, err := c.requiredState()
	if err != nil {
		return "", err
	}
	identity, err := requiredState(c.inner.Repo(), []fsltype.FslID{target})
	if err != nil {
		return "", err
	}
	return state + "\nupdate-target=" + identity, nil
}

func (c *Checkout) checkUpdateRequiredState(target fsltype.FslID, before string) error {
	after, err := c.updateRequiredState(target)
	if err != nil {
		return err
	}
	if after != before {
		return fmt.Errorf("libfossil: update snapshot or policy changed during recovery")
	}
	return nil
}