Top nav works
parent
a8ee907a0f
commit
a6325abca3
|
|
@ -4,29 +4,23 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func isDir(path string) bool {
|
func notesDir(path Path, w http.ResponseWriter, r *http.Request) {
|
||||||
stat, err := os.Stat(path)
|
|
||||||
return err == nil && stat.IsDir()
|
|
||||||
}
|
|
||||||
|
|
||||||
func notesDir(path string, w http.ResponseWriter, r *http.Request) {
|
|
||||||
dirs, files := lsDir(path)
|
dirs, files := lsDir(path)
|
||||||
content := dirs.List()
|
content := dirs.List()
|
||||||
block(content, w)
|
block(content, w)
|
||||||
fmt.Fprintln(w, files.List())
|
fmt.Fprintln(w, files.List())
|
||||||
}
|
}
|
||||||
|
|
||||||
func lsDir(p string) (Paths, Paths) {
|
func lsDir(path Path) (Paths, Paths) {
|
||||||
dirs := newDirs()
|
dirs := newDirs()
|
||||||
files := newFiles()
|
files := newFiles()
|
||||||
|
|
||||||
found, _ := ioutil.ReadDir(p)
|
found, _ := ioutil.ReadDir(path.Local)
|
||||||
for _, f := range found {
|
for _, f := range found {
|
||||||
dirs.Push(p, f)
|
dirs.Push(path, f)
|
||||||
files.Push(p, f)
|
files.Push(path, f)
|
||||||
}
|
}
|
||||||
return Paths(*dirs), Paths(*files)
|
return Paths(*dirs), Paths(*files)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIsDir(t *testing.T) {
|
|
||||||
if ok := isDir("/tmp"); !ok {
|
|
||||||
t.Fatal(ok)
|
|
||||||
}
|
|
||||||
if ok := isDir("/dev/null"); ok {
|
|
||||||
t.Fatal(ok)
|
|
||||||
}
|
|
||||||
if ok := isDir("/proc/not/real/tho"); ok {
|
|
||||||
t.Fatal(ok)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLsDir(t *testing.T) {
|
func TestLsDir(t *testing.T) {
|
||||||
dirs, files := lsDir("/usr/local")
|
p := Path{Local: "/usr/local"}
|
||||||
|
dirs, files := lsDir(p)
|
||||||
if len(dirs) == 0 {
|
if len(dirs) == 0 {
|
||||||
t.Fatal(len(dirs))
|
t.Fatal(len(dirs))
|
||||||
}
|
}
|
||||||
|
|
@ -30,7 +19,7 @@ func TestLsDir(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNotesDir(t *testing.T) {
|
func TestNotesDir(t *testing.T) {
|
||||||
path := "/usr/local"
|
path := Path{Local: "/usr/local"}
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
notesDir(path, w, nil)
|
notesDir(path, w, nil)
|
||||||
t.Logf("%s", w.Body.Bytes())
|
t.Logf("%s", w.Body.Bytes())
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Dirs []Path
|
type Dirs []Path
|
||||||
|
|
@ -11,11 +12,8 @@ func newDirs() *Dirs {
|
||||||
return &d
|
return &d
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dirs) Push(p string, f os.FileInfo) {
|
func (d *Dirs) Push(p Path, f os.FileInfo) {
|
||||||
if f.IsDir() {
|
if f.IsDir() {
|
||||||
*d = append(*d, Path{
|
*d = append(*d, NewPathFromLocal(path.Join(p.Local, f.Name())))
|
||||||
dir: p,
|
|
||||||
base: f.Name(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/gomarkdown/markdown"
|
"github.com/gomarkdown/markdown"
|
||||||
)
|
)
|
||||||
|
|
||||||
func isFile(path string) bool {
|
func notesFile(path Path, w http.ResponseWriter, r *http.Request) {
|
||||||
stat, err := os.Stat(path)
|
b, _ := ioutil.ReadFile(path.Local)
|
||||||
return err == nil && !stat.IsDir()
|
|
||||||
}
|
|
||||||
|
|
||||||
func notesFile(path string, w http.ResponseWriter, r *http.Request) {
|
|
||||||
title := h1(path)
|
|
||||||
block(title, w)
|
|
||||||
b, _ := ioutil.ReadFile(path)
|
|
||||||
content := markdown.ToHTML(b, nil, nil)
|
content := markdown.ToHTML(b, nil, nil)
|
||||||
fmt.Fprintf(w, "%s\n", content)
|
fmt.Fprintf(w, "%s\n", content)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,18 +9,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIsFile(t *testing.T) {
|
|
||||||
if ok := isFile("/tmp"); ok {
|
|
||||||
t.Fatal(ok)
|
|
||||||
}
|
|
||||||
if ok := isFile("/dev/null"); !ok {
|
|
||||||
t.Fatal(ok)
|
|
||||||
}
|
|
||||||
if ok := isFile("/proc/not/real/tho"); ok {
|
|
||||||
t.Fatal(ok)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNotesFile(t *testing.T) {
|
func TestNotesFile(t *testing.T) {
|
||||||
f, err := ioutil.TempFile(os.TempDir(), "until*")
|
f, err := ioutil.TempFile(os.TempDir(), "until*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -41,7 +29,8 @@ func TestNotesFile(t *testing.T) {
|
||||||
`)
|
`)
|
||||||
f.Close()
|
f.Close()
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
notesFile(f.Name(), w, nil)
|
p := Path{Local: f.Name()}
|
||||||
|
notesFile(p, w, nil)
|
||||||
s := string(w.Body.Bytes())
|
s := string(w.Body.Bytes())
|
||||||
shouldContain := []string{
|
shouldContain := []string{
|
||||||
"tbody",
|
"tbody",
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Files []Path
|
type Files []Path
|
||||||
|
|
@ -11,11 +12,8 @@ func newFiles() *Files {
|
||||||
return &d
|
return &d
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Files) Push(p string, f os.FileInfo) {
|
func (d *Files) Push(p Path, f os.FileInfo) {
|
||||||
if !f.IsDir() {
|
if !f.IsDir() {
|
||||||
*d = append(*d, Path{
|
*d = append(*d, NewPathFromLocal(path.Join(p.Local, f.Name())))
|
||||||
dir: p,
|
|
||||||
base: f.Name(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,17 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"local/notes-server/config"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) notes(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) notes(w http.ResponseWriter, r *http.Request) {
|
||||||
p := resolvePath(r.URL.Path)
|
p := NewPath(r.URL.Path)
|
||||||
if isDir(p) {
|
if p.IsDir() {
|
||||||
head(w, r)
|
head(w, r)
|
||||||
notesHead(w, p)
|
notesHead(w, p)
|
||||||
notesDir(p, w, r)
|
notesDir(p, w, r)
|
||||||
foot(w, r)
|
foot(w, r)
|
||||||
} else if isFile(p) {
|
} else if p.IsFile() {
|
||||||
head(w, r)
|
head(w, r)
|
||||||
notesHead(w, p)
|
notesHead(w, p)
|
||||||
notesFile(p, w, r)
|
notesFile(p, w, r)
|
||||||
|
|
@ -25,18 +22,6 @@ func (s *Server) notes(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolvePath(p string) string {
|
func notesHead(w http.ResponseWriter, p Path) {
|
||||||
p = strings.TrimPrefix(p, "/")
|
fmt.Fprintln(w, h2(p.MultiLink()))
|
||||||
p = strings.TrimPrefix(p, "notes")
|
|
||||||
p = strings.TrimPrefix(p, "/")
|
|
||||||
p = path.Join(config.Root, p)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func notesHead(w http.ResponseWriter, p string) {
|
|
||||||
path := Path{
|
|
||||||
dir: path.Dir(p),
|
|
||||||
base: path.Base(p),
|
|
||||||
}
|
|
||||||
fmt.Fprintln(w, h2(path.MultiLink()))
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
|
||||||
"local/notes-server/config"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestResolvePath(t *testing.T) {
|
|
||||||
config.Root = "ROOT"
|
|
||||||
if p := resolvePath("/notes/a/b/c"); p != "ROOT/a/b/c" {
|
|
||||||
t.Fatal(p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package server
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"local/notes-server/config"
|
"local/notes-server/config"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
@ -13,12 +14,23 @@ type Path struct {
|
||||||
Base string
|
Base string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewPathFromLocal(p string) Path {
|
||||||
|
splits := strings.SplitN(p, path.Base(config.Root), 2)
|
||||||
|
href := splits[0]
|
||||||
|
if len(splits) > 1 {
|
||||||
|
href = splits[1]
|
||||||
|
}
|
||||||
|
href = path.Join("/notes", href)
|
||||||
|
return NewPath(href)
|
||||||
|
}
|
||||||
|
|
||||||
func NewPath(p string) Path {
|
func NewPath(p string) Path {
|
||||||
base := path.Base(p)
|
base := path.Base(p)
|
||||||
href := path.Join("/notes", p)
|
href := p
|
||||||
local := strings.TrimPrefix(p, "/")
|
local := strings.TrimPrefix(p, "/notes")
|
||||||
local = strings.TrimPrefix(p, "notes")
|
if len(local) != len(p) {
|
||||||
local = strings.TrimPrefix(p, "/")
|
local = strings.TrimPrefix(local, "/")
|
||||||
|
}
|
||||||
local = path.Join(config.Root, local)
|
local = path.Join(config.Root, local)
|
||||||
return Path{
|
return Path{
|
||||||
Base: base,
|
Base: base,
|
||||||
|
|
@ -28,31 +40,36 @@ func NewPath(p string) Path {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Path) MultiLink() string {
|
func (p Path) MultiLink() string {
|
||||||
pa := path.Join("/notes", p.String())
|
href := p.HREF
|
||||||
|
href = strings.TrimPrefix(href, "/")
|
||||||
|
href = strings.TrimSuffix(href, "/")
|
||||||
|
segments := strings.Split(href, "/")
|
||||||
full := ""
|
full := ""
|
||||||
for pa != "/" {
|
for i := range segments {
|
||||||
base := path.Base(pa)
|
href := "/" + strings.Join(segments[:i], "/") + "/"
|
||||||
full = fmt.Sprintf(`/<a href=%q>%s</a>`, pa, base) + full
|
href += segments[i]
|
||||||
pa = path.Dir(pa)
|
href = path.Clean(href)
|
||||||
|
base := segments[i]
|
||||||
|
add := fmt.Sprintf(`/<a href=%q>%s</a>`, href, base)
|
||||||
|
full += add
|
||||||
}
|
}
|
||||||
return full
|
return full
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Path) String() string {
|
func (p Path) LI() string {
|
||||||
root := path.Base(config.Root)
|
return fmt.Sprintf(`<li><a href=%q>%s</a></li>`, p.HREF, p.Base)
|
||||||
dir := p.dir
|
|
||||||
dirs := strings.SplitN(dir, root, 2)
|
|
||||||
dir = dirs[0]
|
|
||||||
if len(dirs) > 1 {
|
|
||||||
dir = dirs[1]
|
|
||||||
}
|
|
||||||
base := p.base
|
|
||||||
return path.Join(dir, base)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Path) LI() string {
|
func (p Path) IsDir() bool {
|
||||||
content := fmt.Sprintf(`<li><a href="%s">`, path.Join("/notes", p.String()))
|
stat, err := os.Stat(p.Local)
|
||||||
content += p.base
|
return err == nil && stat.IsDir()
|
||||||
content += "</li>"
|
}
|
||||||
return content
|
|
||||||
|
func (p Path) IsFile() bool {
|
||||||
|
stat, err := os.Stat(p.Local)
|
||||||
|
return err == nil && !stat.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Path) String() string {
|
||||||
|
return fmt.Sprintf(`[Local:%s HREF:%s Base:%s]`, p.Local, p.HREF, p.Base)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,23 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import "testing"
|
||||||
"regexp"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPathLI(t *testing.T) {
|
func TestPathIs(t *testing.T) {
|
||||||
p := Path{
|
p := Path{Local: "/dev/null"}
|
||||||
dir: "a/b/c",
|
if ok := p.IsDir(); ok {
|
||||||
base: "d",
|
t.Fatal(ok, p)
|
||||||
}
|
|
||||||
link := p.LI()
|
|
||||||
ok, err := regexp.MatchString(`li.*a.*href="a/b/c/d".d..li`, link)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err, link)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
t.Fatal(ok, link)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Log(p, link)
|
if ok := p.IsFile(); !ok {
|
||||||
|
t.Fatal(ok, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
p = Path{Local: "/tmp"}
|
||||||
|
if ok := p.IsDir(); !ok {
|
||||||
|
t.Fatal(ok, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok := p.IsFile(); ok {
|
||||||
|
t.Fatal(ok, p)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue