Files
distributor/internal/app/run_destination.go

165 lines
6.2 KiB
Go

package app
import (
"context"
"gitea.maximumdirect.net/eric/distributor/internal/bundle"
"gitea.maximumdirect.net/eric/distributor/internal/config"
"gitea.maximumdirect.net/eric/distributor/internal/notify"
"gitea.maximumdirect.net/eric/distributor/internal/publish"
"gitea.maximumdirect.net/eric/distributor/internal/storage"
)
type runDestinationRequest struct {
options RunOptions
notifier notify.Notifier
backends *backendFactory
transforms publish.TransformerResolver
pipeline config.Pipeline
pipelineIndex int
sourceBackend storage.Backend
bundles []bundle.Bundle
destination config.Destination
recorder *runReportRecorder
}
func processDestination(ctx context.Context, request runDestinationRequest) {
selections := selectDestinationBundles(request.destination, request.bundles)
if isFixedPathDestination(request.destination) {
request.recorder.summary.recordFixedPath()
if request.options.DryRun {
warning := fixedPathSelectionWarning(request.pipeline.ID, request.destination.ID, selections, len(request.bundles))
request.recorder.addPipelineWarning(request.pipelineIndex, warning)
}
}
if len(selections) == 0 {
return
}
destinationBackend, err := request.backends.openDestination(ctx, request.destination)
if err != nil {
for _, selection := range selections {
sourceBundle := selection.SourceBundle
request.recorder.recordDestinationFailure(request.pipelineIndex, runFailure{
pipelineID: request.pipeline.ID,
destinationID: request.destination.ID,
backend: request.destination.Backend,
bundlePath: sourceBundle.RootRelativePath,
err: err,
}, errorAction(request.pipeline.ID, request.destination.ID, request.destination.Backend, sourceBundle.RootRelativePath, err), true)
}
return
}
defer closeBackend(destinationBackend)
for _, selection := range selections {
processDestinationSelection(ctx, request, destinationBackend, selection)
}
}
func processDestinationSelection(ctx context.Context, request runDestinationRequest, destinationBackend storage.Backend, selection destinationBundleSelection) {
sourceBundle := selection.SourceBundle
publishRequest := publish.Request{
PipelineID: request.pipeline.ID,
DestinationID: request.destination.ID,
SourceBundle: sourceBundle,
SourceBackend: request.sourceBackend,
DestinationBackend: destinationBackend,
DestinationBundlePath: selection.DestinationBundlePath,
PathMapping: request.destination.PathMap.Mode,
Publish: *request.destination.Publish,
Transform: request.destination.Transform,
Links: request.destination.Links,
Reconciliation: request.destination.Reconciliation,
Transformers: request.transforms,
Transfer: request.destination.Transfer,
DistributorVersion: Version,
Force: request.options.Force,
}
plan, err := publish.Build(ctx, publishRequest)
if err != nil {
plan = completePlanIdentity(plan, request.pipeline, request.destination, selection)
}
if isFixedPathDestination(request.destination) {
plan.PathMapping = config.PathMappingFixed
if request.options.DryRun && isDestructiveFixedPathAction(plan.Action) {
warning := fixedPathReplacementWarning(plan)
request.recorder.addPipelineWarning(request.pipelineIndex, warning)
}
}
action := runActionFromPlan(request.destination.Backend, plan, err)
if err != nil {
request.recorder.recordDestinationFailure(request.pipelineIndex, runFailure{
pipelineID: request.pipeline.ID,
destinationID: request.destination.ID,
backend: request.destination.Backend,
bundlePath: sourceBundle.RootRelativePath,
err: err,
}, action, true)
return
}
request.recorder.addPipelineAction(request.pipelineIndex, action)
request.recorder.summary.recordPlan(plan.Action)
if request.options.DryRun {
return
}
if err := publish.Execute(ctx, publishRequest, plan); err != nil {
request.recorder.recordDestinationFailure(request.pipelineIndex, runFailure{
pipelineID: request.pipeline.ID,
destinationID: request.destination.ID,
backend: request.destination.Backend,
bundlePath: sourceBundle.RootRelativePath,
err: err,
}, RunActionRecord{}, false)
return
}
if shouldNotify(plan.Action) {
if err := request.notifier.Notify(ctx, notifyEvent(plan)); err != nil {
request.recorder.recordDestinationFailure(request.pipelineIndex, runFailure{
pipelineID: request.pipeline.ID,
destinationID: request.destination.ID,
backend: request.destination.Backend,
bundlePath: sourceBundle.RootRelativePath,
err: err,
}, RunActionRecord{}, false)
return
}
}
}
func (recorder *runReportRecorder) addPipelineWarning(pipelineIndex int, warning OutputWarning) {
recorder.report.addWarning(warning)
recorder.report.Pipelines[pipelineIndex].events = append(recorder.report.Pipelines[pipelineIndex].events, warningEvent(warning))
}
func (recorder *runReportRecorder) addPipelineAction(pipelineIndex int, action RunActionRecord) {
recorder.report.Actions = append(recorder.report.Actions, action)
recorder.report.Pipelines[pipelineIndex].events = append(recorder.report.Pipelines[pipelineIndex].events, actionEvent(len(recorder.report.Actions)-1))
}
func (recorder *runReportRecorder) recordDestinationFailure(pipelineIndex int, failure runFailure, action RunActionRecord, includeAction bool) {
recorder.failures.add(failure.pipelineID, failure.destinationID, failure.backend, storage.DisplayPath(failure.bundlePath), failure.err)
recorder.summary.recordFailure()
if includeAction {
recorder.addPipelineAction(pipelineIndex, action)
}
}
func completePlanIdentity(plan publish.Plan, pipeline config.Pipeline, destination config.Destination, selection destinationBundleSelection) publish.Plan {
if plan.PipelineID == "" {
plan.PipelineID = pipeline.ID
}
if plan.DestinationID == "" {
plan.DestinationID = destination.ID
}
if plan.BundleID == "" {
plan.BundleID = selection.SourceBundle.Manifest.ID
}
if plan.BundlePath == "" {
plan.BundlePath = selection.SourceBundle.RootRelativePath
}
if plan.DestinationBundlePath == "" {
plan.DestinationBundlePath = selection.DestinationBundlePath
}
return plan
}