|
|
@ -3,11 +3,13 @@ package dehub |
|
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
import ( |
|
|
|
"bytes" |
|
|
|
"bytes" |
|
|
|
|
|
|
|
"encoding/hex" |
|
|
|
"errors" |
|
|
|
"errors" |
|
|
|
"fmt" |
|
|
|
"fmt" |
|
|
|
"io" |
|
|
|
"io" |
|
|
|
"os" |
|
|
|
"os" |
|
|
|
"path/filepath" |
|
|
|
"path/filepath" |
|
|
|
|
|
|
|
"strings" |
|
|
|
|
|
|
|
|
|
|
|
"dehub.dev/src/dehub.git/fs" |
|
|
|
"dehub.dev/src/dehub.git/fs" |
|
|
|
|
|
|
|
|
|
|
@ -354,21 +356,6 @@ func (r *Repo) GetGitCommit(h plumbing.Hash) (gc GitCommit, err error) { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// GetGitRevision resolves the revision and returns the GitCommit it references.
|
|
|
|
|
|
|
|
func (r *Repo) GetGitRevision(rev plumbing.Revision) (GitCommit, error) { |
|
|
|
|
|
|
|
// This returns a pointer for some reason, not sure why.
|
|
|
|
|
|
|
|
h, err := r.GitRepo.ResolveRevision(rev) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return GitCommit{}, fmt.Errorf("resolving revision: %w", err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gc, err := r.GetGitCommit(*h) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return GitCommit{}, fmt.Errorf("getting commit %q: %w", *h, err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return gc, nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ErrHeadIsZero is used to indicate that HEAD resolves to the zero hash. An
|
|
|
|
// ErrHeadIsZero is used to indicate that HEAD resolves to the zero hash. An
|
|
|
|
// example of when this can happen is if the repo was just initialized and has
|
|
|
|
// example of when this can happen is if the repo was just initialized and has
|
|
|
|
// no commits, or if an orphan branch is checked out.
|
|
|
|
// no commits, or if an orphan branch is checked out.
|
|
|
@ -436,10 +423,85 @@ func (r *Repo) GetGitCommitRange(start, end plumbing.Hash) ([]GitCommit, error) |
|
|
|
return commits, nil |
|
|
|
return commits, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
|
|
|
hashLen = len(plumbing.ZeroHash) |
|
|
|
|
|
|
|
hashStrLen = len(plumbing.ZeroHash.String()) |
|
|
|
|
|
|
|
errNotHex = errors.New("not a valid hex string") |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (r *Repo) findCommitByShortHash(hashStr string) (plumbing.Hash, error) { |
|
|
|
|
|
|
|
paddedHashStr := hashStr |
|
|
|
|
|
|
|
if len(hashStr)%2 > 0 { |
|
|
|
|
|
|
|
paddedHashStr += "0" |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if hashB, err := hex.DecodeString(paddedHashStr); err != nil { |
|
|
|
|
|
|
|
return plumbing.ZeroHash, errNotHex |
|
|
|
|
|
|
|
} else if len(hashStr) == hashStrLen { |
|
|
|
|
|
|
|
var hash plumbing.Hash |
|
|
|
|
|
|
|
copy(hash[:], hashB) |
|
|
|
|
|
|
|
return hash, nil |
|
|
|
|
|
|
|
} else if len(hashStr) < 2 { |
|
|
|
|
|
|
|
return plumbing.ZeroHash, errors.New("hash string must be 2 characters long or more") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for i := 2; i < hashStrLen; i++ { |
|
|
|
|
|
|
|
hashPrefix, hashTail := hashStr[:i], hashStr[i:] |
|
|
|
|
|
|
|
path := filepath.Join("objects", hashPrefix) |
|
|
|
|
|
|
|
fileInfos, err := r.GitDirFS.ReadDir(path) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return plumbing.ZeroHash, fmt.Errorf("listing files in %q: %w", path, err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var matchedHash plumbing.Hash |
|
|
|
|
|
|
|
for _, fileInfo := range fileInfos { |
|
|
|
|
|
|
|
objFileName := fileInfo.Name() |
|
|
|
|
|
|
|
if !strings.HasPrefix(objFileName, hashTail) { |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
objHash := plumbing.NewHash(hashPrefix + objFileName) |
|
|
|
|
|
|
|
obj, err := r.GitRepo.Storer.EncodedObject(plumbing.AnyObject, objHash) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return plumbing.ZeroHash, fmt.Errorf("reading object %q off disk: %w", objHash, err) |
|
|
|
|
|
|
|
} else if obj.Type() != plumbing.CommitObject { |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if matchedHash == plumbing.ZeroHash { |
|
|
|
|
|
|
|
matchedHash = objHash |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return plumbing.ZeroHash, fmt.Errorf("both %q and %q match", matchedHash, objHash) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if matchedHash != plumbing.ZeroHash { |
|
|
|
|
|
|
|
return matchedHash, nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return plumbing.ZeroHash, errors.New("failed to find a commit object with a matching prefix") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (r *Repo) resolveRev(rev plumbing.Revision) (plumbing.Hash, error) { |
|
|
|
func (r *Repo) resolveRev(rev plumbing.Revision) (plumbing.Hash, error) { |
|
|
|
if rev == plumbing.Revision(plumbing.ZeroHash.String()) { |
|
|
|
if rev == plumbing.Revision(plumbing.ZeroHash.String()) { |
|
|
|
return plumbing.ZeroHash, nil |
|
|
|
return plumbing.ZeroHash, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// pretend the revision is a short hash until proven otherwise
|
|
|
|
|
|
|
|
shortHash := string(rev) |
|
|
|
|
|
|
|
hash, err := r.findCommitByShortHash(shortHash) |
|
|
|
|
|
|
|
if errors.Is(err, errNotHex) { |
|
|
|
|
|
|
|
// ok, continue
|
|
|
|
|
|
|
|
} else if err != nil { |
|
|
|
|
|
|
|
return plumbing.ZeroHash, fmt.Errorf("resolving as short hash: %w", err) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// guess it _is_ a short hash, knew it!
|
|
|
|
|
|
|
|
return hash, nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
h, err := r.GitRepo.ResolveRevision(rev) |
|
|
|
h, err := r.GitRepo.ResolveRevision(rev) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return plumbing.ZeroHash, fmt.Errorf("resolving revision %q: %w", rev, err) |
|
|
|
return plumbing.ZeroHash, fmt.Errorf("resolving revision %q: %w", rev, err) |
|
|
@ -447,6 +509,20 @@ func (r *Repo) resolveRev(rev plumbing.Revision) (plumbing.Hash, error) { |
|
|
|
return *h, nil |
|
|
|
return *h, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// GetGitRevision resolves the revision and returns the GitCommit it references.
|
|
|
|
|
|
|
|
func (r *Repo) GetGitRevision(rev plumbing.Revision) (GitCommit, error) { |
|
|
|
|
|
|
|
hash, err := r.resolveRev(rev) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return GitCommit{}, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gc, err := r.GetGitCommit(hash) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return GitCommit{}, fmt.Errorf("getting commit %q: %w", hash, err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return gc, nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// GetGitRevisionRange is like GetGitCommitRange, first resolving the given
|
|
|
|
// GetGitRevisionRange is like GetGitCommitRange, first resolving the given
|
|
|
|
// revisions into hashes before continuing with GetGitCommitRange's behavior.
|
|
|
|
// revisions into hashes before continuing with GetGitCommitRange's behavior.
|
|
|
|
func (r *Repo) GetGitRevisionRange(startRev, endRev plumbing.Revision) ([]GitCommit, error) { |
|
|
|
func (r *Repo) GetGitRevisionRange(startRev, endRev plumbing.Revision) ([]GitCommit, error) { |
|
|
|