2 SGBlog -- Git-based CGI blogging engine
3 Copyright (C) 2020 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Affero General Public License as
7 published by the Free Software Foundation, version 3 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU Affero General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 // Git-based CGI blogging engine
28 "go.cypherpunks.ru/netstring/v2"
29 "gopkg.in/src-d/go-git.v4"
30 "gopkg.in/src-d/go-git.v4/plumbing"
31 "gopkg.in/src-d/go-git.v4/plumbing/object"
39 sha1DigestRe = regexp.MustCompilePOSIX("([0-9a-f]{40,40})")
41 notesTree *object.Tree
42 commentsTree *object.Tree
61 CommentsNotesRef string
67 func msgSplit(msg string) []string {
68 lines := strings.Split(msg, "\n")
69 lines = lines[:len(lines)-1]
71 lines = []string{lines[0], "", ""}
76 func getNote(tree *object.Tree, what plumbing.Hash) []byte {
80 var entry *object.TreeEntry
82 paths := make([]string, 3)
83 paths[0] = what.String()
84 paths[1] = paths[0][:2] + "/" + paths[0][2:]
85 paths[2] = paths[1][:4+1] + "/" + paths[1][4+1:]
86 for _, p := range paths {
87 entry, err = tree.FindEntry(p)
95 blob, err := repo.BlobObject(entry.Hash)
99 r, err := blob.Reader()
103 data, err := ioutil.ReadAll(r)
107 return bytes.TrimSuffix(data, []byte{'\n'})
110 func parseComments(data []byte) []string {
111 comments := []string{}
112 nsr := netstring.NewReader(bytes.NewReader(data))
114 if _, err := nsr.Next(); err != nil {
117 if comment, err := ioutil.ReadAll(nsr); err == nil {
118 comments = append(comments, string(comment))
124 func initRepo(cfg *Cfg) (*plumbing.Hash, error) {
126 repo, err = git.PlainOpen(cfg.GitPath)
130 head, err := repo.Reference(plumbing.ReferenceName(cfg.Branch), false)
134 headHash := head.Hash()
135 if notes, err := repo.Notes(); err == nil {
136 var notesRef *plumbing.Reference
137 var commentsRef *plumbing.Reference
138 notes.ForEach(func(ref *plumbing.Reference) error {
139 switch string(ref.Name()) {
140 case "refs/notes/commits":
142 case cfg.CommentsNotesRef:
148 if commentsCommit, err := repo.CommitObject(notesRef.Hash()); err == nil {
149 notesTree, _ = commentsCommit.Tree()
152 if commentsRef != nil {
153 if commentsCommit, err := repo.CommitObject(commentsRef.Hash()); err == nil {
154 commentsTree, _ = commentsCommit.Tree()
158 return &headHash, nil
162 if len(os.Args) == 3 && os.Args[1] == "-gopher" {