| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- // Copyright 2019 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package files
-
- import (
- "context"
- "errors"
- "fmt"
- "net/url"
- "strings"
- "time"
-
- repo_model "code.gitea.io/gitea/models/repo"
- "code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/setting"
- api "code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/modules/util"
- "code.gitea.io/gitea/routers/api/v1/utils"
- )
-
- func GetContentsListFromTreePaths(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, refCommit *utils.RefCommit, treePaths []string) (files []*api.ContentsResponse) {
- var size int64
- for _, treePath := range treePaths {
- // ok if fails, then will be nil
- fileContents, _ := GetFileContents(ctx, repo, gitRepo, refCommit, GetContentsOrListOptions{
- TreePath: treePath,
- IncludeSingleFileContent: true,
- IncludeCommitMetadata: true,
- })
- if fileContents != nil && fileContents.Content != nil && *fileContents.Content != "" {
- // if content isn't empty (e.g., due to the single blob being too large), add file size to response size
- size += int64(len(*fileContents.Content))
- }
- if size > setting.API.DefaultMaxResponseSize {
- break // stop if max response size would be exceeded
- }
- files = append(files, fileContents)
- if len(files) == setting.API.DefaultPagingNum {
- break // stop if paging num reached
- }
- }
- return files
- }
-
- func GetFilesResponseFromCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, refCommit *utils.RefCommit, treeNames []string) (*api.FilesResponse, error) {
- files := GetContentsListFromTreePaths(ctx, repo, gitRepo, refCommit, treeNames)
- fileCommitResponse, _ := GetFileCommitResponse(repo, refCommit.Commit) // ok if fails, then will be nil
- verification := GetPayloadCommitVerification(ctx, refCommit.Commit)
- filesResponse := &api.FilesResponse{
- Files: files,
- Commit: fileCommitResponse,
- Verification: verification,
- }
- return filesResponse, nil
- }
-
- // constructs a FileResponse with the file at the index from FilesResponse
- func GetFileResponseFromFilesResponse(filesResponse *api.FilesResponse, index int) *api.FileResponse {
- content := &api.ContentsResponse{}
- if len(filesResponse.Files) > index {
- content = filesResponse.Files[index]
- }
- fileResponse := &api.FileResponse{
- Content: content,
- Commit: filesResponse.Commit,
- Verification: filesResponse.Verification,
- }
- return fileResponse
- }
-
- // GetFileCommitResponse Constructs a FileCommitResponse from a Commit object
- func GetFileCommitResponse(repo *repo_model.Repository, commit *git.Commit) (*api.FileCommitResponse, error) {
- if repo == nil {
- return nil, errors.New("repo cannot be nil")
- }
- if commit == nil {
- return nil, errors.New("commit cannot be nil")
- }
- commitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + url.PathEscape(commit.ID.String()))
- commitTreeURL, _ := url.Parse(repo.APIURL() + "/git/trees/" + url.PathEscape(commit.Tree.ID.String()))
- parents := make([]*api.CommitMeta, commit.ParentCount())
- for i := 0; i <= commit.ParentCount(); i++ {
- if parent, err := commit.Parent(i); err == nil && parent != nil {
- parentCommitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + url.PathEscape(parent.ID.String()))
- parents[i] = &api.CommitMeta{
- SHA: parent.ID.String(),
- URL: parentCommitURL.String(),
- }
- }
- }
- commitHTMLURL, _ := url.Parse(repo.HTMLURL() + "/commit/" + url.PathEscape(commit.ID.String()))
- fileCommit := &api.FileCommitResponse{
- CommitMeta: api.CommitMeta{
- SHA: commit.ID.String(),
- URL: commitURL.String(),
- },
- HTMLURL: commitHTMLURL.String(),
- Author: &api.CommitUser{
- Identity: api.Identity{
- Name: commit.Author.Name,
- Email: commit.Author.Email,
- },
- Date: commit.Author.When.UTC().Format(time.RFC3339),
- },
- Committer: &api.CommitUser{
- Identity: api.Identity{
- Name: commit.Committer.Name,
- Email: commit.Committer.Email,
- },
- Date: commit.Committer.When.UTC().Format(time.RFC3339),
- },
- Message: commit.Message(),
- Tree: &api.CommitMeta{
- URL: commitTreeURL.String(),
- SHA: commit.Tree.ID.String(),
- },
- Parents: parents,
- }
- return fileCommit, nil
- }
-
- // ErrFilenameInvalid represents a "FilenameInvalid" kind of error.
- type ErrFilenameInvalid struct {
- Path string
- }
-
- // IsErrFilenameInvalid checks if an error is an ErrFilenameInvalid.
- func IsErrFilenameInvalid(err error) bool {
- _, ok := err.(ErrFilenameInvalid)
- return ok
- }
-
- func (err ErrFilenameInvalid) Error() string {
- return fmt.Sprintf("path contains a malformed path component [path: %s]", err.Path)
- }
-
- func (err ErrFilenameInvalid) Unwrap() error {
- return util.ErrInvalidArgument
- }
-
- // CleanGitTreePath cleans a tree path for git, it returns an empty string the path is invalid (e.g.: contains ".git" part)
- func CleanGitTreePath(name string) string {
- name = util.PathJoinRel(name)
- // Git disallows any filenames to have a .git directory in them.
- for part := range strings.SplitSeq(name, "/") {
- if strings.EqualFold(part, ".git") {
- return ""
- }
- }
- if name == "." {
- name = ""
- }
- return name
- }
|