Files
distributor/internal/publish/output.go

151 lines
4.2 KiB
Go
Raw Normal View History

2026-05-31 02:21:36 +00:00
package publish
import (
2026-05-31 02:28:48 +00:00
"context"
2026-05-31 02:21:36 +00:00
"fmt"
"gitea.maximumdirect.net/eric/distributor/internal/state"
"gitea.maximumdirect.net/eric/distributor/internal/storage"
2026-05-31 02:28:48 +00:00
"gitea.maximumdirect.net/eric/distributor/internal/transform"
2026-05-31 02:21:36 +00:00
)
2026-05-31 02:28:48 +00:00
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 {
2026-05-31 03:30:08 +00:00
transformer, err := resolveTransformer(req.Transformers, transform.MarkdownToHTML)
if err != nil {
return nil, err
}
generatedOutputs, err := transformer.Generate(ctx, transform.Request{
2026-05-31 02:28:48 +00:00
SourceBundle: req.SourceBundle,
SourceBackend: req.SourceBackend,
2026-06-01 21:20:02 +00:00
Markdown: transform.MarkdownOptions{
Mode: req.Transform.MarkdownToHTML.Mode,
Input: req.Transform.MarkdownToHTML.Input,
},
2026-05-31 02:28:48 +00:00
})
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
2026-05-31 02:21:36 +00:00
}
2026-05-31 02:28:48 +00:00
return outputs, nil
}
2026-05-31 03:30:08 +00:00
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
}
2026-05-31 02:28:48 +00:00
func PlanSourceOutputs(req Request) ([]Output, error) {
2026-05-31 02:21:36 +00:00
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,
2026-05-31 02:28:48 +00:00
Kind: state.OutputKindSource,
2026-05-31 02:21:36 +00:00
SHA256: file.SHA256,
Size: file.Size,
})
}
return outputs, nil
}
2026-05-31 02:28:48 +00:00
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
}
2026-06-02 18:43:47 +00:00
func (o Output) StateOutputFile() state.OutputFile {
return state.OutputFile{
Path: o.DestinationPath,
Kind: o.Kind,
SourcePath: o.SourcePath,
Transform: o.Transform,
URL: o.URL,
SHA256: o.SHA256,
Size: o.Size,
}
}
2026-06-08 18:24:12 +00:00
func (o Output) StateOutputProjection() state.OutputProjection {
return state.OutputProjection{
Path: o.DestinationPath,
Kind: o.Kind,
SourcePath: o.SourcePath,
Transform: o.Transform,
URL: o.URL,
SHA256: o.SHA256,
Size: o.Size,
}
}
2026-06-02 18:43:47 +00:00
func (o Output) ManagedPath() string {
return o.DestinationPath
}
func StateOutputFiles(outputs []Output) []state.OutputFile {
2026-05-31 02:21:36 +00:00
files := make([]state.OutputFile, 0, len(outputs))
for _, output := range outputs {
2026-06-02 18:43:47 +00:00
files = append(files, output.StateOutputFile())
2026-05-31 02:21:36 +00:00
}
return files
}
2026-06-08 18:24:12 +00:00
func StateOutputProjections(outputs []Output) []state.OutputProjection {
projections := make([]state.OutputProjection, 0, len(outputs))
for _, output := range outputs {
projections = append(projections, output.StateOutputProjection())
}
return projections
}
2026-06-02 18:43:47 +00:00
func ManagedOutputPaths(outputs []Output) []string {
paths := make([]string, 0, len(outputs))
for _, output := range outputs {
paths = append(paths, output.ManagedPath())
}
return paths
}