summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2021-11-24 15:56:24 +0800
committerGitHub <noreply@github.com>2021-11-24 15:56:24 +0800
commitc97d66d23cf14e88514cccb88c393d21db51ab7a (patch)
tree625857bea77befb61847c01bf17aac1177255787 /modules
parent754fdd8f9c2b1e4e78d507fd414968334cf586fd (diff)
downloadgitea-c97d66d23cf14e88514cccb88c393d21db51ab7a.tar.gz
gitea-c97d66d23cf14e88514cccb88c393d21db51ab7a.zip
Move repofiles from modules/repofiles to services/repository/files (#17774)
* Move repofiles from modules to services * rename services/repository/repofiles -> services/repository/files * Fix test Co-authored-by: 6543 <6543@obermui.de>
Diffstat (limited to 'modules')
-rw-r--r--modules/convert/pull.go10
-rw-r--r--modules/repofiles/blob.go41
-rw-r--r--modules/repofiles/blob_test.go40
-rw-r--r--modules/repofiles/commit.go19
-rw-r--r--modules/repofiles/commit_status.go41
-rw-r--r--modules/repofiles/content.go217
-rw-r--r--modules/repofiles/content_test.go220
-rw-r--r--modules/repofiles/delete.go197
-rw-r--r--modules/repofiles/diff.go42
-rw-r--r--modules/repofiles/diff_test.go172
-rw-r--r--modules/repofiles/file.go125
-rw-r--r--modules/repofiles/file_test.go104
-rw-r--r--modules/repofiles/repofiles.go23
-rw-r--r--modules/repofiles/repofiles_test.go27
-rw-r--r--modules/repofiles/temp_repo.go345
-rw-r--r--modules/repofiles/tree.go98
-rw-r--r--modules/repofiles/tree_test.go53
-rw-r--r--modules/repofiles/update.go479
-rw-r--r--modules/repofiles/upload.go207
-rw-r--r--modules/repofiles/verification.go33
-rw-r--r--modules/repository/branch.go26
-rw-r--r--modules/repository/check.go205
22 files changed, 8 insertions, 2716 deletions
diff --git a/modules/convert/pull.go b/modules/convert/pull.go
index ab17c13421..0f2b5af1b4 100644
--- a/modules/convert/pull.go
+++ b/modules/convert/pull.go
@@ -10,7 +10,6 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
- repo_module "code.gitea.io/gitea/modules/repository"
api "code.gitea.io/gitea/modules/structs"
)
@@ -83,7 +82,14 @@ func ToAPIPullRequest(pr *models.PullRequest, doer *models.User) *api.PullReques
},
}
- baseBranch, err = repo_module.GetBranch(pr.BaseRepo, pr.BaseBranch)
+ gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
+ if err != nil {
+ log.Error("OpenRepository[%s]: %v", pr.BaseRepo.RepoPath(), err)
+ return nil
+ }
+ defer gitRepo.Close()
+
+ baseBranch, err = gitRepo.GetBranch(pr.BaseBranch)
if err != nil && !git.IsErrBranchNotExist(err) {
log.Error("GetBranch[%s]: %v", pr.BaseBranch, err)
return nil
diff --git a/modules/repofiles/blob.go b/modules/repofiles/blob.go
deleted file mode 100644
index 02bc1ebcab..0000000000
--- a/modules/repofiles/blob.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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 (
- "net/url"
-
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/setting"
- api "code.gitea.io/gitea/modules/structs"
-)
-
-// GetBlobBySHA get the GitBlobResponse of a repository using a sha hash.
-func GetBlobBySHA(repo *models.Repository, sha string) (*api.GitBlobResponse, error) {
- gitRepo, err := git.OpenRepository(repo.RepoPath())
- if err != nil {
- return nil, err
- }
- defer gitRepo.Close()
- gitBlob, err := gitRepo.GetBlob(sha)
- if err != nil {
- return nil, err
- }
- content := ""
- if gitBlob.Size() <= setting.API.DefaultMaxBlobSize {
- content, err = gitBlob.GetBlobContentBase64()
- if err != nil {
- return nil, err
- }
- }
- return &api.GitBlobResponse{
- SHA: gitBlob.ID.String(),
- URL: repo.APIURL() + "/git/blobs/" + url.PathEscape(gitBlob.ID.String()),
- Size: gitBlob.Size(),
- Encoding: "base64",
- Content: content,
- }, nil
-}
diff --git a/modules/repofiles/blob_test.go b/modules/repofiles/blob_test.go
deleted file mode 100644
index 8950c349e6..0000000000
--- a/modules/repofiles/blob_test.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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 (
- "testing"
-
- "code.gitea.io/gitea/models/unittest"
- api "code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/modules/test"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestGetBlobBySHA(t *testing.T) {
- unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1")
- test.LoadRepo(t, ctx, 1)
- test.LoadRepoCommit(t, ctx)
- test.LoadUser(t, ctx, 2)
- test.LoadGitRepo(t, ctx)
- defer ctx.Repo.GitRepo.Close()
-
- sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d"
- ctx.SetParams(":id", "1")
- ctx.SetParams(":sha", sha)
-
- gbr, err := GetBlobBySHA(ctx.Repo.Repository, ctx.Params(":sha"))
- expectedGBR := &api.GitBlobResponse{
- Content: "dHJlZSAyYTJmMWQ0NjcwNzI4YTJlMTAwNDllMzQ1YmQ3YTI3NjQ2OGJlYWI2CmF1dGhvciB1c2VyMSA8YWRkcmVzczFAZXhhbXBsZS5jb20+IDE0ODk5NTY0NzkgLTA0MDAKY29tbWl0dGVyIEV0aGFuIEtvZW5pZyA8ZXRoYW50a29lbmlnQGdtYWlsLmNvbT4gMTQ4OTk1NjQ3OSAtMDQwMAoKSW5pdGlhbCBjb21taXQK",
- Encoding: "base64",
- URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/65f1bf27bc3bf70f64657658635e66094edbcb4d",
- SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
- Size: 180,
- }
- assert.NoError(t, err)
- assert.Equal(t, expectedGBR, gbr)
-}
diff --git a/modules/repofiles/commit.go b/modules/repofiles/commit.go
deleted file mode 100644
index 371e6cf3ab..0000000000
--- a/modules/repofiles/commit.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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 (
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/git"
-)
-
-// CountDivergingCommits determines how many commits a branch is ahead or behind the repository's base branch
-func CountDivergingCommits(repo *models.Repository, branch string) (*git.DivergeObject, error) {
- divergence, err := git.GetDivergingCommits(repo.RepoPath(), repo.DefaultBranch, branch)
- if err != nil {
- return nil, err
- }
- return &divergence, nil
-}
diff --git a/modules/repofiles/commit_status.go b/modules/repofiles/commit_status.go
deleted file mode 100644
index 3d93c58d85..0000000000
--- a/modules/repofiles/commit_status.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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"
-)
-
-// CreateCommitStatus creates a new CommitStatus given a bunch of parameters
-// NOTE: All text-values will be trimmed from whitespaces.
-// Requires: Repo, Creator, SHA
-func CreateCommitStatus(repo *models.Repository, creator *models.User, sha string, status *models.CommitStatus) error {
- repoPath := repo.RepoPath()
-
- // confirm that commit is exist
- gitRepo, err := git.OpenRepository(repoPath)
- if err != nil {
- return fmt.Errorf("OpenRepository[%s]: %v", repoPath, err)
- }
- if _, err := gitRepo.GetCommit(sha); err != nil {
- gitRepo.Close()
- return fmt.Errorf("GetCommit[%s]: %v", sha, err)
- }
- gitRepo.Close()
-
- if err := models.NewCommitStatus(models.NewCommitStatusOptions{
- Repo: repo,
- Creator: creator,
- SHA: sha,
- CommitStatus: status,
- }); err != nil {
- return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %v", repo.ID, creator.ID, sha, err)
- }
-
- return nil
-}
diff --git a/modules/repofiles/content.go b/modules/repofiles/content.go
deleted file mode 100644
index 838bfabdc6..0000000000
--- a/modules/repofiles/content.go
+++ /dev/null
@@ -1,217 +0,0 @@
-// 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"
- "net/url"
- "path"
- "strings"
-
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/git"
- api "code.gitea.io/gitea/modules/structs"
-)
-
-// ContentType repo content type
-type ContentType string
-
-// The string representations of different content types
-const (
- // ContentTypeRegular regular content type (file)
- ContentTypeRegular ContentType = "file"
- // ContentTypeDir dir content type (dir)
- ContentTypeDir ContentType = "dir"
- // ContentLink link content type (symlink)
- ContentTypeLink ContentType = "symlink"
- // ContentTag submodule content type (submodule)
- ContentTypeSubmodule ContentType = "submodule"
-)
-
-// String gets the string of ContentType
-func (ct *ContentType) String() string {
- return string(*ct)
-}
-
-// GetContentsOrList gets the meta data of a file's contents (*ContentsResponse) if treePath not a tree
-// directory, otherwise a listing of file contents ([]*ContentsResponse). Ref can be a branch, commit or tag
-func GetContentsOrList(repo *models.Repository, treePath, ref string) (interface{}, error) {
- if repo.IsEmpty {
- return make([]interface{}, 0), nil
- }
- if ref == "" {
- ref = repo.DefaultBranch
- }
- origRef := ref
-
- // Check that the path given in opts.treePath is valid (not a git path)
- cleanTreePath := CleanUploadFileName(treePath)
- if cleanTreePath == "" && treePath != "" {
- return nil, models.ErrFilenameInvalid{
- Path: treePath,
- }
- }
- treePath = cleanTreePath
-
- gitRepo, err := git.OpenRepository(repo.RepoPath())
- if err != nil {
- return nil, err
- }
- defer gitRepo.Close()
-
- // Get the commit object for the ref
- commit, err := gitRepo.GetCommit(ref)
- if err != nil {
- return nil, err
- }
-
- entry, err := commit.GetTreeEntryByPath(treePath)
- if err != nil {
- return nil, err
- }
-
- if entry.Type() != "tree" {
- return GetContents(repo, treePath, origRef, false)
- }
-
- // We are in a directory, so we return a list of FileContentResponse objects
- var fileList []*api.ContentsResponse
-
- gitTree, err := commit.SubTree(treePath)
- if err != nil {
- return nil, err
- }
- entries, err := gitTree.ListEntries()
- if err != nil {
- return nil, err
- }
- for _, e := range entries {
- subTreePath := path.Join(treePath, e.Name())
- fileContentResponse, err := GetContents(repo, subTreePath, origRef, true)
- if err != nil {
- return nil, err
- }
- fileList = append(fileList, fileContentResponse)
- }
- return fileList, nil
-}
-
-// GetContents gets the meta data on a file's contents. Ref can be a branch, commit or tag
-func GetContents(repo *models.Repository, treePath, ref string, forList bool) (*api.ContentsResponse, error) {
- if ref == "" {
- ref = repo.DefaultBranch
- }
- origRef := ref
-
- // Check that the path given in opts.treePath is valid (not a git path)
- cleanTreePath := CleanUploadFileName(treePath)
- if cleanTreePath == "" && treePath != "" {
- return nil, models.ErrFilenameInvalid{
- Path: treePath,
- }
- }
- treePath = cleanTreePath
-
- gitRepo, err := git.OpenRepository(repo.RepoPath())
- if err != nil {
- return nil, err
- }
- defer gitRepo.Close()
-
- // Get the commit object for the ref
- commit, err := gitRepo.GetCommit(ref)
- if err != nil {
- return nil, err
- }
- commitID := commit.ID.String()
- if len(ref) >= 4 && strings.HasPrefix(commitID, ref) {
- ref = commit.ID.String()
- }
-
- entry, err := commit.GetTreeEntryByPath(treePath)
- if err != nil {
- return nil, err
- }
-
- refType := gitRepo.GetRefType(ref)
- if refType == "invalid" {
- return nil, fmt.Errorf("no commit found for the ref [ref: %s]", ref)
- }
-
- selfURL, err := url.Parse(fmt.Sprintf("%s/contents/%s?ref=%s", repo.APIURL(), treePath, origRef))
- if err != nil {
- return nil, err
- }
- selfURLString := selfURL.String()
-
- // All content types have these fields in populated
- contentsResponse := &api.ContentsResponse{
- Name: entry.Name(),
- Path: treePath,
- SHA: entry.ID.String(),
- Size: entry.Size(),
- URL: &selfURLString,
- Links: &api.FileLinksResponse{
- Self: &selfURLString,
- },
- }
-
- // Now populate the rest of the ContentsResponse based on entry type
- if entry.IsRegular() || entry.IsExecutable() {
- contentsResponse.Type = string(ContentTypeRegular)
- if blobResponse, err := GetBlobBySHA(repo, entry.ID.String()); err != nil {
- return nil, err
- } else if !forList {
- // We don't show the content if we are getting a list of FileContentResponses
- contentsResponse.Encoding = &blobResponse.Encoding
- contentsResponse.Content = &blobResponse.Content
- }
- } else if entry.IsDir() {
- contentsResponse.Type = string(ContentTypeDir)
- } else if entry.IsLink() {
- contentsResponse.Type = string(ContentTypeLink)
- // The target of a symlink file is the content of the file
- targetFromContent, err := entry.Blob().GetBlobContent()
- if err != nil {
- return nil, err
- }
- contentsResponse.Target = &targetFromContent
- } else if entry.IsSubModule() {
- contentsResponse.Type = string(ContentTypeSubmodule)
- submodule, err := commit.GetSubModule(treePath)
- if err != nil {
- return nil, err
- }
- contentsResponse.SubmoduleGitURL = &submodule.URL
- }
- // Handle links
- if entry.IsRegular() || entry.IsLink() {
- downloadURL, err := url.Parse(fmt.Sprintf("%s/raw/%s/%s/%s", repo.HTMLURL(), refType, ref, treePath))
- if err != nil {
- return nil, err
- }
- downloadURLString := downloadURL.String()
- contentsResponse.DownloadURL = &downloadURLString
- }
- if !entry.IsSubModule() {
- htmlURL, err := url.Parse(fmt.Sprintf("%s/src/%s/%s/%s", repo.HTMLURL(), refType, ref, treePath))
- if err != nil {
- return nil, err
- }
- htmlURLString := htmlURL.String()
- contentsResponse.HTMLURL = &htmlURLString
- contentsResponse.Links.HTMLURL = &htmlURLString
-
- gitURL, err := url.Parse(fmt.Sprintf("%s/git/blobs/%s", repo.APIURL(), entry.ID.String()))
- if err != nil {
- return nil, err
- }
- gitURLString := gitURL.String()
- contentsResponse.GitURL = &gitURLString
- contentsResponse.Links.GitURL = &gitURLString
- }
-
- return contentsResponse, nil
-}
diff --git a/modules/repofiles/content_test.go b/modules/repofiles/content_test.go
deleted file mode 100644
index f6a953fab9..0000000000
--- a/modules/repofiles/content_test.go
+++ /dev/null
@@ -1,220 +0,0 @@
-// 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 (
- "path/filepath"
- "testing"
-
- "code.gitea.io/gitea/models/unittest"
- api "code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/modules/test"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestMain(m *testing.M) {
- unittest.MainTest(m, filepath.Join("..", ".."))
-}
-
-func getExpectedReadmeContentsResponse() *api.ContentsResponse {
- treePath := "README.md"
- sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f"
- encoding := "base64"
- content := "IyByZXBvMQoKRGVzY3JpcHRpb24gZm9yIHJlcG8x"
- selfURL := "https://try.gitea.io/api/v1/repos/user2/repo1/contents/" + treePath + "?ref=master"
- htmlURL := "https://try.gitea.io/user2/repo1/src/branch/master/" + treePath
- gitURL := "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/" + sha
- downloadURL := "https://try.gitea.io/user2/repo1/raw/branch/master/" + treePath
- return &api.ContentsResponse{
- Name: treePath,
- Path: treePath,
- SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f",
- Type: "file",
- Size: 30,
- Encoding: &encoding,
- Content: &content,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
- Links: &api.FileLinksResponse{
- Self: &selfURL,
- GitURL: &gitURL,
- HTMLURL: &htmlURL,
- },
- }
-}
-
-func TestGetContents(t *testing.T) {
- unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1")
- ctx.SetParams(":id", "1")
- test.LoadRepo(t, ctx, 1)
- test.LoadRepoCommit(t, ctx)
- test.LoadUser(t, ctx, 2)
- test.LoadGitRepo(t, ctx)
- defer ctx.Repo.GitRepo.Close()
-
- treePath := "README.md"
- ref := ctx.Repo.Repository.DefaultBranch
-
- expectedContentsResponse := getExpectedReadmeContentsResponse()
-
- t.Run("Get README.md contents with GetContents()", func(t *testing.T) {
- fileContentResponse, err := GetContents(ctx.Repo.Repository, treePath, ref, false)
- assert.EqualValues(t, expectedContentsResponse, fileContentResponse)
- assert.NoError(t, err)
- })
-
- t.Run("Get README.md contents with ref as empty string (should then use the repo's default branch) with GetContents()", func(t *testing.T) {
- fileContentResponse, err := GetContents(ctx.Repo.Repository, treePath, "", false)
- assert.EqualValues(t, expectedContentsResponse, fileContentResponse)
- assert.NoError(t, err)
- })
-}
-
-func TestGetContentsOrListForDir(t *testing.T) {
- unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1")
- ctx.SetParams(":id", "1")
- test.LoadRepo(t, ctx, 1)
- test.LoadRepoCommit(t, ctx)
- test.LoadUser(t, ctx, 2)
- test.LoadGitRepo(t, ctx)
- defer ctx.Repo.GitRepo.Close()
-
- treePath := "" // root dir
- ref := ctx.Repo.Repository.DefaultBranch
-
- readmeContentsResponse := getExpectedReadmeContentsResponse()
- // because will be in a list, doesn't have encoding and content
- readmeContentsResponse.Encoding = nil
- readmeContentsResponse.Content = nil
-
- expectedContentsListResponse := []*api.ContentsResponse{
- readmeContentsResponse,
- }
-
- t.Run("Get root dir contents with GetContentsOrList()", func(t *testing.T) {
- fileContentResponse, err := GetContentsOrList(ctx.Repo.Repository, treePath, ref)
- assert.EqualValues(t, expectedContentsListResponse, fileContentResponse)
- assert.NoError(t, err)
- })
-
- t.Run("Get root dir contents with ref as empty string (should then use the repo's default branch) with GetContentsOrList()", func(t *testing.T) {
- fileContentResponse, err := GetContentsOrList(ctx.Repo.Repository, treePath, "")
- assert.EqualValues(t, expectedContentsListResponse, fileContentResponse)
- assert.NoError(t, err)
- })
-}
-
-func TestGetContentsOrListForFile(t *testing.T) {
- unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1")
- ctx.SetParams(":id", "1")
- test.LoadRepo(t, ctx, 1)
- test.LoadRepoCommit(t, ctx)
- test.LoadUser(t, ctx, 2)
- test.LoadGitRepo(t, ctx)
- defer ctx.Repo.GitRepo.Close()
-
- treePath := "README.md"
- ref := ctx.Repo.Repository.DefaultBranch
-
- expectedContentsResponse := getExpectedReadmeContentsResponse()
-
- t.Run("Get README.md contents with GetContentsOrList()", func(t *testing.T) {
- fileContentResponse, err := GetContentsOrList(ctx.Repo.Repository, treePath, ref)
- assert.EqualValues(t, expectedContentsResponse, fileContentResponse)
- assert.NoError(t, err)
- })
-
- t.Run("Get README.md contents with ref as empty string (should then use the repo's default branch) with GetContentsOrList()", func(t *testing.T) {
- fileContentResponse, err := GetContentsOrList(ctx.Repo.Repository, treePath, "")
- assert.EqualValues(t, expectedContentsResponse, fileContentResponse)
- assert.NoError(t, err)
- })
-}
-
-func TestGetContentsErrors(t *testing.T) {
- unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1")
- ctx.SetParams(":id", "1")
- test.LoadRepo(t, ctx, 1)
- test.LoadRepoCommit(t, ctx)
- test.LoadUser(t, ctx, 2)
- test.LoadGitRepo(t, ctx)
- defer ctx.Repo.GitRepo.Close()
-
- repo := ctx.Repo.Repository
- treePath := "README.md"
- ref := repo.DefaultBranch
-
- t.Run("bad treePath", func(t *testing.T) {
- badTreePath := "bad/tree.md"
- fileContentResponse, err := GetContents(repo, badTreePath, ref, false)
- assert.Error(t, err)
- assert.EqualError(t, err, "object does not exist [id: , rel_path: bad]")
- assert.Nil(t, fileContentResponse)
- })
-
- t.Run("bad ref", func(t *testing.T) {
- badRef := "bad_ref"
- fileContentResponse, err := GetContents(repo, treePath, badRef, false)
- assert.Error(t, err)
- assert.EqualError(t, err, "object does not exist [id: "+badRef+", rel_path: ]")
- assert.Nil(t, fileContentResponse)
- })
-}
-
-func TestGetContentsOrListErrors(t *testing.T) {
- unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1")
- ctx.SetParams(":id", "1")
- test.LoadRepo(t, ctx, 1)
- test.LoadRepoCommit(t, ctx)
- test.LoadUser(t, ctx, 2)
- test.LoadGitRepo(t, ctx)
- defer ctx.Repo.GitRepo.Close()
-
- repo := ctx.Repo.Repository
- treePath := "README.md"
- ref := repo.DefaultBranch
-
- t.Run("bad treePath", func(t *testing.T) {
- badTreePath := "bad/tree.md"
- fileContentResponse, err := GetContentsOrList(repo, badTreePath, ref)
- assert.Error(t, err)
- assert.EqualError(t, err, "object does not exist [id: , rel_path: bad]")
- assert.Nil(t, fileContentResponse)
- })
-
- t.Run("bad ref", func(t *testing.T) {
- badRef := "bad_ref"
- fileContentResponse, err := GetContentsOrList(repo, treePath, badRef)
- assert.Error(t, err)
- assert.EqualError(t, err, "object does not exist [id: "+badRef+", rel_path: ]")
- assert.Nil(t, fileContentResponse)
- })
-}
-
-func TestGetContentsOrListOfEmptyRepos(t *testing.T) {
- unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo15")
- ctx.SetParams(":id", "15")
- test.LoadRepo(t, ctx, 15)
- test.LoadUser(t, ctx, 2)
- test.LoadGitRepo(t, ctx)
- defer ctx.Repo.GitRepo.Close()
-
- repo := ctx.Repo.Repository
-
- t.Run("empty repo", func(t *testing.T) {
- contents, err := GetContentsOrList(repo, "", "")
- assert.NoError(t, err)
- assert.Empty(t, contents)
- })
-}
diff --git a/modules/repofiles/delete.go b/modules/repofiles/delete.go
deleted file mode 100644
index 5ae418b7f6..0000000000
--- a/modules/repofiles/delete.go
+++ /dev/null
@@ -1,197 +0,0 @@
-// 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"
- "strings"
-
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/git"
- repo_module "code.gitea.io/gitea/modules/repository"
- api "code.gitea.io/gitea/modules/structs"
-)
-
-// DeleteRepoFileOptions holds the repository delete file options
-type DeleteRepoFileOptions struct {
- LastCommitID string
- OldBranch string
- NewBranch string
- TreePath string
- Message string
- SHA string
- Author *IdentityOptions
- Committer *IdentityOptions
- Dates *CommitDateOptions
- Signoff bool
-}
-
-// DeleteRepoFile deletes a file in the given repository
-func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepoFileOptions) (*api.FileResponse, error) {
- // If no branch name is set, assume the repo's default branch
- if opts.OldBranch == "" {
- opts.OldBranch = repo.DefaultBranch
- }
- if opts.NewBranch == "" {
- opts.NewBranch = opts.OldBranch
- }
-
- // oldBranch must exist for this operation
- if _, err := repo_module.GetBranch(repo, opts.OldBranch); err != nil {
- return nil, err
- }
-
- // A NewBranch can be specified for the file to be created/updated in a new branch.
- // Check to make sure the branch does not already exist, otherwise we can't proceed.
- // If we aren't branching to a new branch, make sure user can commit to the given branch
- if opts.NewBranch != opts.OldBranch {
- newBranch, err := repo_module.GetBranch(repo, opts.NewBranch)
- if err != nil && !git.IsErrBranchNotExist(err) {
- return nil, err
- }
- if newBranch != nil {
- return nil, models.ErrBranchAlreadyExists{
- BranchName: opts.NewBranch,
- }
- }
- } else if err := VerifyBranchProtection(repo, doer, opts.OldBranch, opts.TreePath); err != nil {
- return nil, err
- }
-
- // Check that the path given in opts.treeName is valid (not a git path)
- treePath := CleanUploadFileName(opts.TreePath)
- if treePath == "" {
- return nil, models.ErrFilenameInvalid{
- Path: opts.TreePath,
- }
- }
-
- message := strings.TrimSpace(opts.Message)
-
- author, committer := GetAuthorAndCommitterUsers(opts.Author, opts.Committer, doer)
-
- t, err := NewTemporaryUploadRepository(repo)
- if err != nil {
- return nil, err
- }
- defer t.Close()
- if err := t.Clone(opts.OldBranch); err != nil {
- return nil, err
- }
- if err := t.SetDefaultIndex(); err != nil {
- return nil, err
- }
-
- // Get the commit of the original branch
- commit, err := t.GetBranchCommit(opts.OldBranch)
- if err != nil {
- return nil, err // Couldn't get a commit for the branch
- }
-
- // Assigned LastCommitID in opts if it hasn't been set
- if opts.LastCommitID == "" {
- opts.LastCommitID = commit.ID.String()
- } else {
- lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
- if err != nil {
- return nil, fmt.Errorf("DeleteRepoFile: Invalid last commit ID: %v", err)
- }
- opts.LastCommitID = lastCommitID.String()
- }
-
- // Get the files in the index
- filesInIndex, err := t.LsFiles(opts.TreePath)
- if err != nil {
- return nil, fmt.Errorf("DeleteRepoFile: %v", err)
- }
-
- // Find the file we want to delete in the index
- inFilelist := false
- for _, file := range filesInIndex {
- if file == opts.TreePath {
- inFilelist = true
- break
- }
- }
- if !inFilelist {
- return nil, models.ErrRepoFileDoesNotExist{
- Path: opts.TreePath,
- }
- }
-
- // Get the entry of treePath and check if the SHA given is the same as the file
- entry, err := commit.GetTreeEntryByPath(treePath)
- if err != nil {
- return nil, err
- }
- if opts.SHA != "" {
- // If a SHA was given and the SHA given doesn't match the SHA of the fromTreePath, throw error
- if opts.SHA != entry.ID.String() {
- return nil, models.ErrSHADoesNotMatch{
- Path: treePath,
- GivenSHA: opts.SHA,
- CurrentSHA: entry.ID.String(),
- }
- }
- } else if opts.LastCommitID != "" {
- // If a lastCommitID was given and it doesn't match the commitID of the head of the branch throw
- // an error, but only if we aren't creating a new branch.
- if commit.ID.String() != opts.LastCommitID && opts.OldBranch == opts.NewBranch {
- // CommitIDs don't match, but we don't want to throw a ErrCommitIDDoesNotMatch unless
- // this specific file has been edited since opts.LastCommitID
- if changed, err := commit.FileChangedSinceCommit(treePath, opts.LastCommitID); err != nil {
- return nil, err
- } else if changed {
- return nil, models.ErrCommitIDDoesNotMatch{
- GivenCommitID: opts.LastCommitID,
- CurrentCommitID: opts.LastCommitID,
- }
- }
- // The file wasn't modified, so we are good to delete it
- }
- } else {
- // When deleting a file, a lastCommitID or SHA needs to be given to make sure other commits haven't been
- // made. We throw an error if one wasn't provided.
- return nil, models.ErrSHAOrCommitIDNotProvided{}
- }
-
- // Remove the file from the index
- if err := t.RemoveFilesFromIndex(opts.TreePath); err != nil {
- return nil, err
- }
-
- // Now write the tree
- treeHash, err := t.WriteTree()
- if err != nil {
- return nil, err
- }
-
- // Now commit the tree
- var commitHash string
- if opts.Dates != nil {
- commitHash, err = t.CommitTreeWithDate(author, committer, treeHash, message, opts.Signoff, opts.Dates.Author, opts.Dates.Committer)
- } else {
- commitHash, err = t.CommitTree(author, committer, treeHash, message, opts.Signoff)
- }
- if err != nil {
- return nil, err
- }
-
- // Then push this tree to NewBranch
- if err := t.Push(doer, commitHash, opts.NewBranch); err != nil {
- return nil, err
- }
-
- commit, err = t.GetCommit(commitHash)
- if err != nil {
- return nil, err
- }
-
- file, err := GetFileResponseFromCommit(repo, commit, opts.NewBranch, treePath)
- if err != nil {
- return nil, err
- }
- return file, nil
-}
diff --git a/modules/repofiles/diff.go b/modules/repofiles/diff.go
deleted file mode 100644
index c98bbc7684..0000000000
--- a/modules/repofiles/diff.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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 (
- "strings"
-
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/services/gitdiff"
-)
-
-// GetDiffPreview produces and returns diff result of a file which is not yet committed.
-func GetDiffPreview(repo *models.Repository, branch, treePath, content string) (*gitdiff.Diff, error) {
- if branch == "" {
- branch = repo.DefaultBranch
- }
- t, err := NewTemporaryUploadRepository(repo)
- if err != nil {
- return nil, err
- }
- defer t.Close()
- if err := t.Clone(branch); err != nil {
- return nil, err
- }
- if err := t.SetDefaultIndex(); err != nil {
- return nil, err
- }
-
- // Add the object to the database
- objectHash, err := t.HashObject(strings.NewReader(content))
- if err != nil {
- return nil, err
- }
-
- // Add the object to the index
- if err := t.AddObjectToIndex("100644", objectHash, treePath); err != nil {
- return nil, err
- }
- return t.DiffIndex()
-}
diff --git a/modules/repofiles/diff_test.go b/modules/repofiles/diff_test.go
deleted file mode 100644
index 4bd1ef6f4d..0000000000
--- a/modules/repofiles/diff_test.go
+++ /dev/null
@@ -1,172 +0,0 @@
-// 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 (
- "testing"
-
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/models/unittest"
- "code.gitea.io/gitea/modules/json"
- "code.gitea.io/gitea/modules/test"
- "code.gitea.io/gitea/services/gitdiff"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestGetDiffPreview(t *testing.T) {
- unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1")
- ctx.SetParams(":id", "1")
- test.LoadRepo(t, ctx, 1)
- test.LoadRepoCommit(t, ctx)
- test.LoadUser(t, ctx, 2)
- test.LoadGitRepo(t, ctx)
- defer ctx.Repo.GitRepo.Close()
-
- branch := ctx.Repo.Repository.DefaultBranch
- treePath := "README.md"
- content := "# repo1\n\nDescription for repo1\nthis is a new line"
-
- expectedDiff := &gitdiff.Diff{
- TotalAddition: 2,
- TotalDeletion: 1,
- Files: []*gitdiff.DiffFile{
- {
- Name: "README.md",
- OldName: "README.md",
- Index: 1,
- Addition: 2,
- Deletion: 1,
- Type: 2,
- IsCreated: false,
- IsDeleted: false,
- IsBin: false,
- IsLFSFile: false,
- IsRenamed: false,
- IsSubmodule: false,
- Sections: []*gitdiff.DiffSection{
- {
- FileName: "README.md",
- Name: "",
- Lines: []*gitdiff.DiffLine{
- {
- LeftIdx: 0,
- RightIdx: 0,
- Type: 4,
- Content: "@@ -1,3 +1,4 @@",
- Comments: nil,
- SectionInfo: &gitdiff.DiffLineSectionInfo{
- Path: "README.md",
- LastLeftIdx: 0,
- LastRightIdx: 0,
- LeftIdx: 1,
- RightIdx: 1,
- LeftHunkSize: 3,
- RightHunkSize: 4,
- },
- },
- {
- LeftIdx: 1,
- RightIdx: 1,
- Type: 1,
- Content: " # repo1",
- Comments: nil,
- },
- {
- LeftIdx: 2,
- RightIdx: 2,
- Type: 1,
- Content: " ",
- Comments: nil,
- },
- {
- LeftIdx: 3,
- RightIdx: 0,
- Match: 4,
- Type: 3,
- Content: "-Description for repo1",
- Comments: nil,
- },
- {
- LeftIdx: 0,
- RightIdx: 3,
- Match: 3,
- Type: 2,
- Content: "+Description for repo1",
- Comments: nil,
- },
- {
- LeftIdx: 0,
- RightIdx: 4,
- Match: -1,
- Type: 2,
- Content: "+this is a new line",
- Comments: nil,
- },
- },
- },
- },
- IsIncomplete: false,
- },
- },
- IsIncomplete: false,
- }
- expectedDiff.NumFiles = len(expectedDiff.Files)
-
- t.Run("with given branch", func(t *testing.T) {
- diff, err := GetDiffPreview(ctx.Repo.Repository, branch, treePath, content)
- assert.NoError(t, err)
- expectedBs, err := json.Marshal(expectedDiff)
- assert.NoError(t, err)
- bs, err := json.Marshal(diff)
- assert.NoError(t, err)
- assert.EqualValues(t, expectedBs, bs)
- })
-
- t.Run("empty branch, same results", func(t *testing.T) {
- diff, err := GetDiffPreview(ctx.Repo.Repository, "", treePath, content)
- assert.NoError(t, err)
- expectedBs, err := json.Marshal(expectedDiff)
- assert.NoError(t, err)
- bs, err := json.Marshal(diff)
- assert.NoError(t, err)
- assert.EqualValues(t, expectedBs, bs)
- })
-}
-
-func TestGetDiffPreviewErrors(t *testing.T) {
- unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1")
- ctx.SetParams(":id", "1")
- test.LoadRepo(t, ctx, 1)
- test.LoadRepoCommit(t, ctx)
- test.LoadUser(t, ctx, 2)
- test.LoadGitRepo(t, ctx)
- defer ctx.Repo.GitRepo.Close()
-
- branch := ctx.Repo.Repository.DefaultBranch
- treePath := "README.md"
- content := "# repo1\n\nDescription for repo1\nthis is a new line"
-
- t.Run("empty repo", func(t *testing.T) {
- diff, err := GetDiffPreview(&models.Repository{}, branch, treePath, content)
- assert.Nil(t, diff)
- assert.EqualError(t, err, "repository does not exist [id: 0, uid: 0, owner_name: , name: ]")
- })
-
- t.Run("bad branch", func(t *testing.T) {
- badBranch := "bad_branch"
- diff, err := GetDiffPreview(ctx.Repo.Repository, badBranch, treePath, content)
- assert.Nil(t, diff)
- assert.EqualError(t, err, "branch does not exist [name: "+badBranch+"]")
- })
-
- t.Run("empty treePath", func(t *testing.T) {
- diff, err := GetDiffPreview(ctx.Repo.Repository, branch, "", content)
- assert.Nil(t, diff)
- assert.EqualError(t, err, "path is invalid [path: ]")
- })
-}
diff --git a/modules/repofiles/file.go b/modules/repofiles/file.go
deleted file mode 100644
index 4030924017..0000000000
--- a/modules/repofiles/file.go
+++ /dev/null
@@ -1,125 +0,0 @@
-// 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"
- "net/url"
- "strings"
- "time"
-
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/git"
- api "code.gitea.io/gitea/modules/structs"
-)
-
-// GetFileResponseFromCommit Constructs a FileResponse from a Commit object
-func GetFileResponseFromCommit(repo *models.Repository, commit *git.Commit, branch, treeName string) (*api.FileResponse, error) {
- fileContents, _ := GetContents(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 *models.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 *models.User) (authorUser, committerUser *models.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 = &models.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 = &models.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
-}
diff --git a/modules/repofiles/file_test.go b/modules/repofiles/file_test.go
deleted file mode 100644
index 54205a89c7..0000000000
--- a/modules/repofiles/file_test.go
+++ /dev/null
@@ -1,104 +0,0 @@
-// 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 (
- "testing"
-
- "code.gitea.io/gitea/models/unittest"
- "code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/setting"
- api "code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/modules/test"
-
- "github.com/stretchr/testify/assert"
-)
-
-func getExpectedFileResponse() *api.FileResponse {
- treePath := "README.md"
- sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f"
- encoding := "base64"
- content := "IyByZXBvMQoKRGVzY3JpcHRpb24gZm9yIHJlcG8x"
- selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=master"
- htmlURL := setting.AppURL + "user2/repo1/src/branch/master/" + treePath
- gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha
- downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath
- return &api.FileResponse{
- Content: &api.ContentsResponse{
- Name: treePath,
- Path: treePath,
- SHA: sha,
- Type: "file",
- Size: 30,
- Encoding: &encoding,
- Content: &content,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
- Links: &api.FileLinksResponse{
- Self: &selfURL,
- GitURL: &gitURL,
- HTMLURL: &htmlURL,
- },
- },
- Commit: &api.FileCommitResponse{
- CommitMeta: api.CommitMeta{
- URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d",
- SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
- },
- HTMLURL: "https://try.gitea.io/user2/repo1/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d",
- Author: &api.CommitUser{
- Identity: api.Identity{
- Name: "user1",
- Email: "address1@example.com",
- },
- Date: "2017-03-19T20:47:59Z",
- },
- Committer: &api.CommitUser{
- Identity: api.Identity{
- Name: "Ethan Koenig",
- Email: "ethantkoenig@gmail.com",
- },
- Date: "2017-03-19T20:47:59Z",
- },
- Parents: []*api.CommitMeta{},
- Message: "Initial commit\n",
- Tree: &api.CommitMeta{
- URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/trees/2a2f1d4670728a2e10049e345bd7a276468beab6",
- SHA: "2a2f1d4670728a2e10049e345bd7a276468beab6",
- },
- },
- Verification: &api.PayloadCommitVerification{
- Verified: false,
- Reason: "gpg.error.not_signed_commit",
- Signature: "",
- Payload: "",
- },
- }
-}
-
-func TestGetFileResponseFromCommit(t *testing.T) {
- unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1")
- ctx.SetParams(":id", "1")
- test.LoadRepo(t, ctx, 1)
- test.LoadRepoCommit(t, ctx)
- test.LoadUser(t, ctx, 2)
- test.LoadGitRepo(t, ctx)
- defer ctx.Repo.GitRepo.Close()
-
- repo := ctx.Repo.Repository
- branch := repo.DefaultBranch
- treePath := "README.md"
- gitRepo, _ := git.OpenRepository(repo.RepoPath())
- defer gitRepo.Close()
- commit, _ := gitRepo.GetBranchCommit(branch)
- expectedFileResponse := getExpectedFileResponse()
-
- fileResponse, err := GetFileResponseFromCommit(repo, commit, branch, treePath)
- assert.NoError(t, err)
- assert.EqualValues(t, expectedFileResponse, fileResponse)
-}
diff --git a/modules/repofiles/repofiles.go b/modules/repofiles/repofiles.go
deleted file mode 100644
index 1fc900490c..0000000000
--- a/modules/repofiles/repofiles.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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
-
-package repofiles
-
-import (
- "path"
- "strings"
-)
-
-// 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
-}
diff --git a/modules/repofiles/repofiles_test.go b/modules/repofiles/repofiles_test.go
deleted file mode 100644
index 1686378a4a..0000000000
--- a/modules/repofiles/repofiles_test.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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 (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCleanUploadFileName(t *testing.T) {
- t.Run("Clean regular file", func(t *testing.T) {
- name := "this/is/test"
- cleanName := CleanUploadFileName(name)
- expectedCleanName := name
- assert.EqualValues(t, expectedCleanName, cleanName)
- })
-
- t.Run("Clean a .git path", func(t *testing.T) {
- name := "this/is/test/.git"
- cleanName := CleanUploadFileName(name)
- expectedCleanName := ""
- assert.EqualValues(t, expectedCleanName, cleanName)
- })
-}
diff --git a/modules/repofiles/temp_repo.go b/modules/repofiles/temp_repo.go
deleted file mode 100644
index 700ce92ebf..0000000000
--- a/modules/repofiles/temp_repo.go
+++ /dev/null
@@ -1,345 +0,0 @@
-// 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 (
- "bytes"
- "context"
- "fmt"
- "io"
- "os"
- "regexp"
- "strings"
- "time"
-
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/services/gitdiff"
-)
-
-// TemporaryUploadRepository is a type to wrap our upload repositories as a shallow clone
-type TemporaryUploadRepository struct {
- repo *models.Repository
- gitRepo *git.Repository
- basePath string
-}
-
-// NewTemporaryUploadRepository creates a new temporary upload repository
-func NewTemporaryUploadRepository(repo *models.Repository) (*TemporaryUploadRepository, error) {
- basePath, err := models.CreateTemporaryPath("upload")
- if err != nil {
- return nil, err
- }
- t := &TemporaryUploadRepository{repo: repo, basePath: basePath}
- return t, nil
-}
-
-// Close the repository cleaning up all files
-func (t *TemporaryUploadRepository) Close() {
- defer t.gitRepo.Close()
- if err := models.RemoveTemporaryPath(t.basePath); err != nil {
- log.Error("Failed to remove temporary path %s: %v", t.basePath, err)
- }
-}
-
-// Clone the base repository to our path and set branch as the HEAD
-func (t *TemporaryUploadRepository) Clone(branch string) error {
- if _, err := git.NewCommand("clone", "-s", "--bare", "-b", branch, t.repo.RepoPath(), t.basePath).Run(); err != nil {
- stderr := err.Error()
- if matched, _ := regexp.MatchString(".*Remote branch .* not found in upstream origin.*", stderr); matched {
- return git.ErrBranchNotExist{
- Name: branch,
- }
- } else if matched, _ := regexp.MatchString(".* repository .* does not exist.*", stderr); matched {
- return models.ErrRepoNotExist{
- ID: t.repo.ID,
- UID: t.repo.OwnerID,
- OwnerName: t.repo.OwnerName,
- Name: t.repo.Name,
- }
- } else {
- return fmt.Errorf("Clone: %v %s", err, stderr)
- }
- }
- gitRepo, err := git.OpenRepository(t.basePath)
- if err != nil {
- return err
- }
- t.gitRepo = gitRepo
- return nil
-}
-
-// SetDefaultIndex sets the git index to our HEAD
-func (t *TemporaryUploadRepository) SetDefaultIndex() error {
- if _, err := git.NewCommand("read-tree", "HEAD").RunInDir(t.basePath); err != nil {
- return fmt.Errorf("SetDefaultIndex: %v", err)
- }
- return nil
-}
-
-// LsFiles checks if the given filename arguments are in the index
-func (t *TemporaryUploadRepository) LsFiles(filenames ...string) ([]string, error) {
- stdOut := new(bytes.Buffer)
- stdErr := new(bytes.Buffer)
-
- cmdArgs := []string{"ls-files", "-z", "--"}
- for _, arg := range filenames {
- if arg != "" {
- cmdArgs = append(cmdArgs, arg)
- }
- }
-
- if err := git.NewCommand(cmdArgs...).RunInDirPipeline(t.basePath, stdOut, stdErr); err != nil {
- log.Error("Unable to run git ls-files for temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String())
- err = fmt.Errorf("Unable to run git ls-files for temporary repo of: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String())
- return nil, err
- }
-
- filelist := make([]string, len(filenames))
- for _, line := range bytes.Split(stdOut.Bytes(), []byte{'\000'}) {
- filelist = append(filelist, string(line))
- }
-
- return filelist, nil
-}
-
-// RemoveFilesFromIndex removes the given files from the index
-func (t *TemporaryUploadRepository) RemoveFilesFromIndex(filenames ...string) error {
- stdOut := new(bytes.Buffer)
- stdErr := new(bytes.Buffer)
- stdIn := new(bytes.Buffer)
- for _, file := range filenames {
- if file != "" {
- stdIn.WriteString("0 0000000000000000000000000000000000000000\t")
- stdIn.WriteString(file)
- stdIn.WriteByte('\000')
- }
- }
-
- if err := git.NewCommand("update-index", "--remove", "-z", "--index-info").RunInDirFullPipeline(t.basePath, stdOut, stdErr, stdIn); err != nil {
- log.Error("Unable to update-index for temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String())
- return fmt.Errorf("Unable to update-index for temporary repo: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String())
- }
- return nil
-}
-
-// HashObject writes the provided content to the object db and returns its hash
-func (t *TemporaryUploadRepository) HashObject(content io.Reader) (string, error) {
- stdOut := new(bytes.Buffer)
- stdErr := new(bytes.Buffer)
-
- if err := git.NewCommand("hash-object", "-w", "--stdin").RunInDirFullPipeline(t.basePath, stdOut, stdErr, content); err != nil {
- log.Error("Unable to hash-object to temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String())
- return "", fmt.Errorf("Unable to hash-object to temporary repo: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String())
- }
-
- return strings.TrimSpace(stdOut.String()), nil
-}
-
-// AddObjectToIndex adds the provided object hash to the index with the provided mode and path
-func (t *TemporaryUploadRepository) AddObjectToIndex(mode, objectHash, objectPath string) error {
- if _, err := git.NewCommand("update-index", "--add", "--replace", "--cacheinfo", mode, objectHash, objectPath).RunInDir(t.basePath); err != nil {
- stderr := err.Error()
- if matched, _ := regexp.MatchString(".*Invalid path '.*", stderr); matched {
- return models.ErrFilePathInvalid{
- Message: objectPath,
- Path: objectPath,
- }
- }
- log.Error("Unable to add object to index: %s %s %s in temporary repo %s(%s) Error: %v", mode, objectHash, objectPath, t.repo.FullName(), t.basePath, err)
- return fmt.Errorf("Unable to add object to index at %s in temporary repo %s Error: %v", objectPath, t.repo.FullName(), err)
- }
- return nil
-}
-
-// WriteTree writes the current index as a tree to the object db and returns its hash
-func (t *TemporaryUploadRepository) WriteTree() (string, error) {
- stdout, err := git.NewCommand("write-tree").RunInDir(t.basePath)
- if err != nil {
- log.Error("Unable to write tree in temporary repo: %s(%s): Error: %v", t.repo.FullName(), t.basePath, err)
- return "", fmt.Errorf("Unable to write-tree in temporary repo for: %s Error: %v", t.repo.FullName(), err)
- }
- return strings.TrimSpace(stdout), nil
-}
-
-// GetLastCommit gets the last commit ID SHA of the repo
-func (t *TemporaryUploadRepository) GetLastCommit() (string, error) {
- return t.GetLastCommitByRef("HEAD")
-}
-
-// GetLastCommitByRef gets the last commit ID SHA of the repo by ref
-func (t *TemporaryUploadRepository) GetLastCommitByRef(ref string) (string, error) {
- if ref == "" {
- ref = "HEAD"
- }
- stdout, err := git.NewCommand("rev-parse", ref).RunInDir(t.basePath)
- if err != nil {
- log.Error("Unable to get last ref for %s in temporary repo: %s(%s): Error: %v", ref, t.repo.FullName(), t.basePath, err)
- return "", fmt.Errorf("Unable to rev-parse %s in temporary repo for: %s Error: %v", ref, t.repo.FullName(), err)
- }
- return strings.TrimSpace(stdout), nil
-}
-
-// CommitTree creates a commit from a given tree for the user with provided message
-func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, treeHash string, message string, signoff bool) (string, error) {
- return t.CommitTreeWithDate(author, committer, treeHash, message, signoff, time.Now(), time.Now())
-}
-
-// CommitTreeWithDate creates a commit from a given tree for the user with provided message
-func (t *TemporaryUploadRepository) CommitTreeWithDate(author, committer *models.User, treeHash string, message string, signoff bool, authorDate, committerDate time.Time) (string, error) {
- authorSig := author.NewGitSig()
- committerSig := committer.NewGitSig()
-
- err := git.LoadGitVersion()
- if err != nil {
- return "", fmt.Errorf("Unable to get git version: %v", err)
- }
-
- // Because this may call hooks we should pass in the environment
- env := append(os.Environ(),
- "GIT_AUTHOR_NAME="+authorSig.Name,
- "GIT_AUTHOR_EMAIL="+authorSig.Email,
- "GIT_AUTHOR_DATE="+authorDate.Format(time.RFC3339),
- "GIT_COMMITTER_DATE="+committerDate.Format(time.RFC3339),
- )
-
- messageBytes := new(bytes.Buffer)
- _, _ = messageBytes.WriteString(message)
- _, _ = messageBytes.WriteString("\n")
-
- args := []string{"commit-tree", treeHash, "-p", "HEAD"}
-
- // Determine if we should sign
- if git.CheckGitVersionAtLeast("1.7.9") == nil {
- sign, keyID, signer, _ := t.repo.SignCRUDAction(author, t.basePath, "HEAD")
- if sign {
- args = append(args, "-S"+keyID)
- if t.repo.GetTrustModel() == models.CommitterTrustModel || t.repo.GetTrustModel() == models.CollaboratorCommitterTrustModel {
- if committerSig.Name != authorSig.Name || committerSig.Email != authorSig.Email {
- // Add trailers
- _, _ = messageBytes.WriteString("\n")
- _, _ = messageBytes.WriteString("Co-authored-by: ")
- _, _ = messageBytes.WriteString(committerSig.String())
- _, _ = messageBytes.WriteString("\n")
- _, _ = messageBytes.WriteString("Co-committed-by: ")
- _, _ = messageBytes.WriteString(committerSig.String())
- _, _ = messageBytes.WriteString("\n")
- }
- committerSig = signer
- }
- } else if git.CheckGitVersionAtLeast("2.0.0") == nil {
- args = append(args, "--no-gpg-sign")
- }
- }
-
- if signoff {
- // Signed-off-by
- _, _ = messageBytes.WriteString("\n")
- _, _ = messageBytes.WriteString("Signed-off-by: ")
- _, _ = messageBytes.WriteString(committerSig.String())
- }
-
- env = append(env,
- "GIT_COMMITTER_NAME="+committerSig.Name,
- "GIT_COMMITTER_EMAIL="+committerSig.Email,
- )
-
- stdout := new(bytes.Buffer)
- stderr := new(bytes.Buffer)
- if err := git.NewCommand(args...).RunInDirTimeoutEnvFullPipeline(env, -1, t.basePath, stdout, stderr, messageBytes); err != nil {
- log.Error("Unable to commit-tree in temporary repo: %s (%s) Error: %v\nStdout: %s\nStderr: %s",
- t.repo.FullName(), t.basePath, err, stdout, stderr)
- return "", fmt.Errorf("Unable to commit-tree in temporary repo: %s Error: %v\nStdout: %s\nStderr: %s",
- t.repo.FullName(), err, stdout, stderr)
- }
- return strings.TrimSpace(stdout.String()), nil
-}
-
-// Push the provided commitHash to the repository branch by the provided user
-func (t *TemporaryUploadRepository) Push(doer *models.User, commitHash string, branch string) error {
- // Because calls hooks we need to pass in the environment
- env := models.PushingEnvironment(doer, t.repo)
- if err := git.Push(t.basePath, git.PushOptions{
- Remote: t.repo.RepoPath(),
- Branch: strings.TrimSpace(commitHash) + ":refs/heads/" + strings.TrimSpace(branch),
- Env: env,
- }); err != nil {
- if git.IsErrPushOutOfDate(err) {
- return err
- } else if git.IsErrPushRejected(err) {
- rejectErr := err.(*git.ErrPushRejected)
- log.Info("Unable to push back to repo from temporary repo due to rejection: %s (%s)\nStdout: %s\nStderr: %s\nError: %v",
- t.repo.FullName(), t.basePath, rejectErr.StdOut, rejectErr.StdErr, rejectErr.Err)
- return err
- }
- log.Error("Unable to push back to repo from temporary repo: %s (%s)\nError: %v",
- t.repo.FullName(), t.basePath, err)
- return fmt.Errorf("Unable to push back to repo from temporary repo: %s (%s) Error: %v",
- t.repo.FullName(), t.basePath, err)
- }
- return nil
-}
-
-// DiffIndex returns a Diff of the current index to the head
-func (t *TemporaryUploadRepository) DiffIndex() (*gitdiff.Diff, error) {
- stdoutReader, stdoutWriter, err := os.Pipe()
- if err != nil {
- log.Error("Unable to open stdout pipe: %v", err)
- return nil, fmt.Errorf("Unable to open stdout pipe: %v", err)
- }
- defer func() {
- _ = stdoutReader.Close()
- _ = stdoutWriter.Close()
- }()
- stderr := new(bytes.Buffer)
- var diff *gitdiff.Diff
- var finalErr error
-
- if err := git.NewCommand("diff-index", "--src-prefix=\\a/", "--dst-prefix=\\b/", "--cached", "-p", "HEAD").
- RunInDirTimeoutEnvFullPipelineFunc(nil, 30*time.Second, t.basePath, stdoutWriter, stderr, nil, func(ctx context.Context, cancel context.CancelFunc) error {
- _ = stdoutWriter.Close()
- diff, finalErr = gitdiff.ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, stdoutReader, "")
- if finalErr != nil {
- log.Error("ParsePatch: %v", finalErr)
- cancel()
- }
- _ = stdoutReader.Close()
- return finalErr
- }); err != nil {
- if finalErr != nil {
- log.Error("Unable to ParsePatch in temporary repo %s (%s). Error: %v", t.repo.FullName(), t.basePath, finalErr)
- return nil, finalErr
- }
- log.Error("Unable to run diff-index pipeline in temporary repo %s (%s). Error: %v\nStderr: %s",
- t.repo.FullName(), t.basePath, err, stderr)
- return nil, fmt.Errorf("Unable to run diff-index pipeline in temporary repo %s. Error: %v\nStderr: %s",
- t.repo.FullName(), err, stderr)
- }
-
- diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(t.basePath, "--cached", "HEAD")
- if err != nil {
- return nil, err
- }
-
- return diff, nil
-}
-
-// GetBranchCommit Gets the commit object of the given branch
-func (t *TemporaryUploadRepository) GetBranchCommit(branch string) (*git.Commit, error) {
- if t.gitRepo == nil {
- return nil, fmt.Errorf("repository has not been cloned")
- }
- return t.gitRepo.GetBranchCommit(branch)
-}
-
-// GetCommit Gets the commit object of the given commit ID
-func (t *TemporaryUploadRepository) GetCommit(commitID string) (*git.Commit, error) {
- if t.gitRepo == nil {
- return nil, fmt.Errorf("repository has not been cloned")
- }
- return t.gitRepo.GetCommit(commitID)
-}
diff --git a/modules/repofiles/tree.go b/modules/repofiles/tree.go
deleted file mode 100644
index 81579dccc5..0000000000
--- a/modules/repofiles/tree.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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"
- "net/url"
-
- "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/" + url.PathEscape(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
-}
diff --git a/modules/repofiles/tree_test.go b/modules/repofiles/tree_test.go
deleted file mode 100644
index 6917b8915b..0000000000
--- a/modules/repofiles/tree_test.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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 (
- "testing"
-
- "code.gitea.io/gitea/models/unittest"
- api "code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/modules/test"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestGetTreeBySHA(t *testing.T) {
- unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1")
- test.LoadRepo(t, ctx, 1)
- test.LoadRepoCommit(t, ctx)
- test.LoadUser(t, ctx, 2)
- test.LoadGitRepo(t, ctx)
- defer ctx.Repo.GitRepo.Close()
-
- sha := ctx.Repo.Repository.DefaultBranch
- page := 1
- perPage := 10
- ctx.SetParams(":id", "1")
- ctx.SetParams(":sha", sha)
-
- tree, err := GetTreeBySHA(ctx.Repo.Repository, ctx.Params(":sha"), page, perPage, true)
- assert.NoError(t, err)
- expectedTree := &api.GitTreeResponse{
- SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
- URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/trees/65f1bf27bc3bf70f64657658635e66094edbcb4d",
- Entries: []api.GitEntry{
- {
- Path: "README.md",
- Mode: "100644",
- Type: "blob",
- Size: 30,
- SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f",
- URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/4b4851ad51df6a7d9f25c979345979eaeb5b349f",
- },
- },
- Truncated: false,
- Page: 1,
- TotalCount: 1,
- }
-
- assert.EqualValues(t, expectedTree, tree)
-}
diff --git a/modules/repofiles/update.go b/modules/repofiles/update.go
deleted file mode 100644
index d25accff18..0000000000
--- a/modules/repofiles/update.go
+++ /dev/null
@@ -1,479 +0,0 @@
-// 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 (
- "bytes"
- "fmt"
- "path"
- "strings"
- "time"
-
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/charset"
- "code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/lfs"
- "code.gitea.io/gitea/modules/log"
- repo_module "code.gitea.io/gitea/modules/repository"
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/modules/util"
-
- stdcharset "golang.org/x/net/html/charset"
- "golang.org/x/text/transform"
-)
-
-// IdentityOptions for a person's identity like an author or committer
-type IdentityOptions struct {
- Name string
- Email string
-}
-
-// CommitDateOptions store dates for GIT_AUTHOR_DATE and GIT_COMMITTER_DATE
-type CommitDateOptions struct {
- Author time.Time
- Committer time.Time
-}
-
-// UpdateRepoFileOptions holds the repository file update options
-type UpdateRepoFileOptions struct {
- LastCommitID string
- OldBranch string
- NewBranch string
- TreePath string
- FromTreePath string
- Message string
- Content string
- SHA string
- IsNewFile bool
- Author *IdentityOptions
- Committer *IdentityOptions
- Dates *CommitDateOptions
- Signoff bool
-}
-
-func detectEncodingAndBOM(entry *git.TreeEntry, repo *models.Repository) (string, bool) {
- reader, err := entry.Blob().DataAsync()
- if err != nil {
- // return default
- return "UTF-8", false
- }
- defer reader.Close()
- buf := make([]byte, 1024)
- n, err := util.ReadAtMost(reader, buf)
- if err != nil {
- // return default
- return "UTF-8", false
- }
- buf = buf[:n]
-
- if setting.LFS.StartServer {
- pointer, _ := lfs.ReadPointerFromBuffer(buf)
- if pointer.IsValid() {
- meta, err := repo.GetLFSMetaObjectByOid(pointer.Oid)
- if err != nil && err != models.ErrLFSObjectNotExist {
- // return default
- return "UTF-8", false
- }
- if meta != nil {
- dataRc, err := lfs.ReadMetaObject(pointer)
- if err != nil {
- // return default
- return "UTF-8", false
- }
- defer dataRc.Close()
- buf = make([]byte, 1024)
- n, err = util.ReadAtMost(dataRc, buf)
- if err != nil {
- // return default
- return "UTF-8", false
- }
- buf = buf[:n]
- }
- }
- }
-
- encoding, err := charset.DetectEncoding(buf)
- if err != nil {
- // just default to utf-8 and no bom
- return "UTF-8", false
- }
- if encoding == "UTF-8" {
- return encoding, bytes.Equal(buf[0:3], charset.UTF8BOM)
- }
- charsetEncoding, _ := stdcharset.Lookup(encoding)
- if charsetEncoding == nil {
- return "UTF-8", false
- }
-
- result, n, err := transform.String(charsetEncoding.NewDecoder(), string(buf))
- if err != nil {
- // return default
- return "UTF-8", false
- }
-
- if n > 2 {
- return encoding, bytes.Equal([]byte(result)[0:3], charset.UTF8BOM)
- }
-
- return encoding, false
-}
-
-// CreateOrUpdateRepoFile adds or updates a file in the given repository
-func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *UpdateRepoFileOptions) (*structs.FileResponse, error) {
- // If no branch name is set, assume default branch
- if opts.OldBranch == "" {
- opts.OldBranch = repo.DefaultBranch
- }
- if opts.NewBranch == "" {
- opts.NewBranch = opts.OldBranch
- }
-
- // oldBranch must exist for this operation
- if _, err := repo_module.GetBranch(repo, opts.OldBranch); err != nil {
- return nil, err
- }
-
- // A NewBranch can be specified for the file to be created/updated in a new branch.
- // Check to make sure the branch does not already exist, otherwise we can't proceed.
- // If we aren't branching to a new branch, make sure user can commit to the given branch
- if opts.NewBranch != opts.OldBranch {
- existingBranch, err := repo_module.GetBranch(repo, opts.NewBranch)
- if existingBranch != nil {
- return nil, models.ErrBranchAlreadyExists{
- BranchName: opts.NewBranch,
- }
- }
- if err != nil && !git.IsErrBranchNotExist(err) {
- return nil, err
- }
- } else if err := VerifyBranchProtection(repo, doer, opts.OldBranch, opts.TreePath); err != nil {
- return nil, err
- }
-
- // If FromTreePath is not set, set it to the opts.TreePath
- if opts.TreePath != "" && opts.FromTreePath == "" {
- opts.FromTreePath = opts.TreePath
- }
-
- // Check that the path given in opts.treePath is valid (not a git path)
- treePath := CleanUploadFileName(opts.TreePath)
- if treePath == "" {
- return nil, models.ErrFilenameInvalid{
- Path: opts.TreePath,
- }
- }
- // If there is a fromTreePath (we are copying it), also clean it up
- fromTreePath := CleanUploadFileName(opts.FromTreePath)
- if fromTreePath == "" && opts.FromTreePath != "" {
- return nil, models.ErrFilenameInvalid{
- Path: opts.FromTreePath,
- }
- }
-
- message := strings.TrimSpace(opts.Message)
-
- author, committer := GetAuthorAndCommitterUsers(opts.Author, opts.Committer, doer)
-
- t, err := NewTemporaryUploadRepository(repo)
- if err != nil {
- log.Error("%v", err)
- }
- defer t.Close()
- if err := t.Clone(opts.OldBranch); err != nil {
- return nil, err
- }
- if err := t.SetDefaultIndex(); err != nil {
- return nil, err
- }
-
- // Get the commit of the original branch
- commit, err := t.GetBranchCommit(opts.OldBranch)
- if err != nil {
- return nil, err // Couldn't get a commit for the branch
- }
-
- // Assigned LastCommitID in opts if it hasn't been set
- if opts.LastCommitID == "" {
- opts.LastCommitID = commit.ID.String()
- } else {
- lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
- if err != nil {
- return nil, fmt.Errorf("DeleteRepoFile: Invalid last commit ID: %v", err)
- }
- opts.LastCommitID = lastCommitID.String()
-
- }
-
- encoding := "UTF-8"
- bom := false
- executable := false
-
- if !opts.IsNewFile {
- fromEntry, err := commit.GetTreeEntryByPath(fromTreePath)
- if err != nil {
- return nil, err
- }
- if opts.SHA != "" {
- // If a SHA was given and the SHA given doesn't match the SHA of the fromTreePath, throw error
- if opts.SHA != fromEntry.ID.String() {
- return nil, models.ErrSHADoesNotMatch{
- Path: treePath,
- GivenSHA: opts.SHA,
- CurrentSHA: fromEntry.ID.String(),
- }
- }
- } else if opts.LastCommitID != "" {
- // If a lastCommitID was given and it doesn't match the commitID of the head of the branch throw
- // an error, but only if we aren't creating a new branch.
- if commit.ID.String() != opts.LastCommitID && opts.OldBranch == opts.NewBranch {
- if changed, err := commit.FileChangedSinceCommit(treePath, opts.LastCommitID); err != nil {
- return nil, err
- } else if changed {
- return nil, models.ErrCommitIDDoesNotMatch{
- GivenCommitID: opts.LastCommitID,
- CurrentCommitID: opts.LastCommitID,
- }
- }
- // The file wasn't modified, so we are good to delete it
- }
- } else {
- // When updating a file, a lastCommitID or SHA needs to be given to make sure other commits
- // haven't been made. We throw an error if one wasn't provided.
- return nil, models.ErrSHAOrCommitIDNotProvided{}
- }
- encoding, bom = detectEncodingAndBOM(fromEntry, repo)
- executable = fromEntry.IsExecutable()
- }
-
- // For the path where this file will be created/updated, we need to make
- // sure no parts of the path are existing files or links except for the last
- // item in the path which is the file name, and that shouldn't exist IF it is
- // a new file OR is being moved to a new path.
- treePathParts := strings.Split(treePath, "/")
- subTreePath := ""
- for index, part := range treePathParts {
- subTreePath = path.Join(subTreePath, part)
- entry, err := commit.GetTreeEntryByPath(subTreePath)
- if err != nil {
- if git.IsErrNotExist(err) {
- // Means there is no item with that name, so we're good
- break
- }
- return nil, err
- }
- if index < len(treePathParts)-1 {
- if !entry.IsDir() {
- return nil, models.ErrFilePathInvalid{
- Message: fmt.Sprintf("a file exists where you’re trying to create a subdirectory [path: %s]", subTreePath),
- Path: subTreePath,
- Name: part,
- Type: git.EntryModeBlob,
- }
- }
- } else if entry.IsLink() {
- return nil, models.ErrFilePathInvalid{
- Message: fmt.Sprintf("a symbolic link exists where you’re trying to create a subdirectory [path: %s]", subTreePath),
- Path: subTreePath,
- Name: part,
- Type: git.EntryModeSymlink,
- }
- } else if entry.IsDir() {
- return nil, models.ErrFilePathInvalid{
- Message: fmt.Sprintf("a directory exists where you’re trying to create a file [path: %s]", subTreePath),
- Path: subTreePath,
- Name: part,
- Type: git.EntryModeTree,
- }
- } else if fromTreePath != treePath || opts.IsNewFile {
- // The entry shouldn't exist if we are creating new file or moving to a new path
- return nil, models.ErrRepoFileAlreadyExists{
- Path: treePath,
- }
- }
-
- }
-
- // Get the two paths (might be the same if not moving) from the index if they exist
- filesInIndex, err := t.LsFiles(opts.TreePath, opts.FromTreePath)
- if err != nil {
- return nil, fmt.Errorf("UpdateRepoFile: %v", err)
- }
- // If is a new file (not updating) then the given path shouldn't exist
- if opts.IsNewFile {
- for _, file := range filesInIndex {
- if file == opts.TreePath {
- return nil, models.ErrRepoFileAlreadyExists{
- Path: opts.TreePath,
- }
- }
- }
- }
-
- // Remove the old path from the tree
- if fromTreePath != treePath && len(filesInIndex) > 0 {
- for _, file := range filesInIndex {
- if file == fromTreePath {
- if err := t.RemoveFilesFromIndex(opts.FromTreePath); err != nil {
- return nil, err
- }
- }
- }
- }
-
- content := opts.Content
- if bom {
- content = string(charset.UTF8BOM) + content
- }
- if encoding != "UTF-8" {
- charsetEncoding, _ := stdcharset.Lookup(encoding)
- if charsetEncoding != nil {
- result, _, err := transform.String(charsetEncoding.NewEncoder(), content)
- if err != nil {
- // Look if we can't encode back in to the original we should just stick with utf-8
- log.Error("Error re-encoding %s (%s) as %s - will stay as UTF-8: %v", opts.TreePath, opts.FromTreePath, encoding, err)
- result = content
- }
- content = result
- } else {
- log.Error("Unknown encoding: %s", encoding)
- }
- }
- // Reset the opts.Content to our adjusted content to ensure that LFS gets the correct content
- opts.Content = content
- var lfsMetaObject *models.LFSMetaObject
-
- if setting.LFS.StartServer {
- // Check there is no way this can return multiple infos
- filename2attribute2info, err := t.gitRepo.CheckAttribute(git.CheckAttributeOpts{
- Attributes: []string{"filter"},
- Filenames: []string{treePath},
- })
- if err != nil {
- return nil, err
- }
-
- if filename2attribute2info[treePath] != nil && filename2attribute2info[treePath]["filter"] == "lfs" {
- // OK so we are supposed to LFS this data!
- pointer, err := lfs.GeneratePointer(strings.NewReader(opts.Content))
- if err != nil {
- return nil, err
- }
- lfsMetaObject = &models.LFSMetaObject{Pointer: pointer, RepositoryID: repo.ID}
- content = pointer.StringContent()
- }
- }
- // Add the object to the database
- objectHash, err := t.HashObject(strings.NewReader(content))
- if err != nil {
- return nil, err
- }
-
- // Add the object to the index
- if executable {
- if err := t.AddObjectToIndex("100755", objectHash, treePath); err != nil {
- return nil, err
- }
- } else {
- if err := t.AddObjectToIndex("100644", objectHash, treePath); err != nil {
- return nil, err
- }
- }
-
- // Now write the tree
- treeHash, err := t.WriteTree()
- if err != nil {
- return nil, err
- }
-
- // Now commit the tree
- var commitHash string
- if opts.Dates != nil {
- commitHash, err = t.CommitTreeWithDate(author, committer, treeHash, message, opts.Signoff, opts.Dates.Author, opts.Dates.Committer)
- } else {
- commitHash, err = t.CommitTree(author, committer, treeHash, message, opts.Signoff)
- }
- if err != nil {
- return nil, err
- }
-
- if lfsMetaObject != nil {
- // We have an LFS object - create it
- lfsMetaObject, err = models.NewLFSMetaObject(lfsMetaObject)
- if err != nil {
- return nil, err
- }
- contentStore := lfs.NewContentStore()
- exist, err := contentStore.Exists(lfsMetaObject.Pointer)
- if err != nil {
- return nil, err
- }
- if !exist {
- if err := contentStore.Put(lfsMetaObject.Pointer, strings.NewReader(opts.Content)); err != nil {
- if _, err2 := repo.RemoveLFSMetaObjectByOid(lfsMetaObject.Oid); err2 != nil {
- return nil, fmt.Errorf("Error whilst removing failed inserted LFS object %s: %v (Prev Error: %v)", lfsMetaObject.Oid, err2, err)
- }
- return nil, err
- }
- }
- }
-
- // Then push this tree to NewBranch
- if err := t.Push(doer, commitHash, opts.NewBranch); err != nil {
- log.Error("%T %v", err, err)
- return nil, err
- }
-
- commit, err = t.GetCommit(commitHash)
- if err != nil {
- return nil, err
- }
-
- file, err := GetFileResponseFromCommit(repo, commit, opts.NewBranch, treePath)
- if err != nil {
- return nil, err
- }
- return file, nil
-}
-
-// VerifyBranchProtection verify the branch protection for modifying the given treePath on the given branch
-func VerifyBranchProtection(repo *models.Repository, doer *models.User, branchName string, treePath string) error {
- protectedBranch, err := repo.GetBranchProtection(branchName)
- if err != nil {
- return err
- }
- if protectedBranch != nil {
- isUnprotectedFile := false
- glob := protectedBranch.GetUnprotectedFilePatterns()
- if len(glob) != 0 {
- isUnprotectedFile = protectedBranch.IsUnprotectedFile(glob, treePath)
- }
- if !protectedBranch.CanUserPush(doer.ID) && !isUnprotectedFile {
- return models.ErrUserCannotCommit{
- UserName: doer.LowerName,
- }
- }
- if protectedBranch.RequireSignedCommits {
- _, _, _, err := repo.SignCRUDAction(doer, repo.RepoPath(), branchName)
- if err != nil {
- if !models.IsErrWontSign(err) {
- return err
- }
- return models.ErrUserCannotCommit{
- UserName: doer.LowerName,
- }
- }
- }
- patterns := protectedBranch.GetProtectedFilePatterns()
- for _, pat := range patterns {
- if pat.Match(strings.ToLower(treePath)) {
- return models.ErrFilePathProtected{
- Path: treePath,
- }
- }
- }
- }
- return nil
-}
diff --git a/modules/repofiles/upload.go b/modules/repofiles/upload.go
deleted file mode 100644
index e97f55a656..0000000000
--- a/modules/repofiles/upload.go
+++ /dev/null
@@ -1,207 +0,0 @@
-// 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"
- "os"
- "path"
- "strings"
-
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/lfs"
- "code.gitea.io/gitea/modules/setting"
-)
-
-// UploadRepoFileOptions contains the uploaded repository file options
-type UploadRepoFileOptions struct {
- LastCommitID string
- OldBranch string
- NewBranch string
- TreePath string
- Message string
- Files []string // In UUID format.
- Signoff bool
-}
-
-type uploadInfo struct {
- upload *models.Upload
- lfsMetaObject *models.LFSMetaObject
-}
-
-func cleanUpAfterFailure(infos *[]uploadInfo, t *TemporaryUploadRepository, original error) error {
- for _, info := range *infos {
- if info.lfsMetaObject == nil {
- continue
- }
- if !info.lfsMetaObject.Existing {
- if _, err := t.repo.RemoveLFSMetaObjectByOid(info.lfsMetaObject.Oid); err != nil {
- original = fmt.Errorf("%v, %v", original, err)
- }
- }
- }
- return original
-}
-
-// UploadRepoFiles uploads files to the given repository
-func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRepoFileOptions) error {
- if len(opts.Files) == 0 {
- return nil
- }
-
- uploads, err := models.GetUploadsByUUIDs(opts.Files)
- if err != nil {
- return fmt.Errorf("GetUploadsByUUIDs [uuids: %v]: %v", opts.Files, err)
- }
-
- names := make([]string, len(uploads))
- infos := make([]uploadInfo, len(uploads))
- for i, upload := range uploads {
- // Check file is not lfs locked, will return nil if lock setting not enabled
- filepath := path.Join(opts.TreePath, upload.Name)
- lfsLock, err := repo.GetTreePathLock(filepath)
- if err != nil {
- return err
- }
- if lfsLock != nil && lfsLock.OwnerID != doer.ID {
- return models.ErrLFSFileLocked{RepoID: repo.ID, Path: filepath, UserName: lfsLock.Owner.Name}
- }
-
- names[i] = upload.Name
- infos[i] = uploadInfo{upload: upload}
- }
-
- t, err := NewTemporaryUploadRepository(repo)
- if err != nil {
- return err
- }
- defer t.Close()
- if err := t.Clone(opts.OldBranch); err != nil {
- return err
- }
- if err := t.SetDefaultIndex(); err != nil {
- return err
- }
-
- var filename2attribute2info map[string]map[string]string
- if setting.LFS.StartServer {
- filename2attribute2info, err = t.gitRepo.CheckAttribute(git.CheckAttributeOpts{
- Attributes: []string{"filter"},
- Filenames: names,
- })
- if err != nil {
- return err
- }
- }
-
- // Copy uploaded files into repository.
- for i := range infos {
- if err := copyUploadedLFSFileIntoRepository(&infos[i], filename2attribute2info, t, opts.TreePath); err != nil {
- return err
- }
- }
-
- // Now write the tree
- treeHash, err := t.WriteTree()
- if err != nil {
- return err
- }
-
- // make author and committer the doer
- author := doer
- committer := doer
-
- // Now commit the tree
- commitHash, err := t.CommitTree(author, committer, treeHash, opts.Message, opts.Signoff)
- if err != nil {
- return err
- }
-
- // Now deal with LFS objects
- for i := range infos {
- if infos[i].lfsMetaObject == nil {
- continue
- }
- infos[i].lfsMetaObject, err = models.NewLFSMetaObject(infos[i].lfsMetaObject)
- if err != nil {
- // OK Now we need to cleanup
- return cleanUpAfterFailure(&infos, t, err)
- }
- // Don't move the files yet - we need to ensure that
- // everything can be inserted first
- }
-
- // OK now we can insert the data into the store - there's no way to clean up the store
- // once it's in there, it's in there.
- contentStore := lfs.NewContentStore()
- for _, info := range infos {
- if err := uploadToLFSContentStore(info, contentStore); err != nil {
- return cleanUpAfterFailure(&infos, t, err)
- }
- }
-
- // Then push this tree to NewBranch
- if err := t.Push(doer, commitHash, opts.NewBranch); err != nil {
- return err
- }
-
- return models.DeleteUploads(uploads...)
-}
-
-func copyUploadedLFSFileIntoRepository(info *uploadInfo, filename2attribute2info map[string]map[string]string, t *TemporaryUploadRepository, treePath string) error {
- file, err := os.Open(info.upload.LocalPath())
- if err != nil {
- return err
- }
- defer file.Close()
-
- var objectHash string
- if setting.LFS.StartServer && filename2attribute2info[info.upload.Name] != nil && filename2attribute2info[info.upload.Name]["filter"] == "lfs" {
- // Handle LFS
- // FIXME: Inefficient! this should probably happen in models.Upload
- pointer, err := lfs.GeneratePointer(file)
- if err != nil {
- return err
- }
-
- info.lfsMetaObject = &models.LFSMetaObject{Pointer: pointer, RepositoryID: t.repo.ID}
-
- if objectHash, err = t.HashObject(strings.NewReader(pointer.StringContent())); err != nil {
- return err
- }
- } else if objectHash, err = t.HashObject(file); err != nil {
- return err
- }
-
- // Add the object to the index
- return t.AddObjectToIndex("100644", objectHash, path.Join(treePath, info.upload.Name))
-}
-
-func uploadToLFSContentStore(info uploadInfo, contentStore *lfs.ContentStore) error {
- if info.lfsMetaObject == nil {
- return nil
- }
- exist, err := contentStore.Exists(info.lfsMetaObject.Pointer)
- if err != nil {
- return err
- }
- if !exist {
- file, err := os.Open(info.upload.LocalPath())
- if err != nil {
- return err
- }
-
- defer file.Close()
- // FIXME: Put regenerates the hash and copies the file over.
- // I guess this strictly ensures the soundness of the store but this is inefficient.
- if err := contentStore.Put(info.lfsMetaObject.Pointer, file); err != nil {
- // OK Now we need to cleanup
- // Can't clean up the store, once uploaded there they're there.
- return err
- }
- }
- return nil
-}
diff --git a/modules/repofiles/verification.go b/modules/repofiles/verification.go
deleted file mode 100644
index 3889b7993c..0000000000
--- a/modules/repofiles/verification.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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 (
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/structs"
-)
-
-// GetPayloadCommitVerification returns the verification information of a commit
-func GetPayloadCommitVerification(commit *git.Commit) *structs.PayloadCommitVerification {
- verification := &structs.PayloadCommitVerification{}
- commitVerification := models.ParseCommitWithSignature(commit)
- if commit.Signature != nil {
- verification.Signature = commit.Signature.Signature
- verification.Payload = commit.Signature.Payload
- }
- if commitVerification.SigningUser != nil {
- verification.Signer = &structs.PayloadUser{
- Name: commitVerification.SigningUser.Name,
- Email: commitVerification.SigningUser.Email,
- }
- }
- verification.Verified = commitVerification.Verified
- verification.Reason = commitVerification.Reason
- if verification.Reason == "" && !verification.Verified {
- verification.Reason = "gpg.error.not_signed_commit"
- }
- return verification
-}
diff --git a/modules/repository/branch.go b/modules/repository/branch.go
deleted file mode 100644
index dcd82554d5..0000000000
--- a/modules/repository/branch.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2020 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 repository
-
-import (
- "fmt"
-
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/git"
-)
-
-// GetBranch returns a branch by its name
-func GetBranch(repo *models.Repository, branch string) (*git.Branch, error) {
- if len(branch) == 0 {
- return nil, fmt.Errorf("GetBranch: empty string for branch")
- }
- gitRepo, err := git.OpenRepository(repo.RepoPath())
- if err != nil {
- return nil, err
- }
- defer gitRepo.Close()
-
- return gitRepo.GetBranch(branch)
-}
diff --git a/modules/repository/check.go b/modules/repository/check.go
deleted file mode 100644
index 36bd4e2e0d..0000000000
--- a/modules/repository/check.go
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright 2020 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 repository
-
-import (
- "context"
- "fmt"
- "strings"
- "time"
-
- "code.gitea.io/gitea/models"
- admin_model "code.gitea.io/gitea/models/admin"
- "code.gitea.io/gitea/models/db"
- "code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/util"
-
- "xorm.io/builder"
-)
-
-// GitFsck calls 'git fsck' to check repository health.
-func GitFsck(ctx context.Context, timeout time.Duration, args []string) error {
- log.Trace("Doing: GitFsck")
-
- if err := db.Iterate(
- db.DefaultContext,
- new(models.Repository),
- builder.Expr("id>0 AND is_fsck_enabled=?", true),
- func(idx int, bean interface{}) error {
- repo := bean.(*models.Repository)
- select {
- case <-ctx.Done():
- return db.ErrCancelledf("before fsck of %s", repo.FullName())
- default:
- }
- log.Trace("Running health check on repository %v", repo)
- repoPath := repo.RepoPath()
- if err := git.Fsck(ctx, repoPath, timeout, args...); err != nil {
- log.Warn("Failed to health check repository (%v): %v", repo, err)
- if err = admin_model.CreateRepositoryNotice("Failed to health check repository (%s): %v", repo.FullName(), err); err != nil {
- log.Error("CreateRepositoryNotice: %v", err)
- }
- }
- return nil
- },
- ); err != nil {
- log.Trace("Error: GitFsck: %v", err)
- return err
- }
-
- log.Trace("Finished: GitFsck")
- return nil
-}
-
-// GitGcRepos calls 'git gc' to remove unnecessary files and optimize the local repository
-func GitGcRepos(ctx context.Context, timeout time.Duration, args ...string) error {
- log.Trace("Doing: GitGcRepos")
- args = append([]string{"gc"}, args...)
-
- if err := db.Iterate(
- db.DefaultContext,
- new(models.Repository),
- builder.Gt{"id": 0},
- func(idx int, bean interface{}) error {
- repo := bean.(*models.Repository)
- select {
- case <-ctx.Done():
- return db.ErrCancelledf("before GC of %s", repo.FullName())
- default:
- }
- log.Trace("Running git gc on %v", repo)
- command := git.NewCommandContext(ctx, args...).
- SetDescription(fmt.Sprintf("Repository Garbage Collection: %s", repo.FullName()))
- var stdout string
- var err error
- if timeout > 0 {
- var stdoutBytes []byte
- stdoutBytes, err = command.RunInDirTimeout(
- timeout,
- repo.RepoPath())
- stdout = string(stdoutBytes)
- } else {
- stdout, err = command.RunInDir(repo.RepoPath())
- }
-
- if err != nil {
- log.Error("Repository garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err)
- desc := fmt.Sprintf("Repository garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err)
- if err = admin_model.CreateRepositoryNotice(desc); err != nil {
- log.Error("CreateRepositoryNotice: %v", err)
- }
- return fmt.Errorf("Repository garbage collection failed in repo: %s: Error: %v", repo.FullName(), err)
- }
-
- // Now update the size of the repository
- if err := repo.UpdateSize(db.DefaultContext); err != nil {
- log.Error("Updating size as part of garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err)
- desc := fmt.Sprintf("Updating size as part of garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err)
- if err = admin_model.CreateRepositoryNotice(desc); err != nil {
- log.Error("CreateRepositoryNotice: %v", err)
- }
- return fmt.Errorf("Updating size as part of garbage collection failed in repo: %s: Error: %v", repo.FullName(), err)
- }
-
- return nil
- },
- ); err != nil {
- return err
- }
-
- log.Trace("Finished: GitGcRepos")
- return nil
-}
-
-func gatherMissingRepoRecords(ctx context.Context) ([]*models.Repository, error) {
- repos := make([]*models.Repository, 0, 10)
- if err := db.Iterate(
- db.DefaultContext,
- new(models.Repository),
- builder.Gt{"id": 0},
- func(idx int, bean interface{}) error {
- repo := bean.(*models.Repository)
- select {
- case <-ctx.Done():
- return db.ErrCancelledf("during gathering missing repo records before checking %s", repo.FullName())
- default:
- }
- isDir, err := util.IsDir(repo.RepoPath())
- if err != nil {
- return fmt.Errorf("Unable to check dir for %s. %w", repo.FullName(), err)
- }
- if !isDir {
- repos = append(repos, repo)
- }
- return nil
- },
- ); err != nil {
- if strings.HasPrefix(err.Error(), "Aborted gathering missing repo") {
- return nil, err
- }
- if err2 := admin_model.CreateRepositoryNotice("gatherMissingRepoRecords: %v", err); err2 != nil {
- log.Error("CreateRepositoryNotice: %v", err2)
- }
- return nil, err
- }
- return repos, nil
-}
-
-// DeleteMissingRepositories deletes all repository records that lost Git files.
-func DeleteMissingRepositories(ctx context.Context, doer *models.User) error {
- repos, err := gatherMissingRepoRecords(ctx)
- if err != nil {
- return err
- }
-
- if len(repos) == 0 {
- return nil
- }
-
- for _, repo := range repos {
- select {
- case <-ctx.Done():
- return db.ErrCancelledf("during DeleteMissingRepositories before %s", repo.FullName())
- default:
- }
- log.Trace("Deleting %d/%d...", repo.OwnerID, repo.ID)
- if err := models.DeleteRepository(doer, repo.OwnerID, repo.ID); err != nil {
- log.Error("Failed to DeleteRepository %s [%d]: Error: %v", repo.FullName(), repo.ID, err)
- if err2 := admin_model.CreateRepositoryNotice("Failed to DeleteRepository %s [%d]: Error: %v", repo.FullName(), repo.ID, err); err2 != nil {
- log.Error("CreateRepositoryNotice: %v", err)
- }
- }
- }
- return nil
-}
-
-// ReinitMissingRepositories reinitializes all repository records that lost Git files.
-func ReinitMissingRepositories(ctx context.Context) error {
- repos, err := gatherMissingRepoRecords(ctx)
- if err != nil {
- return err
- }
-
- if len(repos) == 0 {
- return nil
- }
-
- for _, repo := range repos {
- select {
- case <-ctx.Done():
- return db.ErrCancelledf("during ReinitMissingRepositories before %s", repo.FullName())
- default:
- }
- log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID)
- if err := git.InitRepository(repo.RepoPath(), true); err != nil {
- log.Error("Unable (re)initialize repository %d at %s. Error: %v", repo.ID, repo.RepoPath(), err)
- if err2 := admin_model.CreateRepositoryNotice("InitRepository [%d]: %v", repo.ID, err); err2 != nil {
- log.Error("CreateRepositoryNotice: %v", err2)
- }
- }
- }
- return nil
-}