code.gitea.io/gitea@v1.21.7/services/repository/files/file.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 "strings" 11 "time" 12 13 repo_model "code.gitea.io/gitea/models/repo" 14 user_model "code.gitea.io/gitea/models/user" 15 "code.gitea.io/gitea/modules/git" 16 api "code.gitea.io/gitea/modules/structs" 17 "code.gitea.io/gitea/modules/util" 18 ) 19 20 func GetFilesResponseFromCommit(ctx context.Context, repo *repo_model.Repository, commit *git.Commit, branch string, treeNames []string) (*api.FilesResponse, error) { 21 files := []*api.ContentsResponse{} 22 for _, file := range treeNames { 23 fileContents, _ := GetContents(ctx, repo, file, branch, false) // ok if fails, then will be nil 24 files = append(files, fileContents) 25 } 26 fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil 27 verification := GetPayloadCommitVerification(ctx, commit) 28 filesResponse := &api.FilesResponse{ 29 Files: files, 30 Commit: fileCommitResponse, 31 Verification: verification, 32 } 33 return filesResponse, nil 34 } 35 36 // GetFileResponseFromCommit Constructs a FileResponse from a Commit object 37 func GetFileResponseFromCommit(ctx context.Context, repo *repo_model.Repository, commit *git.Commit, branch, treeName string) (*api.FileResponse, error) { 38 fileContents, _ := GetContents(ctx, repo, treeName, branch, false) // ok if fails, then will be nil 39 fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil 40 verification := GetPayloadCommitVerification(ctx, commit) 41 fileResponse := &api.FileResponse{ 42 Content: fileContents, 43 Commit: fileCommitResponse, 44 Verification: verification, 45 } 46 return fileResponse, nil 47 } 48 49 // constructs a FileResponse with the file at the index from FilesResponse 50 func GetFileResponseFromFilesResponse(filesResponse *api.FilesResponse, index int) *api.FileResponse { 51 content := &api.ContentsResponse{} 52 if len(filesResponse.Files) > index { 53 content = filesResponse.Files[index] 54 } 55 fileResponse := &api.FileResponse{ 56 Content: content, 57 Commit: filesResponse.Commit, 58 Verification: filesResponse.Verification, 59 } 60 return fileResponse 61 } 62 63 // GetFileCommitResponse Constructs a FileCommitResponse from a Commit object 64 func GetFileCommitResponse(repo *repo_model.Repository, commit *git.Commit) (*api.FileCommitResponse, error) { 65 if repo == nil { 66 return nil, fmt.Errorf("repo cannot be nil") 67 } 68 if commit == nil { 69 return nil, fmt.Errorf("commit cannot be nil") 70 } 71 commitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + url.PathEscape(commit.ID.String())) 72 commitTreeURL, _ := url.Parse(repo.APIURL() + "/git/trees/" + url.PathEscape(commit.Tree.ID.String())) 73 parents := make([]*api.CommitMeta, commit.ParentCount()) 74 for i := 0; i <= commit.ParentCount(); i++ { 75 if parent, err := commit.Parent(i); err == nil && parent != nil { 76 parentCommitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + url.PathEscape(parent.ID.String())) 77 parents[i] = &api.CommitMeta{ 78 SHA: parent.ID.String(), 79 URL: parentCommitURL.String(), 80 } 81 } 82 } 83 commitHTMLURL, _ := url.Parse(repo.HTMLURL() + "/commit/" + url.PathEscape(commit.ID.String())) 84 fileCommit := &api.FileCommitResponse{ 85 CommitMeta: api.CommitMeta{ 86 SHA: commit.ID.String(), 87 URL: commitURL.String(), 88 }, 89 HTMLURL: commitHTMLURL.String(), 90 Author: &api.CommitUser{ 91 Identity: api.Identity{ 92 Name: commit.Author.Name, 93 Email: commit.Author.Email, 94 }, 95 Date: commit.Author.When.UTC().Format(time.RFC3339), 96 }, 97 Committer: &api.CommitUser{ 98 Identity: api.Identity{ 99 Name: commit.Committer.Name, 100 Email: commit.Committer.Email, 101 }, 102 Date: commit.Committer.When.UTC().Format(time.RFC3339), 103 }, 104 Message: commit.Message(), 105 Tree: &api.CommitMeta{ 106 URL: commitTreeURL.String(), 107 SHA: commit.Tree.ID.String(), 108 }, 109 Parents: parents, 110 } 111 return fileCommit, nil 112 } 113 114 // GetAuthorAndCommitterUsers Gets the author and committer user objects from the IdentityOptions 115 func GetAuthorAndCommitterUsers(author, committer *IdentityOptions, doer *user_model.User) (authorUser, committerUser *user_model.User) { 116 // Committer and author are optional. If they are not the doer (not same email address) 117 // then we use bogus User objects for them to store their FullName and Email. 118 // If only one of the two are provided, we set both of them to it. 119 // If neither are provided, both are the doer. 120 if committer != nil && committer.Email != "" { 121 if doer != nil && strings.EqualFold(doer.Email, committer.Email) { 122 committerUser = doer // the committer is the doer, so will use their user object 123 if committer.Name != "" { 124 committerUser.FullName = committer.Name 125 } 126 } else { 127 committerUser = &user_model.User{ 128 FullName: committer.Name, 129 Email: committer.Email, 130 } 131 } 132 } 133 if author != nil && author.Email != "" { 134 if doer != nil && strings.EqualFold(doer.Email, author.Email) { 135 authorUser = doer // the author is the doer, so will use their user object 136 if authorUser.Name != "" { 137 authorUser.FullName = author.Name 138 } 139 } else { 140 authorUser = &user_model.User{ 141 FullName: author.Name, 142 Email: author.Email, 143 } 144 } 145 } 146 if authorUser == nil { 147 if committerUser != nil { 148 authorUser = committerUser // No valid author was given so use the committer 149 } else if doer != nil { 150 authorUser = doer // No valid author was given and no valid committer so use the doer 151 } 152 } 153 if committerUser == nil { 154 committerUser = authorUser // No valid committer so use the author as the committer (was set to a valid user above) 155 } 156 return authorUser, committerUser 157 } 158 159 // CleanUploadFileName Trims a filename and returns empty string if it is a .git directory 160 func CleanUploadFileName(name string) string { 161 // Rebase the filename 162 name = util.PathJoinRel(name) 163 // Git disallows any filenames to have a .git directory in them. 164 for _, part := range strings.Split(name, "/") { 165 if strings.ToLower(part) == ".git" { 166 return "" 167 } 168 } 169 return name 170 }