@@ -31,6 +31,15 @@ type Handler struct {
3131 PathConfigs
3232}
3333
34+ // vcsPrefixMap provides defaults for VCS type if it's not provided.
35+ // The list of strings is used in strings.HasPrefix().
36+ var vcsPrefixMap = map [string ][]string {
37+ "git" : []string {"https://git" , "https://bitbucket" },
38+ "bzr" : []string {"https://bazaar" },
39+ "hg" : []string {"https://hg." , "https://mercurial" },
40+ "svn" : []string {"https://svn." },
41+ }
42+
3443// Config contains the config file data.
3544type Config struct {
3645 Title string `yaml:"title,omitempty"`
@@ -81,47 +90,77 @@ func newHandler(configData []byte) (*Handler, error) {
8190 if h .CacheAge != nil {
8291 cacheControl = fmt .Sprintf ("public, max-age=%d" , * h .CacheAge )
8392 }
84-
85- for p , e := range h .Paths {
93+ for p := range h .Paths {
8694 h .Paths [p ].Path = p
87-
88- if len (e .RedirPaths ) < 1 {
95+ if len (h .Paths [p ].RedirPaths ) < 1 {
8996 // was not provided, pass in global value.
90- e .RedirPaths = h .RedirPaths
97+ h . Paths [ p ] .RedirPaths = h .RedirPaths
9198 }
92- h .Paths [p ].cacheControl = cacheControl
93- if e . CacheAge != nil {
94- // provided, override global value.
95- h . Paths [ p ]. cacheControl = fmt . Sprintf ( "public, max-age=%d" , * e . CacheAge )
99+ h .Paths [p ].setRepoCacheControl ( cacheControl )
100+ h . Paths [ p ]. setRepoDisplay ()
101+ if err := h . Paths [ p ]. setRepoVCS (); err != nil {
102+ return nil , err
96103 }
104+ h .PathConfigs = append (h .PathConfigs , h .Paths [p ])
105+ }
106+ sort .Sort (h .PathConfigs )
107+ return h , nil
108+ }
109+
110+ func (p * PathConfig ) setRepoCacheControl (cc string ) {
111+ p .cacheControl = cc
112+ if p .CacheAge != nil {
113+ // provided, override global value.
114+ p .cacheControl = fmt .Sprintf ("public, max-age=%d" , * p .CacheAge )
115+ }
116+ }
97117
98- switch {
99- case e .Display != "" :
100- // Already filled in.
101- case strings .HasPrefix (e .Repo , "https://github.com/" ):
102- h .Paths [p ].Display = fmt .Sprintf ("%v %v/tree/master{/dir} %v/blob/master{/dir}/{file}#L{line}" , e .Repo , e .Repo , e .Repo )
103- case strings .HasPrefix (e .Repo , "https://bitbucket.org" ):
104- h .Paths [p ].Display = fmt .Sprintf ("%v %v/src/default{/dir} %v/src/default{/dir}/{file}#{file}-{line}" , e .Repo , e .Repo , e .Repo )
118+ // Set display path.
119+ func (p * PathConfig ) setRepoDisplay () {
120+ if p .Display != "" {
121+ return
122+ }
123+ // github, gitlab, git, svn, hg, bzr - may need more tweaking for some of these.
124+ p .Display = fmt .Sprintf ("%v %v/tree/master{/dir} %v/blob/master{/dir}/{file}#L{line}" , p .Repo , p .Repo , p .Repo )
125+ if strings .HasPrefix (p .Repo , "https://bitbucket.org" ) {
126+ // bitbucket is weird.
127+ p .Display = fmt .Sprintf ("%v %v/src/default{/dir} %v/src/default{/dir}/{file}#{file}-{line}" , p .Repo , p .Repo , p .Repo )
128+ }
129+ }
130+
131+ // setRepoVCS makes sure the provides VCS type is supported,
132+ // or sets it automatically based on the repo's prefix.
133+ func (p * PathConfig ) setRepoVCS () error {
134+ // Check and set VCS type.
135+ switch {
136+ case p .Repo == "" && p .Redir != "" :
137+ // Redirect-only can go anywhere.
138+ case p .VCS == "github" || p .VCS == "gitlab" || p .VCS == "bitbucket" :
139+ p .VCS = "git"
140+ case p .VCS == "" :
141+ // Try to figure it out.
142+ var err error
143+ p .VCS , err = findRepoVCS (p .Repo )
144+ return err
145+ default :
146+ // Already filled in, make sure it's supported.
147+ if _ , ok := vcsPrefixMap [p .VCS ]; ! ok {
148+ return fmt .Errorf ("configuration for %v: unknown VCS %s" , p , p .VCS )
105149 }
150+ }
151+ return nil
152+ }
106153
107- switch {
108- case e .VCS != "" :
109- // Already filled in.
110- if e .VCS != "bzr" && e .VCS != "git" && e .VCS != "hg" && e .VCS != "svn" {
111- return nil , fmt .Errorf ("configuration for %v: unknown VCS %s" , p , e .VCS )
154+ // findRepoVCS checks the vcsMapList for a supported vcs type based on a repo's prefix.
155+ func findRepoVCS (repo string ) (string , error ) {
156+ for vcs , prefixList := range vcsPrefixMap {
157+ for _ , prefix := range prefixList {
158+ if strings .HasPrefix (repo , prefix ) {
159+ return vcs , nil
112160 }
113- case strings .HasPrefix (e .Repo , "https://github.com/" ):
114- h .Paths [p ].VCS = "git"
115- case e .Repo == "" && e .Redir != "" :
116- // Redirect-only can go anywhere.
117- default :
118- return nil , fmt .Errorf ("configuration for %v: cannot infer VCS from %s" , p , e .Repo )
119161 }
120-
121- h .PathConfigs = append (h .PathConfigs , e )
122162 }
123- sort .Sort (h .PathConfigs )
124- return h , nil
163+ return "" , fmt .Errorf ("cannot infer VCS from %s" , repo )
125164}
126165
127166func (h * Handler ) ServeHTTP (w http.ResponseWriter , r * http.Request ) {
@@ -169,7 +208,8 @@ func (h *Handler) Hostname(r *http.Request) string {
169208}
170209
171210// StringInSlices checks if a string exists in a list of strings.
172- // Used to determine if a sub path shouuld be redirected or not.
211+ // Used to determine if a sub path should be redirected or not.
212+ // Not used for normal vanity URLs, only used for `redir`.
173213func StringInSlices (str string , slice []string ) bool {
174214 for _ , s := range slice {
175215 if strings .Contains (str , s ) {
0 commit comments