Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2bfec03

Browse filesBrowse files
committed
git: implement upload-server-info. Fixes #731
This adds UpdateServerInfo along with a new go-git command to generate info files to help git dumb http serve refs and their objects. Docs: https://git-scm.com/docs/git-update-server-info Fixes: #731
1 parent 843d4f4 commit 2bfec03
Copy full SHA for 2bfec03

File tree

Expand file treeCollapse file tree

6 files changed

+243
-0
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+243
-0
lines changed

‎cli/go-git/main.go

Copy file name to clipboardExpand all lines: cli/go-git/main.go
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ func main() {
2222
}
2323

2424
parser := flags.NewNamedParser(bin, flags.Default)
25+
parser.AddCommand("update-server-info", "", "", &CmdUpdateServerInfo{})
2526
parser.AddCommand("receive-pack", "", "", &CmdReceivePack{})
2627
parser.AddCommand("upload-pack", "", "", &CmdUploadPack{})
2728
parser.AddCommand("version", "Show the version information.", "", &CmdVersion{})

‎cli/go-git/update_server_info.go

Copy file name to clipboard
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/go-git/go-git/v5"
8+
"github.com/go-git/go-git/v5/storage/filesystem"
9+
)
10+
11+
type CmdUpdateServerInfo struct {
12+
cmd
13+
}
14+
15+
func (CmdUpdateServerInfo) Usage() string {
16+
return fmt.Sprintf("within a git repository run: %s", os.Args[0])
17+
}
18+
19+
func (c *CmdUpdateServerInfo) Execute(args []string) error {
20+
r, err := git.PlainOpen(".")
21+
if err != nil {
22+
return err
23+
}
24+
25+
fs := r.Storer.(*filesystem.Storage).Filesystem()
26+
return git.UpdateServerInfo(r.Storer, fs)
27+
}

‎server_info.go

Copy file name to clipboard
+85Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package git
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"github.com/go-git/go-billy/v5"
8+
"github.com/go-git/go-git/v5/plumbing"
9+
"github.com/go-git/go-git/v5/plumbing/object"
10+
"github.com/go-git/go-git/v5/plumbing/storer"
11+
"github.com/go-git/go-git/v5/storage"
12+
)
13+
14+
// UpdateServerInfo updates the server info files in the repository.
15+
//
16+
// It generates a list of available refs for the repository.
17+
// Used by git http transport (dumb).
18+
func UpdateServerInfo(s storage.Storer, fs billy.Filesystem) error {
19+
pos, ok := s.(storer.PackedObjectStorer)
20+
if !ok {
21+
return ErrPackedObjectsNotSupported
22+
}
23+
24+
refs, err := s.IterReferences()
25+
if err != nil {
26+
return err
27+
}
28+
29+
infoRefs, err := fs.Create("info/refs")
30+
if err != nil {
31+
log.Printf("error: %v", err)
32+
return err
33+
}
34+
35+
defer infoRefs.Close()
36+
if err := refs.ForEach(func(ref *plumbing.Reference) error {
37+
name := ref.Name()
38+
hash := ref.Hash()
39+
switch ref.Type() {
40+
case plumbing.SymbolicReference:
41+
if name == plumbing.HEAD {
42+
return nil
43+
}
44+
ref, err := s.Reference(ref.Target())
45+
if err != nil {
46+
return err
47+
}
48+
49+
hash = ref.Hash()
50+
fallthrough
51+
case plumbing.HashReference:
52+
fmt.Fprintf(infoRefs, "%s\t%s\n", hash, name)
53+
if name.IsTag() {
54+
tag, err := object.GetTag(s, hash)
55+
if err == nil {
56+
fmt.Fprintf(infoRefs, "%s\t%s%s\n", tag.Target, name, peeledSuffix)
57+
}
58+
}
59+
}
60+
61+
return nil
62+
}); err != nil {
63+
return err
64+
}
65+
66+
infoPacks, err := fs.Create("objects/info/packs")
67+
if err != nil {
68+
return err
69+
}
70+
71+
defer infoPacks.Close()
72+
73+
packs, err := pos.ObjectPacks()
74+
if err != nil {
75+
return err
76+
}
77+
78+
for _, p := range packs {
79+
fmt.Fprintf(infoPacks, "P pack-%s.pack\n", p)
80+
}
81+
82+
fmt.Fprintln(infoPacks)
83+
84+
return nil
85+
}

‎server_info_test.go

Copy file name to clipboard
+124Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package git
2+
3+
import (
4+
"io"
5+
"strings"
6+
7+
"github.com/go-git/go-billy/v5/memfs"
8+
fixtures "github.com/go-git/go-git-fixtures/v4"
9+
"github.com/go-git/go-git/v5/plumbing"
10+
"github.com/go-git/go-git/v5/plumbing/object"
11+
"github.com/go-git/go-git/v5/storage/memory"
12+
. "gopkg.in/check.v1"
13+
)
14+
15+
func (s *RepositorySuite) TestUpdateServerInfoInit(c *C) {
16+
fs := memfs.New()
17+
st := memory.NewStorage()
18+
r, err := Init(st, fs)
19+
c.Assert(err, IsNil)
20+
c.Assert(r, NotNil)
21+
22+
err = UpdateServerInfo(st, fs)
23+
c.Assert(err, IsNil)
24+
}
25+
26+
func testUpdateServerInfo(c *C, f *fixtures.Fixture) {
27+
fs := memfs.New()
28+
st := memory.NewStorage()
29+
r, err := Clone(st, fs, &CloneOptions{
30+
URL: f.URL,
31+
})
32+
33+
c.Assert(err, IsNil)
34+
c.Assert(r, NotNil)
35+
36+
err = UpdateServerInfo(st, fs)
37+
c.Assert(err, IsNil)
38+
39+
refsFile, err := fs.Open("info/refs")
40+
c.Assert(err, IsNil)
41+
42+
defer refsFile.Close()
43+
bts, err := io.ReadAll(refsFile)
44+
c.Assert(err, IsNil)
45+
46+
refs, err := r.References()
47+
c.Assert(err, IsNil)
48+
49+
localRefs := make(map[plumbing.ReferenceName]plumbing.Hash)
50+
for _, line := range strings.Split(string(bts), "\n") {
51+
if line == "" {
52+
continue
53+
}
54+
parts := strings.Split(line, "\t")
55+
c.Assert(parts, HasLen, 2)
56+
hash := plumbing.NewHash(parts[0])
57+
name := plumbing.ReferenceName(parts[1])
58+
localRefs[name] = hash
59+
}
60+
61+
err = refs.ForEach(func(ref *plumbing.Reference) error {
62+
name := ref.Name()
63+
hash := ref.Hash()
64+
switch ref.Type() {
65+
case plumbing.SymbolicReference:
66+
if name == plumbing.HEAD {
67+
return nil
68+
}
69+
ref, err := st.Reference(ref.Target())
70+
c.Assert(err, IsNil)
71+
hash = ref.Hash()
72+
fallthrough
73+
case plumbing.HashReference:
74+
h, ok := localRefs[name]
75+
c.Assert(ok, Equals, true)
76+
c.Assert(h, Equals, hash)
77+
if name.IsTag() {
78+
tag, err := object.GetTag(st, hash)
79+
if err == nil {
80+
t, ok := localRefs[name+peeledSuffix]
81+
c.Assert(ok, Equals, true)
82+
c.Assert(t, Equals, tag.Target)
83+
}
84+
}
85+
}
86+
return nil
87+
})
88+
c.Assert(err, IsNil)
89+
90+
infoPacks, err := fs.Open("objects/info/packs")
91+
c.Assert(err, IsNil)
92+
93+
defer infoPacks.Close()
94+
bts, err = io.ReadAll(infoPacks)
95+
c.Assert(err, IsNil)
96+
97+
localPacks := make(map[string]struct{})
98+
packs, err := st.ObjectPacks()
99+
c.Assert(err, IsNil)
100+
101+
for _, line := range strings.Split(string(bts), "\n") {
102+
if line == "" {
103+
continue
104+
}
105+
parts := strings.Split(line, " ")
106+
c.Assert(parts, HasLen, 2)
107+
pack := strings.TrimPrefix(parts[1], "pack-")
108+
pack = strings.TrimSuffix(pack, ".pack")
109+
localPacks[pack] = struct{}{}
110+
}
111+
112+
for _, p := range packs {
113+
_, ok := localPacks[p.String()]
114+
c.Assert(ok, Equals, true)
115+
}
116+
}
117+
118+
func (s *RepositorySuite) TestUpdateServerInfoTags(c *C) {
119+
testUpdateServerInfo(c, fixtures.ByURL("https://github.com/git-fixtures/tags.git").One())
120+
}
121+
122+
func (s *RepositorySuite) TestUpdateServerInfoBasic(c *C) {
123+
testUpdateServerInfo(c, fixtures.Basic().One())
124+
}

‎storage/filesystem/reference.go

Copy file name to clipboardExpand all lines: storage/filesystem/reference.go
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package filesystem
22

33
import (
4+
"github.com/go-git/go-git/v5/internal/reference"
45
"github.com/go-git/go-git/v5/plumbing"
56
"github.com/go-git/go-git/v5/plumbing/storer"
67
"github.com/go-git/go-git/v5/storage/filesystem/dotgit"
@@ -28,6 +29,8 @@ func (r *ReferenceStorage) IterReferences() (storer.ReferenceIter, error) {
2829
return nil, err
2930
}
3031

32+
reference.Sort(refs)
33+
3134
return storer.NewReferenceSliceIter(refs), nil
3235
}
3336

‎storage/memory/storage.go

Copy file name to clipboardExpand all lines: storage/memory/storage.go
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"time"
77

88
"github.com/go-git/go-git/v5/config"
9+
"github.com/go-git/go-git/v5/internal/reference"
910
"github.com/go-git/go-git/v5/plumbing"
1011
"github.com/go-git/go-git/v5/plumbing/format/index"
1112
"github.com/go-git/go-git/v5/plumbing/storer"
@@ -283,6 +284,8 @@ func (r ReferenceStorage) IterReferences() (storer.ReferenceIter, error) {
283284
refs = append(refs, ref)
284285
}
285286

287+
reference.Sort(refs)
288+
286289
return storer.NewReferenceSliceIter(refs), nil
287290
}
288291

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.