diff --git a/README.md b/README.md index b66138d..e9b393f 100644 --- a/README.md +++ b/README.md @@ -120,5 +120,10 @@ paths: required if ambiguous If the version control system cannot be inferred (e.g. for Bitbucket or a custom domain), then this specifies the version control system as it would appear in go-import meta tag. This can be one of git, hg, svn, or bzr. + + wildcard + optional + Boolean. If true, it allows you to use the * placeholder, for the first sub-path inside your repo or display + diff --git a/handler.go b/handler.go index 8b7738d..b48cf16 100644 --- a/handler.go +++ b/handler.go @@ -24,6 +24,7 @@ import ( "strings" "gopkg.in/yaml.v2" + "regexp" ) type handler struct { @@ -33,6 +34,7 @@ type handler struct { } type pathConfig struct { + wildcard bool path string repo string display string @@ -45,6 +47,7 @@ func newHandler(config []byte) (*handler, error) { CacheAge *int64 `yaml:"cache_max_age,omitempty"` Paths map[string]struct { Repo string `yaml:"repo,omitempty"` + Wildcard bool `yaml:"wildcard,omitempty"` Display string `yaml:"display,omitempty"` VCS string `yaml:"vcs,omitempty"` } `yaml:"paths,omitempty"` @@ -67,6 +70,7 @@ func newHandler(config []byte) (*handler, error) { repo: e.Repo, display: e.Display, vcs: e.VCS, + wildcard: e.Wildcard, } switch { case e.Display != "": @@ -95,7 +99,7 @@ func newHandler(config []byte) (*handler, error) { func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { current := r.URL.Path - pc, subpath := h.paths.find(current) + pc, subpath, wildcard := h.paths.find(current) if pc == nil && current == "/" { h.serveIndex(w, r) return @@ -105,6 +109,11 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + importPath := h.Host(r) + pc.path + if wildcard != "" { + importPath += "/" + wildcard + } + w.Header().Set("Cache-Control", h.cacheControl) if err := vanityTmpl.Execute(w, struct { Import string @@ -113,10 +122,10 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { Display string VCS string }{ - Import: h.Host(r) + pc.path, + Import: importPath, Subpath: subpath, - Repo: pc.repo, - Display: pc.display, + Repo: strings.Replace(pc.repo, "*", wildcard, -1), + Display: strings.Replace(pc.display, "*", wildcard, -1), VCS: pc.vcs, }); err != nil { http.Error(w, "cannot render the page", http.StatusInternalServerError) @@ -184,17 +193,14 @@ func (pset pathConfigSet) Swap(i, j int) { pset[i], pset[j] = pset[j], pset[i] } -func (pset pathConfigSet) find(path string) (pc *pathConfig, subpath string) { +func (pset pathConfigSet) find(path string) (pc *pathConfig, subpath string, wildcard string) { // Fast path with binary search to retrieve exact matches // e.g. given pset ["/", "/abc", "/xyz"], path "/def" won't match. i := sort.Search(len(pset), func(i int) bool { return pset[i].path >= path }) if i < len(pset) && pset[i].path == path { - return &pset[i], "" - } - if i > 0 && strings.HasPrefix(path, pset[i-1].path+"/") { - return &pset[i-1], path[len(pset[i-1].path)+1:] + return &pset[i], "", "" } // Slow path, now looking for the longest prefix/shortest subpath i.e. @@ -214,6 +220,24 @@ func (pset pathConfigSet) find(path string) (pc *pathConfig, subpath string) { // route with equal or greater length is NOT a match. continue } + + if ps.wildcard { + p := ps.path + if !strings.HasSuffix(p, "/") { + p += "/" + } + regex := "^" + strings.Replace(p, "/", "\\/", -1) + "(.+)=?" + r := regexp.MustCompile(regex) + finds := r.FindStringSubmatch(path) + if finds != nil { + parts := strings.SplitN(finds[1], "/", 2) + if len(parts) > 1 { + return &pset[i], parts[1], parts[0] + } + return &pset[i], "", parts[0] + } + } + sSubpath := strings.TrimPrefix(path, ps.path) if len(sSubpath) < lenShortestSubpath { subpath = sSubpath @@ -221,5 +245,5 @@ func (pset pathConfigSet) find(path string) (pc *pathConfig, subpath string) { bestMatchConfig = &pset[i] } } - return bestMatchConfig, subpath + return bestMatchConfig, subpath, "" } diff --git a/vanity.yaml b/vanity.yaml index abfef50..dad98b4 100644 --- a/vanity.yaml +++ b/vanity.yaml @@ -6,3 +6,7 @@ paths: /launchpad: repo: https://github.com/rakyll/launchpad + + /opencensus/: + wildcard: true + repo: https://github.com/rakyll/opencensus-*