118 lines
3.4 KiB
Go
118 lines
3.4 KiB
Go
package publish
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"gitea.maximumdirect.net/eric/distributor/internal/state"
|
|
"gitea.maximumdirect.net/eric/distributor/internal/storage"
|
|
"gitea.maximumdirect.net/eric/distributor/internal/transform"
|
|
)
|
|
|
|
func PlanOutputs(ctx context.Context, req Request) ([]Output, error) {
|
|
var outputs []Output
|
|
if req.Publish.Source {
|
|
sourceOutputs, err := PlanSourceOutputs(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
outputs = append(outputs, sourceOutputs...)
|
|
}
|
|
if req.Publish.HTML {
|
|
transformer, err := resolveTransformer(req.Transformers, transform.MarkdownToHTML)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
generatedOutputs, err := transformer.Generate(ctx, transform.Request{
|
|
SourceBundle: req.SourceBundle,
|
|
SourceBackend: req.SourceBackend,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(generatedOutputs) == 0 {
|
|
return nil, fmt.Errorf("publish html requested but no markdown source files were found")
|
|
}
|
|
for _, generated := range generatedOutputs {
|
|
outputs = append(outputs, Output{
|
|
SourcePath: generated.SourcePath,
|
|
DestinationPath: generated.Path,
|
|
Kind: state.OutputKindGenerated,
|
|
Transform: generated.Transform,
|
|
Data: generated.Data,
|
|
SHA256: generated.SHA256,
|
|
Size: generated.Size,
|
|
})
|
|
}
|
|
}
|
|
if err := rejectOutputCollisions(outputs); err != nil {
|
|
return nil, err
|
|
}
|
|
return outputs, nil
|
|
}
|
|
|
|
func resolveTransformer(resolver TransformerResolver, name string) (transform.Transformer, error) {
|
|
if resolver == nil {
|
|
return nil, fmt.Errorf("transformer resolver is required for %s", name)
|
|
}
|
|
transformer, ok := resolver.Get(name)
|
|
if !ok {
|
|
return nil, fmt.Errorf("transformer %s is not registered", name)
|
|
}
|
|
return transformer, nil
|
|
}
|
|
|
|
func PlanSourceOutputs(req Request) ([]Output, error) {
|
|
outputs := make([]Output, 0, len(req.SourceBundle.Manifest.Files))
|
|
for _, file := range req.SourceBundle.Manifest.Files {
|
|
if err := storage.ValidatePath(file.Path); err != nil {
|
|
return nil, fmt.Errorf("destination output path %q: %w", file.Path, err)
|
|
}
|
|
outputs = append(outputs, Output{
|
|
SourcePath: file.Path,
|
|
DestinationPath: file.Path,
|
|
Kind: state.OutputKindSource,
|
|
SHA256: file.SHA256,
|
|
Size: file.Size,
|
|
})
|
|
}
|
|
return outputs, nil
|
|
}
|
|
|
|
func rejectOutputCollisions(outputs []Output) error {
|
|
seen := make(map[string]struct{}, len(outputs))
|
|
for _, output := range outputs {
|
|
if err := storage.ValidatePath(output.DestinationPath); err != nil {
|
|
return fmt.Errorf("destination output path %q: %w", output.DestinationPath, err)
|
|
}
|
|
if _, exists := seen[output.DestinationPath]; exists {
|
|
return fmt.Errorf("destination output path collision: %s", output.DestinationPath)
|
|
}
|
|
seen[output.DestinationPath] = struct{}{}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func stateOutputs(outputs []Output) []state.OutputFile {
|
|
files := make([]state.OutputFile, 0, len(outputs))
|
|
for _, output := range outputs {
|
|
files = append(files, state.OutputFile{
|
|
Path: output.DestinationPath,
|
|
Kind: output.Kind,
|
|
SourcePath: output.SourcePath,
|
|
Transform: output.Transform,
|
|
SHA256: output.SHA256,
|
|
Size: output.Size,
|
|
})
|
|
}
|
|
return files
|
|
}
|
|
|
|
func managedOutputPaths(outputs []Output) []string {
|
|
paths := make([]string, 0, len(outputs))
|
|
for _, output := range outputs {
|
|
paths = append(paths, output.DestinationPath)
|
|
}
|
|
return paths
|
|
}
|