mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-25 08:59:31 -05:00
Backport #21464 and #21465 Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
6afbef5a8b
commit
cd48a007bb
6 changed files with 64 additions and 27 deletions
|
@ -40,6 +40,7 @@ type Command struct {
|
||||||
parentContext context.Context
|
parentContext context.Context
|
||||||
desc string
|
desc string
|
||||||
globalArgsLength int
|
globalArgsLength int
|
||||||
|
brokenArgs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Command) String() string {
|
func (c *Command) String() string {
|
||||||
|
@ -50,6 +51,7 @@ func (c *Command) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCommand creates and returns a new Git Command based on given command and arguments.
|
// NewCommand creates and returns a new Git Command based on given command and arguments.
|
||||||
|
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
|
||||||
func NewCommand(ctx context.Context, args ...string) *Command {
|
func NewCommand(ctx context.Context, args ...string) *Command {
|
||||||
// Make an explicit copy of globalCommandArgs, otherwise append might overwrite it
|
// Make an explicit copy of globalCommandArgs, otherwise append might overwrite it
|
||||||
cargs := make([]string, len(globalCommandArgs))
|
cargs := make([]string, len(globalCommandArgs))
|
||||||
|
@ -63,11 +65,13 @@ func NewCommand(ctx context.Context, args ...string) *Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCommandNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
|
// NewCommandNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
|
||||||
|
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
|
||||||
func NewCommandNoGlobals(args ...string) *Command {
|
func NewCommandNoGlobals(args ...string) *Command {
|
||||||
return NewCommandContextNoGlobals(DefaultContext, args...)
|
return NewCommandContextNoGlobals(DefaultContext, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCommandContextNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
|
// NewCommandContextNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
|
||||||
|
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
|
||||||
func NewCommandContextNoGlobals(ctx context.Context, args ...string) *Command {
|
func NewCommandContextNoGlobals(ctx context.Context, args ...string) *Command {
|
||||||
return &Command{
|
return &Command{
|
||||||
name: GitExecutable,
|
name: GitExecutable,
|
||||||
|
@ -89,12 +93,28 @@ func (c *Command) SetDescription(desc string) *Command {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddArguments adds new argument(s) to the command.
|
// AddArguments adds new argument(s) to the command. Each argument must be safe to be trusted.
|
||||||
|
// User-provided arguments should be passed to AddDynamicArguments instead.
|
||||||
func (c *Command) AddArguments(args ...string) *Command {
|
func (c *Command) AddArguments(args ...string) *Command {
|
||||||
c.args = append(c.args, args...)
|
c.args = append(c.args, args...)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddDynamicArguments adds new dynamic argument(s) to the command.
|
||||||
|
// The arguments may come from user input and can not be trusted, so no leading '-' is allowed to avoid passing options
|
||||||
|
func (c *Command) AddDynamicArguments(args ...string) *Command {
|
||||||
|
for _, arg := range args {
|
||||||
|
if arg != "" && arg[0] == '-' {
|
||||||
|
c.brokenArgs = append(c.brokenArgs, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(c.brokenArgs) != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
c.args = append(c.args, args...)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
// RunOpts represents parameters to run the command. If UseContextTimeout is specified, then Timeout is ignored.
|
// RunOpts represents parameters to run the command. If UseContextTimeout is specified, then Timeout is ignored.
|
||||||
type RunOpts struct {
|
type RunOpts struct {
|
||||||
Env []string
|
Env []string
|
||||||
|
@ -138,8 +158,14 @@ func CommonCmdServEnvs() []string {
|
||||||
return commonBaseEnvs()
|
return commonBaseEnvs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrBrokenCommand = errors.New("git command is broken")
|
||||||
|
|
||||||
// Run runs the command with the RunOpts
|
// Run runs the command with the RunOpts
|
||||||
func (c *Command) Run(opts *RunOpts) error {
|
func (c *Command) Run(opts *RunOpts) error {
|
||||||
|
if len(c.brokenArgs) != 0 {
|
||||||
|
log.Error("git command is broken: %s, broken args: %s", c.String(), strings.Join(c.brokenArgs, " "))
|
||||||
|
return ErrBrokenCommand
|
||||||
|
}
|
||||||
if opts == nil {
|
if opts == nil {
|
||||||
opts = &RunOpts{}
|
opts = &RunOpts{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,4 +26,19 @@ func TestRunWithContextStd(t *testing.T) {
|
||||||
assert.Contains(t, err.Error(), "exit status 129 - unknown option:")
|
assert.Contains(t, err.Error(), "exit status 129 - unknown option:")
|
||||||
assert.Empty(t, stdout)
|
assert.Empty(t, stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd = NewCommand(context.Background())
|
||||||
|
cmd.AddDynamicArguments("-test")
|
||||||
|
assert.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand)
|
||||||
|
|
||||||
|
cmd = NewCommand(context.Background())
|
||||||
|
cmd.AddDynamicArguments("--test")
|
||||||
|
assert.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand)
|
||||||
|
|
||||||
|
subCmd := "version"
|
||||||
|
cmd = NewCommand(context.Background()).AddDynamicArguments(subCmd) // for test purpose only, the sub-command should never be dynamic for production
|
||||||
|
stdout, stderr, err = cmd.RunStdString(&RunOpts{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Empty(t, stderr)
|
||||||
|
assert.Contains(t, stdout, "git version")
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, file
|
||||||
// CommitsCountFiles returns number of total commits of until given revision.
|
// CommitsCountFiles returns number of total commits of until given revision.
|
||||||
func CommitsCountFiles(ctx context.Context, repoPath string, revision, relpath []string) (int64, error) {
|
func CommitsCountFiles(ctx context.Context, repoPath string, revision, relpath []string) (int64, error) {
|
||||||
cmd := NewCommand(ctx, "rev-list", "--count")
|
cmd := NewCommand(ctx, "rev-list", "--count")
|
||||||
cmd.AddArguments(revision...)
|
cmd.AddDynamicArguments(revision...)
|
||||||
if len(relpath) > 0 {
|
if len(relpath) > 0 {
|
||||||
cmd.AddArguments("--")
|
cmd.AddArguments("--")
|
||||||
cmd.AddArguments(relpath...)
|
cmd.AddArguments(relpath...)
|
||||||
|
|
|
@ -158,7 +158,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
|
||||||
// add previous arguments except for --grep and --all
|
// add previous arguments except for --grep and --all
|
||||||
hashCmd.AddArguments(args...)
|
hashCmd.AddArguments(args...)
|
||||||
// add keyword as <commit>
|
// add keyword as <commit>
|
||||||
hashCmd.AddArguments(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(&RunOpts{Dir: repo.Path})
|
hashMatching, _, err := hashCmd.RunStdBytes(&RunOpts{Dir: repo.Path})
|
||||||
|
@ -208,10 +208,11 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
err := NewCommand(repo.Ctx, "log", revision, "--follow",
|
gitCmd := NewCommand(repo.Ctx, "log", prettyLogFormat, "--follow",
|
||||||
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page),
|
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page))
|
||||||
prettyLogFormat, "--", file).
|
gitCmd.AddDynamicArguments(revision)
|
||||||
Run(&RunOpts{
|
gitCmd.AddArguments("--", file)
|
||||||
|
err := gitCmd.Run(&RunOpts{
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: stdoutWriter,
|
Stdout: stdoutWriter,
|
||||||
Stderr: &stderr,
|
Stderr: &stderr,
|
||||||
|
|
|
@ -59,15 +59,15 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
|
||||||
_ = stdoutWriter.Close()
|
_ = stdoutWriter.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
args := []string{"log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso", fmt.Sprintf("--since='%s'", since)}
|
gitCmd := NewCommand(repo.Ctx, "log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso", fmt.Sprintf("--since='%s'", since))
|
||||||
if len(branch) == 0 {
|
if len(branch) == 0 {
|
||||||
args = append(args, "--branches=*")
|
gitCmd.AddArguments("--branches=*")
|
||||||
} else {
|
} else {
|
||||||
args = append(args, "--first-parent", branch)
|
gitCmd.AddArguments("--first-parent").AddDynamicArguments(branch)
|
||||||
}
|
}
|
||||||
|
|
||||||
stderr := new(strings.Builder)
|
stderr := new(strings.Builder)
|
||||||
err = NewCommand(repo.Ctx, args...).Run(&RunOpts{
|
err = gitCmd.Run(&RunOpts{
|
||||||
Env: []string{},
|
Env: []string{},
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: stdoutWriter,
|
Stdout: stdoutWriter,
|
||||||
|
|
|
@ -24,19 +24,17 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
|
||||||
page = 1
|
page = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
args := make([]string, 0, 12+len(branches)+len(files))
|
graphCmd := git.NewCommand(r.Ctx, "log", "--graph", "--date-order", "--decorate=full")
|
||||||
|
|
||||||
args = append(args, "--graph", "--date-order", "--decorate=full")
|
|
||||||
|
|
||||||
if hidePRRefs {
|
if hidePRRefs {
|
||||||
args = append(args, "--exclude="+git.PullPrefix+"*")
|
graphCmd.AddArguments("--exclude=" + git.PullPrefix + "*")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(branches) == 0 {
|
if len(branches) == 0 {
|
||||||
args = append(args, "--all")
|
graphCmd.AddArguments("--all")
|
||||||
}
|
}
|
||||||
|
|
||||||
args = append(args,
|
graphCmd.AddArguments(
|
||||||
"-C",
|
"-C",
|
||||||
"-M",
|
"-M",
|
||||||
fmt.Sprintf("-n %d", setting.UI.GraphMaxCommitNum*page),
|
fmt.Sprintf("-n %d", setting.UI.GraphMaxCommitNum*page),
|
||||||
|
@ -44,15 +42,12 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
|
||||||
fmt.Sprintf("--pretty=format:%s", format))
|
fmt.Sprintf("--pretty=format:%s", format))
|
||||||
|
|
||||||
if len(branches) > 0 {
|
if len(branches) > 0 {
|
||||||
args = append(args, branches...)
|
graphCmd.AddDynamicArguments(branches...)
|
||||||
}
|
}
|
||||||
args = append(args, "--")
|
|
||||||
if len(files) > 0 {
|
if len(files) > 0 {
|
||||||
args = append(args, files...)
|
graphCmd.AddArguments("--")
|
||||||
|
graphCmd.AddArguments(files...)
|
||||||
}
|
}
|
||||||
|
|
||||||
graphCmd := git.NewCommand(r.Ctx, "log")
|
|
||||||
graphCmd.AddArguments(args...)
|
|
||||||
graph := NewGraph()
|
graph := NewGraph()
|
||||||
|
|
||||||
stderr := new(strings.Builder)
|
stderr := new(strings.Builder)
|
||||||
|
|
Loading…
Reference in a new issue