Home

ugit @main - refs - log -
-
https://git.jolheiser.com/ugit.git
The code powering this h*ckin' site
tree log patch
fix tags
Signature
-----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgBTEvCQk6VqUAdN2RuH6bj1dNkY oOpbPWj+jw4ua1B1cAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQFoCGU3Dv/jN/dj3PzTHiu/0coxAqdklCqHT+qqMqjWiT9voferr6a6obns/0cxMjI urvQQHVmUPtNNSzgVocQk= -----END SSH SIGNATURE-----
jolheiser <git@jolheiser.com>
2 weeks ago
7 changed files, 113 additions(+), 18 deletions(-)
internal/git/meta.gointernal/git/meta_test.gointernal/git/protocol.gointernal/html/index.gointernal/http/http.gointernal/http/index.gointernal/http/middleware.go
M internal/git/meta.gointernal/git/meta.go
 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
diff --git a/internal/git/meta.go b/internal/git/meta.go
index 52bb2628d2f79658a86719f50baa5458c87b0f90..0a13833c1a949c40b3beb1170043183276deed6d 100644
--- a/internal/git/meta.go
+++ b/internal/git/meta.go
@@ -7,13 +7,60 @@ 	"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        []string `json:"tags"`
+	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
+	}
+	for _, ss := range s {
+		t.Add(ss)
+	}
+	return nil
 }
 
 // Update updates meta given another RepoMeta
I internal/git/meta_test.go
 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
diff --git a/internal/git/meta_test.go b/internal/git/meta_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..e51c0298c9b1901e6f4a68786806c4eee09ffcb3
--- /dev/null
+++ b/internal/git/meta_test.go
@@ -0,0 +1,53 @@
+package git
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/alecthomas/assert/v2"
+)
+
+func TestTagSet(t *testing.T) {
+	set := make(TagSet)
+	assert.Equal(t, 0, len(set))
+	assert.Equal(t, 0, len(set.Slice()))
+
+	set.Add("foo")
+	assert.Equal(t, 1, len(set))
+	assert.Equal(t, 1, len(set.Slice()))
+	assert.True(t, set.Contains("foo"))
+
+	set.Add("bar")
+	assert.Equal(t, 2, len(set))
+	assert.Equal(t, 2, len(set.Slice()))
+	assert.True(t, set.Contains("foo"))
+	assert.True(t, set.Contains("bar"))
+
+	set.Add("bar")
+	assert.Equal(t, 2, len(set))
+	assert.Equal(t, 2, len(set.Slice()))
+	assert.True(t, set.Contains("foo"))
+	assert.True(t, set.Contains("bar"))
+
+	set.Remove("foo")
+	assert.Equal(t, 1, len(set))
+	assert.Equal(t, 1, len(set.Slice()))
+	assert.False(t, set.Contains("foo"))
+	assert.True(t, set.Contains("bar"))
+
+	set.Add("foo")
+	set.Add("baz")
+	j, err := json.Marshal(set)
+	assert.NoError(t, err)
+	assert.Equal(t, `["bar","baz","foo"]`, string(j))
+
+	set = make(TagSet)
+	b := []byte(`["foo","bar","baz"]`)
+	err = json.Unmarshal(b, &set)
+	assert.NoError(t, err)
+	assert.Equal(t, 3, len(set))
+	assert.Equal(t, 3, len(set.Slice()))
+	assert.True(t, set.Contains("foo"))
+	assert.True(t, set.Contains("bar"))
+	assert.True(t, set.Contains("baz"))
+}
M internal/git/protocol.gointernal/git/protocol.go
 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
diff --git a/internal/git/protocol.go b/internal/git/protocol.go
index 02921bf105d91da66d9dd219726211dc4b19689e..287347dd7d4dce170b97cb2498dcbd8836efc007 100644
--- a/internal/git/protocol.go
+++ b/internal/git/protocol.go
@@ -58,15 +58,11 @@ 				if strings.HasPrefix(tagValue, "-") {
 					remove = true
 					tagValue = strings.TrimPrefix(tagValue, "-")
 				}
-				for idx, tag := range repo.Meta.Tags {
-					if strings.EqualFold(tag, tagValue) {
-						if remove {
-							repo.Meta.Tags = append(repo.Meta.Tags[:idx], repo.Meta.Tags[idx+1:]...)
-						} else {
-							repo.Meta.Tags = append(repo.Meta.Tags, strings.ToLower(tagValue))
-						}
-						break
-					}
+				tagValue = strings.ToLower(tagValue)
+				if remove {
+					repo.Meta.Tags.Remove(tagValue)
+				} else {
+					repo.Meta.Tags.Add(tagValue)
 				}
 			}
 		}
M internal/html/index.gointernal/html/index.go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
diff --git a/internal/html/index.go b/internal/html/index.go
index 621eaccaa7d50b5ed39eeffdc5704a1667049f19..478cae2a081c35e39dcf2c2f2bb78dafe17897e7 100644
--- a/internal/html/index.go
+++ b/internal/html/index.go
@@ -92,7 +92,7 @@ 								),
 							),
 						),
 						Div(Class("sm:col-span-1 text-subtext0"),
-							Map(repo.Meta.Tags, func(tag string) Node {
+							Map(repo.Meta.Tags.Slice(), func(tag string) Node {
 								return A(Class("rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block"), Href("?tag="+tag), Text(tag))
 							}),
 						),
M internal/http/http.gointernal/http/http.go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
diff --git a/internal/http/http.go b/internal/http/http.go
index 61831c7051c147b8e613715421fbf37896802d6e..b89b8242cf37a25d0bc34562822ffe750a7d53c2 100644
--- a/internal/http/http.go
+++ b/internal/http/http.go
@@ -126,7 +126,7 @@ 		Description: repo.Meta.Description,
 		Name:        chi.URLParam(r, "repo"),
 		Ref:         ref,
 		CloneURL:    rh.s.CloneURL,
-		Tags:        repo.Meta.Tags,
+		Tags:        repo.Meta.Tags.Slice(),
 	}
 }
 
M internal/http/index.gointernal/http/index.go
 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
diff --git a/internal/http/index.go b/internal/http/index.go
index aeac9f82d0d728edb887f6380ff35a93d23b303e..ed752ab1db475fd6e1d086d415884d7f0cc2c3d9 100644
--- a/internal/http/index.go
+++ b/internal/http/index.go
@@ -3,7 +3,6 @@
 import (
 	"net/http"
 	"os"
-	"slices"
 	"sort"
 	"strings"
 	"time"
@@ -34,10 +33,10 @@ 		if repo.Meta.Private {
 			if !rh.s.ShowPrivate {
 				continue
 			}
-			repo.Meta.Tags = append(repo.Meta.Tags, "private")
+			repo.Meta.Tags.Add("private")
 		}
 
-		if tagFilter != "" && !slices.Contains(repo.Meta.Tags, strings.ToLower(tagFilter)) {
+		if tagFilter != "" && !repo.Meta.Tags.Contains(strings.ToLower(tagFilter)) {
 			continue
 		}
 		repos = append(repos, repo)
M internal/http/middleware.gointernal/http/middleware.go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
diff --git a/internal/http/middleware.go b/internal/http/middleware.go
index b5c4ae002cc2c8d33b1b5b95c514174906e5f647..2b40746e1a565a359c6a91781573f39393113746 100644
--- a/internal/http/middleware.go
+++ b/internal/http/middleware.go
@@ -30,7 +30,7 @@ 		if repo.Meta.Private {
 			if !rh.s.ShowPrivate {
 				return httperr.Status(errors.New("could not get git repo"), http.StatusNotFound)
 			}
-			repo.Meta.Tags = append(repo.Meta.Tags, "private")
+			repo.Meta.Tags.Add("private")
 		}
 		r = r.WithContext(context.WithValue(r.Context(), repoCtxKey, repo))
 		next.ServeHTTP(w, r)