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
}