mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2025-01-05 17:40:26 +00:00
WIP history page
This commit is contained in:
parent
c03f8be5cd
commit
60fcbdd30d
1
data
Submodule
1
data
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit b2e78031973e4a6844d943333e823c0714e7a673
|
6
go.mod
6
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
|
||||
|
28
go.sum
28
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=
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
100
history/sh.go
Normal file
100
history/sh.go
Normal file
@ -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(`
|
||||
<tr>
|
||||
<td>%s</td>
|
||||
<td>%s</td>
|
||||
<td><time>%s</time></td>
|
||||
<td>%s</td>
|
||||
</tr>`, rev.Hash, rev.Username, rev.Time.String(), rev.Message)
|
||||
}
|
@ -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()
|
||||
|
@ -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(`
|
||||
<main>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hash</th>
|
||||
<th>Username</th>
|
||||
<th>Time</th>
|
||||
<th>Message</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
%s
|
||||
</tbody>
|
||||
</table>
|
||||
</main>`, 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.
|
||||
|
5
main.go
5
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)
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 30287be4496638e342878e2adf50e0a74ce71a5f
|
||||
Subproject commit 2f58d4e9663806496d7edfdeb24098abe986f454
|
@ -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 `<ul class="navitree__node">` + html + `</ul>`
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user