Home

ugit @d87caf61fd67b5618db44968e560732f66890390 - refs - log -
-
https://git.jolheiser.com/ugit.git
The code powering this h*ckin' site
ugit / internal / git / meta.go
- raw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package git

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/fs"
	"os"
	"path/filepath"
	"slices"
)

// RepoMeta is the meta information a Repo can have
type RepoMeta struct {
	Description string `json:"description"`
	Private     bool   `json:"private"`
	Tags        TagSet `json:"tags"`
}

// TagSet is a Set of tags
type TagSet map[string]struct{}

// Add adds a tag to the set
func (t TagSet) Add(tag string) {
	t[tag] = struct{}{}
}

// Remove removes a tag from the set
func (t TagSet) Remove(tag string) {
	delete(t, tag)
}

// Contains checks if a tag is in the set
func (t TagSet) Contains(tag string) bool {
	_, ok := t[tag]
	return ok
}

// Slice returns the set as a (sorted) slice
func (t TagSet) Slice() []string {
	s := make([]string, 0, len(t))
	for k := range t {
		s = append(s, k)
	}
	slices.Sort(s)
	return s
}

// MarshalJSON implements [json.Marshaler]
func (t TagSet) MarshalJSON() ([]byte, error) {
	return json.Marshal(t.Slice())
}

// UnmarshalJSON implements [json.Unmarshaler]
func (t *TagSet) UnmarshalJSON(b []byte) error {
	var s []string
	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}
	if *t == nil {
		*t = make(TagSet)
	}
	for _, ss := range s {
		t.Add(ss)
	}
	return nil
}

// Update updates meta given another RepoMeta
func (m *RepoMeta) Update(meta RepoMeta) error {
	data, err := json.Marshal(meta)
	if err != nil {
		return err
	}
	return json.Unmarshal(data, m)
}

func (r Repo) metaPath() string {
	return filepath.Join(r.path, "ugit.json")
}

// SaveMeta saves the meta info of a Repo
func (r Repo) SaveMeta() error {
	// Compatibility with gitweb, because why not
	// Ignoring the error because it's not technically detrimental to ugit
	desc, err := os.Create(filepath.Join(r.path, "description"))
	if err == nil {
		defer desc.Close()
		_, _ = desc.WriteString(r.Meta.Description)
	}

	fi, err := os.Create(r.metaPath())
	if err != nil {
		return err
	}
	defer fi.Close()
	return json.NewEncoder(fi).Encode(r.Meta)
}

var defaultMeta = func() []byte {
	b, err := json.Marshal(RepoMeta{
		Private: true,
	})
	if err != nil {
		panic(fmt.Sprintf("could not init default meta: %v", err))
	}
	return b
}()

func ensureJSONFile(path string) error {
	_, err := os.Stat(path)
	if err == nil {
		return nil
	}
	if !errors.Is(err, fs.ErrNotExist) {
		return err
	}
	fi, err := os.Create(path)
	if err != nil {
		return err
	}
	defer fi.Close()
	if _, err := fi.Write(defaultMeta); err != nil {
		return err
	}
	return nil
}