Print some diffs in web feeds
This commit is contained in:
parent
7c1f38d5b0
commit
4ff51352af
@ -3,6 +3,7 @@ package history
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html"
|
||||||
"log"
|
"log"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -44,9 +45,26 @@ type Revision struct {
|
|||||||
Username string
|
Username string
|
||||||
Time time.Time
|
Time time.Time
|
||||||
Message string
|
Message string
|
||||||
|
filesAffectedBuf []string
|
||||||
hyphaeAffectedBuf []string
|
hyphaeAffectedBuf []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filesAffected tells what files have been affected by the revision.
|
||||||
|
func (rev *Revision) filesAffected() (filenames []string) {
|
||||||
|
if nil != rev.filesAffectedBuf {
|
||||||
|
return rev.filesAffectedBuf
|
||||||
|
}
|
||||||
|
// List of files affected by this revision, one per line.
|
||||||
|
out, err := silentGitsh("diff-tree", "--no-commit-id", "--name-only", "-r", rev.Hash)
|
||||||
|
// There's an error? Well, whatever, let's just assign an empty slice, who cares.
|
||||||
|
if err != nil {
|
||||||
|
rev.filesAffectedBuf = []string{}
|
||||||
|
} else {
|
||||||
|
rev.filesAffectedBuf = strings.Split(out.String(), "\n")
|
||||||
|
}
|
||||||
|
return rev.filesAffectedBuf
|
||||||
|
}
|
||||||
|
|
||||||
// determine what hyphae were affected by this revision
|
// determine what hyphae were affected by this revision
|
||||||
func (rev *Revision) hyphaeAffected() (hyphae []string) {
|
func (rev *Revision) hyphaeAffected() (hyphae []string) {
|
||||||
if nil != rev.hyphaeAffectedBuf {
|
if nil != rev.hyphaeAffectedBuf {
|
||||||
@ -54,8 +72,6 @@ func (rev *Revision) hyphaeAffected() (hyphae []string) {
|
|||||||
}
|
}
|
||||||
hyphae = make([]string, 0)
|
hyphae = make([]string, 0)
|
||||||
var (
|
var (
|
||||||
// List of files affected by this revision, one per line.
|
|
||||||
out, err = gitsh("diff-tree", "--no-commit-id", "--name-only", "-r", rev.Hash)
|
|
||||||
// set is used to determine if a certain hypha has been already noted (hyphae are stored in 2 files at most currently).
|
// set is used to determine if a certain hypha has been already noted (hyphae are stored in 2 files at most currently).
|
||||||
set = make(map[string]bool)
|
set = make(map[string]bool)
|
||||||
isNewName = func(hyphaName string) bool {
|
isNewName = func(hyphaName string) bool {
|
||||||
@ -65,11 +81,9 @@ func (rev *Revision) hyphaeAffected() (hyphae []string) {
|
|||||||
set[hyphaName] = true
|
set[hyphaName] = true
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
filesAffected = rev.filesAffected()
|
||||||
)
|
)
|
||||||
if err != nil {
|
for _, filename := range filesAffected {
|
||||||
return hyphae
|
|
||||||
}
|
|
||||||
for _, filename := range strings.Split(out.String(), "\n") {
|
|
||||||
if strings.IndexRune(filename, '.') >= 0 {
|
if strings.IndexRune(filename, '.') >= 0 {
|
||||||
dotPos := strings.LastIndexByte(filename, '.')
|
dotPos := strings.LastIndexByte(filename, '.')
|
||||||
hyphaName := string([]byte(filename)[0:dotPos]) // is it safe?
|
hyphaName := string([]byte(filename)[0:dotPos]) // is it safe?
|
||||||
@ -94,15 +108,44 @@ func (rev Revision) HyphaeLinksHTML() (html string) {
|
|||||||
if i > 0 {
|
if i > 0 {
|
||||||
html += `<span aria-hidden="true">, </span>`
|
html += `<span aria-hidden="true">, </span>`
|
||||||
}
|
}
|
||||||
html += fmt.Sprintf(`<a href="/page/%[1]s">%[1]s</a>`, hyphaName)
|
html += fmt.Sprintf(`<a href="/hypha/%[1]s">%[1]s</a>`, hyphaName)
|
||||||
}
|
}
|
||||||
return html
|
return html
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rev *Revision) descriptionForFeed() (html string) {
|
// descriptionForFeed generates a good enough HTML contents for a web feed.
|
||||||
|
func (rev *Revision) descriptionForFeed() (htmlDesc string) {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
`<p>%s</p>
|
`<p>%s</p>
|
||||||
<p><b>Hyphae affected:</b> %s</p>`, rev.Message, rev.HyphaeLinksHTML())
|
<p><b>Hyphae affected:</b> %s</p>
|
||||||
|
<pre><code>%s</code></pre>`, rev.Message, rev.HyphaeLinksHTML(), html.EscapeString(rev.textDiff()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// textDiff generates a good enough diff to display in a web feed. It is not html-escaped.
|
||||||
|
func (rev *Revision) textDiff() (diff string) {
|
||||||
|
filenames, ok := rev.mycoFiles()
|
||||||
|
if !ok {
|
||||||
|
return "No text changes"
|
||||||
|
}
|
||||||
|
for _, filename := range filenames {
|
||||||
|
text, err := PrimitiveDiffAtRevision(filename, rev.Hash)
|
||||||
|
if err != nil {
|
||||||
|
diff += "\nAn error has occured with " + filename + "\n"
|
||||||
|
}
|
||||||
|
diff += text + "\n"
|
||||||
|
}
|
||||||
|
return diff
|
||||||
|
}
|
||||||
|
|
||||||
|
// mycoFiles returns filenames of .myco file. It is not ok if there are no myco files.
|
||||||
|
func (rev *Revision) mycoFiles() (filenames []string, ok bool) {
|
||||||
|
filenames = []string{}
|
||||||
|
for _, filename := range rev.filesAffected() {
|
||||||
|
if strings.HasSuffix(filename, ".myco") {
|
||||||
|
filenames = append(filenames, filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filenames, len(filenames) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try and guess what link is the most important by looking at the message.
|
// Try and guess what link is the most important by looking at the message.
|
||||||
@ -113,11 +156,11 @@ func (rev *Revision) bestLink() string {
|
|||||||
)
|
)
|
||||||
switch {
|
switch {
|
||||||
case renameRes != nil:
|
case renameRes != nil:
|
||||||
return "/page/" + renameRes[1]
|
return "/hypha/" + renameRes[1]
|
||||||
case len(revs) == 0:
|
case len(revs) == 0:
|
||||||
return ""
|
return ""
|
||||||
default:
|
default:
|
||||||
return "/page/" + revs[0]
|
return "/hypha/" + revs[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +178,15 @@ func gitsh(args ...string) (out bytes.Buffer, err error) {
|
|||||||
return *bytes.NewBuffer(b), err
|
return *bytes.NewBuffer(b), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// silentGitsh is like gitsh, except it writes less to the stdout.
|
||||||
|
func silentGitsh(args ...string) (out bytes.Buffer, err error) {
|
||||||
|
cmd := exec.Command(gitpath, args...)
|
||||||
|
cmd.Dir = util.WikiDir
|
||||||
|
|
||||||
|
b, err := cmd.CombinedOutput()
|
||||||
|
return *bytes.NewBuffer(b), err
|
||||||
|
}
|
||||||
|
|
||||||
// Convert a UNIX timestamp as string into a time. If nil is returned, it means that the timestamp could not be converted.
|
// Convert a UNIX timestamp as string into a time. If nil is returned, it means that the timestamp could not be converted.
|
||||||
func unixTimestampAsTime(ts string) *time.Time {
|
func unixTimestampAsTime(ts string) *time.Time {
|
||||||
i, err := strconv.ParseInt(ts, 10, 64)
|
i, err := strconv.ParseInt(ts, 10, 64)
|
||||||
|
|||||||
@ -4,6 +4,7 @@ package history
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -22,7 +23,7 @@ func recentChangesFeed() *feeds.Feed {
|
|||||||
Updated: time.Now(),
|
Updated: time.Now(),
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
out, err = gitsh(
|
out, err = silentGitsh(
|
||||||
"log", "--oneline", "--no-merges",
|
"log", "--oneline", "--no-merges",
|
||||||
"--pretty=format:\"%h\t%ae\t%at\t%s\"",
|
"--pretty=format:\"%h\t%ae\t%at\t%s\"",
|
||||||
"--max-count=30",
|
"--max-count=30",
|
||||||
@ -34,6 +35,7 @@ func recentChangesFeed() *feeds.Feed {
|
|||||||
revs = append(revs, parseRevisionLine(line))
|
revs = append(revs, parseRevisionLine(line))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Printf("Found %d recent changes", len(revs))
|
||||||
for _, rev := range revs {
|
for _, rev := range revs {
|
||||||
feed.Add(&feeds.Item{
|
feed.Add(&feeds.Item{
|
||||||
Title: rev.Message,
|
Title: rev.Message,
|
||||||
@ -62,7 +64,7 @@ func RecentChangesJSON() (string, error) {
|
|||||||
|
|
||||||
func RecentChanges(n int) []Revision {
|
func RecentChanges(n int) []Revision {
|
||||||
var (
|
var (
|
||||||
out, err = gitsh(
|
out, err = silentGitsh(
|
||||||
"log", "--oneline", "--no-merges",
|
"log", "--oneline", "--no-merges",
|
||||||
"--pretty=format:\"%h\t%ae\t%at\t%s\"",
|
"--pretty=format:\"%h\t%ae\t%at\t%s\"",
|
||||||
"--max-count="+strconv.Itoa(n),
|
"--max-count="+strconv.Itoa(n),
|
||||||
@ -74,6 +76,7 @@ func RecentChanges(n int) []Revision {
|
|||||||
revs = append(revs, parseRevisionLine(line))
|
revs = append(revs, parseRevisionLine(line))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Printf("Found %d recent changes", len(revs))
|
||||||
return revs
|
return revs
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +89,7 @@ func FileChanged(path string) bool {
|
|||||||
// Revisions returns slice of revisions for the given hypha name.
|
// Revisions returns slice of revisions for the given hypha name.
|
||||||
func Revisions(hyphaName string) ([]Revision, error) {
|
func Revisions(hyphaName string) ([]Revision, error) {
|
||||||
var (
|
var (
|
||||||
out, err = gitsh(
|
out, err = silentGitsh(
|
||||||
"log", "--oneline", "--no-merges",
|
"log", "--oneline", "--no-merges",
|
||||||
// Hash, author email, author time, commit msg separated by tab
|
// Hash, author email, author time, commit msg separated by tab
|
||||||
"--pretty=format:\"%h\t%ae\t%at\t%s\"",
|
"--pretty=format:\"%h\t%ae\t%at\t%s\"",
|
||||||
@ -101,6 +104,7 @@ func Revisions(hyphaName string) ([]Revision, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Printf("Found %d revisions for ‘%s’\n", len(revs), hyphaName)
|
||||||
return revs, err
|
return revs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,6 +181,6 @@ func FileAtRevision(filepath, hash string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func PrimitiveDiffAtRevision(filepath, hash string) (string, error) {
|
func PrimitiveDiffAtRevision(filepath, hash string) (string, error) {
|
||||||
out, err := gitsh("diff", "--unified=1", "--no-color", hash+"~", hash, "--", filepath)
|
out, err := silentGitsh("diff", "--unified=1", "--no-color", hash+"~", hash, "--", filepath)
|
||||||
return out.String(), err
|
return out.String(), err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -352,7 +352,7 @@ func StreamAboutHTML(qw422016 *qt422016.Writer) {
|
|||||||
//line views/stuff.qtpl:98
|
//line views/stuff.qtpl:98
|
||||||
qw422016.N().S(`</h1>
|
qw422016.N().S(`</h1>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b><a href="https://mycorrhiza.lesarbr.es">MycorrhizaWiki</a> version:</b> 1.1.0</li>
|
<li><b><a href="https://mycorrhiza.lesarbr.es">MycorrhizaWiki</a> version:</b> 1.2.0 indev</li>
|
||||||
`)
|
`)
|
||||||
//line views/stuff.qtpl:101
|
//line views/stuff.qtpl:101
|
||||||
if user.AuthUsed {
|
if user.AuthUsed {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user