Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Code

392 commit(s) on main

Merge change request 01M70WES5ZZDJ6RP226WB11BBZ: Let people rename and remove their own passkeys keenan · 21m ago 4b8c9e1d
history blame raw 2.5 KiB
1package git
2
3// The sizes and counts a quota check needs. They are one `git` invocation each so
4// a refused push costs a bounded amount of work.
5
6import (
7 "bytes"
8 "fmt"
9 "strconv"
10 "strings"
11)
12
13// EntrySize is one blob under a tree, with the number of bytes it holds.
14type EntrySize struct {
15 Entry
16 Size int64
17}
18
19// LsTreeSizes lists every blob under treeish recursively, with sizes. It is
20// LsTreeR plus `-l`, which is what a metadata quota sums.
21func (r *Repo) LsTreeSizes(treeish string) ([]EntrySize, error) {
22 out, errs, err := r.run(nil, "ls-tree", "-r", "-l", "-z", treeish)
23 if err != nil {
24 return nil, fmt.Errorf("ls-tree -r -l %q: %w: %s", treeish, err, errs)
25 }
26 var es []EntrySize
27 for _, rec := range bytes.Split(out, []byte{0}) {
28 if len(rec) == 0 {
29 continue
30 }
31 tab := bytes.IndexByte(rec, '\t')
32 if tab < 0 {
33 return nil, fmt.Errorf("bad ls-tree record %q", rec)
34 }
35 // "<mode> SP <type> SP <sha> SP* <size> TAB <path>"
36 f := strings.Fields(string(rec[:tab]))
37 if len(f) < 4 {
38 return nil, fmt.Errorf("bad ls-tree record %q", rec)
39 }
40 size, _ := strconv.ParseInt(f[3], 10, 64)
41 es = append(es, EntrySize{
42 Entry: Entry{Mode: f[0], Type: f[1], SHA: f[2], Name: string(rec[tab+1:])},
43 Size: size,
44 })
45 }
46 return es, nil
47}
48
49// RefCount counts the branches and tags. It is a count rather than a listing: the
50// quota check must see every ref, while the pages deliberately cap what they show.
51func (r *Repo) RefCount() (int, error) {
52 out, errs, err := r.run(nil, "for-each-ref", "--format=%(refname)", "refs/heads", "refs/tags")
53 if err != nil {
54 return 0, fmt.Errorf("for-each-ref: %w: %s", err, errs)
55 }
56 n := 0
57 for _, line := range strings.Split(string(out), "\n") {
58 if strings.TrimSpace(line) != "" {
59 n++
60 }
61 }
62 return n, nil
63}
64
65// DiskUsage is how many bytes the repository's objects take on disk: the pack
66// files plus loose objects plus any garbage git has left. It is what a repository
67// size quota compares against.
68func (r *Repo) DiskUsage() (int64, error) {
69 out, errs, err := r.run(nil, "count-objects", "-v")
70 if err != nil {
71 return 0, fmt.Errorf("count-objects: %w: %s", err, errs)
72 }
73 var total int64
74 for _, line := range strings.Split(string(out), "\n") {
75 k, v, ok := strings.Cut(strings.TrimSpace(line), ":")
76 if !ok {
77 continue
78 }
79 n, err := strconv.ParseInt(strings.TrimSpace(v), 10, 64)
80 if err != nil {
81 continue
82 }
83 switch k {
84 case "size", "size-pack", "size-garbage":
85 // KiB, per git-count-objects(1).
86 total += n << 10
87 }
88 }
89 return total, nil
90}
91