mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-03 16:04:26 +00:00
9dc04289aa
before: gitrepo vs git packages after: git package fully handle all git operations by the way, use `WithRepo(repo)` instead of `WithDir(repo.Path)` to hide path details. benefits: 1. remove all unnecessary wrappers, developers no need to struggle with "which package should be used" 2. simplify code, RepositoryFacade can (will) be used everywhere, all "path" details are (will be) hidden
135 lines
5.3 KiB
Go
135 lines
5.3 KiB
Go
// Copyright 2025 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package repo
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"path"
|
|
"strconv"
|
|
"strings"
|
|
|
|
git_model "gitea.dev/models/git"
|
|
repo_model "gitea.dev/models/repo"
|
|
user_model "gitea.dev/models/user"
|
|
"gitea.dev/modules/git"
|
|
"gitea.dev/modules/log"
|
|
"gitea.dev/modules/markup"
|
|
repo_module "gitea.dev/modules/repository"
|
|
"gitea.dev/modules/setting"
|
|
"gitea.dev/modules/util"
|
|
context_service "gitea.dev/services/context"
|
|
)
|
|
|
|
// getUniquePatchBranchName Gets a unique branch name for a new patch branch
|
|
// It will be in the form of <username>-patch-<num> where <num> is the first branch of this format
|
|
// that doesn't already exist. If we exceed 1000 tries or an error is thrown, we just return "" so the user has to
|
|
// type in the branch name themselves (will be an empty field)
|
|
func getUniquePatchBranchName(ctx context.Context, prefixName string, repo *repo_model.Repository) string {
|
|
prefix := prefixName + "-patch-"
|
|
for i := 1; i <= 1000; i++ {
|
|
branchName := fmt.Sprintf("%s%d", prefix, i)
|
|
if exist, err := git_model.IsBranchExist(ctx, repo.ID, branchName); err != nil {
|
|
log.Error("getUniquePatchBranchName: %v", err)
|
|
return ""
|
|
} else if !exist {
|
|
return branchName
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// getClosestParentWithFiles Recursively gets the closest path of parent in a tree that has files when a file in a tree is
|
|
// deleted. It returns "" for the tree root if no parents other than the root have files.
|
|
func getClosestParentWithFiles(ctx context.Context, gitRepo *git.Repository, branchName, originTreePath string) string {
|
|
var f func(treePath string, commit *git.Commit) string
|
|
f = func(treePath string, commit *git.Commit) string {
|
|
if treePath == "" || treePath == "." {
|
|
return ""
|
|
}
|
|
// see if the tree has entries
|
|
if tree, err := commit.SubTree(ctx, gitRepo, treePath); err != nil {
|
|
return f(path.Dir(treePath), commit) // failed to get the tree, going up a dir
|
|
} else if entries, err := tree.ListEntries(ctx, gitRepo); err != nil || len(entries) == 0 {
|
|
return f(path.Dir(treePath), commit) // no files in this dir, going up a dir
|
|
}
|
|
return treePath
|
|
}
|
|
commit, err := gitRepo.GetBranchCommit(ctx, branchName) // must get the commit again to get the latest change
|
|
if err != nil {
|
|
log.Error("GetBranchCommit: %v", err)
|
|
return ""
|
|
}
|
|
return f(originTreePath, commit)
|
|
}
|
|
|
|
// CodeEditorConfig is also used by frontend, defined in "codeeditor" module
|
|
type CodeEditorConfig struct {
|
|
Filename string `json:"filename"` // the base name, not full path
|
|
Autofocus bool `json:"autofocus"`
|
|
PreviewableExtensions []string `json:"previewableExtensions,omitempty"`
|
|
LineWrapExtensions []string `json:"lineWrapExtensions,omitempty"`
|
|
LineWrap bool `json:"lineWrap"`
|
|
Previewable bool `json:"previewable,omitempty"`
|
|
|
|
// the following can be read from .editorconfig if exists, or use default value
|
|
IndentStyle string `json:"indentStyle"` // in most cases, keep it empty by default, detected by the source code
|
|
IndentSize int `json:"indentSize"`
|
|
TabWidth int `json:"tabWidth"`
|
|
TrimTrailingWhitespace *bool `json:"trimTrailingWhitespace,omitempty"`
|
|
}
|
|
|
|
func getCodeEditorConfigByEditorconfig(ctx *context_service.Context, treePath string) CodeEditorConfig {
|
|
ret := CodeEditorConfig{Filename: path.Base(treePath)}
|
|
ret.PreviewableExtensions = markup.PreviewableExtensions()
|
|
ret.LineWrapExtensions = setting.Repository.Editor.LineWrapExtensions
|
|
ret.LineWrap = util.SliceContainsString(ret.LineWrapExtensions, path.Ext(treePath), true)
|
|
ret.Previewable = util.SliceContainsString(ret.PreviewableExtensions, path.Ext(treePath), true)
|
|
ec, _, err := ctx.Repo.GetEditorconfig(ctx)
|
|
if err == nil {
|
|
def, err := ec.GetDefinitionForFilename(treePath)
|
|
if err == nil {
|
|
ret.IndentStyle = util.IfZero(def.IndentStyle, ret.IndentStyle)
|
|
ret.IndentSize, _ = strconv.Atoi(def.IndentSize)
|
|
ret.TabWidth = def.TabWidth
|
|
ret.TrimTrailingWhitespace = def.TrimTrailingWhitespace
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// getParentTreeFields returns list of parent tree names and corresponding tree paths based on given treePath.
|
|
// eg: []{"a", "b", "c"}, []{"a", "a/b", "a/b/c"}
|
|
// or: []{""}, []{""} for the root treePath
|
|
func getParentTreeFields(treePath string) (treeNames, treePaths []string) {
|
|
treeNames = strings.Split(treePath, "/")
|
|
treePaths = make([]string, len(treeNames))
|
|
for i := range treeNames {
|
|
treePaths[i] = strings.Join(treeNames[:i+1], "/")
|
|
}
|
|
return treeNames, treePaths
|
|
}
|
|
|
|
// getUniqueRepositoryName Gets a unique repository name for a user
|
|
// It will append a -<num> postfix if the name is already taken
|
|
func getUniqueRepositoryName(ctx context.Context, ownerID int64, name string) string {
|
|
uniqueName := name
|
|
for i := 1; i < 1000; i++ {
|
|
_, err := repo_model.GetRepositoryByName(ctx, ownerID, uniqueName)
|
|
if err != nil || repo_model.IsErrRepoNotExist(err) {
|
|
return uniqueName
|
|
}
|
|
uniqueName = fmt.Sprintf("%s-%d", name, i)
|
|
i++
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func editorPushBranchToForkedRepository(ctx context.Context, doer *user_model.User, baseRepo *repo_model.Repository, baseBranchName string, targetRepo *repo_model.Repository, targetBranchName string) error {
|
|
return git.PushManaged(ctx, baseRepo, targetRepo, git.PushOptions{
|
|
Branch: baseBranchName + ":" + targetBranchName,
|
|
Env: repo_module.PushingEnvironment(doer, targetRepo),
|
|
})
|
|
}
|