mirror of
https://github.com/fiatjaf/nak.git
synced 2026-10-05 15:18:23 +00:00
git: resolve refs and paths in 'download' the same way 'ls' and 'cat' do.
This commit is contained in:
@@ -509,66 +509,26 @@ aside from those, there is also:
|
|||||||
log("attempting download from %s... ", printUrl)
|
log("attempting download from %s... ", printUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := gitnaturalapi.GetInfoRefs(url)
|
commitHash, err := resolveGitNaturalRef(url, ref, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lastErr = err
|
lastErr = err
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var commitHash string
|
depth := gitPathDepth(path)
|
||||||
|
tree, err := gitnaturalapi.GetDirectoryTreeAt(url, commitHash, &depth)
|
||||||
if ref == "" {
|
|
||||||
if symref, ok := info.Symrefs["HEAD"]; ok && symref != "" {
|
|
||||||
commitHash, _ = info.Refs[symref]
|
|
||||||
} else if head, ok := info.Refs["HEAD"]; ok && head != "" {
|
|
||||||
commitHash = head
|
|
||||||
} else {
|
|
||||||
lastErr = fmt.Errorf("could not resolve default ref for %s", url)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if gitHashRe.MatchString(ref) {
|
|
||||||
commitHash = ref
|
|
||||||
} else if strings.HasPrefix(ref, "refs/") {
|
|
||||||
if ch, ok := info.Refs[ref]; ok {
|
|
||||||
commitHash = ch
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ch, ok := info.Refs["refs/heads/"+ref]; ok {
|
|
||||||
commitHash = ch
|
|
||||||
} else if ch, ok := info.Refs["refs/tags/"+ref]; ok {
|
|
||||||
commitHash = ch
|
|
||||||
} else if sr, ok := info.Symrefs[ref]; ok {
|
|
||||||
commitHash = info.Refs[sr]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if commitHash == "" {
|
|
||||||
lastErr = fmt.Errorf("couldn't get a commit hash for ref '%s'", ref)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !gitHashRe.MatchString(commitHash) {
|
|
||||||
lastErr = fmt.Errorf("couldn't invalid commit hash for ref '%s': '%s'", ref, commitHash)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
entry, err := gitnaturalapi.GetObjectByPath(url, commitHash, path)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lastErr = err
|
lastErr = err
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if entry == nil {
|
|
||||||
lastErr = fmt.Errorf("path '%s' not found", path)
|
hash, err := gitBlobHashInTree(tree, path)
|
||||||
continue
|
if err != nil {
|
||||||
}
|
lastErr = err
|
||||||
if entry.IsDir {
|
|
||||||
lastErr = fmt.Errorf("path '%s' is a directory", path)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := gitnaturalapi.GetObject(url, entry.Hash)
|
obj, err := gitnaturalapi.GetObject(url, hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lastErr = fmt.Errorf("download error: %s", err)
|
lastErr = fmt.Errorf("download error: %s", err)
|
||||||
continue
|
continue
|
||||||
@@ -717,40 +677,16 @@ aside from those, there is also:
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// the path is walked here instead of with GetObjectByPath()
|
depth := gitPathDepth(path)
|
||||||
// because that also treats '\' as a separator, while in git
|
|
||||||
// path names a backslash is just a regular character
|
|
||||||
segments := strings.Split(strings.Trim(path, "/"), "/")
|
|
||||||
name := segments[len(segments)-1]
|
|
||||||
|
|
||||||
depth := len(segments)
|
|
||||||
tree, err := gitnaturalapi.GetDirectoryTreeAt(url, commit, &depth)
|
tree, err := gitnaturalapi.GetDirectoryTreeAt(url, commit, &depth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lastErr = err
|
lastErr = err
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(segments) > 1 {
|
hash, err := gitBlobHashInTree(tree, path)
|
||||||
tree, err = gitTreeAtPath(tree, strings.Join(segments[:len(segments)-1], "/"))
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hash := ""
|
|
||||||
for _, file := range tree.Files {
|
|
||||||
if file.Name == name {
|
|
||||||
hash = file.Hash
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if hash == "" {
|
|
||||||
for _, dir := range tree.Directories {
|
|
||||||
if dir.Name == name {
|
|
||||||
return fmt.Errorf("path '%s' is a directory", path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("path '%s' not found", path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := gitnaturalapi.GetObject(url, hash)
|
obj, err := gitnaturalapi.GetObject(url, hash)
|
||||||
@@ -3960,6 +3896,40 @@ func resolveGitNaturalRef(url string, ref string, state *nip34.RepositoryState)
|
|||||||
|
|
||||||
// gitTreeAtPath navigates a fully loaded git tree to the directory at the given
|
// gitTreeAtPath navigates a fully loaded git tree to the directory at the given
|
||||||
// path, failing if any segment is a file or doesn't exist.
|
// path, failing if any segment is a file or doesn't exist.
|
||||||
|
// gitPathDepth is how deep a tree has to be fetched to resolve the given path.
|
||||||
|
func gitPathDepth(path string) int {
|
||||||
|
return len(strings.Split(strings.Trim(path, "/"), "/"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// gitBlobHashInTree resolves the last segment of path to a blob hash in an
|
||||||
|
// already fetched tree. it splits on '/' only, unlike the api's
|
||||||
|
// GetObjectByPath(), which also treats a backslash as a separator even though
|
||||||
|
// in git a backslash is just a regular character in a path name.
|
||||||
|
func gitBlobHashInTree(tree *gitnaturalapi.Tree, path string) (string, error) {
|
||||||
|
segments := strings.Split(strings.Trim(path, "/"), "/")
|
||||||
|
name := segments[len(segments)-1]
|
||||||
|
|
||||||
|
if len(segments) > 1 {
|
||||||
|
var err error
|
||||||
|
tree, err = gitTreeAtPath(tree, strings.Join(segments[:len(segments)-1], "/"))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range tree.Files {
|
||||||
|
if file.Name == name {
|
||||||
|
return file.Hash, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, dir := range tree.Directories {
|
||||||
|
if dir.Name == name {
|
||||||
|
return "", fmt.Errorf("path '%s' is a directory", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("path '%s' not found", path)
|
||||||
|
}
|
||||||
|
|
||||||
func gitTreeAtPath(tree *gitnaturalapi.Tree, path string) (*gitnaturalapi.Tree, error) {
|
func gitTreeAtPath(tree *gitnaturalapi.Tree, path string) (*gitnaturalapi.Tree, error) {
|
||||||
path = strings.Trim(path, "/")
|
path = strings.Trim(path, "/")
|
||||||
if path == "" {
|
if path == "" {
|
||||||
|
|||||||
Reference in New Issue
Block a user