Skip to content

Commit

Permalink
fix: refactored and fixed bugs
Browse files Browse the repository at this point in the history
close #25, close #26
  • Loading branch information
yusukebe committed Apr 13, 2022
1 parent 0ae4c76 commit ebe95e7
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 127 deletions.
51 changes: 21 additions & 30 deletions cmd/app.go
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
Expand All @@ -13,52 +12,54 @@ import (
"github.com/cli/safeexec"
)

func targetFile(filename string) string {
func targetFile(filename string) (string, error) {
var err error
if filename == "" {
filename = "."
}
info, err := os.Stat(filename)
if err == nil {
if info.IsDir() {
readme := findReadme(filename)
if readme != "" {
return readme
}
if err == nil && info.IsDir() {
readme, err := findReadme(filename)
if err != nil {
return "", err
}
filename = readme
}
return filename
if err != nil {
err = fmt.Errorf("%s is not found", filename)
}
return filename, err
}

func findReadme(dir string) string {
func findReadme(dir string) (string, error) {
files, _ := ioutil.ReadDir(dir)
for _, f := range files {
r := regexp.MustCompile(`(?i)^readme`)
if r.MatchString(f.Name()) {
return filepath.Join(dir, f.Name())

return filepath.Join(dir, f.Name()), nil
}
}
return ""
err := fmt.Errorf("README file is not found in %s/", dir)
return "", err
}

func toHTML(markdown string) string {
func toHTML(markdown string) (string, error) {
sout, _, err := gh("api", "-X", "POST", "/markdown", "-f", fmt.Sprintf("text=%s", markdown))
if err != nil {
log.Fatalf("Error:%v", err)
return "", err
}
return sout.String()
return sout.String(), nil
}

func slurp(fileName string) string {
func slurp(fileName string) (string, error) {
f, err := os.Open(fileName)
if err != nil {
logInfo("Warn: %v", err)
return ""
return "", err
}
defer f.Close()
b, _ := ioutil.ReadAll(f)
text := string(b)
return text
return text, nil
}

func gh(args ...string) (sout, eout bytes.Buffer, err error) {
Expand All @@ -80,13 +81,3 @@ func gh(args ...string) (sout, eout bytes.Buffer, err error) {

return
}

func logInfo(format string, v ...interface{}) {
log.Printf(format, v...)
}

func logDebug(format string, v ...interface{}) {
if verbose {
log.Printf(format, v...)
}
}
60 changes: 43 additions & 17 deletions cmd/app_test.go
Expand Up @@ -6,35 +6,57 @@ import (
"testing"
)

func TestFindReadme(t *testing.T) {
actual := findReadme("../")
expected := "../README.md"
if actual != expected {
t.Errorf("got %v\n want %v", actual, expected)
func TestTargetFile(t *testing.T) {
tests := []struct {
input string
expected string
}{
{"../testdata/markdown-demo.md", "../testdata/markdown-demo.md"},
{"../README.md", "../README.md"},
{"../", "../README.md"},
}
actual = findReadme("../testdata")
expected = "../testdata/README"
if actual != expected {
t.Errorf("got %v\n want %v", actual, expected)
for _, tt := range tests {
actual, err := targetFile(tt.input)
if err != nil {
t.Errorf(err.Error())
}
expected := tt.expected
if actual != expected {
t.Errorf("got %v\n want %v", actual, expected)
}
}
_, err := targetFile("../notfound.md")
if err == nil {
t.Errorf("err is nil")
}
_, err = targetFile("./")
if err == nil {
t.Errorf("err is nil")
}
}

func TestSelectFile(t *testing.T) {
actual := targetFile("../testdata/markdown-demo.md")
expected := "../testdata/markdown-demo.md"
func TestFindReadme(t *testing.T) {
actual, _ := findReadme("../")
expected := "../README.md"
if actual != expected {
t.Errorf("got %v\n want %v", actual, expected)
}

actual = targetFile("../")
expected = "../README.md"
actual, _ = findReadme("../testdata")
expected = "../testdata/README"
if actual != expected {
t.Errorf("got %v\n want %v", actual, expected)
}
_, err := findReadme("../cmd")
if err == nil {
t.Errorf("err is nil")
}
}

func TestSlurp(t *testing.T) {
string := slurp("../testdata/markdown-demo.md")
string, err := slurp("../testdata/markdown-demo.md")
if err != nil {
t.Errorf(err.Error())
}
match := "Headings"
r := regexp.MustCompile(match)
if r.MatchString(string) == false {
Expand All @@ -53,7 +75,11 @@ func TestGh(t *testing.T) {

func TestToHTML(t *testing.T) {
markdown := "text"
actual := strings.TrimSpace(toHTML(markdown))
html, err := toHTML(markdown)
if err != nil {
t.Errorf(err.Error())
}
actual := strings.TrimSpace(html)
expected := "<p>text</p>"
if actual != expected {
t.Errorf("got %v\n want %v", actual, expected)
Expand Down
6 changes: 5 additions & 1 deletion cmd/cli.go
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"log"
"os"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -65,7 +66,10 @@ var rootCmd = &cobra.Command{
autoOpen: autoOpen,
}

server.Serve(param)
err := server.Serve(param)
if err != nil {
log.Fatalf("Error: %v", err)
}
},
}

Expand Down
73 changes: 50 additions & 23 deletions cmd/server.go
Expand Up @@ -3,7 +3,6 @@ package cmd
import (
_ "embed"
"fmt"
"log"
"net"
"net/http"
"path/filepath"
Expand Down Expand Up @@ -32,23 +31,35 @@ var htmlTemplate string

const defaultPort = 3333

func (server *Server) Serve(param *Param) {
func (server *Server) Serve(param *Param) error {
host := server.host
port := defaultPort
if server.port > 0 {
port = server.port
}

filename := targetFile(param.filename)
filename, err := targetFile(param.filename)
if err != nil {
return err
}

dir := filepath.Dir(filename)

r := http.NewServeMux()
r.Handle("/", wrapHandler(handler(filename, param, http.FileServer(http.Dir(dir)))))
r.Handle("/__/md", wrapHandler(mdHandler(filename)))
r.Handle("/ws", wsHandler(dir))
rootHandler := handler(filename, param, http.FileServer(http.Dir(dir)))
r.Handle("/", wrapHandler(rootHandler))

port = getPort(host, port)
watcher, err := createWatcher(dir)
if err != nil {
return err
}
r.Handle("/ws", wsHandler(watcher))

port, err = getPort(host, port)
if err != nil {
return err
}

address := fmt.Sprintf("%s:%d", host, port)

logInfo("Accepting connections at http://%s/\n", address)
Expand All @@ -58,10 +69,12 @@ func (server *Server) Serve(param *Param) {
go openBrowser(fmt.Sprintf("http://%s/", address))
}

err := http.ListenAndServe(address, r)
err = http.ListenAndServe(address, r)
if err != nil {
log.Fatalf("ListenAndServe: %v", err)
return err
}

return nil
}

func handler(filename string, param *Param, h http.Handler) http.Handler {
Expand All @@ -75,29 +88,45 @@ func handler(filename string, param *Param, h http.Handler) http.Handler {

tmpl, err := template.New("HTML Template").Parse(htmlTemplate)
if err != nil {
logInfo("error:%v", err)
logInfo("Warn: %v", err)
http.NotFound(w, r)
return
}

markdown := slurp(filename)
html := toHTML(markdown)
markdown, err := slurp(filename)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

html, err := toHTML(markdown)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

modeString := getModeString(param.forceLightMode, param.forceDarkMode)

param := TemplateParam{Body: html, Host: r.Host, Reload: param.reload, Mode: modeString}

if err := tmpl.Execute(w, param); err != nil {
log.Fatalf("error:%v", err)
}
tmpl.Execute(w, param)
})
}

func mdHandler(filename string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
markdown := slurp(filename)
html := toHTML(markdown)

markdown, err := slurp(filename)
if err != nil {
http.Error(w, err.Error(), 500)
return
}

html, err := toHTML(markdown)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
fmt.Fprintf(w, "%s", html)
})
}
Expand Down Expand Up @@ -130,16 +159,14 @@ func getModeString(lightMode, darkMode bool) string {
return ""
}

func getPort(host string, port int) int {
func getPort(host string, port int) (int, error) {
var err error
listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", host, port))
if err != nil {
logInfo(err.Error())
listener, err = net.Listen("tcp", fmt.Sprintf("%s:0", host))
if err != nil {
log.Fatalf(err.Error())
}
}
port = listener.Addr().(*net.TCPAddr).Port
listener.Close()
return port
return port, err
}
13 changes: 13 additions & 0 deletions cmd/utils.go
@@ -0,0 +1,13 @@
package cmd

import "log"

func logInfo(format string, v ...interface{}) {
log.Printf(format, v...)
}

func logDebug(format string, v ...interface{}) {
if verbose {
log.Printf(format, v...)
}
}
40 changes: 40 additions & 0 deletions cmd/watcher.go
@@ -0,0 +1,40 @@
package cmd

import (
"regexp"

"github.com/fsnotify/fsnotify"
)

const ignorePattern = `\.swp$|~$|^\.DS_Store$|^4913$`

func createWatcher(dir string) (*fsnotify.Watcher, error) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return watcher, err
}
logInfo("Watching %s/ for changes", dir)
err = watcher.Add(dir)
return watcher, err
}

func watch(done <-chan interface{}, errorChan chan<- error, reload chan<- bool, watcher *fsnotify.Watcher) {
for {
select {
case event := <-watcher.Events:
if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create {
r := regexp.MustCompile(ignorePattern)
if r.MatchString(event.Name) {
logDebug("Debug [ignore]: `%s`", event.Name)
} else {
logInfo("Change detected in %s, refreshing", event.Name)
reload <- true
}
}
case err := <-watcher.Errors:
errorChan <- err
case <-done:
return
}
}
}

0 comments on commit ebe95e7

Please sign in to comment.