package main import ( "bytes" "encoding/json" "flag" "html/template" "io/ioutil" "log" "net/http" "os" "os/exec" "path" "strconv" "strings" "github.com/russross/blackfriday" ) func main() { loadConfig() _ = os.Setenv(`GIT_TERMINAL_PROMPT`, `0`) if err := updateTemplate(); err != nil { log.Fatal(`Failed to load template. (` + err.Error() + `)`) } log.Fatal(http.ListenAndServe("127.0.0.1:"+strconv.Itoa(config.Port), http.HandlerFunc(serveRequest))) } var config struct { Port int Template string Pages string Static string Webhook string } func loadConfig() { flag.IntVar(&config.Port, `port`, 80, `The port mdsite will listen on`) flag.StringVar(&config.Template, `template`, `template.html`, `The template used by mdsite`) flag.StringVar(&config.Pages, `pages`, `pages`, `The OS path used when searching a page`) flag.StringVar(&config.Static, `static`, `static`, `The OS path used for static resource`) flag.StringVar(&config.Webhook, `webhook`, ``, `The secret for webhooks to update the content`) flag.Parse() } var t *template.Template func updateTemplate() error { tmpl, err := template.ParseFiles(config.Template) if err != nil { return err } t = tmpl return nil } func serveRequest(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodPost && config.Webhook != `` && r.URL.Path == `/hook` { var input struct { Secret string `json:"secret"` } err := json.NewDecoder(r.Body).Decode(&input) _ = r.Body.Close() if err != nil || input.Secret != config.Webhook { w.WriteHeader(403) return } err = exec.Command(`git`, `fetch`).Run() if err == nil { err = exec.Command(`git`, `reset`, `--hard`, `origin/master`).Run() } if err == nil { err = updateTemplate() } if err != nil { w.WriteHeader(500) w.Write([]byte(`Update failed`)) } return } if strings.HasPrefix(r.URL.Path, `/static/`) { path := path.Join(config.Static, path.Clean(strings.TrimPrefix(r.URL.Path, `/static/`))) http.ServeFile(w, r, path) return } servePage(w, r) } func servePage(w http.ResponseWriter, r *http.Request) { p := path.Join(config.Pages, path.Clean(r.URL.Path)) s, err := os.Stat(p) if err == nil && s.IsDir() { if p[len(p)-1] != '/' { p += `/` } p += `index` } c, err := ioutil.ReadFile(p + `.md`) if err != nil { w.WriteHeader(404) return } var title string if idx := bytes.IndexByte(c, '\n'); idx != -1 { fl := string(c[:idx]) if strings.HasPrefix(fl, `[title]:`) { title = strings.TrimPrefix(fl, `[title]:`) } } data := struct { Title string Content template.HTML }{title, template.HTML(blackfriday.MarkdownCommon(c))} t.Execute(w, data) }