mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-14 00:01:05 +02:00
Merge branch 'main' into lunny/refactor_review_request
This commit is contained in:
commit
a7016ce8d5
1005
.eslintrc.cjs
1005
.eslintrc.cjs
File diff suppressed because it is too large
Load Diff
6
Makefile
6
Makefile
@ -162,7 +162,7 @@ TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(DIST)
|
|||||||
GO_DIRS := build cmd models modules routers services tests
|
GO_DIRS := build cmd models modules routers services tests
|
||||||
WEB_DIRS := web_src/js web_src/css
|
WEB_DIRS := web_src/js web_src/css
|
||||||
|
|
||||||
ESLINT_FILES := web_src/js tools *.ts *.cjs tests/e2e
|
ESLINT_FILES := web_src/js tools *.ts tests/e2e
|
||||||
STYLELINT_FILES := web_src/css web_src/js/components/*.vue
|
STYLELINT_FILES := web_src/css web_src/js/components/*.vue
|
||||||
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.md *.yml *.yaml *.toml)) $(filter-out tools/misspellings.csv, $(wildcard tools/*))
|
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.md *.yml *.yaml *.toml)) $(filter-out tools/misspellings.csv, $(wildcard tools/*))
|
||||||
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini
|
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini
|
||||||
@ -346,12 +346,12 @@ lint-backend-fix: lint-go-fix lint-go-gitea-vet lint-editorconfig ## lint backen
|
|||||||
|
|
||||||
.PHONY: lint-js
|
.PHONY: lint-js
|
||||||
lint-js: node_modules ## lint js files
|
lint-js: node_modules ## lint js files
|
||||||
$(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES)
|
$(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --flag unstable_native_nodejs_ts_config $(ESLINT_FILES)
|
||||||
$(NODE_VARS) pnpm exec vue-tsc
|
$(NODE_VARS) pnpm exec vue-tsc
|
||||||
|
|
||||||
.PHONY: lint-js-fix
|
.PHONY: lint-js-fix
|
||||||
lint-js-fix: node_modules ## lint js files and fix issues
|
lint-js-fix: node_modules ## lint js files and fix issues
|
||||||
$(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES) --fix
|
$(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --flag unstable_native_nodejs_ts_config $(ESLINT_FILES) --fix
|
||||||
$(NODE_VARS) pnpm exec vue-tsc
|
$(NODE_VARS) pnpm exec vue-tsc
|
||||||
|
|
||||||
.PHONY: lint-css
|
.PHONY: lint-css
|
||||||
|
|||||||
5
assets/go-licenses.json
generated
5
assets/go-licenses.json
generated
@ -579,11 +579,6 @@
|
|||||||
"path": "github.com/go-webauthn/x/revoke/LICENSE",
|
"path": "github.com/go-webauthn/x/revoke/LICENSE",
|
||||||
"licenseText": "Copyright (c) 2014 CloudFlare Inc.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\nRedistributions of source code must retain the above copyright notice,\nthis list of conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright notice,\nthis list of conditions and the following disclaimer in the documentation\nand/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nHOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\nTO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\nPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
|
"licenseText": "Copyright (c) 2014 CloudFlare Inc.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\nRedistributions of source code must retain the above copyright notice,\nthis list of conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright notice,\nthis list of conditions and the following disclaimer in the documentation\nand/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nHOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\nTO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\nPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "github.com/gobwas/glob",
|
|
||||||
"path": "github.com/gobwas/glob/LICENSE",
|
|
||||||
"licenseText": "The MIT License (MIT)\n\nCopyright (c) 2016 Sergey Kamardin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "github.com/goccy/go-json",
|
"name": "github.com/goccy/go-json",
|
||||||
"path": "github.com/goccy/go-json/LICENSE",
|
"path": "github.com/goccy/go-json/LICENSE",
|
||||||
|
|||||||
@ -265,6 +265,7 @@ func runDump(ctx context.Context, cmd *cli.Command) error {
|
|||||||
excludes = append(excludes, setting.LFS.Storage.Path)
|
excludes = append(excludes, setting.LFS.Storage.Path)
|
||||||
excludes = append(excludes, setting.Attachment.Storage.Path)
|
excludes = append(excludes, setting.Attachment.Storage.Path)
|
||||||
excludes = append(excludes, setting.Packages.Storage.Path)
|
excludes = append(excludes, setting.Packages.Storage.Path)
|
||||||
|
excludes = append(excludes, setting.RepoArchive.Storage.Path)
|
||||||
excludes = append(excludes, setting.Log.RootPath)
|
excludes = append(excludes, setting.Log.RootPath)
|
||||||
if err := dumper.AddRecursiveExclude("data", setting.AppDataPath, excludes); err != nil {
|
if err := dumper.AddRecursiveExclude("data", setting.AppDataPath, excludes); err != nil {
|
||||||
fatal("Failed to include data directory: %v", err)
|
fatal("Failed to include data directory: %v", err)
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/assetfs"
|
"code.gitea.io/gitea/modules/assetfs"
|
||||||
|
"code.gitea.io/gitea/modules/glob"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/options"
|
"code.gitea.io/gitea/modules/options"
|
||||||
"code.gitea.io/gitea/modules/public"
|
"code.gitea.io/gitea/modules/public"
|
||||||
@ -19,7 +20,6 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/templates"
|
"code.gitea.io/gitea/modules/templates"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
repo_module "code.gitea.io/gitea/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
@ -312,7 +313,7 @@ func runHookPostReceive(ctx context.Context, c *cli.Command) error {
|
|||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
|
|
||||||
// First of all run update-server-info no matter what
|
// First of all run update-server-info no matter what
|
||||||
if _, _, err := git.NewCommand("update-server-info").RunStdString(ctx, nil); err != nil {
|
if _, _, err := gitcmd.NewCommand("update-server-info").RunStdString(ctx, nil); err != nil {
|
||||||
return fmt.Errorf("failed to call 'git update-server-info': %w", err)
|
return fmt.Errorf("failed to call 'git update-server-info': %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
31
cmd/serv.go
31
cmd/serv.go
@ -21,6 +21,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
"code.gitea.io/gitea/models/repo"
|
"code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/lfstransfer"
|
"code.gitea.io/gitea/modules/lfstransfer"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
@ -312,30 +313,30 @@ func runServ(ctx context.Context, c *cli.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var gitcmd *exec.Cmd
|
var command *exec.Cmd
|
||||||
gitBinPath := filepath.Dir(git.GitExecutable) // e.g. /usr/bin
|
gitBinPath := filepath.Dir(gitcmd.GitExecutable) // e.g. /usr/bin
|
||||||
gitBinVerb := filepath.Join(gitBinPath, verb) // e.g. /usr/bin/git-upload-pack
|
gitBinVerb := filepath.Join(gitBinPath, verb) // e.g. /usr/bin/git-upload-pack
|
||||||
if _, err := os.Stat(gitBinVerb); err != nil {
|
if _, err := os.Stat(gitBinVerb); err != nil {
|
||||||
// if the command "git-upload-pack" doesn't exist, try to split "git-upload-pack" to use the sub-command with git
|
// if the command "git-upload-pack" doesn't exist, try to split "git-upload-pack" to use the sub-command with git
|
||||||
// ps: Windows only has "git.exe" in the bin path, so Windows always uses this way
|
// ps: Windows only has "git.exe" in the bin path, so Windows always uses this way
|
||||||
verbFields := strings.SplitN(verb, "-", 2)
|
verbFields := strings.SplitN(verb, "-", 2)
|
||||||
if len(verbFields) == 2 {
|
if len(verbFields) == 2 {
|
||||||
// use git binary with the sub-command part: "C:\...\bin\git.exe", "upload-pack", ...
|
// use git binary with the sub-command part: "C:\...\bin\git.exe", "upload-pack", ...
|
||||||
gitcmd = exec.CommandContext(ctx, git.GitExecutable, verbFields[1], repoPath)
|
command = exec.CommandContext(ctx, gitcmd.GitExecutable, verbFields[1], repoPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if gitcmd == nil {
|
if command == nil {
|
||||||
// by default, use the verb (it has been checked above by allowedCommands)
|
// by default, use the verb (it has been checked above by allowedCommands)
|
||||||
gitcmd = exec.CommandContext(ctx, gitBinVerb, repoPath)
|
command = exec.CommandContext(ctx, gitBinVerb, repoPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
process.SetSysProcAttribute(gitcmd)
|
process.SetSysProcAttribute(command)
|
||||||
gitcmd.Dir = setting.RepoRootPath
|
command.Dir = setting.RepoRootPath
|
||||||
gitcmd.Stdout = os.Stdout
|
command.Stdout = os.Stdout
|
||||||
gitcmd.Stdin = os.Stdin
|
command.Stdin = os.Stdin
|
||||||
gitcmd.Stderr = os.Stderr
|
command.Stderr = os.Stderr
|
||||||
gitcmd.Env = append(gitcmd.Env, os.Environ()...)
|
command.Env = append(command.Env, os.Environ()...)
|
||||||
gitcmd.Env = append(gitcmd.Env,
|
command.Env = append(command.Env,
|
||||||
repo_module.EnvRepoIsWiki+"="+strconv.FormatBool(results.IsWiki),
|
repo_module.EnvRepoIsWiki+"="+strconv.FormatBool(results.IsWiki),
|
||||||
repo_module.EnvRepoName+"="+results.RepoName,
|
repo_module.EnvRepoName+"="+results.RepoName,
|
||||||
repo_module.EnvRepoUsername+"="+results.OwnerName,
|
repo_module.EnvRepoUsername+"="+results.OwnerName,
|
||||||
@ -350,9 +351,9 @@ func runServ(ctx context.Context, c *cli.Command) error {
|
|||||||
)
|
)
|
||||||
// to avoid breaking, here only use the minimal environment variables for the "gitea serv" command.
|
// to avoid breaking, here only use the minimal environment variables for the "gitea serv" command.
|
||||||
// it could be re-considered whether to use the same git.CommonGitCmdEnvs() as "git" command later.
|
// it could be re-considered whether to use the same git.CommonGitCmdEnvs() as "git" command later.
|
||||||
gitcmd.Env = append(gitcmd.Env, git.CommonCmdServEnvs()...)
|
command.Env = append(command.Env, gitcmd.CommonCmdServEnvs()...)
|
||||||
|
|
||||||
if err = gitcmd.Run(); err != nil {
|
if err = command.Run(); err != nil {
|
||||||
return fail(ctx, "Failed to execute git command", "Failed to execute git command: %v", err)
|
return fail(ctx, "Failed to execute git command", "Failed to execute git command: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ The default version will read from `docs/config.yml`. You can override this
|
|||||||
using the option `--version`.
|
using the option `--version`.
|
||||||
|
|
||||||
The upstream branches will be fetched, using the remote `origin`. This can
|
The upstream branches will be fetched, using the remote `origin`. This can
|
||||||
be overrided using `--upstream`, and fetching can be avoided using
|
be overridden using `--upstream`, and fetching can be avoided using
|
||||||
`--no-fetch`.
|
`--no-fetch`.
|
||||||
|
|
||||||
By default the branch created will be called `backport-$PR-$VERSION`. You
|
By default the branch created will be called `backport-$PR-$VERSION`. You
|
||||||
|
|||||||
@ -150,7 +150,7 @@
|
|||||||
|
|
||||||
<p>In general, Your Gitea Instance retains User Personal Information for as long as your account is active, or as needed to provide you service.</p>
|
<p>In general, Your Gitea Instance retains User Personal Information for as long as your account is active, or as needed to provide you service.</p>
|
||||||
|
|
||||||
<p>If you would like to cancel your account or delete your User Personal Information, you may do so in your user profile. We retain and use your information as necessary to comply with our legal obligations, resolve disputes, and enforce our agreements, but barring legal requirements, we will delete your full profile (within reason) within 90 days of your request. Feel free to contact our support to request erasure of the data we process on the bassis of consent within 30 days.</p>
|
<p>If you would like to cancel your account or delete your User Personal Information, you may do so in your user profile. We retain and use your information as necessary to comply with our legal obligations, resolve disputes, and enforce our agreements, but barring legal requirements, we will delete your full profile (within reason) within 90 days of your request. Feel free to contact our support to request erasure of the data we process on the basis of consent within 30 days.</p>
|
||||||
|
|
||||||
<p>After an account has been deleted, certain data, such as contributions to other Users' repositories and comments in others' issues, will remain. However, we will delete or de-identify your User Personal Information, including your username and email address, from the author field of issues, pull requests, and comments by associating them with a ghost user.</p>
|
<p>After an account has been deleted, certain data, such as contributions to other Users' repositories and comments in others' issues, will remain. However, we will delete or de-identify your User Personal Information, including your username and email address, from the author field of issues, pull requests, and comments by associating them with a ghost user.</p>
|
||||||
|
|
||||||
|
|||||||
1029
eslint.config.ts
Normal file
1029
eslint.config.ts
Normal file
File diff suppressed because it is too large
Load Diff
1
go.mod
1
go.mod
@ -61,7 +61,6 @@ require (
|
|||||||
github.com/go-redsync/redsync/v4 v4.13.0
|
github.com/go-redsync/redsync/v4 v4.13.0
|
||||||
github.com/go-sql-driver/mysql v1.9.3
|
github.com/go-sql-driver/mysql v1.9.3
|
||||||
github.com/go-webauthn/webauthn v0.13.4
|
github.com/go-webauthn/webauthn v0.13.4
|
||||||
github.com/gobwas/glob v0.2.3
|
|
||||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -364,8 +364,6 @@ github.com/go-webauthn/webauthn v0.13.4 h1:q68qusWPcqHbg9STSxBLBHnsKaLxNO0RnVKaA
|
|||||||
github.com/go-webauthn/webauthn v0.13.4/go.mod h1:MglN6OH9ECxvhDqoq1wMoF6P6JRYDiQpC9nc5OomQmI=
|
github.com/go-webauthn/webauthn v0.13.4/go.mod h1:MglN6OH9ECxvhDqoq1wMoF6P6JRYDiQpC9nc5OomQmI=
|
||||||
github.com/go-webauthn/x v0.1.24 h1:6LaWf2zzWqbyKT8IyQkhje1/1KCGhlEkMz4V1tDnt/A=
|
github.com/go-webauthn/x v0.1.24 h1:6LaWf2zzWqbyKT8IyQkhje1/1KCGhlEkMz4V1tDnt/A=
|
||||||
github.com/go-webauthn/x v0.1.24/go.mod h1:2o5XKJ+X1AKqYKGgHdKflGnoQFQZ6flJ2IFCBKSbSOw=
|
github.com/go-webauthn/x v0.1.24/go.mod h1:2o5XKJ+X1AKqYKGgHdKflGnoQFQZ6flJ2IFCBKSbSOw=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
|
||||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||||
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||||
|
|||||||
@ -25,7 +25,7 @@ type CommitVerification struct {
|
|||||||
SigningUser *user_model.User // if Verified, then SigningUser is non-nil
|
SigningUser *user_model.User // if Verified, then SigningUser is non-nil
|
||||||
CommittingUser *user_model.User // if Verified, then CommittingUser is non-nil
|
CommittingUser *user_model.User // if Verified, then CommittingUser is non-nil
|
||||||
SigningEmail string
|
SigningEmail string
|
||||||
SigningKey *GPGKey
|
SigningKey *GPGKey // FIXME: need to refactor it to a new name like "SigningGPGKey", it is also used in some templates
|
||||||
SigningSSHKey *PublicKey
|
SigningSSHKey *PublicKey
|
||||||
TrustStatus string
|
TrustStatus string
|
||||||
}
|
}
|
||||||
|
|||||||
37
models/asymkey/key_display.go
Normal file
37
models/asymkey/key_display.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package asymkey
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetDisplaySigningKey(key *git.SigningKey) string {
|
||||||
|
if key == nil || key.Format == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
switch key.Format {
|
||||||
|
case git.SigningKeyFormatOpenPGP:
|
||||||
|
return key.KeyID
|
||||||
|
case git.SigningKeyFormatSSH:
|
||||||
|
content, err := os.ReadFile(key.KeyID)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to read SSH key %s: %v", key.KeyID, err)
|
||||||
|
return "(Unable to read SSH key)"
|
||||||
|
}
|
||||||
|
display, err := CalcFingerprint(string(content))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to calculate fingerprint for SSH key %s: %v", key.KeyID, err)
|
||||||
|
return "(Unable to calculate fingerprint for SSH key)"
|
||||||
|
}
|
||||||
|
return display
|
||||||
|
}
|
||||||
|
setting.PanicInDevOrTesting("Unknown signing key format: %s", key.Format)
|
||||||
|
return "(Unknown key format)"
|
||||||
|
}
|
||||||
@ -67,7 +67,7 @@ func (l *XORMLogBridge) Warn(v ...any) {
|
|||||||
l.Log(stackLevel, log.WARN, "%s", fmt.Sprint(v...))
|
l.Log(stackLevel, log.WARN, "%s", fmt.Sprint(v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warnf show warnning log
|
// Warnf show warning log
|
||||||
func (l *XORMLogBridge) Warnf(format string, v ...any) {
|
func (l *XORMLogBridge) Warnf(format string, v ...any) {
|
||||||
l.Log(stackLevel, log.WARN, format, v...)
|
l.Log(stackLevel, log.WARN, format, v...)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,12 +17,11 @@ import (
|
|||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/glob"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
|
||||||
"github.com/gobwas/glob/syntax"
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -77,7 +76,7 @@ func init() {
|
|||||||
// IsRuleNameSpecial return true if it contains special character
|
// IsRuleNameSpecial return true if it contains special character
|
||||||
func IsRuleNameSpecial(ruleName string) bool {
|
func IsRuleNameSpecial(ruleName string) bool {
|
||||||
for i := 0; i < len(ruleName); i++ {
|
for i := 0; i < len(ruleName); i++ {
|
||||||
if syntax.Special(ruleName[i]) {
|
if glob.IsSpecialByte(ruleName[i]) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,8 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/modules/glob"
|
||||||
"code.gitea.io/gitea/modules/optional"
|
"code.gitea.io/gitea/modules/optional"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProtectedBranchRules []*ProtectedBranch
|
type ProtectedBranchRules []*ProtectedBranch
|
||||||
|
|||||||
@ -11,9 +11,8 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
|
"code.gitea.io/gitea/modules/glob"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProtectedTag struct
|
// ProtectedTag struct
|
||||||
|
|||||||
@ -408,7 +408,7 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
|
|||||||
|
|
||||||
official, err := isOfficialReviewer(sess, review.IssueID, reviewer)
|
official, err := isOfficialReviewer(sess, review.IssueID, reviewer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Branch might not be proteced or other error, ignore it.
|
// Branch might not be protected or other error, ignore it.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
review.Official = official
|
review.Official = official
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
@ -83,17 +84,17 @@ func FixMergeBase(ctx context.Context, x *xorm.Engine) error {
|
|||||||
|
|
||||||
if !pr.HasMerged {
|
if !pr.HasMerged {
|
||||||
var err error
|
var err error
|
||||||
pr.MergeBase, _, err = git.NewCommand("merge-base").AddDashesAndList(pr.BaseBranch, gitRefName).RunStdString(ctx, &git.RunOpts{Dir: repoPath})
|
pr.MergeBase, _, err = gitcmd.NewCommand("merge-base").AddDashesAndList(pr.BaseBranch, gitRefName).RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var err2 error
|
var err2 error
|
||||||
pr.MergeBase, _, err2 = git.NewCommand("rev-parse").AddDynamicArguments(git.BranchPrefix+pr.BaseBranch).RunStdString(ctx, &git.RunOpts{Dir: repoPath})
|
pr.MergeBase, _, err2 = gitcmd.NewCommand("rev-parse").AddDynamicArguments(git.BranchPrefix+pr.BaseBranch).RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
log.Error("Unable to get merge base for PR ID %d, Index %d in %s/%s. Error: %v & %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err, err2)
|
log.Error("Unable to get merge base for PR ID %d, Index %d in %s/%s. Error: %v & %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err, err2)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parentsString, _, err := git.NewCommand("rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).RunStdString(ctx, &git.RunOpts{Dir: repoPath})
|
parentsString, _, err := gitcmd.NewCommand("rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
|
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
|
||||||
continue
|
continue
|
||||||
@ -105,9 +106,9 @@ func FixMergeBase(ctx context.Context, x *xorm.Engine) error {
|
|||||||
|
|
||||||
refs := append([]string{}, parents[1:]...)
|
refs := append([]string{}, parents[1:]...)
|
||||||
refs = append(refs, gitRefName)
|
refs = append(refs, gitRefName)
|
||||||
cmd := git.NewCommand("merge-base").AddDashesAndList(refs...)
|
cmd := gitcmd.NewCommand("merge-base").AddDashesAndList(refs...)
|
||||||
|
|
||||||
pr.MergeBase, _, err = cmd.RunStdString(ctx, &git.RunOpts{Dir: repoPath})
|
pr.MergeBase, _, err = cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
|
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ func RefixMergeBase(ctx context.Context, x *xorm.Engine) error {
|
|||||||
|
|
||||||
gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index)
|
gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index)
|
||||||
|
|
||||||
parentsString, _, err := git.NewCommand("rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).RunStdString(ctx, &git.RunOpts{Dir: repoPath})
|
parentsString, _, err := gitcmd.NewCommand("rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
|
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
|
||||||
continue
|
continue
|
||||||
@ -93,9 +93,9 @@ func RefixMergeBase(ctx context.Context, x *xorm.Engine) error {
|
|||||||
// we should recalculate
|
// we should recalculate
|
||||||
refs := append([]string{}, parents[1:]...)
|
refs := append([]string{}, parents[1:]...)
|
||||||
refs = append(refs, gitRefName)
|
refs = append(refs, gitRefName)
|
||||||
cmd := git.NewCommand("merge-base").AddDashesAndList(refs...)
|
cmd := gitcmd.NewCommand("merge-base").AddDashesAndList(refs...)
|
||||||
|
|
||||||
pr.MergeBase, _, err = cmd.RunStdString(ctx, &git.RunOpts{Dir: repoPath})
|
pr.MergeBase, _, err = cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
|
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -348,10 +348,8 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
|
|||||||
|
|
||||||
for _, u := range repo.Units {
|
for _, u := range repo.Units {
|
||||||
for _, team := range teams {
|
for _, team := range teams {
|
||||||
unitAccessMode := minAccessMode
|
teamMode, _ := team.UnitAccessModeEx(ctx, u.Type)
|
||||||
if teamMode, exist := team.UnitAccessModeEx(ctx, u.Type); exist {
|
unitAccessMode := max(perm.unitsMode[u.Type], minAccessMode, teamMode)
|
||||||
unitAccessMode = max(perm.unitsMode[u.Type], unitAccessMode, teamMode)
|
|
||||||
}
|
|
||||||
perm.unitsMode[u.Type] = unitAccessMode
|
perm.unitsMode[u.Type] = unitAccessMode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -197,4 +197,37 @@ func TestGetUserRepoPermission(t *testing.T) {
|
|||||||
assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeCode])
|
assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeCode])
|
||||||
assert.Equal(t, perm_model.AccessModeRead, perm.unitsMode[unit.TypeIssues])
|
assert.Equal(t, perm_model.AccessModeRead, perm.unitsMode[unit.TypeIssues])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // org private repo, same org as repo 32
|
||||||
|
require.NoError(t, repo3.LoadOwner(ctx))
|
||||||
|
require.True(t, repo3.Owner.IsOrganization())
|
||||||
|
require.NoError(t, db.TruncateBeans(ctx, &organization.TeamUnit{}, &Access{})) // The user has access set of that repo, remove it, it is useless for our test
|
||||||
|
require.NoError(t, db.Insert(ctx, &organization.TeamRepo{OrgID: org.ID, TeamID: team.ID, RepoID: repo3.ID}))
|
||||||
|
t.Run("DoerWithNoopTeamOnPrivateRepo", func(t *testing.T) {
|
||||||
|
perm, err := GetUserRepoPermission(ctx, repo3, user)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, perm_model.AccessModeNone, perm.AccessMode)
|
||||||
|
assert.Equal(t, perm_model.AccessModeNone, perm.unitsMode[unit.TypeCode])
|
||||||
|
assert.Equal(t, perm_model.AccessModeNone, perm.unitsMode[unit.TypeIssues])
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, db.Insert(ctx, &organization.TeamUnit{OrgID: org.ID, TeamID: team.ID, Type: unit.TypeCode, AccessMode: perm_model.AccessModeNone}))
|
||||||
|
require.NoError(t, db.Insert(ctx, &organization.TeamUnit{OrgID: org.ID, TeamID: team.ID, Type: unit.TypeIssues, AccessMode: perm_model.AccessModeRead}))
|
||||||
|
t.Run("DoerWithReadIssueTeamOnPrivateRepo", func(t *testing.T) {
|
||||||
|
perm, err := GetUserRepoPermission(ctx, repo3, user)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, perm_model.AccessModeNone, perm.AccessMode)
|
||||||
|
assert.Equal(t, perm_model.AccessModeNone, perm.unitsMode[unit.TypeCode])
|
||||||
|
assert.Equal(t, perm_model.AccessModeRead, perm.unitsMode[unit.TypeIssues])
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, db.Insert(ctx, repo_model.Collaboration{RepoID: repo3.ID, UserID: user.ID, Mode: perm_model.AccessModeWrite}))
|
||||||
|
require.NoError(t, db.Insert(ctx, Access{RepoID: repo3.ID, UserID: user.ID, Mode: perm_model.AccessModeWrite}))
|
||||||
|
t.Run("DoerWithReadIssueTeamAndWriteCollaboratorOnPrivateRepo", func(t *testing.T) {
|
||||||
|
perm, err := GetUserRepoPermission(ctx, repo3, user)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, perm_model.AccessModeWrite, perm.AccessMode)
|
||||||
|
assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeCode])
|
||||||
|
assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeIssues])
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ const (
|
|||||||
SettingsKeyHiddenCommentTypes = "issue.hidden_comment_types"
|
SettingsKeyHiddenCommentTypes = "issue.hidden_comment_types"
|
||||||
// SettingsKeyDiffWhitespaceBehavior is the setting key for whitespace behavior of diff
|
// SettingsKeyDiffWhitespaceBehavior is the setting key for whitespace behavior of diff
|
||||||
SettingsKeyDiffWhitespaceBehavior = "diff.whitespace_behaviour"
|
SettingsKeyDiffWhitespaceBehavior = "diff.whitespace_behaviour"
|
||||||
// SettingsKeyShowOutdatedComments is the setting key wether or not to show outdated comments in PRs
|
// SettingsKeyShowOutdatedComments is the setting key whether or not to show outdated comments in PRs
|
||||||
SettingsKeyShowOutdatedComments = "comment_code.show_outdated"
|
SettingsKeyShowOutdatedComments = "comment_code.show_outdated"
|
||||||
|
|
||||||
// UserActivityPubPrivPem is user's private key
|
// UserActivityPubPrivPem is user's private key
|
||||||
|
|||||||
@ -10,11 +10,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/glob"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
webhook_module "code.gitea.io/gitea/modules/webhook"
|
webhook_module "code.gitea.io/gitea/modules/webhook"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
|
||||||
"github.com/nektos/act/pkg/jobparser"
|
"github.com/nektos/act/pkg/jobparser"
|
||||||
"github.com/nektos/act/pkg/model"
|
"github.com/nektos/act/pkg/model"
|
||||||
"github.com/nektos/act/pkg/workflowpattern"
|
"github.com/nektos/act/pkg/workflowpattern"
|
||||||
|
|||||||
@ -70,7 +70,7 @@ func (i *Identicon) render(c, b1, b2, b1Angle, b2Angle, foreColor int) image.Ima
|
|||||||
/*
|
/*
|
||||||
# Algorithm
|
# Algorithm
|
||||||
|
|
||||||
Origin: An image is splitted into 9 areas
|
Origin: An image is split into 9 areas
|
||||||
|
|
||||||
```
|
```
|
||||||
-------------
|
-------------
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ type BatchChecker struct {
|
|||||||
stdOut *nulSeparatedAttributeWriter
|
stdOut *nulSeparatedAttributeWriter
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
cmd *git.Command
|
cmd *gitcmd.Command
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBatchChecker creates a check attribute reader for the current repository and provided commit ID
|
// NewBatchChecker creates a check attribute reader for the current repository and provided commit ID
|
||||||
@ -76,7 +77,7 @@ func NewBatchChecker(repo *git.Repository, treeish string, attributes []string)
|
|||||||
_ = lw.Close()
|
_ = lw.Close()
|
||||||
}()
|
}()
|
||||||
stdErr := new(bytes.Buffer)
|
stdErr := new(bytes.Buffer)
|
||||||
err := cmd.Run(ctx, &git.RunOpts{
|
err := cmd.Run(ctx, &gitcmd.RunOpts{
|
||||||
Env: envs,
|
Env: envs,
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdin: stdinReader,
|
Stdin: stdinReader,
|
||||||
|
|||||||
@ -11,12 +11,13 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkAttrCommand(gitRepo *git.Repository, treeish string, filenames, attributes []string) (*git.Command, []string, func(), error) {
|
func checkAttrCommand(gitRepo *git.Repository, treeish string, filenames, attributes []string) (*gitcmd.Command, []string, func(), error) {
|
||||||
cancel := func() {}
|
cancel := func() {}
|
||||||
envs := []string{"GIT_FLUSH=1"}
|
envs := []string{"GIT_FLUSH=1"}
|
||||||
cmd := git.NewCommand("check-attr", "-z")
|
cmd := gitcmd.NewCommand("check-attr", "-z")
|
||||||
if len(attributes) == 0 {
|
if len(attributes) == 0 {
|
||||||
cmd.AddArguments("--all")
|
cmd.AddArguments("--all")
|
||||||
}
|
}
|
||||||
@ -70,7 +71,7 @@ func CheckAttributes(ctx context.Context, gitRepo *git.Repository, treeish strin
|
|||||||
stdOut := new(bytes.Buffer)
|
stdOut := new(bytes.Buffer)
|
||||||
stdErr := new(bytes.Buffer)
|
stdErr := new(bytes.Buffer)
|
||||||
|
|
||||||
if err := cmd.Run(ctx, &git.RunOpts{
|
if err := cmd.Run(ctx, &gitcmd.RunOpts{
|
||||||
Env: append(os.Environ(), envs...),
|
Env: append(os.Environ(), envs...),
|
||||||
Dir: gitRepo.Path,
|
Dir: gitRepo.Path,
|
||||||
Stdout: stdOut,
|
Stdout: stdOut,
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
|
||||||
"github.com/djherbis/buffer"
|
"github.com/djherbis/buffer"
|
||||||
@ -29,13 +30,13 @@ type WriteCloserError interface {
|
|||||||
// This is needed otherwise the git cat-file will hang for invalid repositories.
|
// This is needed otherwise the git cat-file will hang for invalid repositories.
|
||||||
func ensureValidGitRepository(ctx context.Context, repoPath string) error {
|
func ensureValidGitRepository(ctx context.Context, repoPath string) error {
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
err := NewCommand("rev-parse").
|
err := gitcmd.NewCommand("rev-parse").
|
||||||
Run(ctx, &RunOpts{
|
Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: repoPath,
|
Dir: repoPath,
|
||||||
Stderr: &stderr,
|
Stderr: &stderr,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ConcatenateError(err, (&stderr).String())
|
return gitcmd.ConcatenateError(err, (&stderr).String())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -61,8 +62,8 @@ func catFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError,
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
err := NewCommand("cat-file", "--batch-check").
|
err := gitcmd.NewCommand("cat-file", "--batch-check").
|
||||||
Run(ctx, &RunOpts{
|
Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: repoPath,
|
Dir: repoPath,
|
||||||
Stdin: batchStdinReader,
|
Stdin: batchStdinReader,
|
||||||
Stdout: batchStdoutWriter,
|
Stdout: batchStdoutWriter,
|
||||||
@ -71,8 +72,8 @@ func catFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError,
|
|||||||
UseContextTimeout: true,
|
UseContextTimeout: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = batchStdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
_ = batchStdoutWriter.CloseWithError(gitcmd.ConcatenateError(err, (&stderr).String()))
|
||||||
_ = batchStdinReader.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
_ = batchStdinReader.CloseWithError(gitcmd.ConcatenateError(err, (&stderr).String()))
|
||||||
} else {
|
} else {
|
||||||
_ = batchStdoutWriter.Close()
|
_ = batchStdoutWriter.Close()
|
||||||
_ = batchStdinReader.Close()
|
_ = batchStdinReader.Close()
|
||||||
@ -109,8 +110,8 @@ func catFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
err := NewCommand("cat-file", "--batch").
|
err := gitcmd.NewCommand("cat-file", "--batch").
|
||||||
Run(ctx, &RunOpts{
|
Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: repoPath,
|
Dir: repoPath,
|
||||||
Stdin: batchStdinReader,
|
Stdin: batchStdinReader,
|
||||||
Stdout: batchStdoutWriter,
|
Stdout: batchStdoutWriter,
|
||||||
@ -119,8 +120,8 @@ func catFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi
|
|||||||
UseContextTimeout: true,
|
UseContextTimeout: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = batchStdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
_ = batchStdoutWriter.CloseWithError(gitcmd.ConcatenateError(err, (&stderr).String()))
|
||||||
_ = batchStdinReader.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
_ = batchStdinReader.CloseWithError(gitcmd.ConcatenateError(err, (&stderr).String()))
|
||||||
} else {
|
} else {
|
||||||
_ = batchStdoutWriter.Close()
|
_ = batchStdoutWriter.Close()
|
||||||
_ = batchStdinReader.Close()
|
_ = batchStdinReader.Close()
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
@ -141,7 +142,7 @@ func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
cmd := NewCommand("blame", "--porcelain")
|
cmd := gitcmd.NewCommand("blame", "--porcelain")
|
||||||
|
|
||||||
if DefaultFeatures().CheckVersionAtLeast("2.23") && !bypassBlameIgnore {
|
if DefaultFeatures().CheckVersionAtLeast("2.23") && !bypassBlameIgnore {
|
||||||
ignoreRevsFileName, ignoreRevsFileCleanup, err = tryCreateBlameIgnoreRevsFile(commit)
|
ignoreRevsFileName, ignoreRevsFileCleanup, err = tryCreateBlameIgnoreRevsFile(commit)
|
||||||
@ -165,7 +166,7 @@ func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath
|
|||||||
go func() {
|
go func() {
|
||||||
stderr := bytes.Buffer{}
|
stderr := bytes.Buffer{}
|
||||||
// TODO: it doesn't work for directories (the directories shouldn't be "blamed"), and the "err" should be returned by "Read" but not by "Close"
|
// TODO: it doesn't work for directories (the directories shouldn't be "blamed"), and the "err" should be returned by "Read" but not by "Close"
|
||||||
err := cmd.Run(ctx, &RunOpts{
|
err := cmd.Run(ctx, &gitcmd.RunOpts{
|
||||||
UseContextTimeout: true,
|
UseContextTimeout: true,
|
||||||
Dir: repoPath,
|
Dir: repoPath,
|
||||||
Stdout: stdout,
|
Stdout: stdout,
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
@ -87,12 +88,12 @@ func (c *Commit) GetCommitByPath(relpath string) (*Commit, error) {
|
|||||||
|
|
||||||
// AddChanges marks local changes to be ready for commit.
|
// AddChanges marks local changes to be ready for commit.
|
||||||
func AddChanges(ctx context.Context, repoPath string, all bool, files ...string) error {
|
func AddChanges(ctx context.Context, repoPath string, all bool, files ...string) error {
|
||||||
cmd := NewCommand().AddArguments("add")
|
cmd := gitcmd.NewCommand().AddArguments("add")
|
||||||
if all {
|
if all {
|
||||||
cmd.AddArguments("--all")
|
cmd.AddArguments("--all")
|
||||||
}
|
}
|
||||||
cmd.AddDashesAndList(files...)
|
cmd.AddDashesAndList(files...)
|
||||||
_, _, err := cmd.RunStdString(ctx, &RunOpts{Dir: repoPath})
|
_, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +107,7 @@ type CommitChangesOptions struct {
|
|||||||
// CommitChanges commits local changes with given committer, author and message.
|
// CommitChanges commits local changes with given committer, author and message.
|
||||||
// If author is nil, it will be the same as committer.
|
// If author is nil, it will be the same as committer.
|
||||||
func CommitChanges(ctx context.Context, repoPath string, opts CommitChangesOptions) error {
|
func CommitChanges(ctx context.Context, repoPath string, opts CommitChangesOptions) error {
|
||||||
cmd := NewCommand()
|
cmd := gitcmd.NewCommand()
|
||||||
if opts.Committer != nil {
|
if opts.Committer != nil {
|
||||||
cmd.AddOptionValues("-c", "user.name="+opts.Committer.Name)
|
cmd.AddOptionValues("-c", "user.name="+opts.Committer.Name)
|
||||||
cmd.AddOptionValues("-c", "user.email="+opts.Committer.Email)
|
cmd.AddOptionValues("-c", "user.email="+opts.Committer.Email)
|
||||||
@ -121,7 +122,7 @@ func CommitChanges(ctx context.Context, repoPath string, opts CommitChangesOptio
|
|||||||
}
|
}
|
||||||
cmd.AddOptionFormat("--message=%s", opts.Message)
|
cmd.AddOptionFormat("--message=%s", opts.Message)
|
||||||
|
|
||||||
_, _, err := cmd.RunStdString(ctx, &RunOpts{Dir: repoPath})
|
_, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
// No stderr but exit status 1 means nothing to commit.
|
// No stderr but exit status 1 means nothing to commit.
|
||||||
if err != nil && err.Error() == "exit status 1" {
|
if err != nil && err.Error() == "exit status 1" {
|
||||||
return nil
|
return nil
|
||||||
@ -131,7 +132,7 @@ func CommitChanges(ctx context.Context, repoPath string, opts CommitChangesOptio
|
|||||||
|
|
||||||
// AllCommitsCount returns count of all commits in repository
|
// AllCommitsCount returns count of all commits in repository
|
||||||
func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, files ...string) (int64, error) {
|
func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, files ...string) (int64, error) {
|
||||||
cmd := NewCommand("rev-list")
|
cmd := gitcmd.NewCommand("rev-list")
|
||||||
if hidePRRefs {
|
if hidePRRefs {
|
||||||
cmd.AddArguments("--exclude=" + PullPrefix + "*")
|
cmd.AddArguments("--exclude=" + PullPrefix + "*")
|
||||||
}
|
}
|
||||||
@ -140,7 +141,7 @@ func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, file
|
|||||||
cmd.AddDashesAndList(files...)
|
cmd.AddDashesAndList(files...)
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, _, err := cmd.RunStdString(ctx, &RunOpts{Dir: repoPath})
|
stdout, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -160,7 +161,7 @@ type CommitsCountOptions struct {
|
|||||||
|
|
||||||
// CommitsCount returns number of total commits of until given revision.
|
// CommitsCount returns number of total commits of until given revision.
|
||||||
func CommitsCount(ctx context.Context, opts CommitsCountOptions) (int64, error) {
|
func CommitsCount(ctx context.Context, opts CommitsCountOptions) (int64, error) {
|
||||||
cmd := NewCommand("rev-list", "--count")
|
cmd := gitcmd.NewCommand("rev-list", "--count")
|
||||||
|
|
||||||
cmd.AddDynamicArguments(opts.Revision...)
|
cmd.AddDynamicArguments(opts.Revision...)
|
||||||
|
|
||||||
@ -172,7 +173,7 @@ func CommitsCount(ctx context.Context, opts CommitsCountOptions) (int64, error)
|
|||||||
cmd.AddDashesAndList(opts.RelPath...)
|
cmd.AddDashesAndList(opts.RelPath...)
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, _, err := cmd.RunStdString(ctx, &RunOpts{Dir: opts.RepoPath})
|
stdout, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: opts.RepoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -207,7 +208,7 @@ func (c *Commit) HasPreviousCommit(objectID ObjectID) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err := NewCommand("merge-base", "--is-ancestor").AddDynamicArguments(that, this).RunStdString(c.repo.Ctx, &RunOpts{Dir: c.repo.Path})
|
_, _, err := gitcmd.NewCommand("merge-base", "--is-ancestor").AddDynamicArguments(that, this).RunStdString(c.repo.Ctx, &gitcmd.RunOpts{Dir: c.repo.Path})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
@ -348,12 +349,12 @@ func (c *Commit) GetFileContent(filename string, limit int) (string, error) {
|
|||||||
|
|
||||||
// GetBranchName gets the closest branch name (as returned by 'git name-rev --name-only')
|
// GetBranchName gets the closest branch name (as returned by 'git name-rev --name-only')
|
||||||
func (c *Commit) GetBranchName() (string, error) {
|
func (c *Commit) GetBranchName() (string, error) {
|
||||||
cmd := NewCommand("name-rev")
|
cmd := gitcmd.NewCommand("name-rev")
|
||||||
if DefaultFeatures().CheckVersionAtLeast("2.13.0") {
|
if DefaultFeatures().CheckVersionAtLeast("2.13.0") {
|
||||||
cmd.AddArguments("--exclude", "refs/tags/*")
|
cmd.AddArguments("--exclude", "refs/tags/*")
|
||||||
}
|
}
|
||||||
cmd.AddArguments("--name-only", "--no-undefined").AddDynamicArguments(c.ID.String())
|
cmd.AddArguments("--name-only", "--no-undefined").AddDynamicArguments(c.ID.String())
|
||||||
data, _, err := cmd.RunStdString(c.repo.Ctx, &RunOpts{Dir: c.repo.Path})
|
data, _, err := cmd.RunStdString(c.repo.Ctx, &gitcmd.RunOpts{Dir: c.repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// handle special case where git can not describe commit
|
// handle special case where git can not describe commit
|
||||||
if strings.Contains(err.Error(), "cannot describe") {
|
if strings.Contains(err.Error(), "cannot describe") {
|
||||||
@ -431,14 +432,14 @@ func GetCommitFileStatus(ctx context.Context, repoPath, commitID string) (*Commi
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
err := NewCommand("log", "--name-status", "-m", "--pretty=format:", "--first-parent", "--no-renames", "-z", "-1").AddDynamicArguments(commitID).Run(ctx, &RunOpts{
|
err := gitcmd.NewCommand("log", "--name-status", "-m", "--pretty=format:", "--first-parent", "--no-renames", "-z", "-1").AddDynamicArguments(commitID).Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: repoPath,
|
Dir: repoPath,
|
||||||
Stdout: w,
|
Stdout: w,
|
||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
})
|
})
|
||||||
w.Close() // Close writer to exit parsing goroutine
|
w.Close() // Close writer to exit parsing goroutine
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ConcatenateError(err, stderr.String())
|
return nil, gitcmd.ConcatenateError(err, stderr.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
<-done
|
<-done
|
||||||
@ -447,7 +448,7 @@ func GetCommitFileStatus(ctx context.Context, repoPath, commitID string) (*Commi
|
|||||||
|
|
||||||
// GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository.
|
// GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository.
|
||||||
func GetFullCommitID(ctx context.Context, repoPath, shortID string) (string, error) {
|
func GetFullCommitID(ctx context.Context, repoPath, shortID string) (string, error) {
|
||||||
commitID, _, err := NewCommand("rev-parse").AddDynamicArguments(shortID).RunStdString(ctx, &RunOpts{Dir: repoPath})
|
commitID, _, err := gitcmd.NewCommand("rev-parse").AddDynamicArguments(shortID).RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "exit status 128") {
|
if strings.Contains(err.Error(), "exit status 128") {
|
||||||
return "", ErrNotExist{shortID, ""}
|
return "", ErrNotExist{shortID, ""}
|
||||||
|
|||||||
@ -11,13 +11,14 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
// syncGitConfig only modifies gitconfig, won't change global variables (otherwise there will be data-race problem)
|
// syncGitConfig only modifies gitconfig, won't change global variables (otherwise there will be data-race problem)
|
||||||
func syncGitConfig(ctx context.Context) (err error) {
|
func syncGitConfig(ctx context.Context) (err error) {
|
||||||
if err = os.MkdirAll(HomeDir(), os.ModePerm); err != nil {
|
if err = os.MkdirAll(gitcmd.HomeDir(), os.ModePerm); err != nil {
|
||||||
return fmt.Errorf("unable to prepare git home directory %s, err: %w", HomeDir(), err)
|
return fmt.Errorf("unable to prepare git home directory %s, err: %w", gitcmd.HomeDir(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// first, write user's git config options to git config file
|
// first, write user's git config options to git config file
|
||||||
@ -117,8 +118,8 @@ func syncGitConfig(ctx context.Context) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func configSet(ctx context.Context, key, value string) error {
|
func configSet(ctx context.Context, key, value string) error {
|
||||||
stdout, _, err := NewCommand("config", "--global", "--get").AddDynamicArguments(key).RunStdString(ctx, nil)
|
stdout, _, err := gitcmd.NewCommand("config", "--global", "--get").AddDynamicArguments(key).RunStdString(ctx, nil)
|
||||||
if err != nil && !IsErrorExitCode(err, 1) {
|
if err != nil && !gitcmd.IsErrorExitCode(err, 1) {
|
||||||
return fmt.Errorf("failed to get git config %s, err: %w", key, err)
|
return fmt.Errorf("failed to get git config %s, err: %w", key, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +128,7 @@ func configSet(ctx context.Context, key, value string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = NewCommand("config", "--global").AddDynamicArguments(key, value).RunStdString(ctx, nil)
|
_, _, err = gitcmd.NewCommand("config", "--global").AddDynamicArguments(key, value).RunStdString(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to set git global config %s, err: %w", key, err)
|
return fmt.Errorf("failed to set git global config %s, err: %w", key, err)
|
||||||
}
|
}
|
||||||
@ -136,14 +137,14 @@ func configSet(ctx context.Context, key, value string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func configSetNonExist(ctx context.Context, key, value string) error {
|
func configSetNonExist(ctx context.Context, key, value string) error {
|
||||||
_, _, err := NewCommand("config", "--global", "--get").AddDynamicArguments(key).RunStdString(ctx, nil)
|
_, _, err := gitcmd.NewCommand("config", "--global", "--get").AddDynamicArguments(key).RunStdString(ctx, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// already exist
|
// already exist
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if IsErrorExitCode(err, 1) {
|
if gitcmd.IsErrorExitCode(err, 1) {
|
||||||
// not exist, set new config
|
// not exist, set new config
|
||||||
_, _, err = NewCommand("config", "--global").AddDynamicArguments(key, value).RunStdString(ctx, nil)
|
_, _, err = gitcmd.NewCommand("config", "--global").AddDynamicArguments(key, value).RunStdString(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to set git global config %s, err: %w", key, err)
|
return fmt.Errorf("failed to set git global config %s, err: %w", key, err)
|
||||||
}
|
}
|
||||||
@ -154,14 +155,14 @@ func configSetNonExist(ctx context.Context, key, value string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func configAddNonExist(ctx context.Context, key, value string) error {
|
func configAddNonExist(ctx context.Context, key, value string) error {
|
||||||
_, _, err := NewCommand("config", "--global", "--get").AddDynamicArguments(key, regexp.QuoteMeta(value)).RunStdString(ctx, nil)
|
_, _, err := gitcmd.NewCommand("config", "--global", "--get").AddDynamicArguments(key, regexp.QuoteMeta(value)).RunStdString(ctx, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// already exist
|
// already exist
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if IsErrorExitCode(err, 1) {
|
if gitcmd.IsErrorExitCode(err, 1) {
|
||||||
// not exist, add new config
|
// not exist, add new config
|
||||||
_, _, err = NewCommand("config", "--global", "--add").AddDynamicArguments(key, value).RunStdString(ctx, nil)
|
_, _, err = gitcmd.NewCommand("config", "--global", "--add").AddDynamicArguments(key, value).RunStdString(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to add git global config %s, err: %w", key, err)
|
return fmt.Errorf("failed to add git global config %s, err: %w", key, err)
|
||||||
}
|
}
|
||||||
@ -171,16 +172,16 @@ func configAddNonExist(ctx context.Context, key, value string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func configUnsetAll(ctx context.Context, key, value string) error {
|
func configUnsetAll(ctx context.Context, key, value string) error {
|
||||||
_, _, err := NewCommand("config", "--global", "--get").AddDynamicArguments(key).RunStdString(ctx, nil)
|
_, _, err := gitcmd.NewCommand("config", "--global", "--get").AddDynamicArguments(key).RunStdString(ctx, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// exist, need to remove
|
// exist, need to remove
|
||||||
_, _, err = NewCommand("config", "--global", "--unset-all").AddDynamicArguments(key, regexp.QuoteMeta(value)).RunStdString(ctx, nil)
|
_, _, err = gitcmd.NewCommand("config", "--global", "--unset-all").AddDynamicArguments(key, regexp.QuoteMeta(value)).RunStdString(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to unset git global config %s, err: %w", key, err)
|
return fmt.Errorf("failed to unset git global config %s, err: %w", key, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if IsErrorExitCode(err, 1) {
|
if gitcmd.IsErrorExitCode(err, 1) {
|
||||||
// not exist
|
// not exist
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,13 +8,14 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func gitConfigContains(sub string) bool {
|
func gitConfigContains(sub string) bool {
|
||||||
if b, err := os.ReadFile(HomeDir() + "/.gitconfig"); err == nil {
|
if b, err := os.ReadFile(gitcmd.HomeDir() + "/.gitconfig"); err == nil {
|
||||||
return strings.Contains(string(b), sub)
|
return strings.Contains(string(b), sub)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,8 +35,8 @@ func GetRawDiff(repo *Repository, commitID string, diffType RawDiffType, writer
|
|||||||
// GetReverseRawDiff dumps the reverse diff results of repository in given commit ID to io.Writer.
|
// GetReverseRawDiff dumps the reverse diff results of repository in given commit ID to io.Writer.
|
||||||
func GetReverseRawDiff(ctx context.Context, repoPath, commitID string, writer io.Writer) error {
|
func GetReverseRawDiff(ctx context.Context, repoPath, commitID string, writer io.Writer) error {
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
cmd := NewCommand("show", "--pretty=format:revert %H%n", "-R").AddDynamicArguments(commitID)
|
cmd := gitcmd.NewCommand("show", "--pretty=format:revert %H%n", "-R").AddDynamicArguments(commitID)
|
||||||
if err := cmd.Run(ctx, &RunOpts{
|
if err := cmd.Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: repoPath,
|
Dir: repoPath,
|
||||||
Stdout: writer,
|
Stdout: writer,
|
||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
@ -56,7 +57,7 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
|
|||||||
files = append(files, file)
|
files = append(files, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := NewCommand()
|
cmd := gitcmd.NewCommand()
|
||||||
switch diffType {
|
switch diffType {
|
||||||
case RawDiffNormal:
|
case RawDiffNormal:
|
||||||
if len(startCommit) != 0 {
|
if len(startCommit) != 0 {
|
||||||
@ -89,7 +90,7 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
|
|||||||
}
|
}
|
||||||
|
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
if err = cmd.Run(repo.Ctx, &RunOpts{
|
if err = cmd.Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: writer,
|
Stdout: writer,
|
||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
@ -312,8 +313,8 @@ func GetAffectedFiles(repo *Repository, branchName, oldCommitID, newCommitID str
|
|||||||
affectedFiles := make([]string, 0, 32)
|
affectedFiles := make([]string, 0, 32)
|
||||||
|
|
||||||
// Run `git diff --name-only` to get the names of the changed files
|
// Run `git diff --name-only` to get the names of the changed files
|
||||||
err = NewCommand("diff", "--name-only").AddDynamicArguments(oldCommitID, newCommitID).
|
err = gitcmd.NewCommand("diff", "--name-only").AddDynamicArguments(oldCommitID, newCommitID).
|
||||||
Run(repo.Ctx, &RunOpts{
|
Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Env: env,
|
Env: env,
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: stdoutWriter,
|
Stdout: stdoutWriter,
|
||||||
|
|||||||
@ -9,12 +9,12 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
@ -33,10 +33,7 @@ type Features struct {
|
|||||||
SupportCheckAttrOnBare bool // >= 2.40
|
SupportCheckAttrOnBare bool // >= 2.40
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var defaultFeatures *Features
|
||||||
GitExecutable = "git" // the command name of git, will be updated to an absolute path during initialization
|
|
||||||
defaultFeatures *Features
|
|
||||||
)
|
|
||||||
|
|
||||||
func (f *Features) CheckVersionAtLeast(atLeast string) bool {
|
func (f *Features) CheckVersionAtLeast(atLeast string) bool {
|
||||||
return f.gitVersion.Compare(version.Must(version.NewVersion(atLeast))) >= 0
|
return f.gitVersion.Compare(version.Must(version.NewVersion(atLeast))) >= 0
|
||||||
@ -60,7 +57,7 @@ func DefaultFeatures() *Features {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadGitVersionFeatures() (*Features, error) {
|
func loadGitVersionFeatures() (*Features, error) {
|
||||||
stdout, _, runErr := NewCommand("version").RunStdString(context.Background(), nil)
|
stdout, _, runErr := gitcmd.NewCommand("version").RunStdString(context.Background(), nil)
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
return nil, runErr
|
return nil, runErr
|
||||||
}
|
}
|
||||||
@ -129,32 +126,6 @@ func ensureGitVersion() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetExecutablePath changes the path of git executable and checks the file permission and version.
|
|
||||||
func SetExecutablePath(path string) error {
|
|
||||||
// If path is empty, we use the default value of GitExecutable "git" to search for the location of git.
|
|
||||||
if path != "" {
|
|
||||||
GitExecutable = path
|
|
||||||
}
|
|
||||||
absPath, err := exec.LookPath(GitExecutable)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("git not found: %w", err)
|
|
||||||
}
|
|
||||||
GitExecutable = absPath
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HomeDir is the home dir for git to store the global config file used by Gitea internally
|
|
||||||
func HomeDir() string {
|
|
||||||
if setting.Git.HomePath == "" {
|
|
||||||
// strict check, make sure the git module is initialized correctly.
|
|
||||||
// attention: when the git module is called in gitea sub-command (serv/hook), the log module might not obviously show messages to users/developers.
|
|
||||||
// for example: if there is gitea git hook code calling git.NewCommand before git.InitXxx, the integration test won't show the real failure reasons.
|
|
||||||
log.Fatal("Unable to init Git's HomeDir, incorrect initialization of the setting and git modules")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return setting.Git.HomePath
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitSimple initializes git module with a very simple step, no config changes, no global command arguments.
|
// InitSimple initializes git module with a very simple step, no config changes, no global command arguments.
|
||||||
// This method doesn't change anything to filesystem. At the moment, it is only used by some Gitea sub-commands.
|
// This method doesn't change anything to filesystem. At the moment, it is only used by some Gitea sub-commands.
|
||||||
func InitSimple() error {
|
func InitSimple() error {
|
||||||
@ -167,10 +138,10 @@ func InitSimple() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if setting.Git.Timeout.Default > 0 {
|
if setting.Git.Timeout.Default > 0 {
|
||||||
defaultCommandExecutionTimeout = time.Duration(setting.Git.Timeout.Default) * time.Second
|
gitcmd.SetDefaultCommandExecutionTimeout(time.Duration(setting.Git.Timeout.Default) * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := SetExecutablePath(setting.Git.Path); err != nil {
|
if err := gitcmd.SetExecutablePath(setting.Git.Path); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +156,7 @@ func InitSimple() error {
|
|||||||
|
|
||||||
// when git works with gnupg (commit signing), there should be a stable home for gnupg commands
|
// when git works with gnupg (commit signing), there should be a stable home for gnupg commands
|
||||||
if _, ok := os.LookupEnv("GNUPGHOME"); !ok {
|
if _, ok := os.LookupEnv("GNUPGHOME"); !ok {
|
||||||
_ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg"))
|
_ = os.Setenv("GNUPGHOME", filepath.Join(gitcmd.HomeDir(), ".gnupg"))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Copyright 2016 The Gitea Authors. All rights reserved.
|
// Copyright 2016 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package git
|
package gitcmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -32,6 +32,10 @@ type TrustedCmdArgs []internal.CmdArg
|
|||||||
// defaultCommandExecutionTimeout default command execution timeout duration
|
// defaultCommandExecutionTimeout default command execution timeout duration
|
||||||
var defaultCommandExecutionTimeout = 360 * time.Second
|
var defaultCommandExecutionTimeout = 360 * time.Second
|
||||||
|
|
||||||
|
func SetDefaultCommandExecutionTimeout(timeout time.Duration) {
|
||||||
|
defaultCommandExecutionTimeout = timeout
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultLocale is the default LC_ALL to run git commands in.
|
// DefaultLocale is the default LC_ALL to run git commands in.
|
||||||
const DefaultLocale = "C"
|
const DefaultLocale = "C"
|
||||||
|
|
||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
//go:build race
|
//go:build race
|
||||||
|
|
||||||
package git
|
package gitcmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -1,14 +1,30 @@
|
|||||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package git
|
package gitcmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/tempdir"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
gitHomePath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("git-home")
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "unable to create temp dir: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
setting.Git.HomePath = gitHomePath
|
||||||
|
}
|
||||||
|
|
||||||
func TestRunWithContextStd(t *testing.T) {
|
func TestRunWithContextStd(t *testing.T) {
|
||||||
cmd := NewCommand("--version")
|
cmd := NewCommand("--version")
|
||||||
stdout, stderr, err := cmd.RunStdString(t.Context(), &RunOpts{})
|
stdout, stderr, err := cmd.RunStdString(t.Context(), &RunOpts{})
|
||||||
40
modules/git/gitcmd/env.go
Normal file
40
modules/git/gitcmd/env.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package gitcmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
)
|
||||||
|
|
||||||
|
var GitExecutable = "git" // the command name of git, will be updated to an absolute path during initialization
|
||||||
|
|
||||||
|
// SetExecutablePath changes the path of git executable and checks the file permission and version.
|
||||||
|
func SetExecutablePath(path string) error {
|
||||||
|
// If path is empty, we use the default value of GitExecutable "git" to search for the location of git.
|
||||||
|
if path != "" {
|
||||||
|
GitExecutable = path
|
||||||
|
}
|
||||||
|
absPath, err := exec.LookPath(GitExecutable)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("git not found: %w", err)
|
||||||
|
}
|
||||||
|
GitExecutable = absPath
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HomeDir is the home dir for git to store the global config file used by Gitea internally
|
||||||
|
func HomeDir() string {
|
||||||
|
if setting.Git.HomePath == "" {
|
||||||
|
// strict check, make sure the git module is initialized correctly.
|
||||||
|
// attention: when the git module is called in gitea sub-command (serv/hook), the log module might not obviously show messages to users/developers.
|
||||||
|
// for example: if there is gitea git hook code calling NewCommand before git.InitXxx, the integration test won't show the real failure reasons.
|
||||||
|
log.Fatal("Unable to init Git's HomeDir, incorrect initialization of the setting and git modules")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return setting.Git.HomePath
|
||||||
|
}
|
||||||
14
modules/git/gitcmd/utils.go
Normal file
14
modules/git/gitcmd/utils.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package gitcmd
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// ConcatenateError concatenats an error with stderr string
|
||||||
|
func ConcatenateError(err error, stderr string) error {
|
||||||
|
if len(stderr) == 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return fmt.Errorf("%w - %s", err, stderr)
|
||||||
|
}
|
||||||
@ -14,6 +14,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -60,7 +61,7 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
|
|||||||
2^@repo: go-gitea/gitea
|
2^@repo: go-gitea/gitea
|
||||||
*/
|
*/
|
||||||
var results []*GrepResult
|
var results []*GrepResult
|
||||||
cmd := NewCommand("grep", "--null", "--break", "--heading", "--line-number", "--full-name")
|
cmd := gitcmd.NewCommand("grep", "--null", "--break", "--heading", "--line-number", "--full-name")
|
||||||
cmd.AddOptionValues("--context", strconv.Itoa(opts.ContextLineNumber))
|
cmd.AddOptionValues("--context", strconv.Itoa(opts.ContextLineNumber))
|
||||||
switch opts.GrepMode {
|
switch opts.GrepMode {
|
||||||
case GrepModeExact:
|
case GrepModeExact:
|
||||||
@ -83,7 +84,7 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
|
|||||||
cmd.AddDashesAndList(opts.PathspecList...)
|
cmd.AddDashesAndList(opts.PathspecList...)
|
||||||
opts.MaxResultLimit = util.IfZero(opts.MaxResultLimit, 50)
|
opts.MaxResultLimit = util.IfZero(opts.MaxResultLimit, 50)
|
||||||
stderr := bytes.Buffer{}
|
stderr := bytes.Buffer{}
|
||||||
err = cmd.Run(ctx, &RunOpts{
|
err = cmd.Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: stdoutWriter,
|
Stdout: stdoutWriter,
|
||||||
Stderr: &stderr,
|
Stderr: &stderr,
|
||||||
@ -135,11 +136,11 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
// git grep exits by cancel (killed), usually it is caused by the limit of results
|
// git grep exits by cancel (killed), usually it is caused by the limit of results
|
||||||
if IsErrorExitCode(err, -1) && stderr.Len() == 0 {
|
if gitcmd.IsErrorExitCode(err, -1) && stderr.Len() == 0 {
|
||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
// git grep exits with 1 if no results are found
|
// git grep exits with 1 if no results are found
|
||||||
if IsErrorExitCode(err, 1) && stderr.Len() == 0 {
|
if gitcmd.IsErrorExitCode(err, 1) && stderr.Len() == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
if err != nil && !errors.Is(err, context.Canceled) {
|
if err != nil && !errors.Is(err, context.Canceled) {
|
||||||
|
|||||||
@ -3,13 +3,24 @@
|
|||||||
|
|
||||||
package git
|
package git
|
||||||
|
|
||||||
|
import "code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
// Based on https://git-scm.com/docs/git-config#Documentation/git-config.txt-gpgformat
|
// Based on https://git-scm.com/docs/git-config#Documentation/git-config.txt-gpgformat
|
||||||
const (
|
const (
|
||||||
SigningKeyFormatOpenPGP = "openpgp" // for GPG keys, the expected default of git cli
|
SigningKeyFormatOpenPGP = "openpgp" // for GPG keys, the expected default of git cli
|
||||||
SigningKeyFormatSSH = "ssh"
|
SigningKeyFormatSSH = "ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SigningKey represents an instance key info which will be used to sign git commits.
|
||||||
|
// FIXME: need to refactor it to a new name, this name conflicts with the variable names for "asymkey.GPGKey" in many places.
|
||||||
type SigningKey struct {
|
type SigningKey struct {
|
||||||
KeyID string
|
KeyID string
|
||||||
Format string
|
Format string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SigningKey) String() string {
|
||||||
|
// Do not expose KeyID
|
||||||
|
// In case the key is a file path and the struct is rendered in a template, then the server path will be exposed.
|
||||||
|
setting.PanicInDevOrTesting("don't call SigningKey.String() - it exposes the KeyID which might be a local file path")
|
||||||
|
return "SigningKey:" + s.Format
|
||||||
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
|
|
||||||
"github.com/djherbis/buffer"
|
"github.com/djherbis/buffer"
|
||||||
"github.com/djherbis/nio/v3"
|
"github.com/djherbis/nio/v3"
|
||||||
@ -34,7 +35,7 @@ func LogNameStatusRepo(ctx context.Context, repository, head, treepath string, p
|
|||||||
_ = stdoutWriter.Close()
|
_ = stdoutWriter.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := NewCommand()
|
cmd := gitcmd.NewCommand()
|
||||||
cmd.AddArguments("log", "--name-status", "-c", "--format=commit%x00%H %P%x00", "--parents", "--no-renames", "-t", "-z").AddDynamicArguments(head)
|
cmd.AddArguments("log", "--name-status", "-c", "--format=commit%x00%H %P%x00", "--parents", "--no-renames", "-t", "-z").AddDynamicArguments(head)
|
||||||
|
|
||||||
var files []string
|
var files []string
|
||||||
@ -64,13 +65,13 @@ func LogNameStatusRepo(ctx context.Context, repository, head, treepath string, p
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
err := cmd.Run(ctx, &RunOpts{
|
err := cmd.Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: repository,
|
Dir: repository,
|
||||||
Stdout: stdoutWriter,
|
Stdout: stdoutWriter,
|
||||||
Stderr: &stderr,
|
Stderr: &stderr,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
_ = stdoutWriter.CloseWithError(gitcmd.ConcatenateError(err, (&stderr).String()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -25,8 +25,8 @@ func CatFileBatchCheck(ctx context.Context, shasToCheckReader *io.PipeReader, ca
|
|||||||
|
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
var errbuf strings.Builder
|
var errbuf strings.Builder
|
||||||
cmd := git.NewCommand("cat-file", "--batch-check")
|
cmd := gitcmd.NewCommand("cat-file", "--batch-check")
|
||||||
if err := cmd.Run(ctx, &git.RunOpts{
|
if err := cmd.Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: tmpBasePath,
|
Dir: tmpBasePath,
|
||||||
Stdin: shasToCheckReader,
|
Stdin: shasToCheckReader,
|
||||||
Stdout: catFileCheckWriter,
|
Stdout: catFileCheckWriter,
|
||||||
@ -43,8 +43,8 @@ func CatFileBatchCheckAllObjects(ctx context.Context, catFileCheckWriter *io.Pip
|
|||||||
|
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
var errbuf strings.Builder
|
var errbuf strings.Builder
|
||||||
cmd := git.NewCommand("cat-file", "--batch-check", "--batch-all-objects")
|
cmd := gitcmd.NewCommand("cat-file", "--batch-check", "--batch-all-objects")
|
||||||
if err := cmd.Run(ctx, &git.RunOpts{
|
if err := cmd.Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: tmpBasePath,
|
Dir: tmpBasePath,
|
||||||
Stdout: catFileCheckWriter,
|
Stdout: catFileCheckWriter,
|
||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
@ -64,7 +64,7 @@ func CatFileBatch(ctx context.Context, shasToBatchReader *io.PipeReader, catFile
|
|||||||
|
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
var errbuf strings.Builder
|
var errbuf strings.Builder
|
||||||
if err := git.NewCommand("cat-file", "--batch").Run(ctx, &git.RunOpts{
|
if err := gitcmd.NewCommand("cat-file", "--batch").Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: tmpBasePath,
|
Dir: tmpBasePath,
|
||||||
Stdout: catFileBatchWriter,
|
Stdout: catFileBatchWriter,
|
||||||
Stdin: shasToBatchReader,
|
Stdin: shasToBatchReader,
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FindLFSFile finds commits that contain a provided pointer file hash
|
// FindLFSFile finds commits that contain a provided pointer file hash
|
||||||
@ -32,13 +33,13 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
err := git.NewCommand("rev-list", "--all").Run(repo.Ctx, &git.RunOpts{
|
err := gitcmd.NewCommand("rev-list", "--all").Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: revListWriter,
|
Stdout: revListWriter,
|
||||||
Stderr: &stderr,
|
Stderr: &stderr,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = revListWriter.CloseWithError(git.ConcatenateError(err, (&stderr).String()))
|
_ = revListWriter.CloseWithError(gitcmd.ConcatenateError(err, (&stderr).String()))
|
||||||
} else {
|
} else {
|
||||||
_ = revListWriter.Close()
|
_ = revListWriter.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NameRevStdin runs name-rev --stdin
|
// NameRevStdin runs name-rev --stdin
|
||||||
@ -22,7 +22,7 @@ func NameRevStdin(ctx context.Context, shasToNameReader *io.PipeReader, nameRevS
|
|||||||
|
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
var errbuf strings.Builder
|
var errbuf strings.Builder
|
||||||
if err := git.NewCommand("name-rev", "--stdin", "--name-only", "--always").Run(ctx, &git.RunOpts{
|
if err := gitcmd.NewCommand("name-rev", "--stdin", "--name-only", "--always").Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: tmpBasePath,
|
Dir: tmpBasePath,
|
||||||
Stdout: nameRevStdinWriter,
|
Stdout: nameRevStdinWriter,
|
||||||
Stdin: shasToNameReader,
|
Stdin: shasToNameReader,
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,8 +23,8 @@ func RevListAllObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sy
|
|||||||
|
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
var errbuf strings.Builder
|
var errbuf strings.Builder
|
||||||
cmd := git.NewCommand("rev-list", "--objects", "--all")
|
cmd := gitcmd.NewCommand("rev-list", "--objects", "--all")
|
||||||
if err := cmd.Run(ctx, &git.RunOpts{
|
if err := cmd.Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: basePath,
|
Dir: basePath,
|
||||||
Stdout: revListWriter,
|
Stdout: revListWriter,
|
||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
@ -42,11 +42,11 @@ func RevListObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sync.
|
|||||||
defer revListWriter.Close()
|
defer revListWriter.Close()
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
var errbuf strings.Builder
|
var errbuf strings.Builder
|
||||||
cmd := git.NewCommand("rev-list", "--objects").AddDynamicArguments(headSHA)
|
cmd := gitcmd.NewCommand("rev-list", "--objects").AddDynamicArguments(headSHA)
|
||||||
if baseSHA != "" {
|
if baseSHA != "" {
|
||||||
cmd = cmd.AddArguments("--not").AddDynamicArguments(baseSHA)
|
cmd = cmd.AddArguments("--not").AddDynamicArguments(baseSHA)
|
||||||
}
|
}
|
||||||
if err := cmd.Run(ctx, &git.RunOpts{
|
if err := cmd.Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: tmpBasePath,
|
Dir: tmpBasePath,
|
||||||
Stdout: revListWriter,
|
Stdout: revListWriter,
|
||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
|
|||||||
@ -9,19 +9,20 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetRemoteAddress returns remote url of git repository in the repoPath with special remote name
|
// GetRemoteAddress returns remote url of git repository in the repoPath with special remote name
|
||||||
func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (string, error) {
|
func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (string, error) {
|
||||||
var cmd *Command
|
var cmd *gitcmd.Command
|
||||||
if DefaultFeatures().CheckVersionAtLeast("2.7") {
|
if DefaultFeatures().CheckVersionAtLeast("2.7") {
|
||||||
cmd = NewCommand("remote", "get-url").AddDynamicArguments(remoteName)
|
cmd = gitcmd.NewCommand("remote", "get-url").AddDynamicArguments(remoteName)
|
||||||
} else {
|
} else {
|
||||||
cmd = NewCommand("config", "--get").AddDynamicArguments("remote." + remoteName + ".url")
|
cmd = gitcmd.NewCommand("config", "--get").AddDynamicArguments("remote." + remoteName + ".url")
|
||||||
}
|
}
|
||||||
|
|
||||||
result, _, err := cmd.RunStdString(ctx, &RunOpts{Dir: repoPath})
|
result, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/proxy"
|
"code.gitea.io/gitea/modules/proxy"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
@ -40,9 +41,9 @@ func (repo *Repository) GetAllCommitsCount() (int64, error) {
|
|||||||
|
|
||||||
func (repo *Repository) ShowPrettyFormatLogToList(ctx context.Context, revisionRange string) ([]*Commit, error) {
|
func (repo *Repository) ShowPrettyFormatLogToList(ctx context.Context, revisionRange string) ([]*Commit, error) {
|
||||||
// avoid: ambiguous argument 'refs/a...refs/b': unknown revision or path not in the working tree. Use '--': 'git <command> [<revision>...] -- [<file>...]'
|
// avoid: ambiguous argument 'refs/a...refs/b': unknown revision or path not in the working tree. Use '--': 'git <command> [<revision>...] -- [<file>...]'
|
||||||
logs, _, err := NewCommand("log").AddArguments(prettyLogFormat).
|
logs, _, err := gitcmd.NewCommand("log").AddArguments(prettyLogFormat).
|
||||||
AddDynamicArguments(revisionRange).AddArguments("--").
|
AddDynamicArguments(revisionRange).AddArguments("--").
|
||||||
RunStdBytes(ctx, &RunOpts{Dir: repo.Path})
|
RunStdBytes(ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -70,7 +71,7 @@ func (repo *Repository) parsePrettyFormatLogToList(logs []byte) ([]*Commit, erro
|
|||||||
|
|
||||||
// IsRepoURLAccessible checks if given repository URL is accessible.
|
// IsRepoURLAccessible checks if given repository URL is accessible.
|
||||||
func IsRepoURLAccessible(ctx context.Context, url string) bool {
|
func IsRepoURLAccessible(ctx context.Context, url string) bool {
|
||||||
_, _, err := NewCommand("ls-remote", "-q", "-h").AddDynamicArguments(url, "HEAD").RunStdString(ctx, nil)
|
_, _, err := gitcmd.NewCommand("ls-remote", "-q", "-h").AddDynamicArguments(url, "HEAD").RunStdString(ctx, nil)
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +82,7 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := NewCommand("init")
|
cmd := gitcmd.NewCommand("init")
|
||||||
|
|
||||||
if !IsValidObjectFormat(objectFormatName) {
|
if !IsValidObjectFormat(objectFormatName) {
|
||||||
return fmt.Errorf("invalid object format: %s", objectFormatName)
|
return fmt.Errorf("invalid object format: %s", objectFormatName)
|
||||||
@ -93,15 +94,15 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma
|
|||||||
if bare {
|
if bare {
|
||||||
cmd.AddArguments("--bare")
|
cmd.AddArguments("--bare")
|
||||||
}
|
}
|
||||||
_, _, err = cmd.RunStdString(ctx, &RunOpts{Dir: repoPath})
|
_, _, err = cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEmpty Check if repository is empty.
|
// IsEmpty Check if repository is empty.
|
||||||
func (repo *Repository) IsEmpty() (bool, error) {
|
func (repo *Repository) IsEmpty() (bool, error) {
|
||||||
var errbuf, output strings.Builder
|
var errbuf, output strings.Builder
|
||||||
if err := NewCommand().AddOptionFormat("--git-dir=%s", repo.Path).AddArguments("rev-list", "-n", "1", "--all").
|
if err := gitcmd.NewCommand().AddOptionFormat("--git-dir=%s", repo.Path).AddArguments("rev-list", "-n", "1", "--all").
|
||||||
Run(repo.Ctx, &RunOpts{
|
Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: &output,
|
Stdout: &output,
|
||||||
Stderr: &errbuf,
|
Stderr: &errbuf,
|
||||||
@ -137,7 +138,7 @@ func Clone(ctx context.Context, from, to string, opts CloneRepoOptions) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := NewCommand().AddArguments("clone")
|
cmd := gitcmd.NewCommand().AddArguments("clone")
|
||||||
if opts.SkipTLSVerify {
|
if opts.SkipTLSVerify {
|
||||||
cmd.AddArguments("-c", "http.sslVerify=false")
|
cmd.AddArguments("-c", "http.sslVerify=false")
|
||||||
}
|
}
|
||||||
@ -178,13 +179,13 @@ func Clone(ctx context.Context, from, to string, opts CloneRepoOptions) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
if err = cmd.Run(ctx, &RunOpts{
|
if err = cmd.Run(ctx, &gitcmd.RunOpts{
|
||||||
Timeout: opts.Timeout,
|
Timeout: opts.Timeout,
|
||||||
Env: envs,
|
Env: envs,
|
||||||
Stdout: io.Discard,
|
Stdout: io.Discard,
|
||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return ConcatenateError(err, stderr.String())
|
return gitcmd.ConcatenateError(err, stderr.String())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -201,7 +202,7 @@ type PushOptions struct {
|
|||||||
|
|
||||||
// Push pushs local commits to given remote branch.
|
// Push pushs local commits to given remote branch.
|
||||||
func Push(ctx context.Context, repoPath string, opts PushOptions) error {
|
func Push(ctx context.Context, repoPath string, opts PushOptions) error {
|
||||||
cmd := NewCommand("push")
|
cmd := gitcmd.NewCommand("push")
|
||||||
if opts.Force {
|
if opts.Force {
|
||||||
cmd.AddArguments("-f")
|
cmd.AddArguments("-f")
|
||||||
}
|
}
|
||||||
@ -214,7 +215,7 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
|
|||||||
}
|
}
|
||||||
cmd.AddDashesAndList(remoteBranchArgs...)
|
cmd.AddDashesAndList(remoteBranchArgs...)
|
||||||
|
|
||||||
stdout, stderr, err := cmd.RunStdString(ctx, &RunOpts{Env: opts.Env, Timeout: opts.Timeout, Dir: repoPath})
|
stdout, stderr, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Env: opts.Env, Timeout: opts.Timeout, Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(stderr, "non-fast-forward") {
|
if strings.Contains(stderr, "non-fast-forward") {
|
||||||
return &ErrPushOutOfDate{StdOut: stdout, StdErr: stderr, Err: err}
|
return &ErrPushOutOfDate{StdOut: stdout, StdErr: stderr, Err: err}
|
||||||
@ -233,8 +234,8 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
|
|||||||
|
|
||||||
// GetLatestCommitTime returns time for latest commit in repository (across all branches)
|
// GetLatestCommitTime returns time for latest commit in repository (across all branches)
|
||||||
func GetLatestCommitTime(ctx context.Context, repoPath string) (time.Time, error) {
|
func GetLatestCommitTime(ctx context.Context, repoPath string) (time.Time, error) {
|
||||||
cmd := NewCommand("for-each-ref", "--sort=-committerdate", BranchPrefix, "--count", "1", "--format=%(committerdate)")
|
cmd := gitcmd.NewCommand("for-each-ref", "--sort=-committerdate", BranchPrefix, "--count", "1", "--format=%(committerdate)")
|
||||||
stdout, _, err := cmd.RunStdString(ctx, &RunOpts{Dir: repoPath})
|
stdout, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return time.Time{}, err
|
return time.Time{}, err
|
||||||
}
|
}
|
||||||
@ -250,9 +251,9 @@ type DivergeObject struct {
|
|||||||
|
|
||||||
// GetDivergingCommits returns the number of commits a targetBranch is ahead or behind a baseBranch
|
// GetDivergingCommits returns the number of commits a targetBranch is ahead or behind a baseBranch
|
||||||
func GetDivergingCommits(ctx context.Context, repoPath, baseBranch, targetBranch string) (do DivergeObject, err error) {
|
func GetDivergingCommits(ctx context.Context, repoPath, baseBranch, targetBranch string) (do DivergeObject, err error) {
|
||||||
cmd := NewCommand("rev-list", "--count", "--left-right").
|
cmd := gitcmd.NewCommand("rev-list", "--count", "--left-right").
|
||||||
AddDynamicArguments(baseBranch + "..." + targetBranch).AddArguments("--")
|
AddDynamicArguments(baseBranch + "..." + targetBranch).AddArguments("--")
|
||||||
stdout, _, err := cmd.RunStdString(ctx, &RunOpts{Dir: repoPath})
|
stdout, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return do, err
|
return do, err
|
||||||
}
|
}
|
||||||
@ -281,23 +282,23 @@ func (repo *Repository) CreateBundle(ctx context.Context, commit string, out io.
|
|||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repo.Path, "objects"))
|
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repo.Path, "objects"))
|
||||||
_, _, err = NewCommand("init", "--bare").RunStdString(ctx, &RunOpts{Dir: tmp, Env: env})
|
_, _, err = gitcmd.NewCommand("init", "--bare").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = NewCommand("reset", "--soft").AddDynamicArguments(commit).RunStdString(ctx, &RunOpts{Dir: tmp, Env: env})
|
_, _, err = gitcmd.NewCommand("reset", "--soft").AddDynamicArguments(commit).RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = NewCommand("branch", "-m", "bundle").RunStdString(ctx, &RunOpts{Dir: tmp, Env: env})
|
_, _, err = gitcmd.NewCommand("branch", "-m", "bundle").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpFile := filepath.Join(tmp, "bundle")
|
tmpFile := filepath.Join(tmp, "bundle")
|
||||||
_, _, err = NewCommand("bundle", "create").AddDynamicArguments(tmpFile, "bundle", "HEAD").RunStdString(ctx, &RunOpts{Dir: tmp, Env: env})
|
_, _, err = gitcmd.NewCommand("bundle", "create").AddDynamicArguments(tmpFile, "bundle", "HEAD").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ArchiveType archive types
|
// ArchiveType archive types
|
||||||
@ -53,7 +55,7 @@ func (repo *Repository) CreateArchive(ctx context.Context, format ArchiveType, t
|
|||||||
return fmt.Errorf("unknown format: %v", format)
|
return fmt.Errorf("unknown format: %v", format)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := NewCommand("archive")
|
cmd := gitcmd.NewCommand("archive")
|
||||||
if usePrefix {
|
if usePrefix {
|
||||||
cmd.AddOptionFormat("--prefix=%s", filepath.Base(strings.TrimSuffix(repo.Path, ".git"))+"/")
|
cmd.AddOptionFormat("--prefix=%s", filepath.Base(strings.TrimSuffix(repo.Path, ".git"))+"/")
|
||||||
}
|
}
|
||||||
@ -61,13 +63,13 @@ func (repo *Repository) CreateArchive(ctx context.Context, format ArchiveType, t
|
|||||||
cmd.AddDynamicArguments(commitID)
|
cmd.AddDynamicArguments(commitID)
|
||||||
|
|
||||||
var stderr strings.Builder
|
var stderr strings.Builder
|
||||||
err := cmd.Run(ctx, &RunOpts{
|
err := cmd.Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: target,
|
Stdout: target,
|
||||||
Stderr: &stderr,
|
Stderr: &stderr,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ConcatenateError(err, stderr.String())
|
return gitcmd.ConcatenateError(err, stderr.String())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,14 +5,16 @@ package git
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LineBlame returns the latest commit at the given line
|
// LineBlame returns the latest commit at the given line
|
||||||
func (repo *Repository) LineBlame(revision, path, file string, line uint) (*Commit, error) {
|
func (repo *Repository) LineBlame(revision, path, file string, line uint) (*Commit, error) {
|
||||||
res, _, err := NewCommand("blame").
|
res, _, err := gitcmd.NewCommand("blame").
|
||||||
AddOptionFormat("-L %d,%d", line, line).
|
AddOptionFormat("-L %d,%d", line, line).
|
||||||
AddOptionValues("-p", revision).
|
AddOptionValues("-p", revision).
|
||||||
AddDashesAndList(file).RunStdString(repo.Ctx, &RunOpts{Dir: path})
|
AddDashesAndList(file).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BranchPrefix base dir of the branch information file store on git
|
// BranchPrefix base dir of the branch information file store on git
|
||||||
@ -15,7 +17,7 @@ const BranchPrefix = "refs/heads/"
|
|||||||
|
|
||||||
// IsReferenceExist returns true if given reference exists in the repository.
|
// IsReferenceExist returns true if given reference exists in the repository.
|
||||||
func IsReferenceExist(ctx context.Context, repoPath, name string) bool {
|
func IsReferenceExist(ctx context.Context, repoPath, name string) bool {
|
||||||
_, _, err := NewCommand("show-ref", "--verify").AddDashesAndList(name).RunStdString(ctx, &RunOpts{Dir: repoPath})
|
_, _, err := gitcmd.NewCommand("show-ref", "--verify").AddDashesAndList(name).RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +27,7 @@ func IsBranchExist(ctx context.Context, repoPath, name string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetDefaultBranch(ctx context.Context, repoPath string) (string, error) {
|
func GetDefaultBranch(ctx context.Context, repoPath string) (string, error) {
|
||||||
stdout, _, err := NewCommand("symbolic-ref", "HEAD").RunStdString(ctx, &RunOpts{Dir: repoPath})
|
stdout, _, err := gitcmd.NewCommand("symbolic-ref", "HEAD").RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -43,7 +45,7 @@ type DeleteBranchOptions struct {
|
|||||||
|
|
||||||
// DeleteBranch delete a branch by name on repository.
|
// DeleteBranch delete a branch by name on repository.
|
||||||
func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) error {
|
func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) error {
|
||||||
cmd := NewCommand("branch")
|
cmd := gitcmd.NewCommand("branch")
|
||||||
|
|
||||||
if opts.Force {
|
if opts.Force {
|
||||||
cmd.AddArguments("-D")
|
cmd.AddArguments("-D")
|
||||||
@ -52,35 +54,35 @@ func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddDashesAndList(name)
|
cmd.AddDashesAndList(name)
|
||||||
_, _, err := cmd.RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
_, _, err := cmd.RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateBranch create a new branch
|
// CreateBranch create a new branch
|
||||||
func (repo *Repository) CreateBranch(branch, oldbranchOrCommit string) error {
|
func (repo *Repository) CreateBranch(branch, oldbranchOrCommit string) error {
|
||||||
cmd := NewCommand("branch")
|
cmd := gitcmd.NewCommand("branch")
|
||||||
cmd.AddDashesAndList(branch, oldbranchOrCommit)
|
cmd.AddDashesAndList(branch, oldbranchOrCommit)
|
||||||
|
|
||||||
_, _, err := cmd.RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
_, _, err := cmd.RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddRemote adds a new remote to repository.
|
// AddRemote adds a new remote to repository.
|
||||||
func (repo *Repository) AddRemote(name, url string, fetch bool) error {
|
func (repo *Repository) AddRemote(name, url string, fetch bool) error {
|
||||||
cmd := NewCommand("remote", "add")
|
cmd := gitcmd.NewCommand("remote", "add")
|
||||||
if fetch {
|
if fetch {
|
||||||
cmd.AddArguments("-f")
|
cmd.AddArguments("-f")
|
||||||
}
|
}
|
||||||
cmd.AddDynamicArguments(name, url)
|
cmd.AddDynamicArguments(name, url)
|
||||||
|
|
||||||
_, _, err := cmd.RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
_, _, err := cmd.RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenameBranch rename a branch
|
// RenameBranch rename a branch
|
||||||
func (repo *Repository) RenameBranch(from, to string) error {
|
func (repo *Repository) RenameBranch(from, to string) error {
|
||||||
_, _, err := NewCommand("branch", "-m").AddDynamicArguments(from, to).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
_, _, err := gitcmd.NewCommand("branch", "-m").AddDynamicArguments(from, to).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -70,25 +71,25 @@ func (repo *Repository) IsBranchExist(name string) bool {
|
|||||||
// GetBranchNames returns branches from the repository, skipping "skip" initial branches and
|
// GetBranchNames returns branches from the repository, skipping "skip" initial branches and
|
||||||
// returning at most "limit" branches, or all branches if "limit" is 0.
|
// returning at most "limit" branches, or all branches if "limit" is 0.
|
||||||
func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
|
func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
|
||||||
return callShowRef(repo.Ctx, repo.Path, BranchPrefix, TrustedCmdArgs{BranchPrefix, "--sort=-committerdate"}, skip, limit)
|
return callShowRef(repo.Ctx, repo.Path, BranchPrefix, gitcmd.TrustedCmdArgs{BranchPrefix, "--sort=-committerdate"}, skip, limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WalkReferences walks all the references from the repository
|
// WalkReferences walks all the references from the repository
|
||||||
// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty.
|
// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty.
|
||||||
func (repo *Repository) WalkReferences(refType ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) {
|
func (repo *Repository) WalkReferences(refType ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) {
|
||||||
var args TrustedCmdArgs
|
var args gitcmd.TrustedCmdArgs
|
||||||
switch refType {
|
switch refType {
|
||||||
case ObjectTag:
|
case ObjectTag:
|
||||||
args = TrustedCmdArgs{TagPrefix, "--sort=-taggerdate"}
|
args = gitcmd.TrustedCmdArgs{TagPrefix, "--sort=-taggerdate"}
|
||||||
case ObjectBranch:
|
case ObjectBranch:
|
||||||
args = TrustedCmdArgs{BranchPrefix, "--sort=-committerdate"}
|
args = gitcmd.TrustedCmdArgs{BranchPrefix, "--sort=-committerdate"}
|
||||||
}
|
}
|
||||||
|
|
||||||
return WalkShowRef(repo.Ctx, repo.Path, args, skip, limit, walkfn)
|
return WalkShowRef(repo.Ctx, repo.Path, args, skip, limit, walkfn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// callShowRef return refs, if limit = 0 it will not limit
|
// callShowRef return refs, if limit = 0 it will not limit
|
||||||
func callShowRef(ctx context.Context, repoPath, trimPrefix string, extraArgs TrustedCmdArgs, skip, limit int) (branchNames []string, countAll int, err error) {
|
func callShowRef(ctx context.Context, repoPath, trimPrefix string, extraArgs gitcmd.TrustedCmdArgs, skip, limit int) (branchNames []string, countAll int, err error) {
|
||||||
countAll, err = WalkShowRef(ctx, repoPath, extraArgs, skip, limit, func(_, branchName string) error {
|
countAll, err = WalkShowRef(ctx, repoPath, extraArgs, skip, limit, func(_, branchName string) error {
|
||||||
branchName = strings.TrimPrefix(branchName, trimPrefix)
|
branchName = strings.TrimPrefix(branchName, trimPrefix)
|
||||||
branchNames = append(branchNames, branchName)
|
branchNames = append(branchNames, branchName)
|
||||||
@ -98,7 +99,7 @@ func callShowRef(ctx context.Context, repoPath, trimPrefix string, extraArgs Tru
|
|||||||
return branchNames, countAll, err
|
return branchNames, countAll, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func WalkShowRef(ctx context.Context, repoPath string, extraArgs TrustedCmdArgs, skip, limit int, walkfn func(sha1, refname string) error) (countAll int, err error) {
|
func WalkShowRef(ctx context.Context, repoPath string, extraArgs gitcmd.TrustedCmdArgs, skip, limit int, walkfn func(sha1, refname string) error) (countAll int, err error) {
|
||||||
stdoutReader, stdoutWriter := io.Pipe()
|
stdoutReader, stdoutWriter := io.Pipe()
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = stdoutReader.Close()
|
_ = stdoutReader.Close()
|
||||||
@ -107,9 +108,9 @@ func WalkShowRef(ctx context.Context, repoPath string, extraArgs TrustedCmdArgs,
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
stderrBuilder := &strings.Builder{}
|
stderrBuilder := &strings.Builder{}
|
||||||
args := TrustedCmdArgs{"for-each-ref", "--format=%(objectname) %(refname)"}
|
args := gitcmd.TrustedCmdArgs{"for-each-ref", "--format=%(objectname) %(refname)"}
|
||||||
args = append(args, extraArgs...)
|
args = append(args, extraArgs...)
|
||||||
err := NewCommand(args...).Run(ctx, &RunOpts{
|
err := gitcmd.NewCommand(args...).Run(ctx, &gitcmd.RunOpts{
|
||||||
Dir: repoPath,
|
Dir: repoPath,
|
||||||
Stdout: stdoutWriter,
|
Stdout: stdoutWriter,
|
||||||
Stderr: stderrBuilder,
|
Stderr: stderrBuilder,
|
||||||
@ -119,7 +120,7 @@ func WalkShowRef(ctx context.Context, repoPath string, extraArgs TrustedCmdArgs,
|
|||||||
_ = stdoutWriter.Close()
|
_ = stdoutWriter.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String()))
|
_ = stdoutWriter.CloseWithError(gitcmd.ConcatenateError(err, stderrBuilder.String()))
|
||||||
} else {
|
} else {
|
||||||
_ = stdoutWriter.Close()
|
_ = stdoutWriter.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/cache"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ func (repo *Repository) getCommitByPathWithID(id ObjectID, relpath string) (*Com
|
|||||||
relpath = `\` + relpath
|
relpath = `\` + relpath
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, _, runErr := NewCommand("log", "-1", prettyLogFormat).AddDynamicArguments(id.String()).AddDashesAndList(relpath).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, runErr := gitcmd.NewCommand("log", "-1", prettyLogFormat).AddDynamicArguments(id.String()).AddDashesAndList(relpath).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
return nil, runErr
|
return nil, runErr
|
||||||
}
|
}
|
||||||
@ -74,7 +75,7 @@ func (repo *Repository) getCommitByPathWithID(id ObjectID, relpath string) (*Com
|
|||||||
|
|
||||||
// GetCommitByPath returns the last commit of relative path.
|
// GetCommitByPath returns the last commit of relative path.
|
||||||
func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
|
func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
|
||||||
stdout, _, runErr := NewCommand("log", "-1", prettyLogFormat).AddDashesAndList(relpath).RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, runErr := gitcmd.NewCommand("log", "-1", prettyLogFormat).AddDashesAndList(relpath).RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
return nil, runErr
|
return nil, runErr
|
||||||
}
|
}
|
||||||
@ -91,7 +92,7 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
|
|||||||
|
|
||||||
// commitsByRangeWithTime returns the specific page commits before current revision, with not, since, until support
|
// commitsByRangeWithTime returns the specific page commits before current revision, with not, since, until support
|
||||||
func (repo *Repository) commitsByRangeWithTime(id ObjectID, page, pageSize int, not, since, until string) ([]*Commit, error) {
|
func (repo *Repository) commitsByRangeWithTime(id ObjectID, page, pageSize int, not, since, until string) ([]*Commit, error) {
|
||||||
cmd := NewCommand("log").
|
cmd := gitcmd.NewCommand("log").
|
||||||
AddOptionFormat("--skip=%d", (page-1)*pageSize).
|
AddOptionFormat("--skip=%d", (page-1)*pageSize).
|
||||||
AddOptionFormat("--max-count=%d", pageSize).
|
AddOptionFormat("--max-count=%d", pageSize).
|
||||||
AddArguments(prettyLogFormat).
|
AddArguments(prettyLogFormat).
|
||||||
@ -107,7 +108,7 @@ func (repo *Repository) commitsByRangeWithTime(id ObjectID, page, pageSize int,
|
|||||||
cmd.AddOptionFormat("--until=%s", until)
|
cmd.AddOptionFormat("--until=%s", until)
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, _, err := cmd.RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err := cmd.RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -117,7 +118,7 @@ func (repo *Repository) commitsByRangeWithTime(id ObjectID, page, pageSize int,
|
|||||||
|
|
||||||
func (repo *Repository) searchCommits(id ObjectID, opts SearchCommitsOptions) ([]*Commit, error) {
|
func (repo *Repository) searchCommits(id ObjectID, opts SearchCommitsOptions) ([]*Commit, error) {
|
||||||
// add common arguments to git command
|
// add common arguments to git command
|
||||||
addCommonSearchArgs := func(c *Command) {
|
addCommonSearchArgs := func(c *gitcmd.Command) {
|
||||||
// ignore case
|
// ignore case
|
||||||
c.AddArguments("-i")
|
c.AddArguments("-i")
|
||||||
|
|
||||||
@ -141,7 +142,7 @@ func (repo *Repository) searchCommits(id ObjectID, opts SearchCommitsOptions) ([
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create new git log command with limit of 100 commits
|
// create new git log command with limit of 100 commits
|
||||||
cmd := NewCommand("log", "-100", prettyLogFormat).AddDynamicArguments(id.String())
|
cmd := gitcmd.NewCommand("log", "-100", prettyLogFormat).AddDynamicArguments(id.String())
|
||||||
|
|
||||||
// pretend that all refs along with HEAD were listed on command line as <commis>
|
// pretend that all refs along with HEAD were listed on command line as <commis>
|
||||||
// https://git-scm.com/docs/git-log#Documentation/git-log.txt---all
|
// https://git-scm.com/docs/git-log#Documentation/git-log.txt---all
|
||||||
@ -161,7 +162,7 @@ func (repo *Repository) searchCommits(id ObjectID, opts SearchCommitsOptions) ([
|
|||||||
|
|
||||||
// search for commits matching given constraints and keywords in commit msg
|
// search for commits matching given constraints and keywords in commit msg
|
||||||
addCommonSearchArgs(cmd)
|
addCommonSearchArgs(cmd)
|
||||||
stdout, _, err := cmd.RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err := cmd.RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -175,14 +176,14 @@ func (repo *Repository) searchCommits(id ObjectID, opts SearchCommitsOptions) ([
|
|||||||
// ignore anything not matching a valid sha pattern
|
// ignore anything not matching a valid sha pattern
|
||||||
if id.Type().IsValid(v) {
|
if id.Type().IsValid(v) {
|
||||||
// create new git log command with 1 commit limit
|
// create new git log command with 1 commit limit
|
||||||
hashCmd := NewCommand("log", "-1", prettyLogFormat)
|
hashCmd := gitcmd.NewCommand("log", "-1", prettyLogFormat)
|
||||||
// add previous arguments except for --grep and --all
|
// add previous arguments except for --grep and --all
|
||||||
addCommonSearchArgs(hashCmd)
|
addCommonSearchArgs(hashCmd)
|
||||||
// add keyword as <commit>
|
// add keyword as <commit>
|
||||||
hashCmd.AddDynamicArguments(v)
|
hashCmd.AddDynamicArguments(v)
|
||||||
|
|
||||||
// search with given constraints for commit matching sha hash of v
|
// search with given constraints for commit matching sha hash of v
|
||||||
hashMatching, _, err := hashCmd.RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
hashMatching, _, err := hashCmd.RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil || bytes.Contains(stdout, hashMatching) {
|
if err != nil || bytes.Contains(stdout, hashMatching) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -197,7 +198,7 @@ func (repo *Repository) searchCommits(id ObjectID, opts SearchCommitsOptions) ([
|
|||||||
// FileChangedBetweenCommits Returns true if the file changed between commit IDs id1 and id2
|
// FileChangedBetweenCommits Returns true if the file changed between commit IDs id1 and id2
|
||||||
// You must ensure that id1 and id2 are valid commit ids.
|
// You must ensure that id1 and id2 are valid commit ids.
|
||||||
func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bool, error) {
|
func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bool, error) {
|
||||||
stdout, _, err := NewCommand("diff", "--name-only", "-z").AddDynamicArguments(id1, id2).AddDashesAndList(filename).RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err := gitcmd.NewCommand("diff", "--name-only", "-z").AddDynamicArguments(id1, id2).AddDashesAndList(filename).RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -232,7 +233,7 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions)
|
|||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
gitCmd := NewCommand("rev-list").
|
gitCmd := gitcmd.NewCommand("rev-list").
|
||||||
AddOptionFormat("--max-count=%d", setting.Git.CommitsRangeSize).
|
AddOptionFormat("--max-count=%d", setting.Git.CommitsRangeSize).
|
||||||
AddOptionFormat("--skip=%d", (opts.Page-1)*setting.Git.CommitsRangeSize)
|
AddOptionFormat("--skip=%d", (opts.Page-1)*setting.Git.CommitsRangeSize)
|
||||||
gitCmd.AddDynamicArguments(opts.Revision)
|
gitCmd.AddDynamicArguments(opts.Revision)
|
||||||
@ -248,13 +249,13 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions)
|
|||||||
}
|
}
|
||||||
|
|
||||||
gitCmd.AddDashesAndList(opts.File)
|
gitCmd.AddDashesAndList(opts.File)
|
||||||
err := gitCmd.Run(repo.Ctx, &RunOpts{
|
err := gitCmd.Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: stdoutWriter,
|
Stdout: stdoutWriter,
|
||||||
Stderr: &stderr,
|
Stderr: &stderr,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
_ = stdoutWriter.CloseWithError(gitcmd.ConcatenateError(err, (&stderr).String()))
|
||||||
} else {
|
} else {
|
||||||
_ = stdoutWriter.Close()
|
_ = stdoutWriter.Close()
|
||||||
}
|
}
|
||||||
@ -290,11 +291,11 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions)
|
|||||||
|
|
||||||
// FilesCountBetween return the number of files changed between two commits
|
// FilesCountBetween return the number of files changed between two commits
|
||||||
func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) {
|
func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) {
|
||||||
stdout, _, err := NewCommand("diff", "--name-only").AddDynamicArguments(startCommitID+"..."+endCommitID).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err := gitcmd.NewCommand("diff", "--name-only").AddDynamicArguments(startCommitID+"..."+endCommitID).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
||||||
// git >= 2.28 now returns an error if startCommitID and endCommitID have become unrelated.
|
// git >= 2.28 now returns an error if startCommitID and endCommitID have become unrelated.
|
||||||
// previously it would return the results of git diff --name-only startCommitID endCommitID so let's try that...
|
// previously it would return the results of git diff --name-only startCommitID endCommitID so let's try that...
|
||||||
stdout, _, err = NewCommand("diff", "--name-only").AddDynamicArguments(startCommitID, endCommitID).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err = gitcmd.NewCommand("diff", "--name-only").AddDynamicArguments(startCommitID, endCommitID).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
@ -308,13 +309,13 @@ func (repo *Repository) CommitsBetween(last, before *Commit) ([]*Commit, error)
|
|||||||
var stdout []byte
|
var stdout []byte
|
||||||
var err error
|
var err error
|
||||||
if before == nil {
|
if before == nil {
|
||||||
stdout, _, err = NewCommand("rev-list").AddDynamicArguments(last.ID.String()).RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err = gitcmd.NewCommand("rev-list").AddDynamicArguments(last.ID.String()).RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
} else {
|
} else {
|
||||||
stdout, _, err = NewCommand("rev-list").AddDynamicArguments(before.ID.String()+".."+last.ID.String()).RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err = gitcmd.NewCommand("rev-list").AddDynamicArguments(before.ID.String()+".."+last.ID.String()).RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
||||||
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
|
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
|
||||||
// previously it would return the results of git rev-list before last so let's try that...
|
// previously it would return the results of git rev-list before last so let's try that...
|
||||||
stdout, _, err = NewCommand("rev-list").AddDynamicArguments(before.ID.String(), last.ID.String()).RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err = gitcmd.NewCommand("rev-list").AddDynamicArguments(before.ID.String(), last.ID.String()).RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -328,22 +329,22 @@ func (repo *Repository) CommitsBetweenLimit(last, before *Commit, limit, skip in
|
|||||||
var stdout []byte
|
var stdout []byte
|
||||||
var err error
|
var err error
|
||||||
if before == nil {
|
if before == nil {
|
||||||
stdout, _, err = NewCommand("rev-list").
|
stdout, _, err = gitcmd.NewCommand("rev-list").
|
||||||
AddOptionValues("--max-count", strconv.Itoa(limit)).
|
AddOptionValues("--max-count", strconv.Itoa(limit)).
|
||||||
AddOptionValues("--skip", strconv.Itoa(skip)).
|
AddOptionValues("--skip", strconv.Itoa(skip)).
|
||||||
AddDynamicArguments(last.ID.String()).RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
AddDynamicArguments(last.ID.String()).RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
} else {
|
} else {
|
||||||
stdout, _, err = NewCommand("rev-list").
|
stdout, _, err = gitcmd.NewCommand("rev-list").
|
||||||
AddOptionValues("--max-count", strconv.Itoa(limit)).
|
AddOptionValues("--max-count", strconv.Itoa(limit)).
|
||||||
AddOptionValues("--skip", strconv.Itoa(skip)).
|
AddOptionValues("--skip", strconv.Itoa(skip)).
|
||||||
AddDynamicArguments(before.ID.String()+".."+last.ID.String()).RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
AddDynamicArguments(before.ID.String()+".."+last.ID.String()).RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
||||||
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
|
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
|
||||||
// previously it would return the results of git rev-list --max-count n before last so let's try that...
|
// previously it would return the results of git rev-list --max-count n before last so let's try that...
|
||||||
stdout, _, err = NewCommand("rev-list").
|
stdout, _, err = gitcmd.NewCommand("rev-list").
|
||||||
AddOptionValues("--max-count", strconv.Itoa(limit)).
|
AddOptionValues("--max-count", strconv.Itoa(limit)).
|
||||||
AddOptionValues("--skip", strconv.Itoa(skip)).
|
AddOptionValues("--skip", strconv.Itoa(skip)).
|
||||||
AddDynamicArguments(before.ID.String(), last.ID.String()).RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
AddDynamicArguments(before.ID.String(), last.ID.String()).RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -358,13 +359,13 @@ func (repo *Repository) CommitsBetweenNotBase(last, before *Commit, baseBranch s
|
|||||||
var stdout []byte
|
var stdout []byte
|
||||||
var err error
|
var err error
|
||||||
if before == nil {
|
if before == nil {
|
||||||
stdout, _, err = NewCommand("rev-list").AddDynamicArguments(last.ID.String()).AddOptionValues("--not", baseBranch).RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err = gitcmd.NewCommand("rev-list").AddDynamicArguments(last.ID.String()).AddOptionValues("--not", baseBranch).RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
} else {
|
} else {
|
||||||
stdout, _, err = NewCommand("rev-list").AddDynamicArguments(before.ID.String()+".."+last.ID.String()).AddOptionValues("--not", baseBranch).RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err = gitcmd.NewCommand("rev-list").AddDynamicArguments(before.ID.String()+".."+last.ID.String()).AddOptionValues("--not", baseBranch).RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
||||||
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
|
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
|
||||||
// previously it would return the results of git rev-list before last so let's try that...
|
// previously it would return the results of git rev-list before last so let's try that...
|
||||||
stdout, _, err = NewCommand("rev-list").AddDynamicArguments(before.ID.String(), last.ID.String()).AddOptionValues("--not", baseBranch).RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err = gitcmd.NewCommand("rev-list").AddDynamicArguments(before.ID.String(), last.ID.String()).AddOptionValues("--not", baseBranch).RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -410,13 +411,13 @@ func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) {
|
|||||||
|
|
||||||
// commitsBefore the limit is depth, not total number of returned commits.
|
// commitsBefore the limit is depth, not total number of returned commits.
|
||||||
func (repo *Repository) commitsBefore(id ObjectID, limit int) ([]*Commit, error) {
|
func (repo *Repository) commitsBefore(id ObjectID, limit int) ([]*Commit, error) {
|
||||||
cmd := NewCommand("log", prettyLogFormat)
|
cmd := gitcmd.NewCommand("log", prettyLogFormat)
|
||||||
if limit > 0 {
|
if limit > 0 {
|
||||||
cmd.AddOptionFormat("-%d", limit)
|
cmd.AddOptionFormat("-%d", limit)
|
||||||
}
|
}
|
||||||
cmd.AddDynamicArguments(id.String())
|
cmd.AddDynamicArguments(id.String())
|
||||||
|
|
||||||
stdout, _, runErr := cmd.RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, runErr := cmd.RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
return nil, runErr
|
return nil, runErr
|
||||||
}
|
}
|
||||||
@ -453,10 +454,10 @@ func (repo *Repository) getCommitsBeforeLimit(id ObjectID, num int) ([]*Commit,
|
|||||||
|
|
||||||
func (repo *Repository) getBranches(env []string, commitID string, limit int) ([]string, error) {
|
func (repo *Repository) getBranches(env []string, commitID string, limit int) ([]string, error) {
|
||||||
if DefaultFeatures().CheckVersionAtLeast("2.7.0") {
|
if DefaultFeatures().CheckVersionAtLeast("2.7.0") {
|
||||||
stdout, _, err := NewCommand("for-each-ref", "--format=%(refname:strip=2)").
|
stdout, _, err := gitcmd.NewCommand("for-each-ref", "--format=%(refname:strip=2)").
|
||||||
AddOptionFormat("--count=%d", limit).
|
AddOptionFormat("--count=%d", limit).
|
||||||
AddOptionValues("--contains", commitID, BranchPrefix).
|
AddOptionValues("--contains", commitID, BranchPrefix).
|
||||||
RunStdString(repo.Ctx, &RunOpts{
|
RunStdString(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Env: env,
|
Env: env,
|
||||||
})
|
})
|
||||||
@ -468,7 +469,7 @@ func (repo *Repository) getBranches(env []string, commitID string, limit int) ([
|
|||||||
return branches, nil
|
return branches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, _, err := NewCommand("branch").AddOptionValues("--contains", commitID).RunStdString(repo.Ctx, &RunOpts{
|
stdout, _, err := gitcmd.NewCommand("branch").AddOptionValues("--contains", commitID).RunStdString(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Env: env,
|
Env: env,
|
||||||
})
|
})
|
||||||
@ -510,7 +511,7 @@ func (repo *Repository) GetCommitsFromIDs(commitIDs []string) []*Commit {
|
|||||||
|
|
||||||
// IsCommitInBranch check if the commit is on the branch
|
// IsCommitInBranch check if the commit is on the branch
|
||||||
func (repo *Repository) IsCommitInBranch(commitID, branch string) (r bool, err error) {
|
func (repo *Repository) IsCommitInBranch(commitID, branch string) (r bool, err error) {
|
||||||
stdout, _, err := NewCommand("branch", "--contains").AddDynamicArguments(commitID, branch).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err := gitcmd.NewCommand("branch", "--contains").AddDynamicArguments(commitID, branch).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -536,10 +537,10 @@ func (repo *Repository) AddLastCommitCache(cacheKey, fullName, sha string) error
|
|||||||
|
|
||||||
// GetCommitBranchStart returns the commit where the branch diverged
|
// GetCommitBranchStart returns the commit where the branch diverged
|
||||||
func (repo *Repository) GetCommitBranchStart(env []string, branch, endCommitID string) (string, error) {
|
func (repo *Repository) GetCommitBranchStart(env []string, branch, endCommitID string) (string, error) {
|
||||||
cmd := NewCommand("log", prettyLogFormat)
|
cmd := gitcmd.NewCommand("log", prettyLogFormat)
|
||||||
cmd.AddDynamicArguments(endCommitID)
|
cmd.AddDynamicArguments(endCommitID)
|
||||||
|
|
||||||
stdout, _, runErr := cmd.RunStdBytes(repo.Ctx, &RunOpts{
|
stdout, _, runErr := cmd.RunStdBytes(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Env: env,
|
Env: env,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -9,6 +9,8 @@ package git
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
|
|
||||||
"github.com/go-git/go-git/v5/plumbing"
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
"github.com/go-git/go-git/v5/plumbing/hash"
|
"github.com/go-git/go-git/v5/plumbing/hash"
|
||||||
"github.com/go-git/go-git/v5/plumbing/object"
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
@ -59,7 +61,7 @@ func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actualCommitID, _, err := NewCommand("rev-parse", "--verify").AddDynamicArguments(commitID).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
actualCommitID, _, err := gitcmd.NewCommand("rev-parse", "--verify").AddDynamicArguments(commitID).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
actualCommitID = strings.TrimSpace(actualCommitID)
|
actualCommitID = strings.TrimSpace(actualCommitID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "unknown revision or path") ||
|
if strings.Contains(err.Error(), "unknown revision or path") ||
|
||||||
|
|||||||
@ -11,12 +11,13 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResolveReference resolves a name to a reference
|
// ResolveReference resolves a name to a reference
|
||||||
func (repo *Repository) ResolveReference(name string) (string, error) {
|
func (repo *Repository) ResolveReference(name string) (string, error) {
|
||||||
stdout, _, err := NewCommand("show-ref", "--hash").AddDynamicArguments(name).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err := gitcmd.NewCommand("show-ref", "--hash").AddDynamicArguments(name).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "not a valid ref") {
|
if strings.Contains(err.Error(), "not a valid ref") {
|
||||||
return "", ErrNotExist{name, ""}
|
return "", ErrNotExist{name, ""}
|
||||||
@ -52,13 +53,13 @@ func (repo *Repository) GetRefCommitID(name string) (string, error) {
|
|||||||
|
|
||||||
// SetReference sets the commit ID string of given reference (e.g. branch or tag).
|
// SetReference sets the commit ID string of given reference (e.g. branch or tag).
|
||||||
func (repo *Repository) SetReference(name, commitID string) error {
|
func (repo *Repository) SetReference(name, commitID string) error {
|
||||||
_, _, err := NewCommand("update-ref").AddDynamicArguments(name, commitID).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
_, _, err := gitcmd.NewCommand("update-ref").AddDynamicArguments(name, commitID).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveReference removes the given reference (e.g. branch or tag).
|
// RemoveReference removes the given reference (e.g. branch or tag).
|
||||||
func (repo *Repository) RemoveReference(name string) error {
|
func (repo *Repository) RemoveReference(name string) error {
|
||||||
_, _, err := NewCommand("update-ref", "--no-deref", "-d").AddDynamicArguments(name).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
_, _, err := gitcmd.NewCommand("update-ref", "--no-deref", "-d").AddDynamicArguments(name).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +69,7 @@ func (repo *Repository) IsCommitExist(name string) bool {
|
|||||||
log.Error("IsCommitExist: %v", err)
|
log.Error("IsCommitExist: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
_, _, err := NewCommand("cat-file", "-e").AddDynamicArguments(name).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
_, _, err := gitcmd.NewCommand("cat-file", "-e").AddDynamicArguments(name).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,13 +6,15 @@ package git
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WriteCommitGraph write commit graph to speed up repo access
|
// WriteCommitGraph write commit graph to speed up repo access
|
||||||
// this requires git v2.18 to be installed
|
// this requires git v2.18 to be installed
|
||||||
func WriteCommitGraph(ctx context.Context, repoPath string) error {
|
func WriteCommitGraph(ctx context.Context, repoPath string) error {
|
||||||
if DefaultFeatures().CheckVersionAtLeast("2.18") {
|
if DefaultFeatures().CheckVersionAtLeast("2.18") {
|
||||||
if _, _, err := NewCommand("commit-graph", "write").RunStdString(ctx, &RunOpts{Dir: repoPath}); err != nil {
|
if _, _, err := gitcmd.NewCommand("commit-graph", "write").RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath}); err != nil {
|
||||||
return fmt.Errorf("unable to write commit-graph for '%s' : %w", repoPath, err)
|
return fmt.Errorf("unable to write commit-graph for '%s' : %w", repoPath, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,8 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetMergeBase checks and returns merge base of two branches and the reference used as base.
|
// GetMergeBase checks and returns merge base of two branches and the reference used as base.
|
||||||
@ -27,13 +29,13 @@ func (repo *Repository) GetMergeBase(tmpRemote, base, head string) (string, stri
|
|||||||
if tmpRemote != "origin" {
|
if tmpRemote != "origin" {
|
||||||
tmpBaseName := RemotePrefix + tmpRemote + "/tmp_" + base
|
tmpBaseName := RemotePrefix + tmpRemote + "/tmp_" + base
|
||||||
// Fetch commit into a temporary branch in order to be able to handle commits and tags
|
// Fetch commit into a temporary branch in order to be able to handle commits and tags
|
||||||
_, _, err := NewCommand("fetch", "--no-tags").AddDynamicArguments(tmpRemote).AddDashesAndList(base+":"+tmpBaseName).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
_, _, err := gitcmd.NewCommand("fetch", "--no-tags").AddDynamicArguments(tmpRemote).AddDashesAndList(base+":"+tmpBaseName).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
base = tmpBaseName
|
base = tmpBaseName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, _, err := NewCommand("merge-base").AddDashesAndList(base, head).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err := gitcmd.NewCommand("merge-base").AddDashesAndList(base, head).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
return strings.TrimSpace(stdout), base, err
|
return strings.TrimSpace(stdout), base, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,8 +63,8 @@ func (repo *Repository) GetDiffNumChangedFiles(base, head string, directComparis
|
|||||||
}
|
}
|
||||||
|
|
||||||
// avoid: ambiguous argument 'refs/a...refs/b': unknown revision or path not in the working tree. Use '--': 'git <command> [<revision>...] -- [<file>...]'
|
// avoid: ambiguous argument 'refs/a...refs/b': unknown revision or path not in the working tree. Use '--': 'git <command> [<revision>...] -- [<file>...]'
|
||||||
if err := NewCommand("diff", "-z", "--name-only").AddDynamicArguments(base+separator+head).AddArguments("--").
|
if err := gitcmd.NewCommand("diff", "-z", "--name-only").AddDynamicArguments(base+separator+head).AddArguments("--").
|
||||||
Run(repo.Ctx, &RunOpts{
|
Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: w,
|
Stdout: w,
|
||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
@ -72,7 +74,7 @@ func (repo *Repository) GetDiffNumChangedFiles(base, head string, directComparis
|
|||||||
// previously it would return the results of git diff -z --name-only base head so let's try that...
|
// previously it would return the results of git diff -z --name-only base head so let's try that...
|
||||||
w = &lineCountWriter{}
|
w = &lineCountWriter{}
|
||||||
stderr.Reset()
|
stderr.Reset()
|
||||||
if err = NewCommand("diff", "-z", "--name-only").AddDynamicArguments(base, head).AddArguments("--").Run(repo.Ctx, &RunOpts{
|
if err = gitcmd.NewCommand("diff", "-z", "--name-only").AddDynamicArguments(base, head).AddArguments("--").Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: w,
|
Stdout: w,
|
||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
@ -87,13 +89,13 @@ func (repo *Repository) GetDiffNumChangedFiles(base, head string, directComparis
|
|||||||
|
|
||||||
// GetDiffShortStatByCmdArgs counts number of changed files, number of additions and deletions
|
// GetDiffShortStatByCmdArgs counts number of changed files, number of additions and deletions
|
||||||
// TODO: it can be merged with another "GetDiffShortStat" in the future
|
// TODO: it can be merged with another "GetDiffShortStat" in the future
|
||||||
func GetDiffShortStatByCmdArgs(ctx context.Context, repoPath string, trustedArgs TrustedCmdArgs, dynamicArgs ...string) (numFiles, totalAdditions, totalDeletions int, err error) {
|
func GetDiffShortStatByCmdArgs(ctx context.Context, repoPath string, trustedArgs gitcmd.TrustedCmdArgs, dynamicArgs ...string) (numFiles, totalAdditions, totalDeletions int, err error) {
|
||||||
// Now if we call:
|
// Now if we call:
|
||||||
// $ git diff --shortstat 1ebb35b98889ff77299f24d82da426b434b0cca0...788b8b1440462d477f45b0088875
|
// $ git diff --shortstat 1ebb35b98889ff77299f24d82da426b434b0cca0...788b8b1440462d477f45b0088875
|
||||||
// we get:
|
// we get:
|
||||||
// " 9902 files changed, 2034198 insertions(+), 298800 deletions(-)\n"
|
// " 9902 files changed, 2034198 insertions(+), 298800 deletions(-)\n"
|
||||||
cmd := NewCommand("diff", "--shortstat").AddArguments(trustedArgs...).AddDynamicArguments(dynamicArgs...)
|
cmd := gitcmd.NewCommand("diff", "--shortstat").AddArguments(trustedArgs...).AddDynamicArguments(dynamicArgs...)
|
||||||
stdout, _, err := cmd.RunStdString(ctx, &RunOpts{Dir: repoPath})
|
stdout, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, 0, err
|
return 0, 0, 0, err
|
||||||
}
|
}
|
||||||
@ -139,8 +141,8 @@ func parseDiffStat(stdout string) (numFiles, totalAdditions, totalDeletions int,
|
|||||||
// GetDiff generates and returns patch data between given revisions, optimized for human readability
|
// GetDiff generates and returns patch data between given revisions, optimized for human readability
|
||||||
func (repo *Repository) GetDiff(compareArg string, w io.Writer) error {
|
func (repo *Repository) GetDiff(compareArg string, w io.Writer) error {
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
return NewCommand("diff", "-p").AddDynamicArguments(compareArg).
|
return gitcmd.NewCommand("diff", "-p").AddDynamicArguments(compareArg).
|
||||||
Run(repo.Ctx, &RunOpts{
|
Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: w,
|
Stdout: w,
|
||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
@ -149,7 +151,7 @@ func (repo *Repository) GetDiff(compareArg string, w io.Writer) error {
|
|||||||
|
|
||||||
// GetDiffBinary generates and returns patch data between given revisions, including binary diffs.
|
// GetDiffBinary generates and returns patch data between given revisions, including binary diffs.
|
||||||
func (repo *Repository) GetDiffBinary(compareArg string, w io.Writer) error {
|
func (repo *Repository) GetDiffBinary(compareArg string, w io.Writer) error {
|
||||||
return NewCommand("diff", "-p", "--binary", "--histogram").AddDynamicArguments(compareArg).Run(repo.Ctx, &RunOpts{
|
return gitcmd.NewCommand("diff", "-p", "--binary", "--histogram").AddDynamicArguments(compareArg).Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: w,
|
Stdout: w,
|
||||||
})
|
})
|
||||||
@ -158,8 +160,8 @@ func (repo *Repository) GetDiffBinary(compareArg string, w io.Writer) error {
|
|||||||
// GetPatch generates and returns format-patch data between given revisions, able to be used with `git apply`
|
// GetPatch generates and returns format-patch data between given revisions, able to be used with `git apply`
|
||||||
func (repo *Repository) GetPatch(compareArg string, w io.Writer) error {
|
func (repo *Repository) GetPatch(compareArg string, w io.Writer) error {
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
return NewCommand("format-patch", "--binary", "--stdout").AddDynamicArguments(compareArg).
|
return gitcmd.NewCommand("format-patch", "--binary", "--stdout").AddDynamicArguments(compareArg).
|
||||||
Run(repo.Ctx, &RunOpts{
|
Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: w,
|
Stdout: w,
|
||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
@ -174,13 +176,13 @@ func (repo *Repository) GetFilesChangedBetween(base, head string) ([]string, err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cmd := NewCommand("diff-tree", "--name-only", "--root", "--no-commit-id", "-r", "-z")
|
cmd := gitcmd.NewCommand("diff-tree", "--name-only", "--root", "--no-commit-id", "-r", "-z")
|
||||||
if base == objectFormat.EmptyObjectID().String() {
|
if base == objectFormat.EmptyObjectID().String() {
|
||||||
cmd.AddDynamicArguments(head)
|
cmd.AddDynamicArguments(head)
|
||||||
} else {
|
} else {
|
||||||
cmd.AddDynamicArguments(base, head)
|
cmd.AddDynamicArguments(base, head)
|
||||||
}
|
}
|
||||||
stdout, _, err := cmd.RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err := cmd.RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/process"
|
"code.gitea.io/gitea/modules/process"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ func (repo *Repository) GetDefaultPublicGPGKey(forceUpdate bool) (*GPGSettings,
|
|||||||
Sign: true,
|
Sign: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
value, _, _ := NewCommand("config", "--get", "commit.gpgsign").RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
value, _, _ := gitcmd.NewCommand("config", "--get", "commit.gpgsign").RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
sign, valid := ParseBool(strings.TrimSpace(value))
|
sign, valid := ParseBool(strings.TrimSpace(value))
|
||||||
if !sign || !valid {
|
if !sign || !valid {
|
||||||
gpgSettings.Sign = false
|
gpgSettings.Sign = false
|
||||||
@ -50,16 +51,16 @@ func (repo *Repository) GetDefaultPublicGPGKey(forceUpdate bool) (*GPGSettings,
|
|||||||
return gpgSettings, nil
|
return gpgSettings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
signingKey, _, _ := NewCommand("config", "--get", "user.signingkey").RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
signingKey, _, _ := gitcmd.NewCommand("config", "--get", "user.signingkey").RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
gpgSettings.KeyID = strings.TrimSpace(signingKey)
|
gpgSettings.KeyID = strings.TrimSpace(signingKey)
|
||||||
|
|
||||||
format, _, _ := NewCommand("config", "--default", SigningKeyFormatOpenPGP, "--get", "gpg.format").RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
format, _, _ := gitcmd.NewCommand("config", "--default", SigningKeyFormatOpenPGP, "--get", "gpg.format").RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
gpgSettings.Format = strings.TrimSpace(format)
|
gpgSettings.Format = strings.TrimSpace(format)
|
||||||
|
|
||||||
defaultEmail, _, _ := NewCommand("config", "--get", "user.email").RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
defaultEmail, _, _ := gitcmd.NewCommand("config", "--get", "user.email").RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
gpgSettings.Email = strings.TrimSpace(defaultEmail)
|
gpgSettings.Email = strings.TrimSpace(defaultEmail)
|
||||||
|
|
||||||
defaultName, _, _ := NewCommand("config", "--get", "user.name").RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
defaultName, _, _ := gitcmd.NewCommand("config", "--get", "user.name").RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
gpgSettings.Name = strings.TrimSpace(defaultName)
|
gpgSettings.Name = strings.TrimSpace(defaultName)
|
||||||
|
|
||||||
if err := gpgSettings.LoadPublicKeyContent(); err != nil {
|
if err := gpgSettings.LoadPublicKeyContent(); err != nil {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(treeish) != objectFormat.FullLength() {
|
if len(treeish) != objectFormat.FullLength() {
|
||||||
res, _, err := NewCommand("rev-parse", "--verify").AddDynamicArguments(treeish).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
res, _, err := gitcmd.NewCommand("rev-parse", "--verify").AddDynamicArguments(treeish).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -41,7 +42,7 @@ func (repo *Repository) readTreeToIndex(id ObjectID, indexFilename ...string) er
|
|||||||
if len(indexFilename) > 0 {
|
if len(indexFilename) > 0 {
|
||||||
env = append(os.Environ(), "GIT_INDEX_FILE="+indexFilename[0])
|
env = append(os.Environ(), "GIT_INDEX_FILE="+indexFilename[0])
|
||||||
}
|
}
|
||||||
_, _, err := NewCommand("read-tree").AddDynamicArguments(id.String()).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path, Env: env})
|
_, _, err := gitcmd.NewCommand("read-tree").AddDynamicArguments(id.String()).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path, Env: env})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -74,14 +75,14 @@ func (repo *Repository) ReadTreeToTemporaryIndex(treeish string) (tmpIndexFilena
|
|||||||
|
|
||||||
// EmptyIndex empties the index
|
// EmptyIndex empties the index
|
||||||
func (repo *Repository) EmptyIndex() error {
|
func (repo *Repository) EmptyIndex() error {
|
||||||
_, _, err := NewCommand("read-tree", "--empty").RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
_, _, err := gitcmd.NewCommand("read-tree", "--empty").RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// LsFiles checks if the given filenames are in the index
|
// LsFiles checks if the given filenames are in the index
|
||||||
func (repo *Repository) LsFiles(filenames ...string) ([]string, error) {
|
func (repo *Repository) LsFiles(filenames ...string) ([]string, error) {
|
||||||
cmd := NewCommand("ls-files", "-z").AddDashesAndList(filenames...)
|
cmd := gitcmd.NewCommand("ls-files", "-z").AddDashesAndList(filenames...)
|
||||||
res, _, err := cmd.RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
res, _, err := cmd.RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -99,7 +100,7 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cmd := NewCommand("update-index", "--remove", "-z", "--index-info")
|
cmd := gitcmd.NewCommand("update-index", "--remove", "-z", "--index-info")
|
||||||
stdout := new(bytes.Buffer)
|
stdout := new(bytes.Buffer)
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
buffer := new(bytes.Buffer)
|
buffer := new(bytes.Buffer)
|
||||||
@ -109,7 +110,7 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error {
|
|||||||
buffer.WriteString("0 blob " + objectFormat.EmptyObjectID().String() + "\t" + file + "\000")
|
buffer.WriteString("0 blob " + objectFormat.EmptyObjectID().String() + "\t" + file + "\000")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cmd.Run(repo.Ctx, &RunOpts{
|
return cmd.Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdin: bytes.NewReader(buffer.Bytes()),
|
Stdin: bytes.NewReader(buffer.Bytes()),
|
||||||
Stdout: stdout,
|
Stdout: stdout,
|
||||||
@ -125,7 +126,7 @@ type IndexObjectInfo struct {
|
|||||||
|
|
||||||
// AddObjectsToIndex adds the provided object hashes to the index at the provided filenames
|
// AddObjectsToIndex adds the provided object hashes to the index at the provided filenames
|
||||||
func (repo *Repository) AddObjectsToIndex(objects ...IndexObjectInfo) error {
|
func (repo *Repository) AddObjectsToIndex(objects ...IndexObjectInfo) error {
|
||||||
cmd := NewCommand("update-index", "--add", "--replace", "-z", "--index-info")
|
cmd := gitcmd.NewCommand("update-index", "--add", "--replace", "-z", "--index-info")
|
||||||
stdout := new(bytes.Buffer)
|
stdout := new(bytes.Buffer)
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
buffer := new(bytes.Buffer)
|
buffer := new(bytes.Buffer)
|
||||||
@ -133,7 +134,7 @@ func (repo *Repository) AddObjectsToIndex(objects ...IndexObjectInfo) error {
|
|||||||
// using format: mode SP type SP sha1 TAB path
|
// using format: mode SP type SP sha1 TAB path
|
||||||
buffer.WriteString(object.Mode + " blob " + object.Object.String() + "\t" + object.Filename + "\000")
|
buffer.WriteString(object.Mode + " blob " + object.Object.String() + "\t" + object.Filename + "\000")
|
||||||
}
|
}
|
||||||
return cmd.Run(repo.Ctx, &RunOpts{
|
return cmd.Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdin: bytes.NewReader(buffer.Bytes()),
|
Stdin: bytes.NewReader(buffer.Bytes()),
|
||||||
Stdout: stdout,
|
Stdout: stdout,
|
||||||
@ -148,7 +149,7 @@ func (repo *Repository) AddObjectToIndex(mode string, object ObjectID, filename
|
|||||||
|
|
||||||
// WriteTree writes the current index as a tree to the object db and returns its hash
|
// WriteTree writes the current index as a tree to the object db and returns its hash
|
||||||
func (repo *Repository) WriteTree() (*Tree, error) {
|
func (repo *Repository) WriteTree() (*Tree, error) {
|
||||||
stdout, _, runErr := NewCommand("write-tree").RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, runErr := gitcmd.NewCommand("write-tree").RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
return nil, runErr
|
return nil, runErr
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ObjectType git object type
|
// ObjectType git object type
|
||||||
@ -66,15 +68,15 @@ func (repo *Repository) HashObject(reader io.Reader) (ObjectID, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) hashObject(reader io.Reader, save bool) (string, error) {
|
func (repo *Repository) hashObject(reader io.Reader, save bool) (string, error) {
|
||||||
var cmd *Command
|
var cmd *gitcmd.Command
|
||||||
if save {
|
if save {
|
||||||
cmd = NewCommand("hash-object", "-w", "--stdin")
|
cmd = gitcmd.NewCommand("hash-object", "-w", "--stdin")
|
||||||
} else {
|
} else {
|
||||||
cmd = NewCommand("hash-object", "--stdin")
|
cmd = gitcmd.NewCommand("hash-object", "--stdin")
|
||||||
}
|
}
|
||||||
stdout := new(bytes.Buffer)
|
stdout := new(bytes.Buffer)
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
err := cmd.Run(repo.Ctx, &RunOpts{
|
err := cmd.Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdin: reader,
|
Stdin: reader,
|
||||||
Stdout: stdout,
|
Stdout: stdout,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ func (repo *Repository) GetRefs() ([]*Reference, error) {
|
|||||||
// ListOccurrences lists all refs of the given refType the given commit appears in sorted by creation date DESC
|
// ListOccurrences lists all refs of the given refType the given commit appears in sorted by creation date DESC
|
||||||
// refType should only be a literal "branch" or "tag" and nothing else
|
// refType should only be a literal "branch" or "tag" and nothing else
|
||||||
func (repo *Repository) ListOccurrences(ctx context.Context, refType, commitSHA string) ([]string, error) {
|
func (repo *Repository) ListOccurrences(ctx context.Context, refType, commitSHA string) ([]string, error) {
|
||||||
cmd := NewCommand()
|
cmd := gitcmd.NewCommand()
|
||||||
switch refType {
|
switch refType {
|
||||||
case "branch":
|
case "branch":
|
||||||
cmd.AddArguments("branch")
|
cmd.AddArguments("branch")
|
||||||
@ -27,7 +28,7 @@ func (repo *Repository) ListOccurrences(ctx context.Context, refType, commitSHA
|
|||||||
default:
|
default:
|
||||||
return nil, util.NewInvalidArgumentErrorf(`can only use "branch" or "tag" for refType, but got %q`, refType)
|
return nil, util.NewInvalidArgumentErrorf(`can only use "branch" or "tag" for refType, but got %q`, refType)
|
||||||
}
|
}
|
||||||
stdout, _, err := cmd.AddArguments("--no-color", "--sort=-creatordate", "--contains").AddDynamicArguments(commitSHA).RunStdString(ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err := cmd.AddArguments("--no-color", "--sort=-creatordate", "--contains").AddDynamicArguments(commitSHA).RunStdString(ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,8 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetRefsFiltered returns all references of the repository that matches patterm exactly or starting with.
|
// GetRefsFiltered returns all references of the repository that matches patterm exactly or starting with.
|
||||||
@ -21,13 +23,13 @@ func (repo *Repository) GetRefsFiltered(pattern string) ([]*Reference, error) {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
stderrBuilder := &strings.Builder{}
|
stderrBuilder := &strings.Builder{}
|
||||||
err := NewCommand("for-each-ref").Run(repo.Ctx, &RunOpts{
|
err := gitcmd.NewCommand("for-each-ref").Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: stdoutWriter,
|
Stdout: stdoutWriter,
|
||||||
Stderr: stderrBuilder,
|
Stderr: stderrBuilder,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String()))
|
_ = stdoutWriter.CloseWithError(gitcmd.ConcatenateError(err, stderrBuilder.String()))
|
||||||
} else {
|
} else {
|
||||||
_ = stdoutWriter.Close()
|
_ = stdoutWriter.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CodeActivityStats represents git statistics data
|
// CodeActivityStats represents git statistics data
|
||||||
@ -40,9 +41,9 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
|
|||||||
|
|
||||||
since := fromTime.Format(time.RFC3339)
|
since := fromTime.Format(time.RFC3339)
|
||||||
|
|
||||||
stdout, _, runErr := NewCommand("rev-list", "--count", "--no-merges", "--branches=*", "--date=iso").
|
stdout, _, runErr := gitcmd.NewCommand("rev-list", "--count", "--no-merges", "--branches=*", "--date=iso").
|
||||||
AddOptionFormat("--since=%s", since).
|
AddOptionFormat("--since=%s", since).
|
||||||
RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
return nil, runErr
|
return nil, runErr
|
||||||
}
|
}
|
||||||
@ -62,7 +63,7 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
|
|||||||
_ = stdoutWriter.Close()
|
_ = stdoutWriter.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
gitCmd := NewCommand("log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso").
|
gitCmd := gitcmd.NewCommand("log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso").
|
||||||
AddOptionFormat("--since=%s", since)
|
AddOptionFormat("--since=%s", since)
|
||||||
if len(branch) == 0 {
|
if len(branch) == 0 {
|
||||||
gitCmd.AddArguments("--branches=*")
|
gitCmd.AddArguments("--branches=*")
|
||||||
@ -71,7 +72,7 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
stderr := new(strings.Builder)
|
stderr := new(strings.Builder)
|
||||||
err = gitCmd.Run(repo.Ctx, &RunOpts{
|
err = gitCmd.Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Env: []string{},
|
Env: []string{},
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: stdoutWriter,
|
Stdout: stdoutWriter,
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git/foreachref"
|
"code.gitea.io/gitea/modules/git/foreachref"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,13 +19,13 @@ const TagPrefix = "refs/tags/"
|
|||||||
|
|
||||||
// CreateTag create one tag in the repository
|
// CreateTag create one tag in the repository
|
||||||
func (repo *Repository) CreateTag(name, revision string) error {
|
func (repo *Repository) CreateTag(name, revision string) error {
|
||||||
_, _, err := NewCommand("tag").AddDashesAndList(name, revision).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
_, _, err := gitcmd.NewCommand("tag").AddDashesAndList(name, revision).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateAnnotatedTag create one annotated tag in the repository
|
// CreateAnnotatedTag create one annotated tag in the repository
|
||||||
func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error {
|
func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error {
|
||||||
_, _, err := NewCommand("tag", "-a", "-m").AddDynamicArguments(message).AddDashesAndList(name, revision).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
_, _, err := gitcmd.NewCommand("tag", "-a", "-m").AddDynamicArguments(message).AddDashesAndList(name, revision).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
|
|||||||
return "", fmt.Errorf("SHA is too short: %s", sha)
|
return "", fmt.Errorf("SHA is too short: %s", sha)
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, _, err := NewCommand("show-ref", "--tags", "-d").RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err := gitcmd.NewCommand("show-ref", "--tags", "-d").RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -57,7 +58,7 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
|
|||||||
|
|
||||||
// GetTagID returns the object ID for a tag (annotated tags have both an object SHA AND a commit SHA)
|
// GetTagID returns the object ID for a tag (annotated tags have both an object SHA AND a commit SHA)
|
||||||
func (repo *Repository) GetTagID(name string) (string, error) {
|
func (repo *Repository) GetTagID(name string) (string, error) {
|
||||||
stdout, _, err := NewCommand("show-ref", "--tags").AddDashesAndList(name).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
stdout, _, err := gitcmd.NewCommand("show-ref", "--tags").AddDashesAndList(name).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -114,14 +115,14 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
|
|||||||
defer stdoutReader.Close()
|
defer stdoutReader.Close()
|
||||||
defer stdoutWriter.Close()
|
defer stdoutWriter.Close()
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
rc := &RunOpts{Dir: repo.Path, Stdout: stdoutWriter, Stderr: &stderr}
|
rc := &gitcmd.RunOpts{Dir: repo.Path, Stdout: stdoutWriter, Stderr: &stderr}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err := NewCommand("for-each-ref").
|
err := gitcmd.NewCommand("for-each-ref").
|
||||||
AddOptionFormat("--format=%s", forEachRefFmt.Flag()).
|
AddOptionFormat("--format=%s", forEachRefFmt.Flag()).
|
||||||
AddArguments("--sort", "-*creatordate", "refs/tags").Run(repo.Ctx, rc)
|
AddArguments("--sort", "-*creatordate", "refs/tags").Run(repo.Ctx, rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = stdoutWriter.CloseWithError(ConcatenateError(err, stderr.String()))
|
_ = stdoutWriter.CloseWithError(gitcmd.ConcatenateError(err, stderr.String()))
|
||||||
} else {
|
} else {
|
||||||
_ = stdoutWriter.Close()
|
_ = stdoutWriter.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommitTreeOpts represents the possible options to CommitTree
|
// CommitTreeOpts represents the possible options to CommitTree
|
||||||
@ -33,7 +35,7 @@ func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opt
|
|||||||
"GIT_COMMITTER_EMAIL="+committer.Email,
|
"GIT_COMMITTER_EMAIL="+committer.Email,
|
||||||
"GIT_COMMITTER_DATE="+commitTimeStr,
|
"GIT_COMMITTER_DATE="+commitTimeStr,
|
||||||
)
|
)
|
||||||
cmd := NewCommand("commit-tree").AddDynamicArguments(tree.ID.String())
|
cmd := gitcmd.NewCommand("commit-tree").AddDynamicArguments(tree.ID.String())
|
||||||
|
|
||||||
for _, parent := range opts.Parents {
|
for _, parent := range opts.Parents {
|
||||||
cmd.AddArguments("-p").AddDynamicArguments(parent)
|
cmd.AddArguments("-p").AddDynamicArguments(parent)
|
||||||
@ -58,7 +60,7 @@ func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opt
|
|||||||
|
|
||||||
stdout := new(bytes.Buffer)
|
stdout := new(bytes.Buffer)
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
err := cmd.Run(repo.Ctx, &RunOpts{
|
err := cmd.Run(repo.Ctx, &gitcmd.RunOpts{
|
||||||
Env: env,
|
Env: env,
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdin: messageBytes,
|
Stdin: messageBytes,
|
||||||
@ -66,7 +68,7 @@ func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opt
|
|||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ConcatenateError(err, stderr.String())
|
return nil, gitcmd.ConcatenateError(err, stderr.String())
|
||||||
}
|
}
|
||||||
return NewIDFromString(strings.TrimSpace(stdout.String()))
|
return NewIDFromString(strings.TrimSpace(stdout.String()))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,8 @@ package git
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
|
|
||||||
"github.com/go-git/go-git/v5/plumbing"
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,7 +38,7 @@ func (repo *Repository) GetTree(idStr string) (*Tree, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(idStr) != objectFormat.FullLength() {
|
if len(idStr) != objectFormat.FullLength() {
|
||||||
res, _, err := NewCommand("rev-parse", "--verify").AddDynamicArguments(idStr).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
res, _, err := gitcmd.NewCommand("rev-parse", "--verify").AddDynamicArguments(idStr).RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,7 +25,7 @@ func GetTemplateSubmoduleCommits(ctx context.Context, repoPath string) (submodul
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
opts := &RunOpts{
|
opts := &gitcmd.RunOpts{
|
||||||
Dir: repoPath,
|
Dir: repoPath,
|
||||||
Stdout: stdoutWriter,
|
Stdout: stdoutWriter,
|
||||||
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
|
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
|
||||||
@ -45,7 +46,7 @@ func GetTemplateSubmoduleCommits(ctx context.Context, repoPath string) (submodul
|
|||||||
return scanner.Err()
|
return scanner.Err()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err = NewCommand("ls-tree", "-r", "--", "HEAD").Run(ctx, opts)
|
err = gitcmd.NewCommand("ls-tree", "-r", "--", "HEAD").Run(ctx, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("GetTemplateSubmoduleCommits: error running git ls-tree: %v", err)
|
return nil, fmt.Errorf("GetTemplateSubmoduleCommits: error running git ls-tree: %v", err)
|
||||||
}
|
}
|
||||||
@ -56,8 +57,8 @@ func GetTemplateSubmoduleCommits(ctx context.Context, repoPath string) (submodul
|
|||||||
// It is only for generating new repos based on existing template, requires the .gitmodules file to be already present in the work dir.
|
// It is only for generating new repos based on existing template, requires the .gitmodules file to be already present in the work dir.
|
||||||
func AddTemplateSubmoduleIndexes(ctx context.Context, repoPath string, submodules []TemplateSubmoduleCommit) error {
|
func AddTemplateSubmoduleIndexes(ctx context.Context, repoPath string, submodules []TemplateSubmoduleCommit) error {
|
||||||
for _, submodule := range submodules {
|
for _, submodule := range submodules {
|
||||||
cmd := NewCommand("update-index", "--add", "--cacheinfo", "160000").AddDynamicArguments(submodule.Commit, submodule.Path)
|
cmd := gitcmd.NewCommand("update-index", "--add", "--cacheinfo", "160000").AddDynamicArguments(submodule.Commit, submodule.Path)
|
||||||
if stdout, _, err := cmd.RunStdString(ctx, &RunOpts{Dir: repoPath}); err != nil {
|
if stdout, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath}); err != nil {
|
||||||
log.Error("Unable to add %s as submodule to repo %s: stdout %s\nError: %v", submodule.Path, repoPath, stdout, err)
|
log.Error("Unable to add %s as submodule to repo %s: stdout %s\nError: %v", submodule.Path, repoPath, stdout, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@ -30,14 +32,14 @@ func TestAddTemplateSubmoduleIndexes(t *testing.T) {
|
|||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
var err error
|
var err error
|
||||||
_, _, err = NewCommand("init").RunStdString(ctx, &RunOpts{Dir: tmpDir})
|
_, _, err = gitcmd.NewCommand("init").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmpDir})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_ = os.Mkdir(filepath.Join(tmpDir, "new-dir"), 0o755)
|
_ = os.Mkdir(filepath.Join(tmpDir, "new-dir"), 0o755)
|
||||||
err = AddTemplateSubmoduleIndexes(ctx, tmpDir, []TemplateSubmoduleCommit{{Path: "new-dir", Commit: "1234567890123456789012345678901234567890"}})
|
err = AddTemplateSubmoduleIndexes(ctx, tmpDir, []TemplateSubmoduleCommit{{Path: "new-dir", Commit: "1234567890123456789012345678901234567890"}})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_, _, err = NewCommand("add", "--all").RunStdString(ctx, &RunOpts{Dir: tmpDir})
|
_, _, err = gitcmd.NewCommand("add", "--all").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmpDir})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_, _, err = NewCommand("-c", "user.name=a", "-c", "user.email=b", "commit", "-m=test").RunStdString(ctx, &RunOpts{Dir: tmpDir})
|
_, _, err = gitcmd.NewCommand("-c", "user.name=a", "-c", "user.email=b", "commit", "-m=test").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmpDir})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
submodules, err := GetTemplateSubmoduleCommits(t.Context(), tmpDir)
|
submodules, err := GetTemplateSubmoduleCommits(t.Context(), tmpDir)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|||||||
@ -7,6 +7,8 @@ package git
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewTree create a new tree according the repository and tree id
|
// NewTree create a new tree according the repository and tree id
|
||||||
@ -48,10 +50,10 @@ func (t *Tree) SubTree(rpath string) (*Tree, error) {
|
|||||||
|
|
||||||
// LsTree checks if the given filenames are in the tree
|
// LsTree checks if the given filenames are in the tree
|
||||||
func (repo *Repository) LsTree(ref string, filenames ...string) ([]string, error) {
|
func (repo *Repository) LsTree(ref string, filenames ...string) ([]string, error) {
|
||||||
cmd := NewCommand("ls-tree", "-z", "--name-only").
|
cmd := gitcmd.NewCommand("ls-tree", "-z", "--name-only").
|
||||||
AddDashesAndList(append([]string{ref}, filenames...)...)
|
AddDashesAndList(append([]string{ref}, filenames...)...)
|
||||||
|
|
||||||
res, _, err := cmd.RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path})
|
res, _, err := cmd.RunStdBytes(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -65,9 +67,9 @@ func (repo *Repository) LsTree(ref string, filenames ...string) ([]string, error
|
|||||||
|
|
||||||
// GetTreePathLatestCommit returns the latest commit of a tree path
|
// GetTreePathLatestCommit returns the latest commit of a tree path
|
||||||
func (repo *Repository) GetTreePathLatestCommit(refName, treePath string) (*Commit, error) {
|
func (repo *Repository) GetTreePathLatestCommit(refName, treePath string) (*Commit, error) {
|
||||||
stdout, _, err := NewCommand("rev-list", "-1").
|
stdout, _, err := gitcmd.NewCommand("rev-list", "-1").
|
||||||
AddDynamicArguments(refName).AddDashesAndList(treePath).
|
AddDynamicArguments(refName).AddDashesAndList(treePath).
|
||||||
RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
|
RunStdString(repo.Ctx, &gitcmd.RunOpts{Dir: repo.Path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,8 @@ package git
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tree represents a flat directory listing.
|
// Tree represents a flat directory listing.
|
||||||
@ -70,7 +72,7 @@ func (t *Tree) ListEntries() (Entries, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, _, runErr := NewCommand("ls-tree", "-l").AddDynamicArguments(t.ID.String()).RunStdBytes(t.repo.Ctx, &RunOpts{Dir: t.repo.Path})
|
stdout, _, runErr := gitcmd.NewCommand("ls-tree", "-l").AddDynamicArguments(t.ID.String()).RunStdBytes(t.repo.Ctx, &gitcmd.RunOpts{Dir: t.repo.Path})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
if strings.Contains(runErr.Error(), "fatal: Not a valid object name") || strings.Contains(runErr.Error(), "fatal: not a tree object") {
|
if strings.Contains(runErr.Error(), "fatal: Not a valid object name") || strings.Contains(runErr.Error(), "fatal: not a tree object") {
|
||||||
return nil, ErrNotExist{
|
return nil, ErrNotExist{
|
||||||
@ -91,15 +93,15 @@ func (t *Tree) ListEntries() (Entries, error) {
|
|||||||
|
|
||||||
// listEntriesRecursive returns all entries of current tree recursively including all subtrees
|
// listEntriesRecursive returns all entries of current tree recursively including all subtrees
|
||||||
// extraArgs could be "-l" to get the size, which is slower
|
// extraArgs could be "-l" to get the size, which is slower
|
||||||
func (t *Tree) listEntriesRecursive(extraArgs TrustedCmdArgs) (Entries, error) {
|
func (t *Tree) listEntriesRecursive(extraArgs gitcmd.TrustedCmdArgs) (Entries, error) {
|
||||||
if t.entriesRecursiveParsed {
|
if t.entriesRecursiveParsed {
|
||||||
return t.entriesRecursive, nil
|
return t.entriesRecursive, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, _, runErr := NewCommand("ls-tree", "-t", "-r").
|
stdout, _, runErr := gitcmd.NewCommand("ls-tree", "-t", "-r").
|
||||||
AddArguments(extraArgs...).
|
AddArguments(extraArgs...).
|
||||||
AddDynamicArguments(t.ID.String()).
|
AddDynamicArguments(t.ID.String()).
|
||||||
RunStdBytes(t.repo.Ctx, &RunOpts{Dir: t.repo.Path})
|
RunStdBytes(t.repo.Ctx, &gitcmd.RunOpts{Dir: t.repo.Path})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
return nil, runErr
|
return nil, runErr
|
||||||
}
|
}
|
||||||
@ -120,5 +122,5 @@ func (t *Tree) ListEntriesRecursiveFast() (Entries, error) {
|
|||||||
|
|
||||||
// ListEntriesRecursiveWithSize returns all entries of current tree recursively including all subtrees, with size
|
// ListEntriesRecursiveWithSize returns all entries of current tree recursively including all subtrees, with size
|
||||||
func (t *Tree) ListEntriesRecursiveWithSize() (Entries, error) {
|
func (t *Tree) ListEntriesRecursiveWithSize() (Entries, error) {
|
||||||
return t.listEntriesRecursive(TrustedCmdArgs{"--long"})
|
return t.listEntriesRecursive(gitcmd.TrustedCmdArgs{"--long"})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,6 @@ package git
|
|||||||
import (
|
import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -42,14 +41,6 @@ func (oc *ObjectCache[T]) Get(id string) (T, bool) {
|
|||||||
return obj, has
|
return obj, has
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcatenateError concatenats an error with stderr string
|
|
||||||
func ConcatenateError(err error, stderr string) error {
|
|
||||||
if len(stderr) == 0 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return fmt.Errorf("%w - %s", err, stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseBool returns the boolean value represented by the string as per git's git_config_bool
|
// ParseBool returns the boolean value represented by the string as per git's git_config_bool
|
||||||
// true will be returned for the result if the string is empty, but valid will be false.
|
// true will be returned for the result if the string is empty, but valid will be false.
|
||||||
// "true", "yes", "on" are all true, true
|
// "true", "yes", "on" are all true, true
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetBranchesByPath returns a branch by its path
|
// GetBranchesByPath returns a branch by its path
|
||||||
@ -33,9 +34,9 @@ func GetBranchCommitID(ctx context.Context, repo Repository, branch string) (str
|
|||||||
|
|
||||||
// SetDefaultBranch sets default branch of repository.
|
// SetDefaultBranch sets default branch of repository.
|
||||||
func SetDefaultBranch(ctx context.Context, repo Repository, name string) error {
|
func SetDefaultBranch(ctx context.Context, repo Repository, name string) error {
|
||||||
_, _, err := git.NewCommand("symbolic-ref", "HEAD").
|
_, _, err := gitcmd.NewCommand("symbolic-ref", "HEAD").
|
||||||
AddDynamicArguments(git.BranchPrefix+name).
|
AddDynamicArguments(git.BranchPrefix+name).
|
||||||
RunStdString(ctx, &git.RunOpts{Dir: repoPath(repo)})
|
RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,14 +7,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/globallock"
|
"code.gitea.io/gitea/modules/globallock"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GitConfigGet(ctx context.Context, repo Repository, key string) (string, error) {
|
func GitConfigGet(ctx context.Context, repo Repository, key string) (string, error) {
|
||||||
result, _, err := git.NewCommand("config", "--get").
|
result, _, err := gitcmd.NewCommand("config", "--get").
|
||||||
AddDynamicArguments(key).
|
AddDynamicArguments(key).
|
||||||
RunStdString(ctx, &git.RunOpts{Dir: repoPath(repo)})
|
RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -28,9 +28,9 @@ func getRepoConfigLockKey(repoStoragePath string) string {
|
|||||||
// GitConfigAdd add a git configuration key to a specific value for the given repository.
|
// GitConfigAdd add a git configuration key to a specific value for the given repository.
|
||||||
func GitConfigAdd(ctx context.Context, repo Repository, key, value string) error {
|
func GitConfigAdd(ctx context.Context, repo Repository, key, value string) error {
|
||||||
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
|
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
|
||||||
_, _, err := git.NewCommand("config", "--add").
|
_, _, err := gitcmd.NewCommand("config", "--add").
|
||||||
AddDynamicArguments(key, value).
|
AddDynamicArguments(key, value).
|
||||||
RunStdString(ctx, &git.RunOpts{Dir: repoPath(repo)})
|
RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)})
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -40,9 +40,9 @@ func GitConfigAdd(ctx context.Context, repo Repository, key, value string) error
|
|||||||
// If the key exists, it will be updated to the new value.
|
// If the key exists, it will be updated to the new value.
|
||||||
func GitConfigSet(ctx context.Context, repo Repository, key, value string) error {
|
func GitConfigSet(ctx context.Context, repo Repository, key, value string) error {
|
||||||
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
|
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
|
||||||
_, _, err := git.NewCommand("config").
|
_, _, err := gitcmd.NewCommand("config").
|
||||||
AddDynamicArguments(key, value).
|
AddDynamicArguments(key, value).
|
||||||
RunStdString(ctx, &git.RunOpts{Dir: repoPath(repo)})
|
RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)})
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,10 +7,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fsck verifies the connectivity and validity of the objects in the database
|
// Fsck verifies the connectivity and validity of the objects in the database
|
||||||
func Fsck(ctx context.Context, repo Repository, timeout time.Duration, args git.TrustedCmdArgs) error {
|
func Fsck(ctx context.Context, repo Repository, timeout time.Duration, args gitcmd.TrustedCmdArgs) error {
|
||||||
return git.NewCommand("fsck").AddArguments(args...).Run(ctx, &git.RunOpts{Timeout: timeout, Dir: repoPath(repo)})
|
return gitcmd.NewCommand("fsck").AddArguments(args...).Run(ctx, &gitcmd.RunOpts{Timeout: timeout, Dir: repoPath(repo)})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
giturl "code.gitea.io/gitea/modules/git/url"
|
giturl "code.gitea.io/gitea/modules/git/url"
|
||||||
"code.gitea.io/gitea/modules/globallock"
|
"code.gitea.io/gitea/modules/globallock"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
@ -24,7 +25,7 @@ const (
|
|||||||
|
|
||||||
func GitRemoteAdd(ctx context.Context, repo Repository, remoteName, remoteURL string, options ...RemoteOption) error {
|
func GitRemoteAdd(ctx context.Context, repo Repository, remoteName, remoteURL string, options ...RemoteOption) error {
|
||||||
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
|
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
|
||||||
cmd := git.NewCommand("remote", "add")
|
cmd := gitcmd.NewCommand("remote", "add")
|
||||||
if len(options) > 0 {
|
if len(options) > 0 {
|
||||||
switch options[0] {
|
switch options[0] {
|
||||||
case RemoteOptionMirrorPush:
|
case RemoteOptionMirrorPush:
|
||||||
@ -37,15 +38,15 @@ func GitRemoteAdd(ctx context.Context, repo Repository, remoteName, remoteURL st
|
|||||||
}
|
}
|
||||||
_, _, err := cmd.
|
_, _, err := cmd.
|
||||||
AddDynamicArguments(remoteName, remoteURL).
|
AddDynamicArguments(remoteName, remoteURL).
|
||||||
RunStdString(ctx, &git.RunOpts{Dir: repoPath(repo)})
|
RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)})
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GitRemoteRemove(ctx context.Context, repo Repository, remoteName string) error {
|
func GitRemoteRemove(ctx context.Context, repo Repository, remoteName string) error {
|
||||||
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
|
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
|
||||||
cmd := git.NewCommand("remote", "rm").AddDynamicArguments(remoteName)
|
cmd := gitcmd.NewCommand("remote", "rm").AddDynamicArguments(remoteName)
|
||||||
_, _, err := cmd.RunStdString(ctx, &git.RunOpts{Dir: repoPath(repo)})
|
_, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)})
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -64,8 +65,8 @@ func GitRemoteGetURL(ctx context.Context, repo Repository, remoteName string) (*
|
|||||||
|
|
||||||
// GitRemotePrune prunes the remote branches that no longer exist in the remote repository.
|
// GitRemotePrune prunes the remote branches that no longer exist in the remote repository.
|
||||||
func GitRemotePrune(ctx context.Context, repo Repository, remoteName string, timeout time.Duration, stdout, stderr io.Writer) error {
|
func GitRemotePrune(ctx context.Context, repo Repository, remoteName string, timeout time.Duration, stdout, stderr io.Writer) error {
|
||||||
return git.NewCommand("remote", "prune").AddDynamicArguments(remoteName).
|
return gitcmd.NewCommand("remote", "prune").AddDynamicArguments(remoteName).
|
||||||
Run(ctx, &git.RunOpts{
|
Run(ctx, &gitcmd.RunOpts{
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
Dir: repoPath(repo),
|
Dir: repoPath(repo),
|
||||||
Stdout: stdout,
|
Stdout: stdout,
|
||||||
@ -75,8 +76,8 @@ func GitRemotePrune(ctx context.Context, repo Repository, remoteName string, tim
|
|||||||
|
|
||||||
// GitRemoteUpdatePrune updates the remote branches and prunes the ones that no longer exist in the remote repository.
|
// GitRemoteUpdatePrune updates the remote branches and prunes the ones that no longer exist in the remote repository.
|
||||||
func GitRemoteUpdatePrune(ctx context.Context, repo Repository, remoteName string, timeout time.Duration, stdout, stderr io.Writer) error {
|
func GitRemoteUpdatePrune(ctx context.Context, repo Repository, remoteName string, timeout time.Duration, stdout, stderr io.Writer) error {
|
||||||
return git.NewCommand("remote", "update", "--prune").AddDynamicArguments(remoteName).
|
return gitcmd.NewCommand("remote", "update", "--prune").AddDynamicArguments(remoteName).
|
||||||
Run(ctx, &git.RunOpts{
|
Run(ctx, &gitcmd.RunOpts{
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
Dir: repoPath(repo),
|
Dir: repoPath(repo),
|
||||||
Stdout: stdout,
|
Stdout: stdout,
|
||||||
|
|||||||
184
modules/glob/glob.go
Normal file
184
modules/glob/glob.go
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package glob
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference: https://github.com/gobwas/glob/blob/master/glob.go
|
||||||
|
|
||||||
|
type Glob interface {
|
||||||
|
Match(string) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type globCompiler struct {
|
||||||
|
nonSeparatorChars string
|
||||||
|
globPattern []rune
|
||||||
|
regexpPattern string
|
||||||
|
regexp *regexp.Regexp
|
||||||
|
pos int
|
||||||
|
}
|
||||||
|
|
||||||
|
// compileChars compiles character class patterns like [abc] or [!abc]
|
||||||
|
func (g *globCompiler) compileChars() (string, error) {
|
||||||
|
result := ""
|
||||||
|
if g.pos < len(g.globPattern) && g.globPattern[g.pos] == '!' {
|
||||||
|
g.pos++
|
||||||
|
result += "^"
|
||||||
|
}
|
||||||
|
|
||||||
|
for g.pos < len(g.globPattern) {
|
||||||
|
c := g.globPattern[g.pos]
|
||||||
|
g.pos++
|
||||||
|
|
||||||
|
if c == ']' {
|
||||||
|
return "[" + result + "]", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c == '\\' {
|
||||||
|
if g.pos >= len(g.globPattern) {
|
||||||
|
return "", errors.New("unterminated character class escape")
|
||||||
|
}
|
||||||
|
result += "\\" + string(g.globPattern[g.pos])
|
||||||
|
g.pos++
|
||||||
|
} else {
|
||||||
|
result += string(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("unterminated character class")
|
||||||
|
}
|
||||||
|
|
||||||
|
// compile compiles the glob pattern into a regular expression
|
||||||
|
func (g *globCompiler) compile(subPattern bool) (string, error) {
|
||||||
|
result := ""
|
||||||
|
|
||||||
|
for g.pos < len(g.globPattern) {
|
||||||
|
c := g.globPattern[g.pos]
|
||||||
|
g.pos++
|
||||||
|
|
||||||
|
if subPattern && c == '}' {
|
||||||
|
return "(" + result + ")", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch c {
|
||||||
|
case '*':
|
||||||
|
if g.pos < len(g.globPattern) && g.globPattern[g.pos] == '*' {
|
||||||
|
g.pos++
|
||||||
|
result += ".*" // match any sequence of characters
|
||||||
|
} else {
|
||||||
|
result += g.nonSeparatorChars + "*" // match any sequence of non-separator characters
|
||||||
|
}
|
||||||
|
case '?':
|
||||||
|
result += g.nonSeparatorChars // match any single non-separator character
|
||||||
|
case '[':
|
||||||
|
chars, err := g.compileChars()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
result += chars
|
||||||
|
case '{':
|
||||||
|
subResult, err := g.compile(true)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
result += subResult
|
||||||
|
case ',':
|
||||||
|
if subPattern {
|
||||||
|
result += "|"
|
||||||
|
} else {
|
||||||
|
result += ","
|
||||||
|
}
|
||||||
|
case '\\':
|
||||||
|
if g.pos >= len(g.globPattern) {
|
||||||
|
return "", errors.New("no character to escape")
|
||||||
|
}
|
||||||
|
result += "\\" + string(g.globPattern[g.pos])
|
||||||
|
g.pos++
|
||||||
|
case '.', '+', '^', '$', '(', ')', '|':
|
||||||
|
result += "\\" + string(c) // escape regexp special characters
|
||||||
|
default:
|
||||||
|
result += string(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGlobCompiler(pattern string, separators ...rune) (Glob, error) {
|
||||||
|
g := &globCompiler{globPattern: []rune(pattern)}
|
||||||
|
|
||||||
|
// Escape separators for use in character class
|
||||||
|
escapedSeparators := regexp.QuoteMeta(string(separators))
|
||||||
|
if escapedSeparators != "" {
|
||||||
|
g.nonSeparatorChars = "[^" + escapedSeparators + "]"
|
||||||
|
} else {
|
||||||
|
g.nonSeparatorChars = "."
|
||||||
|
}
|
||||||
|
|
||||||
|
compiled, err := g.compile(false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
g.regexpPattern = "^" + compiled + "$"
|
||||||
|
|
||||||
|
regex, err := regexp.Compile(g.regexpPattern)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to compile regexp: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
g.regexp = regex
|
||||||
|
return g, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *globCompiler) Match(s string) bool {
|
||||||
|
return g.regexp.MatchString(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Compile(pattern string, separators ...rune) (Glob, error) {
|
||||||
|
return newGlobCompiler(pattern, separators...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustCompile(pattern string, separators ...rune) Glob {
|
||||||
|
g, err := Compile(pattern, separators...)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsSpecialByte(c byte) bool {
|
||||||
|
return c == '*' || c == '?' || c == '\\' || c == '[' || c == ']' || c == '{' || c == '}'
|
||||||
|
}
|
||||||
|
|
||||||
|
// QuoteMeta returns a string that quotes all glob pattern meta characters
|
||||||
|
// inside the argument text; For example, QuoteMeta(`{foo*}`) returns `\[foo\*\]`.
|
||||||
|
// Reference: https://github.com/gobwas/glob/blob/master/glob.go
|
||||||
|
func QuoteMeta(s string) string {
|
||||||
|
pos := 0
|
||||||
|
for pos < len(s) && !IsSpecialByte(s[pos]) {
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
if pos == len(s) {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
b := make([]byte, pos+2*(len(s)-pos))
|
||||||
|
copy(b, s[0:pos])
|
||||||
|
to := pos
|
||||||
|
for ; pos < len(s); pos++ {
|
||||||
|
if IsSpecialByte(s[pos]) {
|
||||||
|
b[to] = '\\'
|
||||||
|
to++
|
||||||
|
}
|
||||||
|
b[to] = s[pos]
|
||||||
|
to++
|
||||||
|
}
|
||||||
|
return util.UnsafeBytesToString(b[0:to])
|
||||||
|
}
|
||||||
208
modules/glob/glob_test.go
Normal file
208
modules/glob/glob_test.go
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// Copyright (c) 2016 Sergey Kamardin
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
//nolint:revive // the code is from gobwas/glob
|
||||||
|
package glob
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference: https://github.com/gobwas/glob/blob/master/glob_test.go
|
||||||
|
|
||||||
|
const (
|
||||||
|
pattern_all = "[a-z][!a-x]*cat*[h][!b]*eyes*"
|
||||||
|
regexp_all = `^[a-z][^a-x].*cat.*[h][^b].*eyes.*$`
|
||||||
|
fixture_all_match = "my cat has very bright eyes"
|
||||||
|
fixture_all_mismatch = "my dog has very bright eyes"
|
||||||
|
|
||||||
|
pattern_plain = "google.com"
|
||||||
|
regexp_plain = `^google\.com$`
|
||||||
|
fixture_plain_match = "google.com"
|
||||||
|
fixture_plain_mismatch = "gobwas.com"
|
||||||
|
|
||||||
|
pattern_multiple = "https://*.google.*"
|
||||||
|
regexp_multiple = `^https:\/\/.*\.google\..*$`
|
||||||
|
fixture_multiple_match = "https://account.google.com"
|
||||||
|
fixture_multiple_mismatch = "https://google.com"
|
||||||
|
|
||||||
|
pattern_alternatives = "{https://*.google.*,*yandex.*,*yahoo.*,*mail.ru}"
|
||||||
|
regexp_alternatives = `^(https:\/\/.*\.google\..*|.*yandex\..*|.*yahoo\..*|.*mail\.ru)$`
|
||||||
|
fixture_alternatives_match = "http://yahoo.com"
|
||||||
|
fixture_alternatives_mismatch = "http://google.com"
|
||||||
|
|
||||||
|
pattern_alternatives_suffix = "{https://*gobwas.com,http://exclude.gobwas.com}"
|
||||||
|
regexp_alternatives_suffix = `^(https:\/\/.*gobwas\.com|http://exclude.gobwas.com)$`
|
||||||
|
fixture_alternatives_suffix_first_match = "https://safe.gobwas.com"
|
||||||
|
fixture_alternatives_suffix_first_mismatch = "http://safe.gobwas.com"
|
||||||
|
fixture_alternatives_suffix_second = "http://exclude.gobwas.com"
|
||||||
|
|
||||||
|
pattern_prefix = "abc*"
|
||||||
|
regexp_prefix = `^abc.*$`
|
||||||
|
pattern_suffix = "*def"
|
||||||
|
regexp_suffix = `^.*def$`
|
||||||
|
pattern_prefix_suffix = "ab*ef"
|
||||||
|
regexp_prefix_suffix = `^ab.*ef$`
|
||||||
|
fixture_prefix_suffix_match = "abcdef"
|
||||||
|
fixture_prefix_suffix_mismatch = "af"
|
||||||
|
|
||||||
|
pattern_alternatives_combine_lite = "{abc*def,abc?def,abc[zte]def}"
|
||||||
|
regexp_alternatives_combine_lite = `^(abc.*def|abc.def|abc[zte]def)$`
|
||||||
|
fixture_alternatives_combine_lite = "abczdef"
|
||||||
|
|
||||||
|
pattern_alternatives_combine_hard = "{abc*[a-c]def,abc?[d-g]def,abc[zte]?def}"
|
||||||
|
regexp_alternatives_combine_hard = `^(abc.*[a-c]def|abc.[d-g]def|abc[zte].def)$`
|
||||||
|
fixture_alternatives_combine_hard = "abczqdef"
|
||||||
|
)
|
||||||
|
|
||||||
|
type test struct {
|
||||||
|
pattern, match string
|
||||||
|
should bool
|
||||||
|
delimiters []rune
|
||||||
|
}
|
||||||
|
|
||||||
|
func glob(s bool, p, m string, d ...rune) test {
|
||||||
|
return test{p, m, s, d}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGlob(t *testing.T) {
|
||||||
|
for _, test := range []test{
|
||||||
|
glob(true, "* ?at * eyes", "my cat has very bright eyes"),
|
||||||
|
|
||||||
|
glob(true, "", ""),
|
||||||
|
glob(false, "", "b"),
|
||||||
|
|
||||||
|
glob(true, "*ä", "åä"),
|
||||||
|
glob(true, "abc", "abc"),
|
||||||
|
glob(true, "a*c", "abc"),
|
||||||
|
glob(true, "a*c", "a12345c"),
|
||||||
|
glob(true, "a?c", "a1c"),
|
||||||
|
glob(true, "a.b", "a.b", '.'),
|
||||||
|
glob(true, "a.*", "a.b", '.'),
|
||||||
|
glob(true, "a.**", "a.b.c", '.'),
|
||||||
|
glob(true, "a.?.c", "a.b.c", '.'),
|
||||||
|
glob(true, "a.?.?", "a.b.c", '.'),
|
||||||
|
glob(true, "?at", "cat"),
|
||||||
|
glob(true, "?at", "fat"),
|
||||||
|
glob(true, "*", "abc"),
|
||||||
|
glob(true, `\*`, "*"),
|
||||||
|
glob(true, "**", "a.b.c", '.'),
|
||||||
|
|
||||||
|
glob(false, "?at", "at"),
|
||||||
|
glob(false, "?at", "fat", 'f'),
|
||||||
|
glob(false, "a.*", "a.b.c", '.'),
|
||||||
|
glob(false, "a.?.c", "a.bb.c", '.'),
|
||||||
|
glob(false, "*", "a.b.c", '.'),
|
||||||
|
|
||||||
|
glob(true, "*test", "this is a test"),
|
||||||
|
glob(true, "this*", "this is a test"),
|
||||||
|
glob(true, "*is *", "this is a test"),
|
||||||
|
glob(true, "*is*a*", "this is a test"),
|
||||||
|
glob(true, "**test**", "this is a test"),
|
||||||
|
glob(true, "**is**a***test*", "this is a test"),
|
||||||
|
|
||||||
|
glob(false, "*is", "this is a test"),
|
||||||
|
glob(false, "*no*", "this is a test"),
|
||||||
|
glob(true, "[!a]*", "this is a test3"),
|
||||||
|
|
||||||
|
glob(true, "*abc", "abcabc"),
|
||||||
|
glob(true, "**abc", "abcabc"),
|
||||||
|
glob(true, "???", "abc"),
|
||||||
|
glob(true, "?*?", "abc"),
|
||||||
|
glob(true, "?*?", "ac"),
|
||||||
|
glob(false, "sta", "stagnation"),
|
||||||
|
glob(true, "sta*", "stagnation"),
|
||||||
|
glob(false, "sta?", "stagnation"),
|
||||||
|
glob(false, "sta?n", "stagnation"),
|
||||||
|
|
||||||
|
glob(true, "{abc,def}ghi", "defghi"),
|
||||||
|
glob(true, "{abc,abcd}a", "abcda"),
|
||||||
|
glob(true, "{a,ab}{bc,f}", "abc"),
|
||||||
|
glob(true, "{*,**}{a,b}", "ab"),
|
||||||
|
glob(false, "{*,**}{a,b}", "ac"),
|
||||||
|
|
||||||
|
glob(true, "/{rate,[a-z][a-z][a-z]}*", "/rate"),
|
||||||
|
glob(true, "/{rate,[0-9][0-9][0-9]}*", "/rate"),
|
||||||
|
glob(true, "/{rate,[a-z][a-z][a-z]}*", "/usd"),
|
||||||
|
|
||||||
|
glob(true, "{*.google.*,*.yandex.*}", "www.google.com", '.'),
|
||||||
|
glob(true, "{*.google.*,*.yandex.*}", "www.yandex.com", '.'),
|
||||||
|
glob(false, "{*.google.*,*.yandex.*}", "yandex.com", '.'),
|
||||||
|
glob(false, "{*.google.*,*.yandex.*}", "google.com", '.'),
|
||||||
|
|
||||||
|
glob(true, "{*.google.*,yandex.*}", "www.google.com", '.'),
|
||||||
|
glob(true, "{*.google.*,yandex.*}", "yandex.com", '.'),
|
||||||
|
glob(false, "{*.google.*,yandex.*}", "www.yandex.com", '.'),
|
||||||
|
glob(false, "{*.google.*,yandex.*}", "google.com", '.'),
|
||||||
|
|
||||||
|
glob(true, "*//{,*.}example.com", "https://www.example.com"),
|
||||||
|
glob(true, "*//{,*.}example.com", "http://example.com"),
|
||||||
|
glob(false, "*//{,*.}example.com", "http://example.com.net"),
|
||||||
|
|
||||||
|
glob(true, pattern_all, fixture_all_match),
|
||||||
|
glob(false, pattern_all, fixture_all_mismatch),
|
||||||
|
|
||||||
|
glob(true, pattern_plain, fixture_plain_match),
|
||||||
|
glob(false, pattern_plain, fixture_plain_mismatch),
|
||||||
|
|
||||||
|
glob(true, pattern_multiple, fixture_multiple_match),
|
||||||
|
glob(false, pattern_multiple, fixture_multiple_mismatch),
|
||||||
|
|
||||||
|
glob(true, pattern_alternatives, fixture_alternatives_match),
|
||||||
|
glob(false, pattern_alternatives, fixture_alternatives_mismatch),
|
||||||
|
|
||||||
|
glob(true, pattern_alternatives_suffix, fixture_alternatives_suffix_first_match),
|
||||||
|
glob(false, pattern_alternatives_suffix, fixture_alternatives_suffix_first_mismatch),
|
||||||
|
glob(true, pattern_alternatives_suffix, fixture_alternatives_suffix_second),
|
||||||
|
|
||||||
|
glob(true, pattern_alternatives_combine_hard, fixture_alternatives_combine_hard),
|
||||||
|
|
||||||
|
glob(true, pattern_alternatives_combine_lite, fixture_alternatives_combine_lite),
|
||||||
|
|
||||||
|
glob(true, pattern_prefix, fixture_prefix_suffix_match),
|
||||||
|
glob(false, pattern_prefix, fixture_prefix_suffix_mismatch),
|
||||||
|
|
||||||
|
glob(true, pattern_suffix, fixture_prefix_suffix_match),
|
||||||
|
glob(false, pattern_suffix, fixture_prefix_suffix_mismatch),
|
||||||
|
|
||||||
|
glob(true, pattern_prefix_suffix, fixture_prefix_suffix_match),
|
||||||
|
glob(false, pattern_prefix_suffix, fixture_prefix_suffix_mismatch),
|
||||||
|
} {
|
||||||
|
g, err := Compile(test.pattern, test.delimiters...)
|
||||||
|
require.NoError(t, err)
|
||||||
|
result := g.Match(test.match)
|
||||||
|
assert.Equal(t, test.should, result, "pattern %q matching %q should be %v but got %v, compiled=%s", test.pattern, test.match, test.should, result, g.(*globCompiler).regexpPattern)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQuoteMeta(t *testing.T) {
|
||||||
|
for id, test := range []struct {
|
||||||
|
in, out string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
in: `[foo*]`,
|
||||||
|
out: `\[foo\*\]`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: `{foo*}`,
|
||||||
|
out: `\{foo\*\}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: `*?\[]{}`,
|
||||||
|
out: `\*\?\\\[\]\{\}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: `some text and *?\[]{}`,
|
||||||
|
out: `some text and \*\?\\\[\]\{\}`,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
act := QuoteMeta(test.in)
|
||||||
|
assert.Equal(t, test.out, act, "QuoteMeta(%q)", test.in)
|
||||||
|
_, err := Compile(act)
|
||||||
|
assert.NoError(t, err, "#%d _, err := Compile(QuoteMeta(%q) = %q); err = %q", id, test.in, act, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,6 +16,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/analyze"
|
"code.gitea.io/gitea/modules/analyze"
|
||||||
"code.gitea.io/gitea/modules/charset"
|
"code.gitea.io/gitea/modules/charset"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/indexer"
|
"code.gitea.io/gitea/modules/indexer"
|
||||||
path_filter "code.gitea.io/gitea/modules/indexer/code/bleve/token/path"
|
path_filter "code.gitea.io/gitea/modules/indexer/code/bleve/token/path"
|
||||||
"code.gitea.io/gitea/modules/indexer/code/internal"
|
"code.gitea.io/gitea/modules/indexer/code/internal"
|
||||||
@ -162,7 +163,7 @@ func (b *Indexer) addUpdate(ctx context.Context, batchWriter git.WriteCloserErro
|
|||||||
var err error
|
var err error
|
||||||
if !update.Sized {
|
if !update.Sized {
|
||||||
var stdout string
|
var stdout string
|
||||||
stdout, _, err = git.NewCommand("cat-file", "-s").AddDynamicArguments(update.BlobSha).RunStdString(ctx, &git.RunOpts{Dir: repo.RepoPath()})
|
stdout, _, err = gitcmd.NewCommand("cat-file", "-s").AddDynamicArguments(update.BlobSha).RunStdString(ctx, &gitcmd.RunOpts{Dir: repo.RepoPath()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/analyze"
|
"code.gitea.io/gitea/modules/analyze"
|
||||||
"code.gitea.io/gitea/modules/charset"
|
"code.gitea.io/gitea/modules/charset"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/indexer"
|
"code.gitea.io/gitea/modules/indexer"
|
||||||
"code.gitea.io/gitea/modules/indexer/code/internal"
|
"code.gitea.io/gitea/modules/indexer/code/internal"
|
||||||
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
|
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
|
||||||
@ -147,7 +148,7 @@ func (b *Indexer) addUpdate(ctx context.Context, batchWriter git.WriteCloserErro
|
|||||||
var err error
|
var err error
|
||||||
if !update.Sized {
|
if !update.Sized {
|
||||||
var stdout string
|
var stdout string
|
||||||
stdout, _, err = git.NewCommand("cat-file", "-s").AddDynamicArguments(update.BlobSha).RunStdString(ctx, &git.RunOpts{Dir: repo.RepoPath()})
|
stdout, _, err = gitcmd.NewCommand("cat-file", "-s").AddDynamicArguments(update.BlobSha).RunStdString(ctx, &gitcmd.RunOpts{Dir: repo.RepoPath()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -250,7 +251,7 @@ func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha st
|
|||||||
func (b *Indexer) Delete(ctx context.Context, repoID int64) error {
|
func (b *Indexer) Delete(ctx context.Context, repoID int64) error {
|
||||||
if err := b.doDelete(ctx, repoID); err != nil {
|
if err := b.doDelete(ctx, repoID); err != nil {
|
||||||
// Maybe there is a conflict during the delete operation, so we should retry after a refresh
|
// Maybe there is a conflict during the delete operation, so we should retry after a refresh
|
||||||
log.Warn("Deletion of entries of repo %v within index %v was erroneus. Trying to refresh index before trying again", repoID, b.inner.VersionedIndexName(), err)
|
log.Warn("Deletion of entries of repo %v within index %v was erroneous. Trying to refresh index before trying again", repoID, b.inner.VersionedIndexName(), err)
|
||||||
if err := b.refreshIndex(ctx); err != nil {
|
if err := b.refreshIndex(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,13 +10,14 @@ import (
|
|||||||
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"code.gitea.io/gitea/modules/indexer/code/internal"
|
"code.gitea.io/gitea/modules/indexer/code/internal"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getDefaultBranchSha(ctx context.Context, repo *repo_model.Repository) (string, error) {
|
func getDefaultBranchSha(ctx context.Context, repo *repo_model.Repository) (string, error) {
|
||||||
stdout, _, err := git.NewCommand("show-ref", "-s").AddDynamicArguments(git.BranchPrefix+repo.DefaultBranch).RunStdString(ctx, &git.RunOpts{Dir: repo.RepoPath()})
|
stdout, _, err := gitcmd.NewCommand("show-ref", "-s").AddDynamicArguments(git.BranchPrefix+repo.DefaultBranch).RunStdString(ctx, &gitcmd.RunOpts{Dir: repo.RepoPath()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -32,8 +33,8 @@ func getRepoChanges(ctx context.Context, repo *repo_model.Repository, revision s
|
|||||||
|
|
||||||
needGenesis := len(status.CommitSha) == 0
|
needGenesis := len(status.CommitSha) == 0
|
||||||
if !needGenesis {
|
if !needGenesis {
|
||||||
hasAncestorCmd := git.NewCommand("merge-base").AddDynamicArguments(status.CommitSha, revision)
|
hasAncestorCmd := gitcmd.NewCommand("merge-base").AddDynamicArguments(status.CommitSha, revision)
|
||||||
stdout, _, _ := hasAncestorCmd.RunStdString(ctx, &git.RunOpts{Dir: repo.RepoPath()})
|
stdout, _, _ := hasAncestorCmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repo.RepoPath()})
|
||||||
needGenesis = len(stdout) == 0
|
needGenesis = len(stdout) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ func parseGitLsTreeOutput(stdout []byte) ([]internal.FileUpdate, error) {
|
|||||||
// genesisChanges get changes to add repo to the indexer for the first time
|
// genesisChanges get changes to add repo to the indexer for the first time
|
||||||
func genesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*internal.RepoChanges, error) {
|
func genesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*internal.RepoChanges, error) {
|
||||||
var changes internal.RepoChanges
|
var changes internal.RepoChanges
|
||||||
stdout, _, runErr := git.NewCommand("ls-tree", "--full-tree", "-l", "-r").AddDynamicArguments(revision).RunStdBytes(ctx, &git.RunOpts{Dir: repo.RepoPath()})
|
stdout, _, runErr := gitcmd.NewCommand("ls-tree", "--full-tree", "-l", "-r").AddDynamicArguments(revision).RunStdBytes(ctx, &gitcmd.RunOpts{Dir: repo.RepoPath()})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
return nil, runErr
|
return nil, runErr
|
||||||
}
|
}
|
||||||
@ -98,8 +99,8 @@ func genesisChanges(ctx context.Context, repo *repo_model.Repository, revision s
|
|||||||
|
|
||||||
// nonGenesisChanges get changes since the previous indexer update
|
// nonGenesisChanges get changes since the previous indexer update
|
||||||
func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*internal.RepoChanges, error) {
|
func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*internal.RepoChanges, error) {
|
||||||
diffCmd := git.NewCommand("diff", "--name-status").AddDynamicArguments(repo.CodeIndexerStatus.CommitSha, revision)
|
diffCmd := gitcmd.NewCommand("diff", "--name-status").AddDynamicArguments(repo.CodeIndexerStatus.CommitSha, revision)
|
||||||
stdout, _, runErr := diffCmd.RunStdString(ctx, &git.RunOpts{Dir: repo.RepoPath()})
|
stdout, _, runErr := diffCmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repo.RepoPath()})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
// previous commit sha may have been removed by a force push, so
|
// previous commit sha may have been removed by a force push, so
|
||||||
// try rebuilding from scratch
|
// try rebuilding from scratch
|
||||||
@ -115,9 +116,9 @@ func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revisio
|
|||||||
updatedFilenames := make([]string, 0, 10)
|
updatedFilenames := make([]string, 0, 10)
|
||||||
|
|
||||||
updateChanges := func() error {
|
updateChanges := func() error {
|
||||||
cmd := git.NewCommand("ls-tree", "--full-tree", "-l").AddDynamicArguments(revision).
|
cmd := gitcmd.NewCommand("ls-tree", "--full-tree", "-l").AddDynamicArguments(revision).
|
||||||
AddDashesAndList(updatedFilenames...)
|
AddDashesAndList(updatedFilenames...)
|
||||||
lsTreeStdout, _, err := cmd.RunStdBytes(ctx, &git.RunOpts{Dir: repo.RepoPath()})
|
lsTreeStdout, _, err := cmd.RunStdBytes(ctx, &gitcmd.RunOpts{Dir: repo.RepoPath()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -134,7 +134,7 @@ func testIndexer(name string, t *testing.T, indexer internal.Indexer) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Search for matches on both the contents and the filenames within the repo '62'.
|
// Search for matches on both the contents and the filenames within the repo '62'.
|
||||||
// This scenario yields two results: the first result is baed on the file (cucumber.md) while the second is based on the contents
|
// This scenario yields two results: the first result is based on the file (cucumber.md) while the second is based on the contents
|
||||||
{
|
{
|
||||||
RepoIDs: []int64{62},
|
RepoIDs: []int64{62},
|
||||||
Keyword: "cucumber",
|
Keyword: "cucumber",
|
||||||
|
|||||||
@ -28,7 +28,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// IndexerMetadata is used to send data to the queue, so it contains only the ids.
|
// IndexerMetadata is used to send data to the queue, so it contains only the ids.
|
||||||
// It may look weired, because it has to be compatible with the old queue data format.
|
// It may look weird, because it has to be compatible with the old queue data format.
|
||||||
// If the IsDelete flag is true, the IDs specify the issues to delete from the index without querying the database.
|
// If the IsDelete flag is true, the IDs specify the issues to delete from the index without querying the database.
|
||||||
// If the IsDelete flag is false, the ID specify the issue to index, so Indexer will query the database to get the issue data.
|
// If the IsDelete flag is false, the ID specify the issue to index, so Indexer will query the database to get the issue data.
|
||||||
// It should be noted that if the id is not existing in the database, it's index will be deleted too even if IsDelete is false.
|
// It should be noted that if the id is not existing in the database, it's index will be deleted too even if IsDelete is false.
|
||||||
|
|||||||
@ -18,7 +18,7 @@ func resolveLinkRelative(ctx context.Context, base, cur, link string, absolute b
|
|||||||
}
|
}
|
||||||
if strings.HasPrefix(link, "/") {
|
if strings.HasPrefix(link, "/") {
|
||||||
if strings.HasPrefix(link, base) && strings.Count(base, "/") >= 4 {
|
if strings.HasPrefix(link, base) && strings.Count(base, "/") >= 4 {
|
||||||
// a trick to tolerate that some users were using absolut paths (the old gitea's behavior)
|
// a trick to tolerate that some users were using absolute paths (the old gitea's behavior)
|
||||||
finalLink = link
|
finalLink = link
|
||||||
} else {
|
} else {
|
||||||
finalLink = util.URLJoin(base, "./", link)
|
finalLink = util.URLJoin(base, "./", link)
|
||||||
|
|||||||
@ -10,10 +10,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/glob"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
//
|
//
|
||||||
// 4. Handler (represented by HandlerFuncT type):
|
// 4. Handler (represented by HandlerFuncT type):
|
||||||
// - It's the function responsible for processing items. Each active worker will call it.
|
// - It's the function responsible for processing items. Each active worker will call it.
|
||||||
// - If an item or some items are not psuccessfully rocessed, the handler could return them as "unhandled items".
|
// - If an item or some items are not successfully processed, the handler could return them as "unhandled items".
|
||||||
// In such scenarios, the queue system ensures these unhandled items are returned to the base queue after a brief delay.
|
// In such scenarios, the queue system ensures these unhandled items are returned to the base queue after a brief delay.
|
||||||
// This mechanism is particularly beneficial in cases where the processing entity (like a document indexer) is
|
// This mechanism is particularly beneficial in cases where the processing entity (like a document indexer) is
|
||||||
// temporarily unavailable. It ensures that no item is skipped or lost due to transient failures in the processing
|
// temporarily unavailable. It ensures that no item is skipped or lost due to transient failures in the processing
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
package setting
|
package setting
|
||||||
|
|
||||||
import "github.com/gobwas/glob"
|
import "code.gitea.io/gitea/modules/glob"
|
||||||
|
|
||||||
type GlobMatcher struct {
|
type GlobMatcher struct {
|
||||||
compiledGlob glob.Glob
|
compiledGlob glob.Glob
|
||||||
|
|||||||
@ -9,10 +9,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/glob"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// enumerates all the types of captchas
|
// enumerates all the types of captchas
|
||||||
|
|||||||
@ -6,10 +6,10 @@ package setting
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/glob"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/test"
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import (
|
|||||||
type StateType string
|
type StateType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// StateOpen pr is opend
|
// StateOpen pr is opened
|
||||||
StateOpen StateType = "open"
|
StateOpen StateType = "open"
|
||||||
// StateClosed pr is closed
|
// StateClosed pr is closed
|
||||||
StateClosed StateType = "closed"
|
StateClosed StateType = "closed"
|
||||||
@ -76,6 +76,8 @@ type Issue struct {
|
|||||||
// swagger:strfmt date-time
|
// swagger:strfmt date-time
|
||||||
Deadline *time.Time `json:"due_date"`
|
Deadline *time.Time `json:"due_date"`
|
||||||
|
|
||||||
|
TimeEstimate int64 `json:"time_estimate"`
|
||||||
|
|
||||||
PullRequest *PullRequestMeta `json:"pull_request"`
|
PullRequest *PullRequestMeta `json:"pull_request"`
|
||||||
Repo *RepositoryMeta `json:"repository"`
|
Repo *RepositoryMeta `json:"repository"`
|
||||||
|
|
||||||
|
|||||||
@ -319,7 +319,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Name represents the service type's name
|
// Name represents the service type's name
|
||||||
// WARNNING: the name have to be equal to that on goth's library
|
// WARNING: the name has to be equal to that on goth's library
|
||||||
func (gt GitServiceType) Name() string {
|
func (gt GitServiceType) Name() string {
|
||||||
return strings.ToLower(gt.Title())
|
return strings.ToLower(gt.Title())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,7 +61,7 @@ type User struct {
|
|||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface for User, adding field(s) for backward compatibility
|
// MarshalJSON implements the json.Marshaler interface for User, adding field(s) for backward compatibility
|
||||||
func (u User) MarshalJSON() ([]byte, error) {
|
func (u User) MarshalJSON() ([]byte, error) {
|
||||||
// Re-declaring User to avoid recursion
|
// Redeclaring User to avoid recursion
|
||||||
type shadow User
|
type shadow User
|
||||||
return json.Marshal(struct {
|
return json.Marshal(struct {
|
||||||
shadow
|
shadow
|
||||||
|
|||||||
@ -48,12 +48,12 @@ func TestIsSvgImage(t *testing.T) {
|
|||||||
<!-- Comments -->
|
<!-- Comments -->
|
||||||
<svg></svg>`)).IsSvgImage())
|
<svg></svg>`)).IsSvgImage())
|
||||||
assert.True(t, DetectContentType([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
assert.True(t, DetectContentType([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- Multline
|
<!-- Multiline
|
||||||
Comment -->
|
Comment -->
|
||||||
<svg></svg>`)).IsSvgImage())
|
<svg></svg>`)).IsSvgImage())
|
||||||
assert.True(t, DetectContentType([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
assert.True(t, DetectContentType([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
<!-- Multline
|
<!-- Multiline
|
||||||
Comment -->
|
Comment -->
|
||||||
<svg></svg>`)).IsSvgImage())
|
<svg></svg>`)).IsSvgImage())
|
||||||
|
|
||||||
|
|||||||
@ -10,10 +10,10 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/modules/auth"
|
"code.gitea.io/gitea/modules/auth"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/glob"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"gitea.com/go-chi/binding"
|
"gitea.com/go-chi/binding"
|
||||||
"github.com/gobwas/glob"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@ -6,8 +6,9 @@ package validation
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/glob"
|
||||||
|
|
||||||
"gitea.com/go-chi/binding"
|
"gitea.com/go-chi/binding"
|
||||||
"github.com/gobwas/glob"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getGlobPatternErrorString(pattern string) string {
|
func getGlobPatternErrorString(pattern string) string {
|
||||||
|
|||||||
@ -11,9 +11,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/glob"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type globalVarsStruct struct {
|
type globalVarsStruct struct {
|
||||||
|
|||||||
@ -8,7 +8,7 @@ gradle-app.setting
|
|||||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||||
!gradle-wrapper.jar
|
!gradle-wrapper.jar
|
||||||
|
|
||||||
# Avoid ignore Gradle wrappper properties
|
# Avoid ignore Gradle wrapper properties
|
||||||
!gradle-wrapper.properties
|
!gradle-wrapper.properties
|
||||||
|
|
||||||
# Cache of project
|
# Cache of project
|
||||||
|
|||||||
@ -3425,7 +3425,6 @@ swift.install=Přidejte balíček do svého <code>Package.swift</code> souboru:
|
|||||||
swift.install2=a spustit následující příkaz:
|
swift.install2=a spustit následující příkaz:
|
||||||
vagrant.install=Pro přidání Vagrant box spusťte následující příkaz:
|
vagrant.install=Pro přidání Vagrant box spusťte následující příkaz:
|
||||||
settings.link=Propojit tento balíček s repozitářem
|
settings.link=Propojit tento balíček s repozitářem
|
||||||
settings.link.description=Pokud propojíte balíček s repozitářem, je tento balíček uveden v seznamu balíčků repozitáře.
|
|
||||||
settings.link.select=Vybrat repozitář
|
settings.link.select=Vybrat repozitář
|
||||||
settings.link.button=Aktualizovat odkaz na repozitář
|
settings.link.button=Aktualizovat odkaz na repozitář
|
||||||
settings.link.success=Odkaz na repozitář byl úspěšně aktualizován.
|
settings.link.success=Odkaz na repozitář byl úspěšně aktualizován.
|
||||||
|
|||||||
@ -3475,7 +3475,6 @@ swift.install=Füge das Paket deiner <code>Package.swift</code> Datei hinzu:
|
|||||||
swift.install2=und führe den folgenden Befehl aus:
|
swift.install2=und führe den folgenden Befehl aus:
|
||||||
vagrant.install=Um eine Vagrant-Box hinzuzufügen, führe den folgenden Befehl aus:
|
vagrant.install=Um eine Vagrant-Box hinzuzufügen, führe den folgenden Befehl aus:
|
||||||
settings.link=Dieses Paket einem Repository zuweisen
|
settings.link=Dieses Paket einem Repository zuweisen
|
||||||
settings.link.description=Wenn du ein Paket mit einem Repository verknüpfst, wird es in der Paketliste des Repositories angezeigt.
|
|
||||||
settings.link.select=Repository auswählen
|
settings.link.select=Repository auswählen
|
||||||
settings.link.button=Repository-Link aktualisieren
|
settings.link.button=Repository-Link aktualisieren
|
||||||
settings.link.success=Repository-Link wurde erfolgreich aktualisiert.
|
settings.link.success=Repository-Link wurde erfolgreich aktualisiert.
|
||||||
|
|||||||
@ -3133,7 +3133,6 @@ swift.install=Προσθέστε το πακέτο στο αρχείο <code>Pac
|
|||||||
swift.install2=και εκτελέστε την ακόλουθη εντολή:
|
swift.install2=και εκτελέστε την ακόλουθη εντολή:
|
||||||
vagrant.install=Για προσθήκη ενός κυτίου Vagrant, εκτελέστε την ακόλουθη εντολή:
|
vagrant.install=Για προσθήκη ενός κυτίου Vagrant, εκτελέστε την ακόλουθη εντολή:
|
||||||
settings.link=Σύνδεση αυτού του πακέτου με ένα αποθετήριο
|
settings.link=Σύνδεση αυτού του πακέτου με ένα αποθετήριο
|
||||||
settings.link.description=Εάν συνδέσετε ένα πακέτο με ένα αποθετήριο, το πακέτο περιλαμβάνεται στη λίστα πακέτων του αποθετηρίου.
|
|
||||||
settings.link.select=Επιλογή Αποθετηρίου
|
settings.link.select=Επιλογή Αποθετηρίου
|
||||||
settings.link.button=Ενημέρωση Συνδέσμου Αποθετηρίου
|
settings.link.button=Ενημέρωση Συνδέσμου Αποθετηρίου
|
||||||
settings.link.success=Ο σύνδεσμος αποθετηρίου ενημερώθηκε επιτυχώς.
|
settings.link.success=Ο σύνδεσμος αποθετηρίου ενημερώθηκε επιτυχώς.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user