Files
distributor/internal/app/source_select.go

139 lines
4.3 KiB
Go

package app
import (
"context"
"errors"
"fmt"
"gitea.maximumdirect.net/eric/distributor/internal/bundle"
"gitea.maximumdirect.net/eric/distributor/internal/config"
"gitea.maximumdirect.net/eric/distributor/internal/storage"
)
type PipelineNotFoundError struct {
ID string
}
func (e PipelineNotFoundError) Error() string {
return fmt.Sprintf("pipeline %q not found", e.ID)
}
func IsPipelineNotFound(err error) bool {
var notFound PipelineNotFoundError
return errors.As(err, &notFound)
}
type sourceCommandOptions struct {
CommandName string
Path string
ConfigPath string
PipelineID string
BundlePath string
}
type sourceSelection struct {
Bundles []bundle.Bundle
PipelineID string
SourceBackend string
ConfigMode bool
Warnings []OutputWarning
}
func selectSourceBundles(ctx context.Context, options sourceCommandOptions, provider backendFactoryProvider) (sourceSelection, error) {
if err := ctx.Err(); err != nil {
return sourceSelection{}, err
}
if options.ConfigPath != "" {
setup, err := loadRuntimeSetup(options.ConfigPath)
if err != nil {
return sourceSelection{}, err
}
return selectSourceBundlesFromSetup(ctx, setup, options, provider)
}
if options.PipelineID != "" {
return sourceSelection{}, fmt.Errorf("configured source mode requires --config")
}
if options.BundlePath != "" {
return sourceSelection{}, fmt.Errorf("configured source mode requires --config")
}
if options.Path == "" {
return sourceSelection{}, fmt.Errorf("%s command requires a path", options.CommandName)
}
backend, err := newBackendFactory().openLocalPath(ctx, options.Path)
if err != nil {
return sourceSelection{}, err
}
defer closeBackend(backend)
bundles, err := bundle.Discover(ctx, backend, "")
if err != nil {
return sourceSelection{}, err
}
return sourceSelection{Bundles: bundles}, nil
}
func selectSourceBundlesFromConfig(ctx context.Context, cfg config.Config, options sourceCommandOptions, provider backendFactoryProvider) (sourceSelection, error) {
setup, err := runtimeSetupFromConfig("", cfg)
if err != nil {
return sourceSelection{}, err
}
return selectSourceBundlesFromSetup(ctx, setup, options, provider)
}
func selectSourceBundlesFromSetup(ctx context.Context, setup runtimeSetup, options sourceCommandOptions, provider backendFactoryProvider) (sourceSelection, error) {
if options.Path != "" {
return sourceSelection{}, fmt.Errorf("configured source mode does not accept a local path")
}
if options.PipelineID == "" {
return sourceSelection{}, fmt.Errorf("configured source mode requires --pipeline")
}
pipeline, ok := findPipeline(setup.Config, options.PipelineID)
if !ok {
return sourceSelection{}, PipelineNotFoundError{ID: options.PipelineID}
}
backends := provider(setup.Environment)
sourceBackend, err := backends.openSource(ctx, pipeline.Source)
if err != nil {
return sourceSelection{}, fmt.Errorf("pipeline %s source backend %s: %w", pipeline.ID, pipeline.Source.Backend, err)
}
defer closeBackend(sourceBackend)
var bundles []bundle.Bundle
if options.BundlePath != "" {
sourceBundle, err := bundle.Validate(ctx, sourceBackend, options.BundlePath)
if err != nil {
return sourceSelection{}, fmt.Errorf("pipeline %s source backend %s bundle %s: %w", pipeline.ID, pipeline.Source.Backend, storage.DisplayPath(options.BundlePath), err)
}
bundles = []bundle.Bundle{sourceBundle}
} else {
bundles, err = bundle.Discover(ctx, sourceBackend, "")
if err != nil {
return sourceSelection{}, fmt.Errorf("pipeline %s source backend %s discover source bundles: %w", pipeline.ID, pipeline.Source.Backend, err)
}
}
return sourceSelection{
Bundles: bundles,
PipelineID: pipeline.ID,
SourceBackend: pipeline.Source.Backend,
ConfigMode: true,
Warnings: append(setup.Warnings, sourceSSHWarnings(pipeline)...),
}, nil
}
func findPipeline(cfg config.Config, id string) (config.Pipeline, bool) {
for _, pipeline := range cfg.Pipelines {
if pipeline.ID == id {
return pipeline, true
}
}
return config.Pipeline{}, false
}
func sourceSSHWarnings(pipeline config.Pipeline) []OutputWarning {
if pipeline.Source.Backend != config.BackendSSH || pipeline.Source.SSH.HostKeyPolicy != config.HostKeyPolicyOff {
return nil
}
return []OutputWarning{{
Message: fmt.Sprintf("pipeline=%s source host_key_policy=off disables SSH host key checking", pipeline.ID),
}}
}