package main import ( "bufio" "bytes" "fmt" "github.com/sergi/go-diff/diffmatchpatch" "html" "html/template" "io/ioutil" "log" "os" "os/exec" "path/filepath" "strings" "time" ) type FilePages struct { dirname string } func NewFilePages(dirname string) PagesRepository { fp := &FilePages{dirname} return fp } func (fp *FilePages) Get(p string) Page { f, err := os.Open(filepath.Join(fp.dirname, strings.Replace(p, " ", "_", -1))) if err != nil { return Page{} } defer f.Close() body, err := ioutil.ReadAll(f) if err != nil { return Page{} } return Page{Content: string(body)} } func (fp *FilePages) Save(p string, page Page, summary, author string) error { f, err := os.Create(filepath.Join(fp.dirname, strings.Replace(p, " ", "_", -1))) if err != nil { return err } defer f.Close() f.WriteString(strings.Replace(page.Content, "\r\n", "\n", -1)) return saveWithGit(fp, p, summary, author) } func saveWithGit(fp *FilePages, p string, summary, author string) error { cmd := exec.Command("git", "add", ".") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Dir = fp.dirname err := cmd.Run() if err != nil { return fmt.Errorf("while adding page %s: %s", p, err) } cmd = exec.Command("git", "commit", "-m", "Changes to "+p+" by "+author+"\n\n"+summary) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Dir = fp.dirname err = cmd.Run() if err != nil { return fmt.Errorf("while commiting page %s: %s", p, err) } return nil } func (fp *FilePages) Exist(p string) bool { f, err := os.Open(filepath.Join(fp.dirname, strings.Replace(p, " ", "_", -1))) if err != nil { return os.IsExist(err) } f.Close() return true } func DiffPrettyHtml(diffs []diffmatchpatch.Diff) string { var buff bytes.Buffer for _, diff := range diffs { // text := strings.Replace(html.EscapeString(diff.Text), "\n", "
", -1) text := html.EscapeString(diff.Text) switch diff.Type { case diffmatchpatch.DiffInsert: _, _ = buff.WriteString("") _, _ = buff.WriteString(text) _, _ = buff.WriteString("") case diffmatchpatch.DiffDelete: _, _ = buff.WriteString("") _, _ = buff.WriteString(text) _, _ = buff.WriteString("") case diffmatchpatch.DiffEqual: _, _ = buff.WriteString("") _, _ = buff.WriteString(text) _, _ = buff.WriteString("") } } return buff.String() } func (fp *FilePages) PageHistory(p string) ([]Revision, error) { page := strings.Replace(p, " ", "_", -1) cmd := exec.Command("git", "log", "--pretty=oneline", "--no-decorate", "--color=never", page) cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout cmd.Dir = fp.dirname output, err := cmd.StdoutPipe() if err != nil { return nil, err } defer output.Close() err = cmd.Start() if err != nil { log.Println("Start") return nil, err } buf := bufio.NewScanner(output) var revisions []Revision for buf.Scan() { line := buf.Text() start := strings.Index(line, " ") commitId := line[0:start] rest := line[start+1:] pageText := gitRevision(fp.dirname, page, commitId) revisions = append(revisions, Revision{ Version: commitId, Page: DiffPage{Content: pageText}, Summary: rest, }) } dmp := diffmatchpatch.New() prevText := "" for i := len(revisions) - 1; i >= 0; i-- { diffs := dmp.DiffMain(prevText, revisions[i].Page.Content, false) revisions[i].Page.Diff = template.HTML(DiffPrettyHtml(diffs)) prevText = revisions[i].Page.Content } if err := cmd.Wait(); err != nil { log.Println("wait") return nil, err } return revisions, nil } func gitRevision(dirname, page, version string) string { cmd := exec.Command("git", "show", version+":"+page) cmd.Dir = dirname cmd.Stderr = os.Stderr buf := bytes.Buffer{} cmd.Stdout = &buf cmd.Start() cmd.Wait() return buf.String() } func (fp *FilePages) RecentChanges() ([]Change, error) { cmd := exec.Command("git", "log", "--format=--1--%nDate: %aI%n--2--", "--name-only") cmd.Dir = fp.dirname cmd.Stderr = os.Stderr buf := bytes.Buffer{} cmd.Stdout = &buf err := cmd.Start() if err != nil { return nil, err } err = cmd.Wait() if err != nil { return nil, err } scanner := bufio.NewScanner(&buf) first := false second := false var changes []Change var change Change for scanner.Scan() { line := scanner.Text() if line == "--1--" { second = false first = true continue } if line == "--2--" { first = false second = true continue } if first && strings.HasPrefix(line, "Date: ") { line = line[6:] changeTime, err := time.Parse(time.RFC3339, line) if err != nil { return changes, err } change.Date = changeTime continue } if second { if line == "" { continue } change.Page = line } changes = append(changes, change) } return changes, nil }