A read-only clone of the dehub project, for until dehub.dev can be brought back online.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
dehub/repo.go

104 lines
2.7 KiB

// Package dehub TODO needs package docs
package dehub
import (
"dehub/fs"
"errors"
"fmt"
"path/filepath"
"gopkg.in/src-d/go-billy.v4"
"gopkg.in/src-d/go-billy.v4/memfs"
"gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/object"
"gopkg.in/src-d/go-git.v4/storage/memory"
)
const (
// DehubDir defines the name of the directory where all dehub-related files are
// expected to be found.
DehubDir = ".dehub"
)
var (
// ConfigPath defines the expected path to the Repo's configuration file.
ConfigPath = filepath.Join(DehubDir, "config.yml")
)
// Repo is an object which allows accessing and modifying the dehub repo.
type Repo struct {
GitRepo *git.Repository
}
// OpenRepo opens the dehub repo in the given directory and returns the object
// for it.
//
// The given path is expected to have a git repo and .dehub folder already
// initialized.
func OpenRepo(path string) (*Repo, error) {
r := Repo{}
var err error
openOpts := &git.PlainOpenOptions{
DetectDotGit: true,
}
if r.GitRepo, err = git.PlainOpenWithOptions(path, openOpts); err != nil {
return nil, fmt.Errorf("could not open git repo: %w", err)
}
return &r, nil
}
// InitMemRepo initializes an empty repository which only exists in memory.
func InitMemRepo() *Repo {
r, err := git.Init(memory.NewStorage(), memfs.New())
if err != nil {
panic(err)
}
return &Repo{GitRepo: r}
}
func (r *Repo) billyFilesystem() (billy.Filesystem, error) {
w, err := r.GitRepo.Worktree()
if err != nil {
return nil, fmt.Errorf("could not open git worktree: %w", err)
}
return w.Filesystem, nil
}
func (r *Repo) head() (*object.Commit, *object.Tree, error) {
head, err := r.GitRepo.Head()
if err != nil {
return nil, nil, fmt.Errorf("could not get repo HEAD: %w", err)
}
headHash := head.Hash()
headCommit, err := r.GitRepo.CommitObject(headHash)
if err != nil {
return nil, nil, fmt.Errorf("could not get commit at HEAD (%q): %w", headHash, err)
}
headTree, err := r.GitRepo.TreeObject(headCommit.TreeHash)
if err != nil {
return nil, nil, fmt.Errorf("could not get tree object at HEAD (commit:%q tree:%q): %w",
headHash, headCommit.TreeHash, err)
}
return headCommit, headTree, nil
}
// headOrRawFS returns an FS based on the HEAD commit, or if there is no HEAD
// commit (it's an empty repo) an FS based on the raw filesystem.
func (r *Repo) headOrRawFS() (fs.FS, error) {
_, headTree, err := r.head()
if errors.Is(err, plumbing.ErrReferenceNotFound) {
bfs, err := r.billyFilesystem()
if err != nil {
return nil, fmt.Errorf("could not get underlying filesystem: %w", err)
}
return fs.FromBillyFilesystem(bfs), nil
} else if err != nil {
return nil, fmt.Errorf("could not get HEAD tree: %w", err)
}
return fs.FromTree(headTree), nil
}