Serve the api docs from the speculator
There are a few parts to this: * when we generate the spec for a particular git sha, also run the script which turns our yaml api descriptions into a swagger json file. * tweak serveSpec to add another header when serving the generated json. * add a link to the generated index which will (via js hackery) redirect to our hosted swagger UI at http://matrix.org/docs/api/client-server, with a "url" query-param pointing at the generated json. Also, factor makeTempDir out of gitClone, so that we can give clearer log lines.
This commit is contained in:
parent
459f4b953d
commit
1320a86cbe
1 changed files with 86 additions and 22 deletions
|
@ -27,6 +27,7 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/golang-lru"
|
||||
|
@ -83,19 +84,15 @@ func accessTokenQuerystring() string {
|
|||
return fmt.Sprintf("?access_token=%s", *accessToken)
|
||||
}
|
||||
|
||||
func gitClone(url string, shared bool) (string, error) {
|
||||
directory := path.Join("/tmp/matrix-doc", strconv.FormatInt(rand.Int63(), 10))
|
||||
if err := os.MkdirAll(directory, permissionsOwnerFull); err != nil {
|
||||
return "", fmt.Errorf("error making directory %s: %v", directory, err)
|
||||
}
|
||||
func gitClone(url string, directory string, shared bool) error {
|
||||
args := []string{"clone", url, directory}
|
||||
if shared {
|
||||
args = append(args, "--shared")
|
||||
}
|
||||
if err := runGitCommand(directory, args); err != nil {
|
||||
return "", err
|
||||
return err
|
||||
}
|
||||
return directory, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func gitCheckout(path, sha string) error {
|
||||
|
@ -159,6 +156,16 @@ func generate(dir string) error {
|
|||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("error generating spec: %v\nOutput from gendoc:\n%v", err, b.String())
|
||||
}
|
||||
|
||||
// cheekily dump the swagger docs into the gen directory so they can be
|
||||
// served by serveSpec
|
||||
cmd = exec.Command("python", "dump-swagger.py", "gen/api-docs.json")
|
||||
cmd.Dir = path.Join(dir, "scripts")
|
||||
cmd.Stderr = &b
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("error generating api docs: %v\nOutput from dump-swagger:\n%v", err, b.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -195,8 +202,14 @@ func (s *server) generateAt(sha string) (dst string, err error) {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
dst, err = makeTempDir()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("Generating %s in %s\n", sha, dst)
|
||||
s.mu.Lock()
|
||||
dst, err = gitClone(s.matrixDocCloneURL, true)
|
||||
err = gitClone(s.matrixDocCloneURL, dst, true)
|
||||
s.mu.Unlock()
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -219,7 +232,7 @@ func (s *server) getSHAOf(ref string) (string, error) {
|
|||
err := cmd.Run()
|
||||
s.mu.Unlock()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error generating spec: %v\nOutput from gendoc:\n%v", err, b.String())
|
||||
return "", fmt.Errorf("error generating spec: %v\nOutput from git:\n%v", err, b.String())
|
||||
}
|
||||
return strings.TrimSpace(b.String()), nil
|
||||
}
|
||||
|
@ -396,6 +409,11 @@ func (s *server) serveSpec(w http.ResponseWriter, req *http.Request) {
|
|||
cache.Add(sha, pathToContent)
|
||||
}
|
||||
|
||||
if requestedPath == "api-docs.json" {
|
||||
// allow other swagger UIs access to our swagger
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
}
|
||||
|
||||
if b, ok := pathToContent[requestedPath]; ok {
|
||||
w.Write(b)
|
||||
return
|
||||
|
@ -588,12 +606,6 @@ func (srv *server) makeIndex(w http.ResponseWriter, req *http.Request) {
|
|||
writeError(w, 500, err)
|
||||
return
|
||||
}
|
||||
s := "<body><ul>"
|
||||
for _, pull := range pulls {
|
||||
s += fmt.Sprintf(`<li>%d: <a href="%s">%s</a>: <a href="%s">%s</a>: <a href="spec/%d/">spec</a> <a href="diff/html/%d/">spec diff</a> <a href="diff/rst/%d/">rst diff</a></li>`,
|
||||
pull.Number, pull.User.HTMLURL, pull.User.Login, pull.HTMLURL, pull.Title, pull.Number, pull.Number, pull.Number)
|
||||
}
|
||||
s += "</ul>"
|
||||
|
||||
branches, err := srv.getBranches()
|
||||
if err != nil {
|
||||
|
@ -601,7 +613,48 @@ func (srv *server) makeIndex(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
s += `<div>View the spec at:<ul>`
|
||||
// write our stuff into a buffer so that we can change our minds
|
||||
// and write a 500 if it all goes wrong.
|
||||
var b bytes.Buffer
|
||||
b.Write([]byte(`
|
||||
<head>
|
||||
<script>
|
||||
function redirectToApiDocs(relativePath) {
|
||||
var url = new URL(window.location);
|
||||
url.pathname += relativePath;
|
||||
var newLoc = "http://matrix.org/docs/api/client-server/?url=" + encodeURIComponent(url);
|
||||
window.location = newLoc;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body><ul>
|
||||
`))
|
||||
|
||||
tmpl, err := template.New("pr entry").Parse(`
|
||||
<li>{{.Number}}:
|
||||
<a href="{{.User.HTMLURL}}">{{.User.Login}}</a>:
|
||||
<a href="{{.HTMLURL}}">{{.Title}}</a>:
|
||||
<a href="spec/{{.Number}}/">spec</a>
|
||||
<a href="#" onclick="redirectToApiDocs('spec/{{.Number}}/api-docs.json')">api docs</a>
|
||||
<a href="diff/html/{{.Number}}/">spec diff</a>
|
||||
<a href="diff/rst/{{.Number}}/">rst diff</a>
|
||||
</li>
|
||||
`)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, pull := range pulls {
|
||||
err = tmpl.Execute(&b, pull)
|
||||
if err != nil {
|
||||
writeError(w, 500, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
b.Write([]byte(`
|
||||
</ul>
|
||||
<div>View the spec at:<ul>
|
||||
`))
|
||||
branchNames := []string{}
|
||||
for _, branch := range branches {
|
||||
if strings.HasPrefix(branch, "drafts/") {
|
||||
|
@ -611,15 +664,14 @@ func (srv *server) makeIndex(w http.ResponseWriter, req *http.Request) {
|
|||
branchNames = append(branchNames, "HEAD")
|
||||
for _, branch := range branchNames {
|
||||
href := "spec/" + url.QueryEscape(branch) + "/"
|
||||
s += fmt.Sprintf(`<li><a href="%s">%s</a></li>`, href, branch)
|
||||
fmt.Fprintf(&b, `<li><a href="%s">%s</a></li>`, href, branch)
|
||||
if *includesDir != "" {
|
||||
s += fmt.Sprintf(`<li><a href="%s?matrixdotorgstyle=1">%s, styled like matrix.org</a></li>`,
|
||||
fmt.Fprintf(&b, `<li><a href="%s?matrixdotorgstyle=1">%s, styled like matrix.org</a></li>`,
|
||||
href, branch)
|
||||
}
|
||||
}
|
||||
s += "</ul></div></body>"
|
||||
|
||||
io.WriteString(w, s)
|
||||
b.Write([]byte("</ul></div></body>"))
|
||||
b.WriteTo(w)
|
||||
}
|
||||
|
||||
func ignoreExitCodeOne(err error) error {
|
||||
|
@ -655,10 +707,14 @@ func main() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
rand.Seed(time.Now().Unix())
|
||||
masterCloneDir, err := gitClone(matrixDocCloneURL, false)
|
||||
masterCloneDir, err := makeTempDir()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf("Creating master clone dir %s\n", masterCloneDir)
|
||||
if err = gitClone(matrixDocCloneURL, masterCloneDir, false); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
s := server{matrixDocCloneURL: masterCloneDir}
|
||||
http.HandleFunc("/spec/", forceHTML(s.serveSpec))
|
||||
http.HandleFunc("/diff/rst/", s.serveRSTDiff)
|
||||
|
@ -691,3 +747,11 @@ func initCache() error {
|
|||
styledSpecCache = c2
|
||||
return err
|
||||
}
|
||||
|
||||
func makeTempDir() (string, error) {
|
||||
directory := path.Join("/tmp/matrix-doc", strconv.FormatInt(rand.Int63(), 10))
|
||||
if err := os.MkdirAll(directory, permissionsOwnerFull); err != nil {
|
||||
return "", fmt.Errorf("error making directory %s: %v", directory, err)
|
||||
}
|
||||
return directory, nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue