]> Sergey Matveev's repositories - sgblog.git/blobdiff - cmd/sgblog-comment-add/main.go
Cleanup dependencies
[sgblog.git] / cmd / sgblog-comment-add / main.go
index b967d949d90bfd399d8f71db02b8e7975c6b9e3f..e632ca68cf7f1cad29f746793d410cd1ea2802d0 100644 (file)
@@ -1,6 +1,6 @@
 /*
-SGBlog -- Git-based CGI blogging engine
-Copyright (C) 2020 Sergey Matveev <stargrave@stargrave.org>
+SGBlog -- Git-backed CGI/inetd blogging/phlogging engine
+Copyright (C) 2020-2021 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as
@@ -15,7 +15,7 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-// Git-based CGI blogging engine email to comments adder
+// Git-backed CGI/inetd blogging/phlogging engine
 package main
 
 import (
@@ -26,18 +26,52 @@ import (
        "fmt"
        "io/ioutil"
        "log"
+       "mime"
        "net/mail"
        "os"
        "os/exec"
+       "regexp"
        "strconv"
        "strings"
        "syscall"
        "time"
 
-       "go.cypherpunks.ru/netstring/v2"
+       "go.cypherpunks.ru/recfile"
+       "go.stargrave.org/sgblog"
 )
 
-const WhenFmt = "2006-01-02 15:04:05Z07:00"
+var hashFinder = regexp.MustCompile("([0-9a-f]{40})")
+
+// Remove various whitespaces and excess lines, because git-notes-add
+// will remove and we have to know exact bytes count
+func cleanupBody(body string) []string {
+       lines := strings.Split(string(body), "\n")
+       for i, line := range lines {
+               line = strings.ReplaceAll(line, "       ", "    ")
+               line = strings.TrimRight(line, " \r")
+               lines[i] = line
+       }
+       for lines[0] == "" {
+               lines = lines[1:]
+       }
+       for lines[len(lines)-1] == "" {
+               lines = lines[:len(lines)-1]
+       }
+       withoutDups := make([]string, 0, len(lines))
+       emptyMet := false
+       for _, line := range lines {
+               if line == "" {
+                       if emptyMet {
+                               continue
+                       }
+                       emptyMet = true
+               } else {
+                       emptyMet = false
+               }
+               withoutDups = append(withoutDups, line)
+       }
+       return withoutDups
+}
 
 func main() {
        gitCmd := flag.String("git-cmd", "/usr/local/bin/git", "Path to git executable")
@@ -45,6 +79,11 @@ func main() {
        notesRef := flag.String("ref", "comments", "notes reference name")
        umask := flag.String("umask", "027", "umask value")
        dryRun := flag.Bool("dryrun", false, "Show comment, do not add")
+       committerEmail := flag.String(
+               "committer-email",
+               "comment@blog.example.com",
+               "Git committer's email",
+       )
        flag.Parse()
        uid := syscall.Geteuid()
        if err := syscall.Setuid(uid); err != nil {
@@ -75,7 +114,15 @@ func main() {
        if len(body) == 0 {
                log.Fatal("no body")
        }
+       from, err = new(mime.WordDecoder).DecodeHeader(from)
+       if err != nil {
+               log.Fatal(err)
+       }
 
+       subj = hashFinder.FindString(subj)
+       if subj == "" {
+               log.Fatal("no commit hash found in subject")
+       }
        if h, err := hex.DecodeString(subj); err != nil || len(h) != sha1.Size {
                os.Exit(0)
        }
@@ -93,26 +140,28 @@ func main() {
                "notes", "--ref", *notesRef, "show", subj,
        )
        note, _ := cmd.Output()
-       note = bytes.TrimSuffix(note, []byte{'\n'})
+       note = bytes.TrimRight(note, "\r\n")
 
-       // Remove trailing whitespaces, because git-notes-add will remove
-       // them anyway, and we have to know exact bytes count
-       lines := strings.Split(string(body), "\n")
-       for i, line := range lines {
-               lines[i] = strings.TrimRight(line, " ")
+       buf := bytes.NewBuffer(note)
+       recfileW := recfile.NewWriter(buf)
+       if _, err = recfileW.RecordStart(); err != nil {
+               log.Fatal(err)
        }
-       for lines[len(lines)-1] == "" {
-               lines = lines[:len(lines)-1]
+       // We trimmed newline, so have to start record twice
+       if _, err = recfileW.RecordStart(); err != nil {
+               log.Fatal(err)
+       }
+       if _, err = recfileW.WriteFields(
+               recfile.Field{Name: "From", Value: from},
+               recfile.Field{Name: "Date", Value: time.Now().UTC().Format(sgblog.WhenFmt)},
+       ); err != nil {
+               log.Fatal(err)
+       }
+       if _, err = recfileW.WriteFieldMultiline(
+               "Body", append([]string{""}, cleanupBody(string(body))...),
+       ); err != nil {
+               log.Fatal(err)
        }
-
-       buf := bytes.NewBuffer(note)
-       w := netstring.NewWriter(buf)
-       w.WriteChunk([]byte(fmt.Sprintf(
-               "From: %s\nDate: %s\n\n%s",
-               from,
-               time.Now().Format(WhenFmt),
-               strings.Join(lines, "\n"),
-       )))
 
        if *dryRun {
                fmt.Print(buf.String())
@@ -124,6 +173,13 @@ func main() {
                "notes", "--ref", *notesRef, "add",
                "-F", "-", "-f", subj,
        )
+       cmd.Env = append(
+               cmd.Env,
+               "GIT_AUTHOR_NAME=SGBlog "+sgblog.Version,
+               "GIT_AUTHOR_EMAIL="+*committerEmail,
+               "GIT_COMMITTER_NAME=SGBlog "+sgblog.Version,
+               "GIT_COMMITTER_EMAIL="+*committerEmail,
+       )
        cmd.Stdin = buf
        if err = cmd.Run(); err != nil {
                log.Fatal(err)