Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

fix(os/gproc): missing arguments on Windows platform #3482

Merged
merged 6 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion os/gproc/gproc_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"os"
"os/exec"
"runtime"
"strings"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
Expand Down Expand Up @@ -53,7 +54,14 @@ func NewProcess(path string, args []string, environment ...[]string) *Process {
},
}
process.Dir, _ = os.Getwd()
process = newProcess(process, args, path)
if len(args) > 0 {
// Exclude of current binary path.
start := 0
if strings.EqualFold(path, args[0]) {
start = 1
}
process.Args = append(process.Args, args[start:]...)
}
return process
}

Expand Down Expand Up @@ -95,6 +103,11 @@ func (p *Process) Start(ctx context.Context) (int, error) {
p.Env = append(p.Env, fmt.Sprintf("%s=%d", envKeyPPid, p.PPid))
p.Env = genv.Filter(p.Env)

// On Windows, this works and doesn't work on other platforms
if runtime.GOOS == "windows" {
joinProcessArgs(p)
}

if err := p.Cmd.Start(); err == nil {
if p.Manager != nil {
p.Manager.processes.Set(p.Process.Pid, p)
Expand Down
15 changes: 2 additions & 13 deletions os/gproc/gproc_process_newprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,5 @@

package gproc

import "strings"

func newProcess(p *Process, args []string, path string) *Process {
if len(args) > 0 {
// Exclude of current binary path.
start := 0
if strings.EqualFold(path, args[0]) {
start = 1
}
p.Args = append(p.Args, args[start:]...)
}
return p
}
// Do nothing, just set it on the Windows platform
func joinProcessArgs(p *Process) {}
8 changes: 3 additions & 5 deletions os/gproc/gproc_process_newprocess_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ import (
"github.com/gogf/gf/v2/text/gstr"
)

// Because when the underlying parameters are passed in on the Windows platform,
// escape characters will be added, causing some commands to fail.
func newProcess(p *Process, args []string, path string) *Process {
// Set the underlying parameters directly on the Windows platform
func joinProcessArgs(p *Process) {
p.SysProcAttr = &syscall.SysProcAttr{}
p.SysProcAttr.CmdLine = path + " " + gstr.Join(args, " ")
return p
p.SysProcAttr.CmdLine = gstr.Join(p.Args, " ")
}
78 changes: 78 additions & 0 deletions os/gproc/gproc_z_unit_process_windows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// go test *.go -bench=".*" -benchmem

//go:build windows

package gproc_test

import (
"path/filepath"
"strings"
"testing"

"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/test/gtest"
)

func Test_ProcessRun(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
binary := gproc.SearchBinary("go")
t.AssertNE(binary, "")
var command = gproc.NewProcess(binary, nil)

testPath := gtest.DataPath("gobuild")
filename := filepath.Join(testPath, "main.go")
output := filepath.Join(testPath, "main.exe")

command.Args = append(command.Args, "build")
command.Args = append(command.Args, `-ldflags="-X 'main.TestString=\"test string\"'"`)
command.Args = append(command.Args, "-o", output)
command.Args = append(command.Args, filename)

err := command.Run(gctx.GetInitCtx())
t.AssertNil(err)

exists := gfile.Exists(output)
t.Assert(exists, true)
defer gfile.Remove(output)

runCmd := gproc.NewProcess(output, nil)
var buf strings.Builder
runCmd.Stdout = &buf
runCmd.Stderr = &buf
err = runCmd.Run(gctx.GetInitCtx())
t.Assert(err, nil)
t.Assert(buf.String(), `"test string"`)
})

gtest.C(t, func(t *gtest.T) {
binary := gproc.SearchBinary("go")
t.AssertNE(binary, "")
// NewProcess(path,args) path: It's best not to have spaces
var command = gproc.NewProcess(binary, nil)

testPath := gtest.DataPath("gobuild")
filename := filepath.Join(testPath, "main.go")
output := filepath.Join(testPath, "main.exe")

command.Args = append(command.Args, "build")
command.Args = append(command.Args, `-ldflags="-s -w"`)
command.Args = append(command.Args, "-o", output)
command.Args = append(command.Args, filename)

err := command.Run(gctx.GetInitCtx())
t.AssertNil(err)

exists := gfile.Exists(output)
t.Assert(exists, true)

defer gfile.Remove(output)
})
}
124 changes: 124 additions & 0 deletions os/gproc/gproc_z_unit_shell_windows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// go test *.go -bench=".*" -benchmem

//go:build windows

package gproc_test

import (
"fmt"
"path/filepath"
"testing"

"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/test/gtest"
)

func Test_ShellExec_GoBuild_Windows(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
testPath := gtest.DataPath("gobuild")
filename := filepath.Join(testPath, "main.go")
output := filepath.Join(testPath, "main.exe")
cmd := fmt.Sprintf(`go build -ldflags="-s -w" -o %s %s`, output, filename)

err := gproc.ShellRun(gctx.New(), cmd)
t.Assert(err, nil)

exists := gfile.Exists(output)
t.Assert(exists, true)

defer gfile.Remove(output)
})

gtest.C(t, func(t *gtest.T) {
testPath := gtest.DataPath("gobuild")
filename := filepath.Join(testPath, "main.go")
output := filepath.Join(testPath, "main.exe")
cmd := fmt.Sprintf(`go build -ldflags="-X 'main.TestString=\"test string\"'" -o %s %s`, output, filename)

err := gproc.ShellRun(gctx.New(), cmd)
t.Assert(err, nil)

exists := gfile.Exists(output)
t.Assert(exists, true)
defer gfile.Remove(output)

result, err := gproc.ShellExec(gctx.New(), output)
t.Assert(err, nil)
t.Assert(result, `"test string"`)
})

}

func Test_ShellExec_SpaceDir_Windows(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
testPath := gtest.DataPath("shellexec")
filename := filepath.Join(testPath, "main.go")
// go build -o test.exe main.go
cmd := fmt.Sprintf(`go build -o test.exe %s`, filename)
r, err := gproc.ShellExec(gctx.New(), cmd)
t.AssertNil(err)
t.Assert(r, "")

exists := gfile.Exists(filename)
t.Assert(exists, true)

outputDir := filepath.Join(testPath, "testdir")
output := filepath.Join(outputDir, "test.exe")
err = gfile.Move("test.exe", output)
t.AssertNil(err)
defer gfile.Remove(output)

expectContent := "123"
testOutput := filepath.Join(testPath, "space dir", "test.txt")
cmd = fmt.Sprintf(`%s -c %s -o "%s"`, output, expectContent, testOutput)
r, err = gproc.ShellExec(gctx.New(), cmd)
t.AssertNil(err)

exists = gfile.Exists(testOutput)
t.Assert(exists, true)
defer gfile.Remove(testOutput)

contents := gfile.GetContents(testOutput)
t.Assert(contents, expectContent)
})
gtest.C(t, func(t *gtest.T) {
testPath := gtest.DataPath("shellexec")
filename := filepath.Join(testPath, "main.go")
// go build -o test.exe main.go
cmd := fmt.Sprintf(`go build -o test.exe %s`, filename)
r, err := gproc.ShellExec(gctx.New(), cmd)
t.AssertNil(err)
t.Assert(r, "")

exists := gfile.Exists(filename)
t.Assert(exists, true)

outputDir := filepath.Join(testPath, "space dir")
output := filepath.Join(outputDir, "test.exe")
err = gfile.Move("test.exe", output)
t.AssertNil(err)
defer gfile.Remove(output)

expectContent := "123"
testOutput := filepath.Join(testPath, "testdir", "test.txt")
cmd = fmt.Sprintf(`"%s" -c %s -o %s`, output, expectContent, testOutput)
r, err = gproc.ShellExec(gctx.New(), cmd)
t.AssertNil(err)

exists = gfile.Exists(testOutput)
t.Assert(exists, true)
defer gfile.Remove(testOutput)

contents := gfile.GetContents(testOutput)
t.Assert(contents, expectContent)

})
}
15 changes: 15 additions & 0 deletions os/gproc/testdata/gobuild/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package main

var (
TestString string
)

func main() {
print(TestString)
}
32 changes: 32 additions & 0 deletions os/gproc/testdata/shellexec/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package main

import (
"flag"
"fmt"
"os"
)

func main() {
var content string
var output string
flag.StringVar(&content, "c", "", "写入内容")
flag.StringVar(&output, "o", "", "写入路径")
flag.Parse()
fmt.Println(os.Args)
fmt.Println(content)
fmt.Println(output)
if output != "" {
file, err := os.Create(output)
if err != nil {
panic("create file fail: " + err.Error())
}
defer file.Close()
file.WriteString(content)
}
}
Loading