package publish import ( "fmt" "net/url" "strings" "gitea.maximumdirect.net/eric/distributor/internal/config" "gitea.maximumdirect.net/eric/distributor/internal/link" "gitea.maximumdirect.net/eric/distributor/internal/state" ) func PlanLinks(req Request, outputs []Output) ([]Output, string, error) { if req.Links == nil { return outputs, "", nil } if err := link.ValidateHTTPURL(req.Links.BaseURL); err != nil { return nil, "", fmt.Errorf("link base URL: %w", err) } linked := make([]Output, 0, len(outputs)) for _, output := range outputs { outputURL, err := OutputURL(req.Links.BaseURL, req.DestinationBundlePath, output.DestinationPath) if err != nil { return nil, "", err } output.URL = outputURL linked = append(linked, output) } return linked, primaryURL(linked, req.Links.Primary), nil } func OutputURL(baseURL, destinationBundlePath, outputPath string) (string, error) { parsed, err := url.Parse(baseURL) if err != nil { return "", fmt.Errorf("link base URL: %w", err) } segments := pathSegments(parsed.Path) segments = append(segments, pathSegments(destinationBundlePath)...) outputSegments := pathSegments(outputPath) trailingSlash := false if len(outputSegments) > 0 && outputSegments[len(outputSegments)-1] == "index.html" { outputSegments = outputSegments[:len(outputSegments)-1] trailingSlash = true } segments = append(segments, outputSegments...) parsed.Path = urlPath(segments, trailingSlash) parsed.RawPath = "" return parsed.String(), nil } func pathSegments(value string) []string { trimmed := strings.Trim(value, "/") if trimmed == "" { return nil } return strings.Split(trimmed, "/") } func urlPath(segments []string, trailingSlash bool) string { if len(segments) == 0 { return "/" } path := "/" + strings.Join(segments, "/") if trailingSlash && !strings.HasSuffix(path, "/") { path += "/" } return path } func primaryURL(outputs []Output, policy string) string { switch policy { case config.LinkPrimaryHTML: return firstGeneratedHTMLURL(outputs) case config.LinkPrimarySource: return firstSourceURL(outputs) default: if url := firstIndexURL(outputs); url != "" { return url } if url := firstGeneratedHTMLURL(outputs); url != "" { return url } return firstSourceURL(outputs) } } func firstIndexURL(outputs []Output) string { for _, output := range outputs { if isIndexOutput(output.DestinationPath) { return output.URL } } return "" } func firstGeneratedHTMLURL(outputs []Output) string { for _, output := range outputs { if output.Kind == state.OutputKindGenerated && isHTMLOutput(output.DestinationPath) { return output.URL } } return "" } func firstSourceURL(outputs []Output) string { for _, output := range outputs { if output.Kind == state.OutputKindSource { return output.URL } } return "" } func isIndexOutput(path string) bool { return path == "index.html" || strings.HasSuffix(path, "/index.html") } func isHTMLOutput(path string) bool { return strings.HasSuffix(path, ".html") }