// SGBlog -- Git-backed CGI/UCSPI blogging/phlogging/gemlogging engine // Copyright (C) 2020-2024 Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, version 3 of the License. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // SGBlog -- Git-backed CGI/UCSPI blogging/phlogging/gemlogging engine package sgblog import ( "bytes" "fmt" "io" "sort" "text/scanner" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" "go.cypherpunks.ru/recfile" ) const ( Version = "0.34.0" WhenFmt = "2006-01-02 15:04:05Z07:00" ) func ParseComments(data []byte) []string { comments := []string{} r := recfile.NewReader(bytes.NewReader(data)) for { fields, err := r.Next() if err != nil { break } if len(fields) != 3 || fields[0].Name != "From" || fields[1].Name != "Date" || fields[2].Name != "Body" { continue } comments = append(comments, fmt.Sprintf( "%s: %s\n%s: %s\n%s", fields[0].Name, fields[0].Value, fields[1].Name, fields[1].Value, fields[2].Value, )) } return comments } func ParseTopics(data []byte) []string { var s scanner.Scanner s.Init(bytes.NewBuffer(data)) topics := []string{} for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() { topics = append(topics, s.TokenText()) } sort.Strings(topics) return topics } func GetNote(repo *git.Repository, tree *object.Tree, what plumbing.Hash) []byte { if tree == nil { return nil } var entry *object.TreeEntry var err error paths := make([]string, 3) paths[0] = what.String() paths[1] = paths[0][:2] + "/" + paths[0][2:] paths[2] = paths[1][:4+1] + "/" + paths[1][4+1:] for _, p := range paths { entry, err = tree.FindEntry(p) if err == nil { break } } if entry == nil { return nil } blob, err := repo.BlobObject(entry.Hash) if err != nil { return nil } r, err := blob.Reader() if err != nil { return nil } data, err := io.ReadAll(r) if err != nil { return nil } return bytes.TrimSuffix(data, []byte{'\n'}) }