code.gitea.io/gitea@v1.21.7/services/repository/files/tree.go (about) 1 // Copyright 2019 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package files 5 6 import ( 7 "context" 8 "fmt" 9 "net/url" 10 11 "code.gitea.io/gitea/models" 12 repo_model "code.gitea.io/gitea/models/repo" 13 "code.gitea.io/gitea/modules/git" 14 "code.gitea.io/gitea/modules/setting" 15 api "code.gitea.io/gitea/modules/structs" 16 ) 17 18 // GetTreeBySHA get the GitTreeResponse of a repository using a sha hash. 19 func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, sha string, page, perPage int, recursive bool) (*api.GitTreeResponse, error) { 20 gitTree, err := gitRepo.GetTree(sha) 21 if err != nil || gitTree == nil { 22 return nil, models.ErrSHANotFound{ 23 SHA: sha, 24 } 25 } 26 tree := new(api.GitTreeResponse) 27 tree.SHA = gitTree.ResolvedID.String() 28 tree.URL = repo.APIURL() + "/git/trees/" + url.PathEscape(tree.SHA) 29 var entries git.Entries 30 if recursive { 31 entries, err = gitTree.ListEntriesRecursiveWithSize() 32 } else { 33 entries, err = gitTree.ListEntries() 34 } 35 if err != nil { 36 return nil, err 37 } 38 apiURL := repo.APIURL() 39 apiURLLen := len(apiURL) 40 41 // 51 is len(sha1) + len("/git/blobs/"). 40 + 11. 42 blobURL := make([]byte, apiURLLen+51) 43 copy(blobURL, apiURL) 44 copy(blobURL[apiURLLen:], "/git/blobs/") 45 46 // 51 is len(sha1) + len("/git/trees/"). 40 + 11. 47 treeURL := make([]byte, apiURLLen+51) 48 copy(treeURL, apiURL) 49 copy(treeURL[apiURLLen:], "/git/trees/") 50 51 // 40 is the size of the sha1 hash in hexadecimal format. 52 copyPos := len(treeURL) - git.SHAFullLength 53 54 if perPage <= 0 || perPage > setting.API.DefaultGitTreesPerPage { 55 perPage = setting.API.DefaultGitTreesPerPage 56 } 57 if page <= 0 { 58 page = 1 59 } 60 tree.Page = page 61 tree.TotalCount = len(entries) 62 rangeStart := perPage * (page - 1) 63 if rangeStart >= len(entries) { 64 return tree, nil 65 } 66 var rangeEnd int 67 if len(entries) > perPage { 68 tree.Truncated = true 69 } 70 if rangeStart+perPage < len(entries) { 71 rangeEnd = rangeStart + perPage 72 } else { 73 rangeEnd = len(entries) 74 } 75 tree.Entries = make([]api.GitEntry, rangeEnd-rangeStart) 76 for e := rangeStart; e < rangeEnd; e++ { 77 i := e - rangeStart 78 79 tree.Entries[i].Path = entries[e].Name() 80 tree.Entries[i].Mode = fmt.Sprintf("%06o", entries[e].Mode()) 81 tree.Entries[i].Type = entries[e].Type() 82 tree.Entries[i].Size = entries[e].Size() 83 tree.Entries[i].SHA = entries[e].ID.String() 84 85 if entries[e].IsDir() { 86 copy(treeURL[copyPos:], entries[e].ID.String()) 87 tree.Entries[i].URL = string(treeURL) 88 } else if entries[e].IsSubModule() { 89 // In Github Rest API Version=2022-11-28, if a tree entry is a submodule, 90 // its url will be returned as an empty string. 91 // So the URL will be set to "" here. 92 tree.Entries[i].URL = "" 93 } else { 94 copy(blobURL[copyPos:], entries[e].ID.String()) 95 tree.Entries[i].URL = string(blobURL) 96 } 97 } 98 return tree, nil 99 }