--- /dev/null
+// Copyright 2024 Nikita Shubin <nikita.shubin@maquefel.me>. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package hugolib
+
+import (
+ "path/filepath"
+ "os/exec"
+ "strings"
+ "errors"
+ "bytes"
+ "fmt"
+
+ "github.com/gohugoio/hugo/config"
+ "github.com/gohugoio/hugo/resources/page"
+
+ "gopkg.in/yaml.v2"
+)
+
+func git(args ...string) ([]byte, error) {
+ out, err := exec.Command(gitExec, args...).CombinedOutput()
+
+ if err != nil {
+ if ee, ok := err.(*exec.Error); ok {
+ if ee.Err == exec.ErrNotFound {
+ return nil, GitNotFound
+ }
+ }
+
+ return nil, errors.New(string(bytes.TrimSpace(out)))
+ }
+
+ return out, nil
+}
+
+var (
+ // will be modified during tests
+ gitExec string = "git"
+ GitNotFound = errors.New("Git executable not found in $PATH")
+)
+
+type gitPurismInfo struct {
+ contentDir string
+}
+
+type GitPurismInfo struct {
+ Tags []string
+ Categories []string
+}
+
+type Tags struct {
+ Tags []string `yaml:"tags"`
+}
+
+type Cats struct {
+ Categories []string `yaml:"categories"`
+}
+
+func (g *gitPurismInfo) forPage(p page.Page) *GitPurismInfo {
+ var t_res []string
+ var c_res []string
+
+ name := strings.TrimPrefix(filepath.ToSlash(p.File().Filename()), g.contentDir)
+ name = strings.TrimPrefix(name, "/")
+
+ gitLogArgs := strings.Fields(fmt.Sprintf(
+ `--no-pager -C %s log --notes=%s --notes=%s --format=%%N -- %s`,
+ g.contentDir,
+ "tags",
+ "categories",
+ name,
+ ))
+
+ out, err := git(gitLogArgs...)
+ entriesStr := string(out)
+ entriesStr = strings.Trim(entriesStr, "\n\x1e'")
+ entries := strings.Split(string(entriesStr), "\n")
+
+ for _, e := range entries {
+ var t Tags
+ var c Cats
+ err = yaml.Unmarshal([]byte(e), &t)
+ if err != nil {
+ continue
+ }
+
+ err = yaml.Unmarshal([]byte(e), &c)
+ if err != nil {
+ continue
+ }
+
+ t_res = append(t_res, t.Tags...)
+ c_res = append(c_res, c.Categories...)
+ }
+
+ return &GitPurismInfo{Tags: t_res, Categories: c_res}
+}
+
+func newGitPurismInfo(cfg config.Provider) (*gitPurismInfo, error) {
+ contentDir := cfg.GetString("contentDir")
+ absRepoPath, err := filepath.Abs(contentDir)
+
+ if err != nil {
+ return nil, err
+ }
+
+ _, err = git("-C", absRepoPath, "rev-parse", "--show-cdup")
+ if err != nil {
+ return nil, err
+ }
+
+ return &gitPurismInfo{contentDir: absRepoPath}, nil
+}