-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathgithub.go
156 lines (139 loc) · 4.95 KB
/
github.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright 2014 The Azul3D Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package semver
import (
"fmt"
"net/http"
"net/url"
"path"
"regexp"
"strings"
)
var rePkgVersion = regexp.MustCompile(`^([a-zA-Z0-9-]+).(v[0-9]+[\.]?[0-9]*[\.]?[0-9]*(?:\-unstable)?)`)
// github is a Matcher that represents a single GitHub user or organization.
type github struct {
host, user string
}
// githubGoSource returns a go-source meta-tag for the given repository and go
// get URL.
func githubGoSource(r *Repo, u *url.URL) string {
// The Go package path corresponding to the repository root, for example:
//
// right: azul3d.org/gfx.v2
// wrong: azul3d.org/gfx.v2/window
//
prefix := path.Join(u.Host, strings.TrimSuffix(u.Path, r.SubPath))
// Default to godoc.org's home:
home := "_"
// A basic GitHub repository URL.
ghURL := *r.URL
if len(ghURL.Scheme) == 0 {
ghURL.Scheme = "https"
}
// Build a directory-view URL like so:
//
// https://github.com/go-yaml/yaml/tree/v2{/dir}
//
dirURL := ghURL
dirURL.Path = path.Join(dirURL.Path, "tree", r.Version.String())
dir := dirURL.String() + "{/dir}"
// Build a file-view URL like so:
//
// https://github.com/go-yaml/yaml/blob/v2{/dir}/{file}#L{line}
//
fileURL := ghURL
fileURL.Path = path.Join(fileURL.Path, "blob", r.Version.String())
file := fileURL.String() + "{/dir}/{file}#L{line}"
return strings.Join([]string{prefix, home, dir, file}, " ")
}
// Match implements the Matcher interface.
func (user github) Match(u *url.URL) (repo *Repo, err error) {
// Split the path elements. If any element is an empty string then it
// is because there are two consecutive slashes ("/a//b/c") or the path
// ends with a trailing slash ("example.com/pkg.v1/").
//
// If more than one element contains a version match then it's invalid
// as well ("example.com/foo.v1/bar.v1/something.v2").
var (
rel = strings.TrimPrefix(u.Path, "/")
s = strings.Split(rel, "/")
versionElem = -1 // Index of version element in s.
version string // e.g. "v3".
pkgName string // e.g. "pkg" from "foo/bar/pkg.v3/sub".
)
for index, elem := range s {
if len(elem) == 0 {
// Path has two consecutive slashes ("/a//b/c") or ends with
// trailing slash.
return nil, ErrNotPackageURL
}
m := rePkgVersion.FindStringSubmatch(elem)
if m != nil {
if versionElem != -1 {
// Multiple versions in path.
return nil, ErrNotPackageURL
}
pkgName = m[1]
version = m[2]
versionElem = index
}
}
if versionElem == -1 {
// No version in path.
return nil, ErrNotPackageURL
}
// Parse the version string.
v := ParseVersion(version)
if v.Minor > 0 || v.Patch > 0 {
return nil, &HTTPError{
error: fmt.Errorf("Import path may only contain major version."),
Status: http.StatusNotFound,
}
}
// Everything in the path up to the path element index [found] is part
// of the repository name. We replace all slashes with dashes (the same
// thing GitHub does if you try to create a repository with slashes in
// the name).
repoName := strings.Join(append(s[:versionElem], pkgName), "-")
repoSubPath := strings.Join(s[versionElem+1:], "/")
repo = &Repo{
Version: v,
SubPath: repoSubPath,
URL: &url.URL{
Scheme: u.Scheme,
Host: user.host,
Path: path.Join(user.user, repoName),
},
}
// Attach the go-source meta-tag.
repo.GoSource = githubGoSource(repo, u)
// TODO(slimsag): godoc.org requires that repos end in .git: very strange.
repo.URL.Path += ".git"
return
}
// GitHub returns a URL Matcher that operates on a single GitHub user or
// organization. For instance if the service was running at example.com and the
// user string was "bob", it would match URLS in the pattern of:
//
// example.com/pkg.v3 → github.com/bob/pkg (branch/tag v3, v3.N, or v3.N.M)
// example.com/folder/pkg.v3 → github.com/bob/folder-pkg (branch/tag v3, v3.N, or v3.N.M)
// example.com/multi/folder/pkg.v3 → github.com/bob/multi-folder-pkg (branch/tag v3, v3.N, or v3.N.M)
// example.com/folder/pkg.v3/subpkg → github.com/bob/folder-pkg (branch/tag v3, v3.N, or v3.N.M)
// example.com/pkg.v3/folder/subpkg → github.com/bob/pkg (branch/tag v3, v3.N, or v3.N.M)
// example.com/pkg.v3-unstable → github.com/bob/pkg (branch/tag v3-unstable, v3.N-unstable, or v3.N.M-unstable)
//
func GitHub(user string) Matcher {
return github{"github.com", user}
}
// GitHub returns a URL Matcher that operates on a single GitHub user or organization
// on a custom domain instance of github ee or gitlab.
// For instance if the service was running at example.com, the custom host was gitlab.com and the
// user string was "bob", it would match URLS in the pattern of:
//
// example.com/pkg.v3 → gitlab.com/bob/pkg (branch/tag v3, v3.N, or v3.N.M)
// example.com/folder/pkg.v3 → gitlab.com/bob/folder-pkg (branch/tag v3, v3.N, or v3.N.M)
//
func GitHubCustomHost(host, user string) Matcher {
return github{host, user}
}