0
Fork 0
mirror of https://codeberg.org/forgejo/forgejo.git synced 2025-02-03 12:19:28 -05:00
forgejo/services/repository/files/file.go
zeripath 5cb0c9aa0d
Propagate context and ensure git commands run in request context ()
This PR continues the work in  by progressively ensuring that git
commands run within the request context.

This now means that the if there is a git repo already open in the context it will be used instead of reopening it.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-01-19 23:26:57 +00:00

141 lines
4.8 KiB
Go

// 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 files
import (
"context"
"fmt"
"net/url"
"path"
"strings"
"time"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
api "code.gitea.io/gitea/modules/structs"
)
// GetFileResponseFromCommit Constructs a FileResponse from a Commit object
func GetFileResponseFromCommit(ctx context.Context, repo *repo_model.Repository, commit *git.Commit, branch, treeName string) (*api.FileResponse, error) {
fileContents, _ := GetContents(ctx, repo, treeName, branch, false) // ok if fails, then will be nil
fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil
verification := GetPayloadCommitVerification(commit)
fileResponse := &api.FileResponse{
Content: fileContents,
Commit: fileCommitResponse,
Verification: verification,
}
return fileResponse, nil
}
// 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, fmt.Errorf("repo cannot be nil")
}
if commit == nil {
return nil, fmt.Errorf("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
}
// GetAuthorAndCommitterUsers Gets the author and committer user objects from the IdentityOptions
func GetAuthorAndCommitterUsers(author, committer *IdentityOptions, doer *user_model.User) (authorUser, committerUser *user_model.User) {
// Committer and author are optional. If they are not the doer (not same email address)
// then we use bogus User objects for them to store their FullName and Email.
// If only one of the two are provided, we set both of them to it.
// If neither are provided, both are the doer.
if committer != nil && committer.Email != "" {
if doer != nil && strings.EqualFold(doer.Email, committer.Email) {
committerUser = doer // the committer is the doer, so will use their user object
if committer.Name != "" {
committerUser.FullName = committer.Name
}
} else {
committerUser = &user_model.User{
FullName: committer.Name,
Email: committer.Email,
}
}
}
if author != nil && author.Email != "" {
if doer != nil && strings.EqualFold(doer.Email, author.Email) {
authorUser = doer // the author is the doer, so will use their user object
if authorUser.Name != "" {
authorUser.FullName = author.Name
}
} else {
authorUser = &user_model.User{
FullName: author.Name,
Email: author.Email,
}
}
}
if authorUser == nil {
if committerUser != nil {
authorUser = committerUser // No valid author was given so use the committer
} else if doer != nil {
authorUser = doer // No valid author was given and no valid committer so use the doer
}
}
if committerUser == nil {
committerUser = authorUser // No valid committer so use the author as the committer (was set to a valid user above)
}
return authorUser, committerUser
}
// CleanUploadFileName Trims a filename and returns empty string if it is a .git directory
func CleanUploadFileName(name string) string {
// Rebase the filename
name = strings.Trim(path.Clean("/"+name), "/")
// Git disallows any filenames to have a .git directory in them.
for _, part := range strings.Split(name, "/") {
if strings.ToLower(part) == ".git" {
return ""
}
}
return name
}