mirror of
https://github.com/hanzoai/forge.git
synced 2026-10-30 15:00:39 +00:00
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in NOTICE, alongside LICENSE. The header lint accepts any copyright line above the SPDX line, so it no longer demands an upstream one. Co-authored-by: Hanzo Dev <[email protected]>
140 lines
3.2 KiB
Go
140 lines
3.2 KiB
Go
// Copyright 2026 Hanzo AI, Inc. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
//go:build !gogit
|
|
|
|
package git
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"strings"
|
|
|
|
"github.com/hanzoai/git/modules/git/gitcmd"
|
|
"github.com/hanzoai/git/modules/log"
|
|
)
|
|
|
|
// ResolveReference resolves a name to a reference
|
|
func (repo *Repository) ResolveReference(name string) (string, error) {
|
|
stdout, _, err := gitcmd.NewCommand("show-ref", "--hash").
|
|
AddDynamicArguments(name).
|
|
WithDir(repo.Path).
|
|
RunStdString(repo.Ctx)
|
|
if err != nil {
|
|
if strings.Contains(err.Error(), "not a valid ref") {
|
|
return "", ErrNotExist{name, ""}
|
|
}
|
|
return "", err
|
|
}
|
|
stdout = strings.TrimSpace(stdout)
|
|
if stdout == "" {
|
|
return "", ErrNotExist{name, ""}
|
|
}
|
|
|
|
return stdout, nil
|
|
}
|
|
|
|
// GetRefCommitID returns the last commit ID string of given reference (branch or tag).
|
|
func (repo *Repository) GetRefCommitID(name string) (string, error) {
|
|
batch, cancel, err := repo.CatFileBatch(repo.Ctx)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer cancel()
|
|
info, err := batch.QueryInfo(name)
|
|
if IsErrNotExist(err) {
|
|
return "", ErrNotExist{name, ""}
|
|
} else if err != nil {
|
|
return "", err
|
|
}
|
|
return info.ID, nil
|
|
}
|
|
|
|
func (repo *Repository) getCommit(id ObjectID) (*Commit, error) {
|
|
batch, cancel, err := repo.CatFileBatch(repo.Ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer cancel()
|
|
return repo.getCommitWithBatch(batch, id)
|
|
}
|
|
|
|
func (repo *Repository) getCommitWithBatch(batch CatFileBatch, id ObjectID) (*Commit, error) {
|
|
info, rd, err := batch.QueryContent(id.String())
|
|
if err != nil {
|
|
if errors.Is(err, io.EOF) || IsErrNotExist(err) {
|
|
return nil, ErrNotExist{ID: id.String()}
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
switch info.Type {
|
|
case "missing":
|
|
return nil, ErrNotExist{ID: id.String()}
|
|
case "tag":
|
|
// then we need to parse the tag
|
|
// and load the commit
|
|
data, err := io.ReadAll(io.LimitReader(rd, info.Size))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
_, err = rd.Discard(1)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
tag, err := parseTagData(id.Type(), data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return repo.getCommitWithBatch(batch, tag.Object)
|
|
case "commit":
|
|
commit, err := CommitFromReader(id, io.LimitReader(rd, info.Size))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
_, err = rd.Discard(1)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return commit, nil
|
|
default:
|
|
log.Debug("Unknown cat-file object type: %s", info.Type)
|
|
if err := DiscardFull(rd, info.Size+1); err != nil {
|
|
return nil, err
|
|
}
|
|
return nil, ErrNotExist{
|
|
ID: id.String(),
|
|
}
|
|
}
|
|
}
|
|
|
|
// ConvertToGitID returns a git object ID from the git ref, it doesn't guarantee the returned ID really exists
|
|
func (repo *Repository) ConvertToGitID(ref string) (ObjectID, error) {
|
|
objectFormat, err := repo.GetObjectFormat()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(ref) == objectFormat.FullLength() && objectFormat.IsValid(ref) {
|
|
id, err := NewIDFromString(ref)
|
|
if err == nil {
|
|
return id, nil
|
|
}
|
|
}
|
|
|
|
batch, cancel, err := repo.CatFileBatch(repo.Ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer cancel()
|
|
info, err := batch.QueryInfo(ref)
|
|
if err != nil {
|
|
if IsErrNotExist(err) {
|
|
return nil, ErrNotExist{ref, ""}
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
return MustIDFromString(info.ID), nil
|
|
}
|