aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/serverinfo/serverinfo.go
diff options
context:
space:
mode:
Diffstat (limited to 'plumbing/serverinfo/serverinfo.go')
-rw-r--r--plumbing/serverinfo/serverinfo.go94
1 files changed, 94 insertions, 0 deletions
diff --git a/plumbing/serverinfo/serverinfo.go b/plumbing/serverinfo/serverinfo.go
new file mode 100644
index 0000000..d7ea7ef
--- /dev/null
+++ b/plumbing/serverinfo/serverinfo.go
@@ -0,0 +1,94 @@
+package serverinfo
+
+import (
+ "fmt"
+
+ "github.com/go-git/go-billy/v5"
+ "github.com/go-git/go-git/v5"
+ "github.com/go-git/go-git/v5/internal/reference"
+ "github.com/go-git/go-git/v5/plumbing"
+ "github.com/go-git/go-git/v5/plumbing/object"
+ "github.com/go-git/go-git/v5/plumbing/storer"
+ "github.com/go-git/go-git/v5/storage"
+)
+
+// UpdateServerInfo updates the server info files in the repository.
+//
+// It generates a list of available refs for the repository.
+// Used by git http transport (dumb), for more information refer to:
+// https://git-scm.com/book/id/v2/Git-Internals-Transfer-Protocols#_the_dumb_protocol
+func UpdateServerInfo(s storage.Storer, fs billy.Filesystem) error {
+ pos, ok := s.(storer.PackedObjectStorer)
+ if !ok {
+ return git.ErrPackedObjectsNotSupported
+ }
+
+ infoRefs, err := fs.Create("info/refs")
+ if err != nil {
+ return err
+ }
+
+ defer infoRefs.Close()
+
+ refsIter, err := s.IterReferences()
+ if err != nil {
+ return err
+ }
+
+ defer refsIter.Close()
+
+ var refs []*plumbing.Reference
+ if err := refsIter.ForEach(func(ref *plumbing.Reference) error {
+ refs = append(refs, ref)
+ return nil
+ }); err != nil {
+ return err
+ }
+
+ reference.Sort(refs)
+ for _, ref := range refs {
+ name := ref.Name()
+ hash := ref.Hash()
+ switch ref.Type() {
+ case plumbing.SymbolicReference:
+ if name == plumbing.HEAD {
+ continue
+ }
+ ref, err := s.Reference(ref.Target())
+ if err != nil {
+ return err
+ }
+
+ hash = ref.Hash()
+ fallthrough
+ case plumbing.HashReference:
+ fmt.Fprintf(infoRefs, "%s\t%s\n", hash, name)
+ if name.IsTag() {
+ tag, err := object.GetTag(s, hash)
+ if err == nil {
+ fmt.Fprintf(infoRefs, "%s\t%s^{}\n", tag.Target, name)
+ }
+ }
+ }
+ }
+
+ infoPacks, err := fs.Create("objects/info/packs")
+ if err != nil {
+ return err
+ }
+
+ defer infoPacks.Close()
+
+ packs, err := pos.ObjectPacks()
+ if err != nil {
+ return err
+ }
+
+ for _, p := range packs {
+ fmt.Fprintf(infoPacks, "P pack-%s.pack\n", p)
+ }
+
+ fmt.Fprintln(infoPacks)
+
+ return nil
+}