package pluginmgr import ( "fmt" "net/url" "path" "strings" ) // resolveSource parses a plugin source string into a download URL and plugin name. // // Supported formats: // // user/repo → GitHub (HEAD) // user/repo@v1.0 → GitHub (tag) // gitlab:user/repo → GitLab (HEAD) // gitlab:user/repo@v1.0 → GitLab (tag) // codeberg:user/repo → Codeberg (main) // codeberg:user/repo@v1 → Codeberg (tag) // https://example.com/plugin.lua → raw URL func resolveSource(source string) (urls []string, name string, err error) { // Raw URL. if strings.HasPrefix(source, "http://") || strings.HasPrefix(source, "https://") { u, err := url.Parse(source) if err != nil { return nil, "", fmt.Errorf("invalid URL: %w", err) } base := path.Base(u.Path) name = strings.TrimSuffix(base, ".lua") if name == "" || name == "." || name == "/" { return nil, "", fmt.Errorf("cannot derive a plugin name from URL %q; it should end in .lua", source) } return []string{source}, name, nil } // Detect forge prefix. forge := "github" repo := source if prefix, rest, ok := strings.Cut(source, ":"); ok { switch prefix { case "gitlab", "codeberg": forge = prefix repo = rest default: return nil, "", fmt.Errorf("unknown forge prefix %q (supported: gitlab, codeberg)", prefix) } } // Split repo@tag. ref := "" if r, tag, ok := strings.Cut(repo, "@"); ok { repo = r ref = tag } // Validate user/repo format. parts := strings.SplitN(repo, "/", 3) if len(parts) != 2 || parts[0] == "" || parts[1] == "" { return nil, "", fmt.Errorf("invalid source %q (expected user/repo)", source) } name = parts[1] // Convention: repos are named cliamp-plugin- with entry point .lua. short := strings.TrimPrefix(name, "cliamp-plugin-") u, err := buildForgeURL(forge, repo, ref, short) if err != nil { return nil, "", err } return []string{u}, short, nil } func buildForgeURL(forge, repo, ref, entrypoint string) (string, error) { var base string switch forge { case "github": if ref == "" { ref = "HEAD" } base = fmt.Sprintf("https://raw.githubusercontent.com/%s/%s", repo, ref) case "gitlab": if ref == "" { ref = "HEAD" } base = fmt.Sprintf("https://gitlab.com/%s/-/raw/%s", repo, ref) case "codeberg": if ref == "" { base = fmt.Sprintf("https://codeberg.org/%s/raw/branch/main", repo) } else { base = fmt.Sprintf("https://codeberg.org/%s/raw/tag/%s", repo, ref) } default: return "", fmt.Errorf("unsupported forge %q", forge) } return base + "/" + entrypoint + ".lua", nil }