diff --git a/config.yaml b/config.yaml index 9676b79..7440190 100644 --- a/config.yaml +++ b/config.yaml @@ -58,6 +58,15 @@ paths: /securityspy: repo: https://github.com/golift/securityspy redir: https://github.com/golift/securityspy + + # Unused Examples. + /david/: + repo: https://github.com/davidnewhall/ + wildcard: true + /captain-: + repo: https://github.com/davidnewhall/ + wildcard: true + # No repos. /unifi-poller: redir: https://github.com/davidnewhall/unifi-poller diff --git a/handler.go b/handler.go index b23c217..a30b56f 100644 --- a/handler.go +++ b/handler.go @@ -66,6 +66,7 @@ type PathConfig struct { Redir string `yaml:"redir,omitempty"` Display string `yaml:"display,omitempty"` VCS string `yaml:"vcs,omitempty"` + Wildcard bool `yaml:"wildcard,omitempty"` cacheControl string } @@ -97,7 +98,6 @@ func newHandler(configData []byte) (*Handler, error) { h.Paths[p].RedirPaths = h.RedirPaths } h.Paths[p].setRepoCacheControl(cacheControl) - h.Paths[p].setRepoDisplay() if err := h.Paths[p].setRepoVCS(); err != nil { return nil, err } @@ -115,19 +115,6 @@ func (p *PathConfig) setRepoCacheControl(cc string) { } } -// Set display path. -func (p *PathConfig) setRepoDisplay() { - if p.Display != "" { - return - } - // github, gitlab, git, svn, hg, bzr - may need more tweaking for some of these. - p.Display = fmt.Sprintf("%v %v/tree/master{/dir} %v/blob/master{/dir}/{file}#L{line}", p.Repo, p.Repo, p.Repo) - if strings.HasPrefix(p.Repo, "https://bitbucket.org") { - // bitbucket is weird. - p.Display = fmt.Sprintf("%v %v/src/default{/dir} %v/src/default{/dir}/{file}#{file}-{line}", p.Repo, p.Repo, p.Repo) - } -} - // setRepoVCS makes sure the provides VCS type is supported, // or sets it automatically based on the repo's prefix. func (p *PathConfig) setRepoVCS() error { @@ -188,8 +175,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Create a vanity redirect page. w.Header().Set("Cache-Control", pc.cacheControl) pc.Host = h.Hostname(r) - pc.Path = strings.TrimSuffix(pc.Path, "/") - if err := vanityTmpl.Execute(w, pc); err != nil { + if err := vanityTmpl.Execute(w, &pc); err != nil { http.Error(w, "cannot render the page", http.StatusInternalServerError) } } @@ -221,17 +207,58 @@ func (p *PathReq) RedirectablePath() bool { return false } -// Len is a sort.Search interface method. +// ImportPath is used in the template to generate the import path. +func (p *PathReq) ImportPath() string { + path := p.Path + repo := p.Repo + if p.Wildcard { + sub := strings.Split(p.Subpath, "/")[0] + path += sub + repo += sub + } + return p.Host + strings.TrimSuffix(path, "/") + " " + p.VCS + " " + repo +} + +// SourcePath is used in the template to generate the source path. +func (p *PathReq) SourcePath() string { + if p.Display != "" { + return p.Host + strings.TrimSuffix(p.Path, "/") + " " + p.Display + } + // TODO: add branch control. + template := "%v%v %v %v/tree/master{/dir} %v/blob/master{/dir}/{file}#L{line}" + if strings.HasPrefix(p.Repo, "https://bitbucket.org") { + template = "%v%v %v %v/src/default{/dir} %v/src/default{/dir}/{file}#{file}-{line}" + } + path := p.Path + repo := p.Repo + if p.Wildcard { + sub := strings.Split(p.Subpath, "/")[0] + path += sub + repo += sub + } + // github, gitlab, git, svn, hg, bzr - may need more tweaking for some of these. + return fmt.Sprintf(template, p.Host, strings.TrimSuffix(path, "/"), repo, repo, repo) +} + +// GoDocPath is used in the template to generate the GoDoc path. +func (p *PathReq) GoDocPath() string { + if p.Wildcard { + return p.Host + "/" + p.Subpath + } + return p.Host + p.Path + "/" + p.Subpath +} + +// Len is a sort.Sort interface method. func (pset PathConfigs) Len() int { return len(pset) } -// Less is a sort.Search interface method. +// Less is a sort.Sort interface method. func (pset PathConfigs) Less(i, j int) bool { return pset[i].Path < pset[j].Path } -// Swap is a sort.Search interface method. +// Swap is a sort.Sort interface method. func (pset PathConfigs) Swap(i, j int) { pset[i], pset[j] = pset[j], pset[i] } @@ -243,9 +270,12 @@ func (pset PathConfigs) find(path string) PathReq { return pset[i].Path >= path }) if i < len(pset) && pset[i].Path == path { + // We have an exact match to a configured path. return PathReq{PathConfig: pset[i]} } + // This attempts to match /some/path/here but not /some/pathhere if i > 0 && strings.HasPrefix(path, pset[i-1].Path+"/") { + // We have a partial match with a subpath! return PathReq{ PathConfig: pset[i-1], Subpath: path[len(pset[i-1].Path)+1:], @@ -253,8 +283,8 @@ func (pset PathConfigs) find(path string) PathReq { } // Slow path, now looking for the longest prefix/shortest subpath i.e. - // e.g. given pset ["/", "/abc/", "/abc/def/", "/xyz"/] - // * query "/abc/foo" returns "/abc/" with a subpath of "foo" + // e.g. given pset ["/", "/abc", "/abc/def", "/xyz"] + // * query "/abc/foo" returns "/abc" with a subpath of "foo" // * query "/x" returns "/" with a subpath of "x" lenShortestSubpath := len(path) var p PathReq @@ -263,14 +293,16 @@ func (pset PathConfigs) find(path string) PathReq { // nothing greater than i will be a prefix of path. max := i for i := 0; i < max; i++ { - ps := pset[i] - if len(ps.Path) >= len(path) { - // We previously didn't find the path by search, so any - // route with equal or greater length is NOT a match. + if len(pset[i].Path) >= len(path) { + // We previously didn't find the request path by search, so any + // configured path with equal or greater length is NOT a match. continue } - sSubpath := strings.TrimPrefix(path, ps.Path) + sSubpath := strings.TrimPrefix(path, pset[i].Path) if len(sSubpath) < lenShortestSubpath { + // We get into this if statement only if TrimPrefix trimmed something. + // Then we try the next path, and check to see if what's left after we + // trimmed the configured path off is shorter than this one. /x is better than /xyz. p.Subpath = sSubpath lenShortestSubpath = len(sSubpath) p.PathConfig = pset[i] diff --git a/handler_test.go b/handler_test.go index f5ddc52..e92f527 100644 --- a/handler_test.go +++ b/handler_test.go @@ -108,6 +108,51 @@ func TestHandler(t *testing.T) { goImport: "example.com git https://github.com/rakyll/portmidi", goSource: "example.com https://github.com/rakyll/portmidi _ _", }, + { + name: "wildcard with sub path", + config: "host: example.com\n" + + "paths:\n" + + " /rakyll/:\n" + + " repo: https://github.com/rakyll/\n" + + " wildcard: true\n", + path: "/rakyll/repo/foo", + goImport: "example.com/rakyll/repo git https://github.com/rakyll/repo", + goSource: "example.com/rakyll/repo https://github.com/rakyll/repo https://github.com/rakyll/repo/tree/master{/dir} https://github.com/rakyll/repo/blob/master{/dir}/{file}#L{line}", + }, + { + name: "wildcard with no slashes", + config: "host: example.com\n" + + "paths:\n" + + " /rakyll/:\n" + + " repo: https://github.com/rakyll/\n" + + " wildcard: true\n", + path: "/rakyll/repo", + goImport: "example.com/rakyll/repo git https://github.com/rakyll/repo", + goSource: "example.com/rakyll/repo https://github.com/rakyll/repo https://github.com/rakyll/repo/tree/master{/dir} https://github.com/rakyll/repo/blob/master{/dir}/{file}#L{line}", + }, + { + name: "wildcard with dashes", + config: "host: example.com\n" + + "paths:\n" + + " /rakyll-:\n" + + " repo: https://github.com/rakyll/\n" + + " wildcard: true\n", + path: "/rakyll-repo", + goImport: "example.com/rakyll-repo git https://github.com/rakyll/repo", + goSource: "example.com/rakyll-repo https://github.com/rakyll/repo https://github.com/rakyll/repo/tree/master{/dir} https://github.com/rakyll/repo/blob/master{/dir}/{file}#L{line}", + }, + { + name: "wildcard bare word", + config: "host: example.com\n" + + "paths:\n" + + " /rakyll:\n" + + " repo: https://github.com/rakyll/\n" + + " cache_max_age: 99\n" + + " wildcard: true\n", + path: "/rakyllrepo", + goImport: "example.com/rakyllrepo git https://github.com/rakyll/repo", + goSource: "example.com/rakyllrepo https://github.com/rakyll/repo https://github.com/rakyll/repo/tree/master{/dir} https://github.com/rakyll/repo/blob/master{/dir}/{file}#L{line}", + }, { name: "display Gitlab inference", config: "host: example.com\n" + diff --git a/templates.go b/templates.go index 8367a5f..947468b 100644 --- a/templates.go +++ b/templates.go @@ -28,7 +28,7 @@ var indexTmpl = template.Must(template.New("index").Parse(`

{{.Title}}

{{end -}}