]> Sergey Matveev's repositories - sgblog.git/blobdiff - cmd/sgblog/gopher.go
Use templates for code simplicity
[sgblog.git] / cmd / sgblog / gopher.go
index e98d65b9f08d25c50639b39af32aec232495f08b..d8e4fe4bc62e413bcd4babef51dcfcf89269fb65 100644 (file)
@@ -1,5 +1,5 @@
 /*
-SGBlog -- Git-based CGI blogging engine
+SGBlog -- Git-backed CGI/inetd blogging/phlogging engine
 Copyright (C) 2020 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
@@ -15,12 +15,10 @@ 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
 package main
 
 import (
        "bufio"
-       "bytes"
        "encoding/json"
        "errors"
        "fmt"
@@ -30,17 +28,55 @@ import (
        "os"
        "strconv"
        "strings"
-       "time"
+       "text/template"
 
        "github.com/hjson/hjson-go"
        "go.stargrave.org/sgblog"
        "gopkg.in/src-d/go-git.v4"
        "gopkg.in/src-d/go-git.v4/plumbing"
+       "gopkg.in/src-d/go-git.v4/plumbing/object"
 )
 
-const CRLF = "\r\n"
+const (
+       TmplGopherMenu = `{{$Cfg := .Cfg}}{{$CR := .CR}}i{{.Cfg.Title}} ({{.Offset}}-{{.OffsetNext}})   err     {{.Cfg.GopherDomain}}   70{{.CR}}
+{{if .Cfg.AboutURL}}hAbout     URL:{{.Cfg.AboutURL}}   {{.Cfg.GopherDomain}}   70{{.CR}}{{end}}
+{{if .Offset}}1Prev    offset/{{.OffsetPrev}}  {{.Cfg.GopherDomain}}   70{{.CR}}{{end}}
+{{if not .LogEnded}}1Next      offset/{{.OffsetNext}}  {{.Cfg.GopherDomain}}   70{{.CR}}{{end -}}
+{{- $yearPrev := 0}}{{$monthPrev := 0}}{{$dayPrev := 0 -}}
+{{- range .Entries }}{{$yearCur := .Commit.Author.When.Year}}{{$monthCur := .Commit.Author.When.Month}}{{$dayCur := .Commit.Author.When.Day -}}
+{{- if or (ne $dayCur $dayPrev) (ne $monthCur $monthPrev) (ne $yearCur $yearPrev)}}{{$dayPrev = $dayCur}}{{$monthPrev = $monthCur}}{{$yearPrev = $yearCur}}
+i{{$yearCur | printf "%04d"}}-{{$monthCur | printf "%02d"}}-{{$dayCur | printf "%02d"}}        err     {{$Cfg.GopherDomain}}   70{{$CR}}{{end}}
+0[{{.Commit.Author.When.Hour | printf "%02d"}}:{{.Commit.Author.When.Minute | printf "%02d"}}] {{.Title}} ({{.LinesNum}}L){{if .CommentsNum}} ({{.CommentsNum}}C){{end}}       /{{.Commit.Hash.String}}        {{$Cfg.GopherDomain}}   70{{$CR}}{{end}}
+iGenerated by: SGBlog {{.Version}}     err     {{.Cfg.GopherDomain}}   70{{.CR}}
+.{{.CR}}
+`
+       TmplGopherEntry = `What: {{.Commit.Hash.String}}
+When: {{.When}}
+------------------------------------------------------------------------
+{{.Commit.Message -}}
+{{- if .Note}}
+------------------------------------------------------------------------
+Note:
+{{.Note}}{{end -}}
+{{- if .Cfg.CommentsEmail}}
+------------------------------------------------------------------------
+leave comment: mailto:{{.Cfg.CommentsEmail}}?subject={{.Commit.Hash.String}}
+{{end}}{{range $idx, $comment := .Comments}}
+------------------------------------------------------------------------
+comment {{$idx}}:
+{{$comment}}
+{{end}}
+------------------------------------------------------------------------
+Generated by: SGBlog {{.Version}}
+`
+)
 
-var DashLine = strings.Repeat("-", 72)
+type TableMenuEntry struct {
+       Commit      *object.Commit
+       Title       string
+       LinesNum    int
+       CommentsNum int
+}
 
 func serveGopher() {
        cfgPath := os.Args[2]
@@ -86,102 +122,85 @@ func serveGopher() {
                if err != nil {
                        log.Fatalln(err)
                }
-               commitN := 0
                for i := 0; i < offset; i++ {
                        if _, err = repoLog.Next(); err != nil {
                                break
                        }
-                       commitN++
                }
-
                logEnded := false
-               var menu bytes.Buffer
-               var yearPrev int
-               var monthPrev time.Month
-               var dayPrev int
+               entries := make([]TableMenuEntry, 0, PageEntries)
                for i := 0; i < PageEntries; i++ {
                        commit, err := repoLog.Next()
                        if err != nil {
                                logEnded = true
                                break
                        }
-                       yearCur, monthCur, dayCur := commit.Author.When.Date()
-                       if dayCur != dayPrev || monthCur != monthPrev || yearCur != yearPrev {
-                               menu.WriteString(fmt.Sprintf(
-                                       "i%04d-%02d-%02d\t\tnull.host\t1%s",
-                                       yearCur, monthCur, dayCur, CRLF,
-                               ))
-                               yearPrev, monthPrev, dayPrev = yearCur, monthCur, dayCur
-                       }
-                       commitN++
                        lines := msgSplit(commit.Message)
-                       var commentsValue string
-                       if l := len(parseComments(getNote(commentsTree, commit.Hash))); l > 0 {
-                               commentsValue = fmt.Sprintf(" (%dC)", l)
-                       }
-                       menu.WriteString(fmt.Sprintf(
-                               "0[%02d:%02d] %s (%dL)%s\t/%s\t%s\t%d%s",
-                               commit.Author.When.Hour(),
-                               commit.Author.When.Minute(),
-                               lines[0],
-                               len(lines)-2,
-                               commentsValue,
-                               commit.Hash.String(),
-                               cfg.GopherDomain, 70, CRLF,
-                       ))
-               }
-
-               var links bytes.Buffer
-               if offset > 0 {
-                       offsetPrev := offset - PageEntries
-                       if offsetPrev < 0 {
-                               offsetPrev = 0
-                       }
-                       links.WriteString(fmt.Sprintf(
-                               "1Prev\toffset/%d\t%s\t%d%s",
-                               offsetPrev,
-                               cfg.GopherDomain, 70, CRLF,
-                       ))
+                       entries = append(entries, TableMenuEntry{
+                               Commit:      commit,
+                               Title:       lines[0],
+                               LinesNum:    len(lines) - 2,
+                               CommentsNum: len(parseComments(getNote(commentsTree, commit.Hash))),
+                       })
                }
-               if !logEnded {
-                       links.WriteString(fmt.Sprintf(
-                               "1Next\toffset/%d\t%s\t%d%s",
-                               offset+PageEntries,
-                               cfg.GopherDomain, 70, CRLF,
-                       ))
-               }
-
-               fmt.Printf(
-                       "i%s (%d-%d)\t\tnull.host\t1%s",
-                       cfg.Title,
-                       offset,
-                       offset+PageEntries,
-                       CRLF,
-               )
-               if cfg.AboutURL != "" {
-                       fmt.Printf("iAbout: %s\t\tnull.host\t1%s", cfg.AboutURL, CRLF)
+               tmpl := template.Must(template.New("menu").Parse(TmplGopherMenu))
+               err = tmpl.Execute(os.Stdout, struct {
+                       Cfg        *Cfg
+                       Offset     int
+                       OffsetPrev int
+                       OffsetNext int
+                       LogEnded   bool
+                       Entries    []TableMenuEntry
+                       Version    string
+                       CR         string
+               }{
+                       Cfg:        cfg,
+                       Offset:     offset,
+                       OffsetPrev: offset - PageEntries,
+                       OffsetNext: offset + PageEntries,
+                       LogEnded:   logEnded,
+                       Entries:    entries,
+                       Version:    sgblog.Version,
+                       CR:         "\r",
+               })
+               if err != nil {
+                       log.Fatalln(err)
                }
-               fmt.Print(links.String())
-               fmt.Print(menu.String())
-               fmt.Print("." + CRLF)
+       } else if strings.HasPrefix(selector, "URL:") {
+               selector = selector[len("URL:"):]
+               fmt.Printf(`<html>
+<head>
+       <meta http-equiv="Refresh" content="1; url=%s" />
+       <title>Redirect to non-gopher URL</title>
+</head>
+<body>
+Redirecting to <a href="%s">%s</a>...
+</body>
+</html>
+`, selector, selector, selector)
        } else if sha1DigestRe.MatchString(selector) {
                commit, err := repo.CommitObject(plumbing.NewHash(selector[1:]))
                if err != nil {
                        log.Fatalln(err)
                }
-               fmt.Printf(
-                       "What: %s\nWhen: %s\n%s\n%s",
-                       commit.Hash.String(),
-                       commit.Author.When.Format(sgblog.WhenFmt),
-                       DashLine,
-                       commit.Message,
-               )
-               notesRaw := getNote(notesTree, commit.Hash)
-               if len(notesRaw) > 0 {
-                       fmt.Printf("%s\nNote:\n%s\n", DashLine, string(notesRaw))
-               }
-               for i, comment := range parseComments(getNote(commentsTree, commit.Hash)) {
-                       fmt.Printf("%s\ncomment %d:\n%s\n", DashLine, i, comment)
+               tmpl := template.Must(template.New("entry").Parse(TmplGopherEntry))
+               err = tmpl.Execute(os.Stdout, struct {
+                       Commit   *object.Commit
+                       When     string
+                       Cfg      *Cfg
+                       Note     string
+                       Comments []string
+                       Version  string
+               }{
+                       Commit:   commit,
+                       When:     commit.Author.When.Format(sgblog.WhenFmt),
+                       Cfg:      cfg,
+                       Note:     string(getNote(notesTree, commit.Hash)),
+                       Comments: parseComments(getNote(commentsTree, commit.Hash)),
+                       Version:  sgblog.Version,
+               })
+               if err != nil {
+                       log.Fatalln(err)
                }
        } else {
                log.Fatalln(errors.New("unknown selector"))