diff --git a/data b/data
new file mode 160000
index 0000000..b2e7803
--- /dev/null
+++ b/data
@@ -0,0 +1 @@
+Subproject commit b2e78031973e4a6844d943333e823c0714e7a673
diff --git a/go.mod b/go.mod
index 52eea2b..a66370d 100644
--- a/go.mod
+++ b/go.mod
@@ -2,8 +2,4 @@ module github.com/bouncepaw/mycorrhiza
go 1.14
-require (
- github.com/go-git/go-git/v5 v5.1.0
- golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
- golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6 // indirect
-)
+require github.com/go-git/go-git/v5 v5.1.0
diff --git a/go.sum b/go.sum
index 594e00c..66994b3 100644
--- a/go.sum
+++ b/go.sum
@@ -12,8 +12,6 @@ github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
-github.com/go-git/go-git v1.0.0 h1:YcN9iDGDoXuIw0vHls6rINwV416HYa0EB2X+RBsyYp4=
-github.com/go-git/go-git v4.7.0+incompatible h1:+W9rgGY4DOKKdX2x6HxSR7HNeTxqiKrOvKnuittYVdA=
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEssk=
github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM=
@@ -40,41 +38,21 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
-github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 h1:EBZoQjiKKPaLbPrbpssUfuHtwM6KV/vb4U85g/cigFY=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6 h1:qKpj8TpV+LEhel7H/fR788J+KvhWZ3o3V6N2fU/iuLU=
-golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/history/history.go b/history/history.go
index 3d9d081..5a54ac0 100644
--- a/history/history.go
+++ b/history/history.go
@@ -3,6 +3,7 @@ package history
import (
"fmt"
"log"
+ "os"
"time"
"github.com/bouncepaw/mycorrhiza/util"
@@ -107,9 +108,10 @@ func (hop *HistoryOp) Apply() *HistoryOp {
return hop
}
+// Rename renames from `from` to `to`. NB. It uses os.Rename internally rather than git.Move because git.Move works wrong for some reason.
func Rename(from, to string) error {
log.Println(util.ShorterPath(from), util.ShorterPath(to))
- _, err := Worktree.Move(util.ShorterPath(from), util.ShorterPath(to))
+ err := os.Rename(from, to)
return err
}
diff --git a/history/sh.go b/history/sh.go
new file mode 100644
index 0000000..34af389
--- /dev/null
+++ b/history/sh.go
@@ -0,0 +1,100 @@
+package history
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "os/exec"
+ "regexp"
+ "strconv"
+ "strings"
+ "time"
+)
+
+type Revision struct {
+ Hash string
+ Username string
+ Time time.Time
+ Message string
+}
+
+var gitpath string
+
+func init() {
+ path, err := exec.LookPath("git")
+ if err != nil {
+ log.Fatal("Cound not find the git executable. Check your $PATH.")
+ } else {
+ log.Println("Git path is", path)
+ }
+ gitpath = path
+}
+
+// I pronounce it as [gɪt͡ʃ].
+func gitsh(args ...string) (out bytes.Buffer, err error) {
+ cmd := exec.Command(gitpath, args...)
+ cmd.Stdout = &out
+ cmd.Run()
+ if err != nil {
+ log.Println("gitsh:", err)
+ }
+ return out, err
+}
+
+func Revisions(filepath string) ([]Revision, error) {
+ if filepath == "" {
+ return []Revision{}, nil
+ }
+ var (
+ out, err = gitsh(
+ "log", "--oneline", "--no-merges",
+ // Hash, Commiter email, Commiter time, Commit msg separated by tab
+ "--pretty=format:\"%h\t%ce\t%ct\t%s\"",
+ "--", filepath,
+ )
+ revs []Revision
+ )
+ if err == nil {
+ for _, line := range strings.Split(out.String(), "\n") {
+ if rev := parseRevisionLine(line); rev != nil {
+ revs = append(revs, *rev)
+ }
+ }
+ }
+ return revs, err
+}
+
+func unixTimestampAsTime(ts string) *time.Time {
+ i, err := strconv.ParseInt(ts, 10, 64)
+ if err != nil {
+ return nil
+ }
+ tm := time.Unix(i, 0)
+ return &tm
+}
+
+// This regex is wrapped in "". For some reason, these quotes appear at some time and we have to get rid of them.
+var revisionLinePattern = regexp.MustCompile("\"(.*)\t(.*)@.*\t(.*)\t(.*)\"")
+
+func parseRevisionLine(line string) *Revision {
+ var (
+ results = revisionLinePattern.FindStringSubmatch(line)
+ rev = Revision{
+ Hash: results[1],
+ Username: results[2],
+ Time: *unixTimestampAsTime(results[3]),
+ Message: results[4],
+ }
+ )
+ return &rev
+}
+
+func (rev *Revision) AsHtmlTableRow() string {
+ return fmt.Sprintf(`
+
+ %s |
+ %s |
+ |
+ %s |
+
`, rev.Hash, rev.Username, rev.Time.String(), rev.Message)
+}
diff --git a/http_mutators.go b/http_mutators.go
index c943da3..7012839 100644
--- a/http_mutators.go
+++ b/http_mutators.go
@@ -134,11 +134,6 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) {
if err := os.MkdirAll(filepath.Dir(fullPath), 0777); err != nil {
log.Println(err)
}
- if err = ioutil.WriteFile(fullPath, data, 0644); err != nil {
- HttpErr(w, http.StatusInternalServerError, hyphaName, "Error",
- "Could not save passed data")
- return
- }
if !isOld {
HyphaStorage[hyphaName] = &HyphaData{
binaryPath: fullPath,
@@ -155,9 +150,14 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) {
hyphaData.binaryPath = fullPath
hyphaData.binaryType = mimeType
}
+ if err = ioutil.WriteFile(fullPath, data, 0644); err != nil {
+ HttpErr(w, http.StatusInternalServerError, hyphaName, "Error",
+ "Could not save passed data")
+ return
+ }
log.Println("Written", len(data), "of binary data for", hyphaName, "to path", fullPath)
history.Operation(history.TypeEditText).
- WithFiles(fullPath).
+ WithFiles(fullPath, hyphaData.binaryPath).
WithMsg(fmt.Sprintf("Upload binary part for ‘%s’ with type ‘%s’", hyphaName, mimeType.Mime())).
WithSignature("anon").
Apply()
diff --git a/http_readers.go b/http_readers.go
index fab83ee..889d83d 100644
--- a/http_readers.go
+++ b/http_readers.go
@@ -8,6 +8,7 @@ import (
"os"
"github.com/bouncepaw/mycorrhiza/gemtext"
+ "github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/tree"
)
@@ -15,6 +16,49 @@ func init() {
http.HandleFunc("/page/", handlerPage)
http.HandleFunc("/text/", handlerText)
http.HandleFunc("/binary/", handlerBinary)
+ http.HandleFunc("/history/", handlerHistory)
+}
+
+// handlerHistory lists all revisions of a hypha
+func handlerHistory(w http.ResponseWriter, rq *http.Request) {
+ log.Println(rq.URL)
+ hyphaName := HyphaNameFromRq(rq, "history")
+ var tbody string
+ if data, ok := HyphaStorage[hyphaName]; ok {
+ revsT, err := history.Revisions(data.textPath)
+ if err == nil {
+ for _, rev := range revsT {
+ tbody += rev.AsHtmlTableRow()
+ }
+ }
+ revsB, err := history.Revisions(data.binaryPath)
+ if err == nil {
+ for _, rev := range revsB {
+ tbody += rev.AsHtmlTableRow()
+ }
+ }
+ log.Println(revsT, revsB)
+ }
+
+ table := fmt.Sprintf(`
+
+
+
+
+ Hash |
+ Username |
+ Time |
+ Message |
+
+
+
+ %s
+
+
+ `, tbody)
+ w.Header().Set("Content-Type", "text/html;charset=utf-8")
+ w.WriteHeader(http.StatusOK)
+ w.Write([]byte(base(hyphaName, table)))
}
// handlerText serves raw source text of the hypha.
diff --git a/main.go b/main.go
index cab791b..39663cc 100644
--- a/main.go
+++ b/main.go
@@ -130,6 +130,9 @@ func main() {
if err != nil {
log.Fatal(err)
}
+ if err := os.Chdir(WikiDir); err != nil {
+ log.Fatal(err)
+ }
log.Println("Wiki storage directory is", WikiDir)
log.Println("Start indexing hyphae...")
Index(WikiDir)
@@ -138,7 +141,7 @@ func main() {
history.Start(WikiDir)
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(WikiDir+"/static"))))
- // See http_readers.go for /page/, /text/, /binary/.
+ // See http_readers.go for /page/, /text/, /binary/, /history/.
// See http_mutators.go for /upload-binary/, /upload-text/, /edit/.
http.HandleFunc("/list", handlerList)
http.HandleFunc("/reindex", handlerReindex)
diff --git a/metarrhiza b/metarrhiza
index 30287be..2f58d4e 160000
--- a/metarrhiza
+++ b/metarrhiza
@@ -1 +1 @@
-Subproject commit 30287be4496638e342878e2adf50e0a74ce71a5f
+Subproject commit 2f58d4e9663806496d7edfdeb24098abe986f454
diff --git a/tree/tree.go b/tree/tree.go
index d7e8c45..1655664 100644
--- a/tree/tree.go
+++ b/tree/tree.go
@@ -60,9 +60,6 @@ func (t *tree) fill() {
// It applies itself recursively on the tree's children.
func (t *tree) asHtml() (html string) {
if t.root {
- for _, siblingName := range t.siblings {
- html += navitreeEntry(siblingName, "navitree__sibling")
- }
html += navitreeEntry(t.name, "navitree__pagename")
} else {
html += navitreeEntry(t.name, "navitree__name")
@@ -72,6 +69,12 @@ func (t *tree) asHtml() (html string) {
html += subtree.asHtml()
}
+ if t.root {
+ for _, siblingName := range t.siblings {
+ html += navitreeEntry(siblingName, "navitree__sibling")
+ }
+ }
+
return ``
}