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  }