// Copyright 2019 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package repofiles import ( "fmt" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" ) // GetTreeBySHA get the GitTreeResponse of a repository using a sha hash. func GetTreeBySHA(repo *models.Repository, sha string, page, perPage int, recursive bool) (*api.GitTreeResponse, error) { gitRepo, err := git.OpenRepository(repo.RepoPath()) if err != nil { return nil, err } defer gitRepo.Close() gitTree, err := gitRepo.GetTree(sha) if err != nil || gitTree == nil { return nil, models.ErrSHANotFound{ SHA: sha, } } tree := new(api.GitTreeResponse) tree.SHA = gitTree.ResolvedID.String() tree.URL = repo.APIURL() + "/git/trees/" + tree.SHA var entries git.Entries if recursive { entries, err = gitTree.ListEntriesRecursive() } else { entries, err = gitTree.ListEntries() } if err != nil { return nil, err } apiURL := repo.APIURL() apiURLLen := len(apiURL) // 51 is len(sha1) + len("/git/blobs/"). 40 + 11. blobURL := make([]byte, apiURLLen+51) copy(blobURL, apiURL) copy(blobURL[apiURLLen:], "/git/blobs/") // 51 is len(sha1) + len("/git/trees/"). 40 + 11. treeURL := make([]byte, apiURLLen+51) copy(treeURL, apiURL) copy(treeURL[apiURLLen:], "/git/trees/") // 40 is the size of the sha1 hash in hexadecimal format. copyPos := len(treeURL) - 40 if perPage <= 0 || perPage > setting.API.DefaultGitTreesPerPage { perPage = setting.API.DefaultGitTreesPerPage } if page <= 0 { page = 1 } tree.Page = page tree.TotalCount = len(entries) rangeStart := perPage * (page - 1) if rangeStart >= len(entries) { return tree, nil } var rangeEnd int if len(entries) > perPage { tree.Truncated = true } if rangeStart+perPage < len(entries) { rangeEnd = rangeStart + perPage } else { rangeEnd = len(entries) } tree.Entries = make([]api.GitEntry, rangeEnd-rangeStart) for e := rangeStart; e < rangeEnd; e++ { i := e - rangeStart tree.Entries[i].Path = entries[e].Name() tree.Entries[i].Mode = fmt.Sprintf("%06o", entries[e].Mode()) tree.Entries[i].Type = entries[e].Type() tree.Entries[i].Size = entries[e].Size() tree.Entries[i].SHA = entries[e].ID.String() if entries[e].IsDir() { copy(treeURL[copyPos:], entries[e].ID.String()) tree.Entries[i].URL = string(treeURL) } else { copy(blobURL[copyPos:], entries[e].ID.String()) tree.Entries[i].URL = string(blobURL) } } return tree, nil }