Add local source publication
This commit is contained in:
141
internal/publish/plan.go
Normal file
141
internal/publish/plan.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package publish
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"gitea.maximumdirect.net/eric/distributor/internal/bundle"
|
||||
"gitea.maximumdirect.net/eric/distributor/internal/config"
|
||||
"gitea.maximumdirect.net/eric/distributor/internal/state"
|
||||
"gitea.maximumdirect.net/eric/distributor/internal/storage"
|
||||
)
|
||||
|
||||
type Action string
|
||||
|
||||
const (
|
||||
ActionPublishNew Action = "publish_new"
|
||||
ActionReplaceOlder Action = "replace_older"
|
||||
ActionSkipSame Action = "skip_same"
|
||||
ActionSkipDestinationNewer Action = "skip_destination_newer"
|
||||
ActionFailConflict Action = "fail_conflict"
|
||||
ActionFailUnmanaged Action = "fail_unmanaged"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
PipelineID string
|
||||
DestinationID string
|
||||
SourceBundle bundle.Bundle
|
||||
SourceBackend storage.Backend
|
||||
DestinationBackend storage.Backend
|
||||
DestinationBundlePath string
|
||||
Publish config.PublishPolicy
|
||||
Transfer config.TransferPolicy
|
||||
DistributorVersion string
|
||||
}
|
||||
|
||||
type Plan struct {
|
||||
PipelineID string
|
||||
DestinationID string
|
||||
BundleID string
|
||||
BundlePath string
|
||||
DestinationBundlePath string
|
||||
Action Action
|
||||
Reason string
|
||||
Outputs []Output
|
||||
ExistingState *state.DistributorState
|
||||
}
|
||||
|
||||
type Output struct {
|
||||
SourcePath string
|
||||
DestinationPath string
|
||||
SHA256 string
|
||||
Size int64
|
||||
}
|
||||
|
||||
func Build(ctx context.Context, req Request) (Plan, error) {
|
||||
if err := validateRequest(req); err != nil {
|
||||
return Plan{}, err
|
||||
}
|
||||
outputs, err := PlanSourceOutputs(req)
|
||||
if err != nil {
|
||||
return Plan{}, err
|
||||
}
|
||||
status, err := inspectDestination(ctx, req.DestinationBackend, req.DestinationBundlePath)
|
||||
if err != nil {
|
||||
return Plan{}, err
|
||||
}
|
||||
comparison := state.Compare(req.SourceBundle.Manifest, req.PipelineID, req.DestinationID, status)
|
||||
action, reason := actionForComparison(comparison, req.Transfer)
|
||||
plan := Plan{
|
||||
PipelineID: req.PipelineID,
|
||||
DestinationID: req.DestinationID,
|
||||
BundleID: req.SourceBundle.Manifest.ID,
|
||||
BundlePath: req.SourceBundle.RootRelativePath,
|
||||
DestinationBundlePath: req.DestinationBundlePath,
|
||||
Action: action,
|
||||
Reason: reason,
|
||||
Outputs: outputs,
|
||||
ExistingState: status.State,
|
||||
}
|
||||
if action == ActionFailConflict || action == ActionFailUnmanaged {
|
||||
return plan, fmt.Errorf("%s: %s", action, reason)
|
||||
}
|
||||
return plan, nil
|
||||
}
|
||||
|
||||
func validateRequest(req Request) error {
|
||||
if req.PipelineID == "" {
|
||||
return fmt.Errorf("pipeline id is required")
|
||||
}
|
||||
if req.DestinationID == "" {
|
||||
return fmt.Errorf("destination id is required")
|
||||
}
|
||||
if req.SourceBackend == nil {
|
||||
return fmt.Errorf("source backend is required")
|
||||
}
|
||||
if req.DestinationBackend == nil {
|
||||
return fmt.Errorf("destination backend is required")
|
||||
}
|
||||
if req.Publish.HTML {
|
||||
return fmt.Errorf("publish html is not implemented")
|
||||
}
|
||||
if !req.Publish.Source {
|
||||
return fmt.Errorf("publish source must be enabled")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func actionForComparison(comparison state.Comparison, transfer config.TransferPolicy) (Action, string) {
|
||||
switch comparison.Outcome {
|
||||
case state.OutcomeDestinationAbsent:
|
||||
return ActionPublishNew, comparison.Reason
|
||||
case state.OutcomeDestinationUnmanaged:
|
||||
return ActionFailUnmanaged, comparison.Reason
|
||||
case state.OutcomeInvalidState, state.OutcomeIdentityMismatch, state.OutcomeSameCreatedConflict, state.OutcomeDifferentSourceConflict:
|
||||
return ActionFailConflict, comparison.Reason
|
||||
case state.OutcomeSameSource:
|
||||
if transfer.OnDestinationSame == config.TransferActionFail {
|
||||
return ActionFailConflict, "destination matches source and transfer policy requires failure"
|
||||
}
|
||||
return ActionSkipSame, comparison.Reason
|
||||
case state.OutcomeDestinationOlder:
|
||||
if transfer.OnDestinationOlder == config.TransferActionFail {
|
||||
return ActionFailConflict, "destination is older and transfer policy requires failure"
|
||||
}
|
||||
return ActionReplaceOlder, comparison.Reason
|
||||
case state.OutcomeDestinationNewer:
|
||||
if transfer.OnDestinationNewer == config.TransferActionFail {
|
||||
return ActionFailConflict, "destination is newer and transfer policy requires failure"
|
||||
}
|
||||
return ActionSkipDestinationNewer, comparison.Reason
|
||||
default:
|
||||
return ActionFailConflict, "unsupported comparison outcome"
|
||||
}
|
||||
}
|
||||
|
||||
func displayPath(path string) string {
|
||||
if path == "" {
|
||||
return "."
|
||||
}
|
||||
return path
|
||||
}
|
||||
Reference in New Issue
Block a user