From a1099096cbb1a28d4f71763ce1f9065d6b13d7ff Mon Sep 17 00:00:00 2001 From: yystopf Date: Thu, 23 Feb 2023 09:47:54 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E5=88=86=E6=94=AF?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=8E=A5=E5=8F=A3=E6=94=AF=E6=8C=81=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 10 +-- modules/git/repo_branch_nogogit.go | 124 +++++++++++++++++++++++++++++ routers/hat/hat.go | 1 + routers/hat/repo/branch.go | 38 +++++++++ 4 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 modules/git/repo_branch_nogogit.go diff --git a/go.mod b/go.mod index 2a63605..6e6c87e 100644 --- a/go.mod +++ b/go.mod @@ -8,9 +8,14 @@ require ( github.com/caddyserver/certmagic v0.17.2 github.com/felixge/fgprof v0.9.3 github.com/go-chi/cors v1.2.1 + github.com/gobwas/glob v0.2.3 github.com/klauspost/cpuid/v2 v2.2.2 + github.com/russross/blackfriday/v2 v2.1.0 github.com/urfave/cli v1.22.10 + golang.org/x/net v0.4.0 + golang.org/x/text v0.5.0 gopkg.in/ini.v1 v1.67.0 + xorm.io/builder v0.3.12 xorm.io/xorm v1.3.2 ) @@ -93,7 +98,6 @@ require ( github.com/go-ldap/ldap/v3 v3.4.4 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect - github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.0 // indirect github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 // indirect @@ -172,7 +176,6 @@ require ( github.com/quasoft/websspi v1.1.2 // indirect github.com/rivo/uniseg v0.4.3 // indirect github.com/rs/xid v1.4.0 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/santhosh-tekuri/jsonschema/v5 v5.1.1 // indirect github.com/sergi/go-diff v1.2.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect @@ -201,10 +204,8 @@ require ( go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.4.0 // indirect golang.org/x/mod v0.7.0 // indirect - golang.org/x/net v0.4.0 // indirect golang.org/x/oauth2 v0.3.0 // indirect golang.org/x/sys v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.4.0 // indirect google.golang.org/appengine v1.6.7 // indirect @@ -216,5 +217,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect mvdan.cc/xurls/v2 v2.4.0 // indirect strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 // indirect - xorm.io/builder v0.3.12 // indirect ) diff --git a/modules/git/repo_branch_nogogit.go b/modules/git/repo_branch_nogogit.go new file mode 100644 index 0000000..c33e9af --- /dev/null +++ b/modules/git/repo_branch_nogogit.go @@ -0,0 +1,124 @@ +package git + +import ( + "bufio" + "context" + "fmt" + "io" + "strings" + + gitea_git "code.gitea.io/gitea/modules/git" +) + +func GetSearchBranches(ctx context.Context, repo *gitea_git.Repository, search string, skip, limit int) ([]*gitea_git.Branch, int, error) { + brs, countAll, err := callShowSearchRef(ctx, repo.Path, gitea_git.BranchPrefix, "--heads", search, skip, limit) + if err != nil { + return nil, 0, err + } + branches := make([]*gitea_git.Branch, len(brs)) + for i := range brs { + branches[i] = &gitea_git.Branch{ + Name: brs[i], + Path: repo.Path, + } + } + + return branches, countAll, nil +} + +func callShowSearchRef(ctx context.Context, repoPath, prefix, arg, search string, skip, limit int) (branchNames []string, countAll int, err error) { + stdoutReader, stdoutWriter := io.Pipe() + defer func() { + _ = stdoutReader.Close() + _ = stdoutWriter.Close() + }() + + go func() { + stderrBuilder := &strings.Builder{} + err := gitea_git.NewCommand(ctx, "show-ref", gitea_git.CmdArg(arg)). + Run(&gitea_git.RunOpts{ + Dir: repoPath, + Stdout: stdoutWriter, + Stderr: stderrBuilder, + }) + if err != nil { + if stderrBuilder.Len() == 0 { + _ = stdoutWriter.Close() + return + } + _ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String())) + } else { + _ = stdoutWriter.Close() + } + }() + + i := 0 + bufReader := bufio.NewReader(stdoutReader) + for i < skip { + line, isPrefix, err := bufReader.ReadLine() + if err == io.EOF { + return branchNames, i, nil + } + if err != nil { + return nil, 0, err + } + + branchName := strings.TrimPrefix(strings.Split(string(line), " ")[1], prefix) + if len(branchName) > 0 { + branchName = branchName[:len(branchName)-1] + } + isSeached := strings.Contains(branchName, search) + + if !isPrefix && isSeached { + i++ + } + } + for limit == 0 || i < skip+limit { + + branchName, err := bufReader.ReadString('\n') + if err == io.EOF { + // This shouldn't happen... but we'll tolerate it for the sake of peace + return branchNames, i, nil + } + if err != nil { + return nil, i, err + } + branchName = strings.TrimPrefix(strings.Split(string(branchName), " ")[1], prefix) + if len(branchName) > 0 { + branchName = branchName[:len(branchName)-1] + } + isSeached := strings.Contains(branchName, search) + if isSeached { + i++ + branchNames = append(branchNames, branchName) + } + } + // count all refs + for limit != 0 { + line, isPrefix, err := bufReader.ReadLine() + if err == io.EOF { + return branchNames, i, nil + } + if err != nil { + return nil, 0, err + } + + branchName := strings.TrimPrefix(strings.Split(string(line), " ")[1], prefix) + if len(branchName) > 0 { + branchName = branchName[:len(branchName)-1] + } + isSeached := strings.Contains(branchName, search) + + if !isPrefix && isSeached { + i++ + } + } + return branchNames, i, nil +} + +func ConcatenateError(err error, stderr string) error { + if len(stderr) == 0 { + return err + } + return fmt.Errorf("%w - %s", err, stderr) +} diff --git a/routers/hat/hat.go b/routers/hat/hat.go index fbd3937..5a5a05f 100644 --- a/routers/hat/hat.go +++ b/routers/hat/hat.go @@ -71,6 +71,7 @@ func Routers(ctx gocontext.Context) *web.Route { m.Get("/tag_name_set", context.ReferencesGitRepo(), repo.TagNameSet) m.Get("/branch_tag_count", context.ReferencesGitRepo(), repo.BranchTagCount) m.Group("/branches", func() { + m.Get("", repo.ListBranches) m.Get("/branches_slice", context.ReferencesGitRepo(), repo.ListBranchesSlice) }, reqRepoReader(unit_model.TypeCode)) m.Group("/commits", func() { diff --git a/routers/hat/repo/branch.go b/routers/hat/repo/branch.go index 3d08d21..bb2f192 100644 --- a/routers/hat/repo/branch.go +++ b/routers/hat/repo/branch.go @@ -9,12 +9,50 @@ import ( git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/convert" + gitea_api "code.gitea.io/gitea/modules/structs" hat_convert "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/convert" + hat_git "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/git" + "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/git" "code.gitea.io/gitea/routers/api/v1/utils" ) +func ListBranches(ctx *context.APIContext) { + searchName := ctx.Params("name") + listOptions := utils.GetListOptions(ctx) + skip, _ := listOptions.GetStartEnd() + branches, totalNumOfBranches, err := hat_git.GetSearchBranches(ctx, ctx.Repo.GitRepo, searchName, skip, listOptions.PageSize) + if err != nil { + ctx.Error(http.StatusInternalServerError, "GetBranches", err) + return + } + + apiBranches := make([]*gitea_api.Branch, len(branches)) + for i := range branches { + c, err := branches[i].GetCommit() + if err != nil { + ctx.Error(http.StatusInternalServerError, "GetCommit", err) + return + } + branchProtection, err := git_model.GetProtectedBranchBy(ctx, ctx.Repo.Repository.ID, branches[i].Name) + if err != nil { + ctx.Error(http.StatusInternalServerError, "GetProtectedBranchBy", err) + return + } + apiBranches[i], err = convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin()) + if err != nil { + ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err) + return + } + } + + ctx.SetLinkHeader(int(totalNumOfBranches), listOptions.PageSize) + ctx.RespHeader().Set("X-Total-Count", fmt.Sprintf("%d", totalNumOfBranches)) + ctx.RespHeader().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") + ctx.JSON(http.StatusOK, &apiBranches) +} + func ListBranchesSlice(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx)