-
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
316 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package main | ||
|
||
import ( | ||
"net/http" | ||
"strings" | ||
|
||
"github.com/go-chi/chi" | ||
"github.com/go-chi/render" | ||
) | ||
|
||
// taken from | ||
// - https://github.com/go-chi/chi/blob/cca4135d8dddff765463feaf1118047a9e506b4a/_examples/fileserver/main.go | ||
// - https://github.com/go-chi/chi/blob/cca4135d8dddff765463feaf1118047a9e506b4a/_examples/rest/main.go | ||
|
||
func (e *ErrResponse) Render(w http.ResponseWriter, r *http.Request) error { | ||
render.Status(r, e.HTTPStatusCode) | ||
return nil | ||
} | ||
|
||
type ErrResponse struct { | ||
Err error `json:"-"` // low-level runtime error | ||
HTTPStatusCode int `json:"-"` // http response status code | ||
|
||
StatusText string `json:"status"` // user-level status message | ||
AppCode int64 `json:"code,omitempty"` // application-specific error code | ||
ErrorText string `json:"error,omitempty"` // application-level error message, for debugging | ||
} | ||
|
||
func ErrRender(err error) render.Renderer { | ||
return &ErrResponse{ | ||
Err: err, | ||
HTTPStatusCode: 422, | ||
StatusText: "Error rendering response.", | ||
ErrorText: err.Error(), | ||
} | ||
} | ||
|
||
func FileServer(r chi.Router, path string, root http.FileSystem) { | ||
if strings.ContainsAny(path, "{}*") { | ||
panic("FileServer does not permit URL parameters.") | ||
} | ||
|
||
fs := http.StripPrefix(path, http.FileServer(root)) | ||
|
||
if path != "/" && path[len(path)-1] != '/' { | ||
r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP) | ||
path += "/" | ||
} | ||
path += "*" | ||
|
||
r.Get(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
fs.ServeHTTP(w, r) | ||
})) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"strings" | ||
"time" | ||
|
||
"github.com/go-chi/chi" | ||
"github.com/go-chi/chi/middleware" | ||
"github.com/go-chi/docgen" | ||
"github.com/go-chi/render" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/pflag" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
type webOptions struct { | ||
// web specific | ||
Bind string | ||
ShowRoutes bool | ||
|
||
// db | ||
DBOpts dbOptions | ||
} | ||
|
||
func (opts webOptions) String() string { | ||
out, _ := json.Marshal(opts) | ||
return string(out) | ||
} | ||
|
||
func webSetupFlags(flags *pflag.FlagSet, opts *webOptions) { | ||
flags.StringVarP(&opts.Bind, "bind", "b", ":2020", "web server bind address") | ||
flags.BoolVarP(&opts.ShowRoutes, "show-routes", "", false, "display available routes and quit") | ||
viper.BindPFlags(flags) | ||
} | ||
|
||
func newWebCommand() *cobra.Command { | ||
opts := &webOptions{} | ||
cmd := &cobra.Command{ | ||
Use: "web", | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
if err := viper.Unmarshal(opts); err != nil { | ||
return err | ||
} | ||
if err := viper.Unmarshal(&opts.DBOpts); err != nil { | ||
return err | ||
} | ||
return web(opts) | ||
}, | ||
} | ||
webSetupFlags(cmd.Flags(), opts) | ||
dbSetupFlags(cmd.Flags(), &opts.DBOpts) | ||
return cmd | ||
} | ||
|
||
func (i *Issue) Render(w http.ResponseWriter, r *http.Request) error { | ||
return nil | ||
} | ||
|
||
func webListIssues(w http.ResponseWriter, r *http.Request) { | ||
issues, err := loadIssues(db, nil) | ||
if err != nil { | ||
render.Render(w, r, ErrRender(err)) | ||
return | ||
} | ||
|
||
list := []render.Renderer{} | ||
for _, issue := range issues { | ||
list = append(list, issue) | ||
} | ||
|
||
if err := render.RenderList(w, r, list); err != nil { | ||
render.Render(w, r, ErrRender(err)) | ||
return | ||
} | ||
} | ||
|
||
func webGraphviz(r *http.Request) (string, error) { | ||
opts := &graphOptions{ | ||
Targets: strings.Split(r.URL.Query().Get("targets"), ","), | ||
ShowClosed: r.URL.Query().Get("show-closed") == "1", | ||
} | ||
return graphviz(opts) | ||
} | ||
|
||
func webDotIssues(w http.ResponseWriter, r *http.Request) { | ||
out, err := webGraphviz(r) | ||
if err != nil { | ||
render.Render(w, r, ErrRender(err)) | ||
return | ||
} | ||
|
||
w.Write([]byte(out)) | ||
} | ||
|
||
func webImageIssues(w http.ResponseWriter, r *http.Request) { | ||
out, err := webGraphviz(r) | ||
if err != nil { | ||
render.Render(w, r, ErrRender(err)) | ||
return | ||
} | ||
|
||
cmd := exec.Command("dot", "-Tsvg") | ||
cmd.Stdin = bytes.NewBuffer([]byte(out)) | ||
cmd.Stdout = w | ||
|
||
if err := cmd.Run(); err != nil { | ||
render.Render(w, r, ErrRender(err)) | ||
return | ||
} | ||
} | ||
|
||
func web(opts *webOptions) error { | ||
r := chi.NewRouter() | ||
|
||
//r.Use(middleware.RequestID) | ||
//r.Use(middleware.RealIP) | ||
r.Use(middleware.Logger) | ||
r.Use(middleware.Recoverer) | ||
//r.Use(middleware.URLFormat) | ||
r.Use(middleware.Timeout(5 * time.Second)) | ||
|
||
r.Route("/api", func(r chi.Router) { | ||
r.Route("/", func(r chi.Router) { | ||
r.Use(render.SetContentType(render.ContentTypeJSON)) | ||
r.Get("/issues.json", webListIssues) | ||
}) | ||
r.Get("/graph/dot", webDotIssues) | ||
r.Get("/graph/image", webImageIssues) | ||
}) | ||
|
||
workDir, _ := os.Getwd() | ||
filesDir := filepath.Join(workDir, "web") | ||
FileServer(r, "/", http.Dir(filesDir)) | ||
|
||
if opts.ShowRoutes { | ||
fmt.Println(docgen.MarkdownRoutesDoc(r, docgen.MarkdownOpts{ | ||
ProjectPath: "moul.io/depviz", | ||
Intro: "Welcome to depviz generated docs.", | ||
})) | ||
return nil | ||
} | ||
|
||
log.Printf("Listening on %s", opts.Bind) | ||
return http.ListenAndServe(opts.Bind, r) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,34 @@ | ||
module moul.io/depviz | ||
|
||
require ( | ||
cloud.google.com/go v0.29.0 // indirect | ||
github.com/BurntSushi/toml v0.3.1 // indirect | ||
github.com/awalterschulze/gographviz v0.0.0-20180927133620-e69668a01397 | ||
github.com/denisenkom/go-mssqldb v0.0.0-20180901172138-1eb28afdf9b6 // indirect | ||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 // indirect | ||
github.com/go-chi/chi v3.3.3+incompatible | ||
github.com/go-chi/docgen v1.0.2 // indirect | ||
github.com/go-chi/render v1.0.1 | ||
github.com/go-sql-driver/mysql v1.4.0 // indirect | ||
github.com/google/go-cmp v0.2.0 // indirect | ||
github.com/google/go-github v17.0.0+incompatible | ||
github.com/google/go-querystring v1.0.0 // indirect | ||
github.com/inconshreveable/mousetrap v1.0.0 // indirect | ||
github.com/jinzhu/gorm v1.9.1 | ||
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a // indirect | ||
github.com/jinzhu/now v0.0.0-20180511015916-ed742868f2ae // indirect | ||
github.com/lib/pq v1.0.0 // indirect | ||
github.com/mattn/go-sqlite3 v1.9.0 | ||
github.com/pkg/errors v0.8.0 | ||
github.com/spf13/cobra v0.0.3 | ||
github.com/spf13/pflag v1.0.3 | ||
github.com/spf13/viper v1.2.1 | ||
github.com/xanzy/go-gitlab v0.11.1 | ||
go.uber.org/zap v1.9.1 | ||
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4 // indirect | ||
golang.org/x/net v0.0.0-20181003013248-f5e5bdd77824 // indirect | ||
golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced | ||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect | ||
google.golang.org/appengine v1.2.0 // indirect | ||
moul.io/zapgorm v0.0.0-20181003053625-c808c1c4adc6 | ||
) |
Oops, something went wrong.