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 { generatedOutputs, err := markdownTransformer().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 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 }