mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-02-03 13:21:56 +02:00
Provide a simple way to debug an integration test
This commit is contained in:
parent
28d12e4e5d
commit
b6c892a08a
12
.vscode/launch.json
vendored
12
.vscode/launch.json
vendored
@ -41,6 +41,18 @@
|
||||
"hideSystemGoroutines": true,
|
||||
"console": "integratedTerminal",
|
||||
},
|
||||
{
|
||||
// To use this, first start an integration test with the "cli" runner and
|
||||
// use the -debug option; e.g.
|
||||
// $ make integration-test-cli -- -debug tag/reset.go
|
||||
"name": "Attach to integration test runner",
|
||||
"type": "go",
|
||||
"request": "attach",
|
||||
"mode": "local",
|
||||
"processId": "test_lazygit",
|
||||
"hideSystemGoroutines": true,
|
||||
"console": "integratedTerminal",
|
||||
},
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
|
@ -38,6 +38,7 @@ func main() {
|
||||
testNames := os.Args[2:]
|
||||
slow := false
|
||||
sandbox := false
|
||||
waitForDebugger := false
|
||||
// get the next arg if it's --slow
|
||||
if len(os.Args) > 2 {
|
||||
if os.Args[2] == "--slow" || os.Args[2] == "-slow" {
|
||||
@ -46,10 +47,13 @@ func main() {
|
||||
} else if os.Args[2] == "--sandbox" || os.Args[2] == "-sandbox" {
|
||||
testNames = os.Args[3:]
|
||||
sandbox = true
|
||||
} else if os.Args[2] == "--debug" || os.Args[2] == "-debug" {
|
||||
testNames = os.Args[3:]
|
||||
waitForDebugger = true
|
||||
}
|
||||
}
|
||||
|
||||
clients.RunCLI(testNames, slow, sandbox)
|
||||
clients.RunCLI(testNames, slow, sandbox, waitForDebugger)
|
||||
case "tui":
|
||||
clients.RunTUI()
|
||||
default:
|
||||
|
1
go.mod
1
go.mod
@ -25,6 +25,7 @@ require (
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0
|
||||
github.com/mattn/go-runewidth v0.0.15
|
||||
github.com/mgutz/str v1.2.0
|
||||
github.com/mitchellh/go-ps v1.0.0
|
||||
github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/sahilm/fuzzy v0.1.0
|
||||
github.com/samber/lo v1.31.0
|
||||
|
2
go.sum
2
go.sum
@ -230,6 +230,8 @@ github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=
|
||||
github.com/mgutz/str v1.2.0/go.mod h1:w1v0ofgLaJdoD0HpQ3fycxKD1WtxpjSo151pK/31q6w=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
||||
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
|
@ -61,6 +61,15 @@ If you've opened an integration test file in your editor you can run that file b
|
||||
The test will run in a VSCode terminal:
|
||||
![image](https://user-images.githubusercontent.com/8456633/201500446-b87abf11-9653-438f-8a9a-e0bf8abdb7ee.png)
|
||||
|
||||
### Debugging tests
|
||||
|
||||
Debugging an integration test is possible in two ways:
|
||||
|
||||
1. Use the -debug option of the integration test runner's "cli" command, e.g. `go run cmd/integration_test/main.go cli -debug tag/reset.go`
|
||||
2. Select a test in the "tui" runner and hit "d" to debug it.
|
||||
|
||||
In both cases the test runner will print to the console that it is waiting for a debugger to attach, so now you need to tell your debugger to attach to a running process with the name "test_lazygit". If you are using Visual Studio Code, an easy way to do that is to use the "Attach to integration test runner" debug configuration. The test runner will resume automatically when it detects that a debugger was attached. Don't forget to set a breakpoint in the code that you want to step through, otherwise the test will just finish (i.e. it doesn't stop in the debugger automatically).
|
||||
|
||||
### Sandbox mode
|
||||
|
||||
Say you want to do a manual test of how lazygit handles merge-conflicts, but you can't be bothered actually finding a way to create merge conflicts in a repo. To make your life easier, you can simply run a merge-conflicts test in sandbox mode, meaning the setup step is run for you, and then instead of the test driving the lazygit session, you're allowed to drive it yourself.
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
|
||||
// If invoked directly, you can specify tests to run by passing their names as positional arguments
|
||||
|
||||
func RunCLI(testNames []string, slow bool, sandbox bool) {
|
||||
func RunCLI(testNames []string, slow bool, sandbox bool, waitForDebugger bool) {
|
||||
inputDelay := tryConvert(os.Getenv("INPUT_DELAY"), 0)
|
||||
if slow {
|
||||
inputDelay = SLOW_INPUT_DELAY
|
||||
@ -35,6 +35,7 @@ func RunCLI(testNames []string, slow bool, sandbox bool) {
|
||||
runCmdInTerminal,
|
||||
runAndPrintFatalError,
|
||||
sandbox,
|
||||
waitForDebugger,
|
||||
inputDelay,
|
||||
1,
|
||||
)
|
||||
|
@ -52,6 +52,7 @@ func TestIntegration(t *testing.T) {
|
||||
})
|
||||
},
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
// Allow two attempts at each test to get around flakiness
|
||||
2,
|
||||
|
@ -3,12 +3,14 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/app"
|
||||
"github.com/jesseduffield/lazygit/pkg/app/daemon"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/tests"
|
||||
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
|
||||
"github.com/mitchellh/go-ps"
|
||||
)
|
||||
|
||||
// The purpose of this program is to run lazygit with an integration test passed in.
|
||||
@ -29,6 +31,15 @@ func main() {
|
||||
|
||||
integrationTest := getIntegrationTest()
|
||||
|
||||
if os.Getenv("WAIT_FOR_DEBUGGER") != "" {
|
||||
println("Waiting for debugger to attach...")
|
||||
for !isDebuggerAttached() {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
|
||||
println("Debugger attached, continuing")
|
||||
}
|
||||
|
||||
app.Start(dummyBuildInfo, integrationTest)
|
||||
}
|
||||
|
||||
@ -56,3 +67,21 @@ func getIntegrationTest() integrationTypes.IntegrationTest {
|
||||
|
||||
panic("Could not find integration test with name: " + integrationTestName)
|
||||
}
|
||||
|
||||
// Returns whether we are running under a debugger. It uses a heuristic to find
|
||||
// out: when using dlv, it starts a debugserver executable (which is part of
|
||||
// lldb), and the debuggee becomes a child process of that. So if the name of
|
||||
// our parent process is "debugserver", we run under a debugger. This works even
|
||||
// if the parent process used to be the shell and you then attach to the running
|
||||
// executable.
|
||||
//
|
||||
// On Mac this works with VS Code, with the Jetbrains Goland IDE, and when using
|
||||
// dlv attach in a terminal. I have not been able to verify that it works on
|
||||
// other platforms, it may have to be adapted there.
|
||||
func isDebuggerAttached() bool {
|
||||
process, err := ps.FindProcess(os.Getppid())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return process.Executable() == "debugserver"
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ func RunTUI() {
|
||||
return nil
|
||||
}
|
||||
|
||||
suspendAndRunTest(currentTest, true, 0)
|
||||
suspendAndRunTest(currentTest, true, false, 0)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
@ -98,7 +98,7 @@ func RunTUI() {
|
||||
return nil
|
||||
}
|
||||
|
||||
suspendAndRunTest(currentTest, false, 0)
|
||||
suspendAndRunTest(currentTest, false, false, 0)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
@ -111,7 +111,20 @@ func RunTUI() {
|
||||
return nil
|
||||
}
|
||||
|
||||
suspendAndRunTest(currentTest, false, SLOW_INPUT_DELAY)
|
||||
suspendAndRunTest(currentTest, false, false, SLOW_INPUT_DELAY)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 'd', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
suspendAndRunTest(currentTest, false, true, 0)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
@ -271,12 +284,12 @@ func (self *app) wrapEditor(f func(v *gocui.View, key gocui.Key, ch rune, mod go
|
||||
}
|
||||
}
|
||||
|
||||
func suspendAndRunTest(test *components.IntegrationTest, sandbox bool, inputDelay int) {
|
||||
func suspendAndRunTest(test *components.IntegrationTest, sandbox bool, waitForDebugger bool, inputDelay int) {
|
||||
if err := gocui.Screen.Suspend(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
runTuiTest(test, sandbox, inputDelay)
|
||||
runTuiTest(test, sandbox, waitForDebugger, inputDelay)
|
||||
|
||||
fmt.Fprintf(os.Stdout, "\n%s", style.FgGreen.Sprint("press enter to return"))
|
||||
fmt.Scanln() // wait for enter press
|
||||
@ -337,7 +350,7 @@ func (self *app) layout(g *gocui.Gui) error {
|
||||
keybindingsView.Title = "Keybindings"
|
||||
keybindingsView.Wrap = true
|
||||
keybindingsView.FgColor = gocui.ColorDefault
|
||||
fmt.Fprintln(keybindingsView, "up/down: navigate, enter: run test, t: run test slow, s: sandbox, o: open test file, shift+o: open test snapshot directory, forward-slash: filter")
|
||||
fmt.Fprintln(keybindingsView, "up/down: navigate, enter: run test, t: run test slow, s: sandbox, d: debug test, o: open test file, shift+o: open test snapshot directory, forward-slash: filter")
|
||||
}
|
||||
|
||||
editorView, err := g.SetViewBeneath("editor", "keybindings", editorViewHeight)
|
||||
@ -371,13 +384,14 @@ func quit(g *gocui.Gui, v *gocui.View) error {
|
||||
return gocui.ErrQuit
|
||||
}
|
||||
|
||||
func runTuiTest(test *components.IntegrationTest, sandbox bool, inputDelay int) {
|
||||
func runTuiTest(test *components.IntegrationTest, sandbox bool, waitForDebugger bool, inputDelay int) {
|
||||
err := components.RunTests(
|
||||
[]*components.IntegrationTest{test},
|
||||
log.Printf,
|
||||
runCmdInTerminal,
|
||||
runAndPrintError,
|
||||
sandbox,
|
||||
waitForDebugger,
|
||||
inputDelay,
|
||||
1,
|
||||
)
|
||||
|
@ -29,6 +29,7 @@ func RunTests(
|
||||
runCmd func(cmd *exec.Cmd) error,
|
||||
testWrapper func(test *IntegrationTest, f func() error),
|
||||
sandbox bool,
|
||||
waitForDebugger bool,
|
||||
inputDelay int,
|
||||
maxAttempts int,
|
||||
) error {
|
||||
@ -58,7 +59,7 @@ func RunTests(
|
||||
)
|
||||
|
||||
for i := 0; i < maxAttempts; i++ {
|
||||
err := runTest(test, paths, projectRootDir, logf, runCmd, sandbox, inputDelay, gitVersion)
|
||||
err := runTest(test, paths, projectRootDir, logf, runCmd, sandbox, waitForDebugger, inputDelay, gitVersion)
|
||||
if err != nil {
|
||||
if i == maxAttempts-1 {
|
||||
return err
|
||||
@ -83,6 +84,7 @@ func runTest(
|
||||
logf func(format string, formatArgs ...interface{}),
|
||||
runCmd func(cmd *exec.Cmd) error,
|
||||
sandbox bool,
|
||||
waitForDebugger bool,
|
||||
inputDelay int,
|
||||
gitVersion *git_commands.GitVersion,
|
||||
) error {
|
||||
@ -100,7 +102,7 @@ func runTest(
|
||||
return err
|
||||
}
|
||||
|
||||
cmd, err := getLazygitCommand(test, paths, projectRootDir, sandbox, inputDelay)
|
||||
cmd, err := getLazygitCommand(test, paths, projectRootDir, sandbox, waitForDebugger, inputDelay)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -165,7 +167,7 @@ func getGitVersion() (*git_commands.GitVersion, error) {
|
||||
return git_commands.ParseGitVersion(versionStr)
|
||||
}
|
||||
|
||||
func getLazygitCommand(test *IntegrationTest, paths Paths, rootDir string, sandbox bool, inputDelay int) (*exec.Cmd, error) {
|
||||
func getLazygitCommand(test *IntegrationTest, paths Paths, rootDir string, sandbox bool, waitForDebugger bool, inputDelay int) (*exec.Cmd, error) {
|
||||
osCommand := oscommands.NewDummyOSCommand()
|
||||
|
||||
err := os.RemoveAll(paths.Config())
|
||||
@ -197,6 +199,9 @@ func getLazygitCommand(test *IntegrationTest, paths Paths, rootDir string, sandb
|
||||
if sandbox {
|
||||
cmdObj.AddEnvVars(fmt.Sprintf("%s=%s", SANDBOX_ENV_VAR, "true"))
|
||||
}
|
||||
if waitForDebugger {
|
||||
cmdObj.AddEnvVars("WAIT_FOR_DEBUGGER=true")
|
||||
}
|
||||
if test.ExtraEnvVars() != nil {
|
||||
for key, value := range test.ExtraEnvVars() {
|
||||
cmdObj.AddEnvVars(fmt.Sprintf("%s=%s", key, value))
|
||||
|
1
vendor/github.com/mitchellh/go-ps/.gitignore
generated
vendored
Normal file
1
vendor/github.com/mitchellh/go-ps/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
.vagrant/
|
21
vendor/github.com/mitchellh/go-ps/LICENSE.md
generated
vendored
Normal file
21
vendor/github.com/mitchellh/go-ps/LICENSE.md
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Mitchell Hashimoto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
34
vendor/github.com/mitchellh/go-ps/README.md
generated
vendored
Normal file
34
vendor/github.com/mitchellh/go-ps/README.md
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
# Process List Library for Go [![GoDoc](https://godoc.org/github.com/mitchellh/go-ps?status.png)](https://godoc.org/github.com/mitchellh/go-ps)
|
||||
|
||||
go-ps is a library for Go that implements OS-specific APIs to list and
|
||||
manipulate processes in a platform-safe way. The library can find and
|
||||
list processes on Linux, Mac OS X, Solaris, and Windows.
|
||||
|
||||
If you're new to Go, this library has a good amount of advanced Go educational
|
||||
value as well. It uses some advanced features of Go: build tags, accessing
|
||||
DLL methods for Windows, cgo for Darwin, etc.
|
||||
|
||||
How it works:
|
||||
|
||||
* **Darwin** uses the `sysctl` syscall to retrieve the process table.
|
||||
* **Unix** uses the procfs at `/proc` to inspect the process tree.
|
||||
* **Windows** uses the Windows API, and methods such as
|
||||
`CreateToolhelp32Snapshot` to get a point-in-time snapshot of
|
||||
the process table.
|
||||
|
||||
## Installation
|
||||
|
||||
Install using standard `go get`:
|
||||
|
||||
```
|
||||
$ go get github.com/mitchellh/go-ps
|
||||
...
|
||||
```
|
||||
|
||||
## TODO
|
||||
|
||||
Want to contribute? Here is a short TODO list of things that aren't
|
||||
implemented for this library that would be nice:
|
||||
|
||||
* FreeBSD support
|
||||
* Plan9 support
|
43
vendor/github.com/mitchellh/go-ps/Vagrantfile
generated
vendored
Normal file
43
vendor/github.com/mitchellh/go-ps/Vagrantfile
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
|
||||
VAGRANTFILE_API_VERSION = "2"
|
||||
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
config.vm.box = "chef/ubuntu-12.04"
|
||||
|
||||
config.vm.provision "shell", inline: $script
|
||||
|
||||
["vmware_fusion", "vmware_workstation"].each do |p|
|
||||
config.vm.provider "p" do |v|
|
||||
v.vmx["memsize"] = "1024"
|
||||
v.vmx["numvcpus"] = "2"
|
||||
v.vmx["cpuid.coresPerSocket"] = "1"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
$script = <<SCRIPT
|
||||
SRCROOT="/opt/go"
|
||||
|
||||
# Install Go
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential mercurial
|
||||
sudo hg clone -u release https://code.google.com/p/go ${SRCROOT}
|
||||
cd ${SRCROOT}/src
|
||||
sudo ./all.bash
|
||||
|
||||
# Setup the GOPATH
|
||||
sudo mkdir -p /opt/gopath
|
||||
cat <<EOF >/tmp/gopath.sh
|
||||
export GOPATH="/opt/gopath"
|
||||
export PATH="/opt/go/bin:\$GOPATH/bin:\$PATH"
|
||||
EOF
|
||||
sudo mv /tmp/gopath.sh /etc/profile.d/gopath.sh
|
||||
sudo chmod 0755 /etc/profile.d/gopath.sh
|
||||
|
||||
# Make sure the gopath is usable by bamboo
|
||||
sudo chown -R vagrant:vagrant $SRCROOT
|
||||
sudo chown -R vagrant:vagrant /opt/gopath
|
||||
SCRIPT
|
40
vendor/github.com/mitchellh/go-ps/process.go
generated
vendored
Normal file
40
vendor/github.com/mitchellh/go-ps/process.go
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
// ps provides an API for finding and listing processes in a platform-agnostic
|
||||
// way.
|
||||
//
|
||||
// NOTE: If you're reading these docs online via GoDocs or some other system,
|
||||
// you might only see the Unix docs. This project makes heavy use of
|
||||
// platform-specific implementations. We recommend reading the source if you
|
||||
// are interested.
|
||||
package ps
|
||||
|
||||
// Process is the generic interface that is implemented on every platform
|
||||
// and provides common operations for processes.
|
||||
type Process interface {
|
||||
// Pid is the process ID for this process.
|
||||
Pid() int
|
||||
|
||||
// PPid is the parent process ID for this process.
|
||||
PPid() int
|
||||
|
||||
// Executable name running this process. This is not a path to the
|
||||
// executable.
|
||||
Executable() string
|
||||
}
|
||||
|
||||
// Processes returns all processes.
|
||||
//
|
||||
// This of course will be a point-in-time snapshot of when this method was
|
||||
// called. Some operating systems don't provide snapshot capability of the
|
||||
// process table, in which case the process table returned might contain
|
||||
// ephemeral entities that happened to be running when this was called.
|
||||
func Processes() ([]Process, error) {
|
||||
return processes()
|
||||
}
|
||||
|
||||
// FindProcess looks up a single process by pid.
|
||||
//
|
||||
// Process will be nil and error will be nil if a matching process is
|
||||
// not found.
|
||||
func FindProcess(pid int) (Process, error) {
|
||||
return findProcess(pid)
|
||||
}
|
138
vendor/github.com/mitchellh/go-ps/process_darwin.go
generated
vendored
Normal file
138
vendor/github.com/mitchellh/go-ps/process_darwin.go
generated
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
// +build darwin
|
||||
|
||||
package ps
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type DarwinProcess struct {
|
||||
pid int
|
||||
ppid int
|
||||
binary string
|
||||
}
|
||||
|
||||
func (p *DarwinProcess) Pid() int {
|
||||
return p.pid
|
||||
}
|
||||
|
||||
func (p *DarwinProcess) PPid() int {
|
||||
return p.ppid
|
||||
}
|
||||
|
||||
func (p *DarwinProcess) Executable() string {
|
||||
return p.binary
|
||||
}
|
||||
|
||||
func findProcess(pid int) (Process, error) {
|
||||
ps, err := processes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, p := range ps {
|
||||
if p.Pid() == pid {
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func processes() ([]Process, error) {
|
||||
buf, err := darwinSyscall()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
procs := make([]*kinfoProc, 0, 50)
|
||||
k := 0
|
||||
for i := _KINFO_STRUCT_SIZE; i < buf.Len(); i += _KINFO_STRUCT_SIZE {
|
||||
proc := &kinfoProc{}
|
||||
err = binary.Read(bytes.NewBuffer(buf.Bytes()[k:i]), binary.LittleEndian, proc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
k = i
|
||||
procs = append(procs, proc)
|
||||
}
|
||||
|
||||
darwinProcs := make([]Process, len(procs))
|
||||
for i, p := range procs {
|
||||
darwinProcs[i] = &DarwinProcess{
|
||||
pid: int(p.Pid),
|
||||
ppid: int(p.PPid),
|
||||
binary: darwinCstring(p.Comm),
|
||||
}
|
||||
}
|
||||
|
||||
return darwinProcs, nil
|
||||
}
|
||||
|
||||
func darwinCstring(s [16]byte) string {
|
||||
i := 0
|
||||
for _, b := range s {
|
||||
if b != 0 {
|
||||
i++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return string(s[:i])
|
||||
}
|
||||
|
||||
func darwinSyscall() (*bytes.Buffer, error) {
|
||||
mib := [4]int32{_CTRL_KERN, _KERN_PROC, _KERN_PROC_ALL, 0}
|
||||
size := uintptr(0)
|
||||
|
||||
_, _, errno := syscall.Syscall6(
|
||||
syscall.SYS___SYSCTL,
|
||||
uintptr(unsafe.Pointer(&mib[0])),
|
||||
4,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&size)),
|
||||
0,
|
||||
0)
|
||||
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
bs := make([]byte, size)
|
||||
_, _, errno = syscall.Syscall6(
|
||||
syscall.SYS___SYSCTL,
|
||||
uintptr(unsafe.Pointer(&mib[0])),
|
||||
4,
|
||||
uintptr(unsafe.Pointer(&bs[0])),
|
||||
uintptr(unsafe.Pointer(&size)),
|
||||
0,
|
||||
0)
|
||||
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
return bytes.NewBuffer(bs[0:size]), nil
|
||||
}
|
||||
|
||||
const (
|
||||
_CTRL_KERN = 1
|
||||
_KERN_PROC = 14
|
||||
_KERN_PROC_ALL = 0
|
||||
_KINFO_STRUCT_SIZE = 648
|
||||
)
|
||||
|
||||
type kinfoProc struct {
|
||||
_ [40]byte
|
||||
Pid int32
|
||||
_ [199]byte
|
||||
Comm [16]byte
|
||||
_ [301]byte
|
||||
PPid int32
|
||||
_ [84]byte
|
||||
}
|
260
vendor/github.com/mitchellh/go-ps/process_freebsd.go
generated
vendored
Normal file
260
vendor/github.com/mitchellh/go-ps/process_freebsd.go
generated
vendored
Normal file
@ -0,0 +1,260 @@
|
||||
// +build freebsd
|
||||
|
||||
package ps
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// copied from sys/sysctl.h
|
||||
const (
|
||||
CTL_KERN = 1 // "high kernel": proc, limits
|
||||
KERN_PROC = 14 // struct: process entries
|
||||
KERN_PROC_PID = 1 // by process id
|
||||
KERN_PROC_PROC = 8 // only return procs
|
||||
KERN_PROC_PATHNAME = 12 // path to executable
|
||||
)
|
||||
|
||||
// copied from sys/user.h
|
||||
type Kinfo_proc struct {
|
||||
Ki_structsize int32
|
||||
Ki_layout int32
|
||||
Ki_args int64
|
||||
Ki_paddr int64
|
||||
Ki_addr int64
|
||||
Ki_tracep int64
|
||||
Ki_textvp int64
|
||||
Ki_fd int64
|
||||
Ki_vmspace int64
|
||||
Ki_wchan int64
|
||||
Ki_pid int32
|
||||
Ki_ppid int32
|
||||
Ki_pgid int32
|
||||
Ki_tpgid int32
|
||||
Ki_sid int32
|
||||
Ki_tsid int32
|
||||
Ki_jobc [2]byte
|
||||
Ki_spare_short1 [2]byte
|
||||
Ki_tdev int32
|
||||
Ki_siglist [16]byte
|
||||
Ki_sigmask [16]byte
|
||||
Ki_sigignore [16]byte
|
||||
Ki_sigcatch [16]byte
|
||||
Ki_uid int32
|
||||
Ki_ruid int32
|
||||
Ki_svuid int32
|
||||
Ki_rgid int32
|
||||
Ki_svgid int32
|
||||
Ki_ngroups [2]byte
|
||||
Ki_spare_short2 [2]byte
|
||||
Ki_groups [64]byte
|
||||
Ki_size int64
|
||||
Ki_rssize int64
|
||||
Ki_swrss int64
|
||||
Ki_tsize int64
|
||||
Ki_dsize int64
|
||||
Ki_ssize int64
|
||||
Ki_xstat [2]byte
|
||||
Ki_acflag [2]byte
|
||||
Ki_pctcpu int32
|
||||
Ki_estcpu int32
|
||||
Ki_slptime int32
|
||||
Ki_swtime int32
|
||||
Ki_cow int32
|
||||
Ki_runtime int64
|
||||
Ki_start [16]byte
|
||||
Ki_childtime [16]byte
|
||||
Ki_flag int64
|
||||
Ki_kiflag int64
|
||||
Ki_traceflag int32
|
||||
Ki_stat [1]byte
|
||||
Ki_nice [1]byte
|
||||
Ki_lock [1]byte
|
||||
Ki_rqindex [1]byte
|
||||
Ki_oncpu [1]byte
|
||||
Ki_lastcpu [1]byte
|
||||
Ki_ocomm [17]byte
|
||||
Ki_wmesg [9]byte
|
||||
Ki_login [18]byte
|
||||
Ki_lockname [9]byte
|
||||
Ki_comm [20]byte
|
||||
Ki_emul [17]byte
|
||||
Ki_sparestrings [68]byte
|
||||
Ki_spareints [36]byte
|
||||
Ki_cr_flags int32
|
||||
Ki_jid int32
|
||||
Ki_numthreads int32
|
||||
Ki_tid int32
|
||||
Ki_pri int32
|
||||
Ki_rusage [144]byte
|
||||
Ki_rusage_ch [144]byte
|
||||
Ki_pcb int64
|
||||
Ki_kstack int64
|
||||
Ki_udata int64
|
||||
Ki_tdaddr int64
|
||||
Ki_spareptrs [48]byte
|
||||
Ki_spareint64s [96]byte
|
||||
Ki_sflag int64
|
||||
Ki_tdflags int64
|
||||
}
|
||||
|
||||
// UnixProcess is an implementation of Process that contains Unix-specific
|
||||
// fields and information.
|
||||
type UnixProcess struct {
|
||||
pid int
|
||||
ppid int
|
||||
state rune
|
||||
pgrp int
|
||||
sid int
|
||||
|
||||
binary string
|
||||
}
|
||||
|
||||
func (p *UnixProcess) Pid() int {
|
||||
return p.pid
|
||||
}
|
||||
|
||||
func (p *UnixProcess) PPid() int {
|
||||
return p.ppid
|
||||
}
|
||||
|
||||
func (p *UnixProcess) Executable() string {
|
||||
return p.binary
|
||||
}
|
||||
|
||||
// Refresh reloads all the data associated with this process.
|
||||
func (p *UnixProcess) Refresh() error {
|
||||
|
||||
mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PID, int32(p.pid)}
|
||||
|
||||
buf, length, err := call_syscall(mib)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
proc_k := Kinfo_proc{}
|
||||
if length != uint64(unsafe.Sizeof(proc_k)) {
|
||||
return err
|
||||
}
|
||||
|
||||
k, err := parse_kinfo_proc(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.ppid, p.pgrp, p.sid, p.binary = copy_params(&k)
|
||||
return nil
|
||||
}
|
||||
|
||||
func copy_params(k *Kinfo_proc) (int, int, int, string) {
|
||||
n := -1
|
||||
for i, b := range k.Ki_comm {
|
||||
if b == 0 {
|
||||
break
|
||||
}
|
||||
n = i + 1
|
||||
}
|
||||
comm := string(k.Ki_comm[:n])
|
||||
|
||||
return int(k.Ki_ppid), int(k.Ki_pgid), int(k.Ki_sid), comm
|
||||
}
|
||||
|
||||
func findProcess(pid int) (Process, error) {
|
||||
mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, int32(pid)}
|
||||
|
||||
_, _, err := call_syscall(mib)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newUnixProcess(pid)
|
||||
}
|
||||
|
||||
func processes() ([]Process, error) {
|
||||
results := make([]Process, 0, 50)
|
||||
|
||||
mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0}
|
||||
buf, length, err := call_syscall(mib)
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
|
||||
// get kinfo_proc size
|
||||
k := Kinfo_proc{}
|
||||
procinfo_len := int(unsafe.Sizeof(k))
|
||||
count := int(length / uint64(procinfo_len))
|
||||
|
||||
// parse buf to procs
|
||||
for i := 0; i < count; i++ {
|
||||
b := buf[i*procinfo_len : i*procinfo_len+procinfo_len]
|
||||
k, err := parse_kinfo_proc(b)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
p, err := newUnixProcess(int(k.Ki_pid))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
p.ppid, p.pgrp, p.sid, p.binary = copy_params(&k)
|
||||
|
||||
results = append(results, p)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func parse_kinfo_proc(buf []byte) (Kinfo_proc, error) {
|
||||
var k Kinfo_proc
|
||||
br := bytes.NewReader(buf)
|
||||
err := binary.Read(br, binary.LittleEndian, &k)
|
||||
if err != nil {
|
||||
return k, err
|
||||
}
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
||||
func call_syscall(mib []int32) ([]byte, uint64, error) {
|
||||
miblen := uint64(len(mib))
|
||||
|
||||
// get required buffer size
|
||||
length := uint64(0)
|
||||
_, _, err := syscall.RawSyscall6(
|
||||
syscall.SYS___SYSCTL,
|
||||
uintptr(unsafe.Pointer(&mib[0])),
|
||||
uintptr(miblen),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&length)),
|
||||
0,
|
||||
0)
|
||||
if err != 0 {
|
||||
b := make([]byte, 0)
|
||||
return b, length, err
|
||||
}
|
||||
if length == 0 {
|
||||
b := make([]byte, 0)
|
||||
return b, length, err
|
||||
}
|
||||
// get proc info itself
|
||||
buf := make([]byte, length)
|
||||
_, _, err = syscall.RawSyscall6(
|
||||
syscall.SYS___SYSCTL,
|
||||
uintptr(unsafe.Pointer(&mib[0])),
|
||||
uintptr(miblen),
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
uintptr(unsafe.Pointer(&length)),
|
||||
0,
|
||||
0)
|
||||
if err != 0 {
|
||||
return buf, length, err
|
||||
}
|
||||
|
||||
return buf, length, nil
|
||||
}
|
||||
|
||||
func newUnixProcess(pid int) (*UnixProcess, error) {
|
||||
p := &UnixProcess{pid: pid}
|
||||
return p, p.Refresh()
|
||||
}
|
35
vendor/github.com/mitchellh/go-ps/process_linux.go
generated
vendored
Normal file
35
vendor/github.com/mitchellh/go-ps/process_linux.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
// +build linux
|
||||
|
||||
package ps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Refresh reloads all the data associated with this process.
|
||||
func (p *UnixProcess) Refresh() error {
|
||||
statPath := fmt.Sprintf("/proc/%d/stat", p.pid)
|
||||
dataBytes, err := ioutil.ReadFile(statPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// First, parse out the image name
|
||||
data := string(dataBytes)
|
||||
binStart := strings.IndexRune(data, '(') + 1
|
||||
binEnd := strings.IndexRune(data[binStart:], ')')
|
||||
p.binary = data[binStart : binStart+binEnd]
|
||||
|
||||
// Move past the image name and start parsing the rest
|
||||
data = data[binStart+binEnd+2:]
|
||||
_, err = fmt.Sscanf(data,
|
||||
"%c %d %d %d",
|
||||
&p.state,
|
||||
&p.ppid,
|
||||
&p.pgrp,
|
||||
&p.sid)
|
||||
|
||||
return err
|
||||
}
|
96
vendor/github.com/mitchellh/go-ps/process_solaris.go
generated
vendored
Normal file
96
vendor/github.com/mitchellh/go-ps/process_solaris.go
generated
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
// +build solaris
|
||||
|
||||
package ps
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type ushort_t uint16
|
||||
|
||||
type id_t int32
|
||||
type pid_t int32
|
||||
type uid_t int32
|
||||
type gid_t int32
|
||||
|
||||
type dev_t uint64
|
||||
type size_t uint64
|
||||
type uintptr_t uint64
|
||||
|
||||
type timestruc_t [16]byte
|
||||
|
||||
// This is copy from /usr/include/sys/procfs.h
|
||||
type psinfo_t struct {
|
||||
Pr_flag int32 /* process flags (DEPRECATED; do not use) */
|
||||
Pr_nlwp int32 /* number of active lwps in the process */
|
||||
Pr_pid pid_t /* unique process id */
|
||||
Pr_ppid pid_t /* process id of parent */
|
||||
Pr_pgid pid_t /* pid of process group leader */
|
||||
Pr_sid pid_t /* session id */
|
||||
Pr_uid uid_t /* real user id */
|
||||
Pr_euid uid_t /* effective user id */
|
||||
Pr_gid gid_t /* real group id */
|
||||
Pr_egid gid_t /* effective group id */
|
||||
Pr_addr uintptr_t /* address of process */
|
||||
Pr_size size_t /* size of process image in Kbytes */
|
||||
Pr_rssize size_t /* resident set size in Kbytes */
|
||||
Pr_pad1 size_t
|
||||
Pr_ttydev dev_t /* controlling tty device (or PRNODEV) */
|
||||
|
||||
// Guess this following 2 ushort_t values require a padding to properly
|
||||
// align to the 64bit mark.
|
||||
Pr_pctcpu ushort_t /* % of recent cpu time used by all lwps */
|
||||
Pr_pctmem ushort_t /* % of system memory used by process */
|
||||
Pr_pad64bit [4]byte
|
||||
|
||||
Pr_start timestruc_t /* process start time, from the epoch */
|
||||
Pr_time timestruc_t /* usr+sys cpu time for this process */
|
||||
Pr_ctime timestruc_t /* usr+sys cpu time for reaped children */
|
||||
Pr_fname [16]byte /* name of execed file */
|
||||
Pr_psargs [80]byte /* initial characters of arg list */
|
||||
Pr_wstat int32 /* if zombie, the wait() status */
|
||||
Pr_argc int32 /* initial argument count */
|
||||
Pr_argv uintptr_t /* address of initial argument vector */
|
||||
Pr_envp uintptr_t /* address of initial environment vector */
|
||||
Pr_dmodel [1]byte /* data model of the process */
|
||||
Pr_pad2 [3]byte
|
||||
Pr_taskid id_t /* task id */
|
||||
Pr_projid id_t /* project id */
|
||||
Pr_nzomb int32 /* number of zombie lwps in the process */
|
||||
Pr_poolid id_t /* pool id */
|
||||
Pr_zoneid id_t /* zone id */
|
||||
Pr_contract id_t /* process contract */
|
||||
Pr_filler int32 /* reserved for future use */
|
||||
Pr_lwp [128]byte /* information for representative lwp */
|
||||
}
|
||||
|
||||
func (p *UnixProcess) Refresh() error {
|
||||
var psinfo psinfo_t
|
||||
|
||||
path := fmt.Sprintf("/proc/%d/psinfo", p.pid)
|
||||
fh, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fh.Close()
|
||||
|
||||
err = binary.Read(fh, binary.LittleEndian, &psinfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.ppid = int(psinfo.Pr_ppid)
|
||||
p.binary = toString(psinfo.Pr_fname[:], 16)
|
||||
return nil
|
||||
}
|
||||
|
||||
func toString(array []byte, len int) string {
|
||||
for i := 0; i < len; i++ {
|
||||
if array[i] == 0 {
|
||||
return string(array[:i])
|
||||
}
|
||||
}
|
||||
return string(array[:])
|
||||
}
|
95
vendor/github.com/mitchellh/go-ps/process_unix.go
generated
vendored
Normal file
95
vendor/github.com/mitchellh/go-ps/process_unix.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
// +build linux solaris
|
||||
|
||||
package ps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// UnixProcess is an implementation of Process that contains Unix-specific
|
||||
// fields and information.
|
||||
type UnixProcess struct {
|
||||
pid int
|
||||
ppid int
|
||||
state rune
|
||||
pgrp int
|
||||
sid int
|
||||
|
||||
binary string
|
||||
}
|
||||
|
||||
func (p *UnixProcess) Pid() int {
|
||||
return p.pid
|
||||
}
|
||||
|
||||
func (p *UnixProcess) PPid() int {
|
||||
return p.ppid
|
||||
}
|
||||
|
||||
func (p *UnixProcess) Executable() string {
|
||||
return p.binary
|
||||
}
|
||||
|
||||
func findProcess(pid int) (Process, error) {
|
||||
dir := fmt.Sprintf("/proc/%d", pid)
|
||||
_, err := os.Stat(dir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newUnixProcess(pid)
|
||||
}
|
||||
|
||||
func processes() ([]Process, error) {
|
||||
d, err := os.Open("/proc")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
results := make([]Process, 0, 50)
|
||||
for {
|
||||
names, err := d.Readdirnames(10)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
// We only care if the name starts with a numeric
|
||||
if name[0] < '0' || name[0] > '9' {
|
||||
continue
|
||||
}
|
||||
|
||||
// From this point forward, any errors we just ignore, because
|
||||
// it might simply be that the process doesn't exist anymore.
|
||||
pid, err := strconv.ParseInt(name, 10, 0)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
p, err := newUnixProcess(int(pid))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
results = append(results, p)
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func newUnixProcess(pid int) (*UnixProcess, error) {
|
||||
p := &UnixProcess{pid: pid}
|
||||
return p, p.Refresh()
|
||||
}
|
119
vendor/github.com/mitchellh/go-ps/process_windows.go
generated
vendored
Normal file
119
vendor/github.com/mitchellh/go-ps/process_windows.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
// +build windows
|
||||
|
||||
package ps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Windows API functions
|
||||
var (
|
||||
modKernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
procCloseHandle = modKernel32.NewProc("CloseHandle")
|
||||
procCreateToolhelp32Snapshot = modKernel32.NewProc("CreateToolhelp32Snapshot")
|
||||
procProcess32First = modKernel32.NewProc("Process32FirstW")
|
||||
procProcess32Next = modKernel32.NewProc("Process32NextW")
|
||||
)
|
||||
|
||||
// Some constants from the Windows API
|
||||
const (
|
||||
ERROR_NO_MORE_FILES = 0x12
|
||||
MAX_PATH = 260
|
||||
)
|
||||
|
||||
// PROCESSENTRY32 is the Windows API structure that contains a process's
|
||||
// information.
|
||||
type PROCESSENTRY32 struct {
|
||||
Size uint32
|
||||
CntUsage uint32
|
||||
ProcessID uint32
|
||||
DefaultHeapID uintptr
|
||||
ModuleID uint32
|
||||
CntThreads uint32
|
||||
ParentProcessID uint32
|
||||
PriorityClassBase int32
|
||||
Flags uint32
|
||||
ExeFile [MAX_PATH]uint16
|
||||
}
|
||||
|
||||
// WindowsProcess is an implementation of Process for Windows.
|
||||
type WindowsProcess struct {
|
||||
pid int
|
||||
ppid int
|
||||
exe string
|
||||
}
|
||||
|
||||
func (p *WindowsProcess) Pid() int {
|
||||
return p.pid
|
||||
}
|
||||
|
||||
func (p *WindowsProcess) PPid() int {
|
||||
return p.ppid
|
||||
}
|
||||
|
||||
func (p *WindowsProcess) Executable() string {
|
||||
return p.exe
|
||||
}
|
||||
|
||||
func newWindowsProcess(e *PROCESSENTRY32) *WindowsProcess {
|
||||
// Find when the string ends for decoding
|
||||
end := 0
|
||||
for {
|
||||
if e.ExeFile[end] == 0 {
|
||||
break
|
||||
}
|
||||
end++
|
||||
}
|
||||
|
||||
return &WindowsProcess{
|
||||
pid: int(e.ProcessID),
|
||||
ppid: int(e.ParentProcessID),
|
||||
exe: syscall.UTF16ToString(e.ExeFile[:end]),
|
||||
}
|
||||
}
|
||||
|
||||
func findProcess(pid int) (Process, error) {
|
||||
ps, err := processes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, p := range ps {
|
||||
if p.Pid() == pid {
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func processes() ([]Process, error) {
|
||||
handle, _, _ := procCreateToolhelp32Snapshot.Call(
|
||||
0x00000002,
|
||||
0)
|
||||
if handle < 0 {
|
||||
return nil, syscall.GetLastError()
|
||||
}
|
||||
defer procCloseHandle.Call(handle)
|
||||
|
||||
var entry PROCESSENTRY32
|
||||
entry.Size = uint32(unsafe.Sizeof(entry))
|
||||
ret, _, _ := procProcess32First.Call(handle, uintptr(unsafe.Pointer(&entry)))
|
||||
if ret == 0 {
|
||||
return nil, fmt.Errorf("Error retrieving process info.")
|
||||
}
|
||||
|
||||
results := make([]Process, 0, 50)
|
||||
for {
|
||||
results = append(results, newWindowsProcess(&entry))
|
||||
|
||||
ret, _, _ := procProcess32Next.Call(handle, uintptr(unsafe.Pointer(&entry)))
|
||||
if ret == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@ -175,6 +175,9 @@ github.com/mgutz/str
|
||||
# github.com/mitchellh/go-homedir v1.1.0
|
||||
## explicit
|
||||
github.com/mitchellh/go-homedir
|
||||
# github.com/mitchellh/go-ps v1.0.0
|
||||
## explicit; go 1.13
|
||||
github.com/mitchellh/go-ps
|
||||
# github.com/onsi/ginkgo v1.10.3
|
||||
## explicit
|
||||
# github.com/onsi/gomega v1.7.1
|
||||
|
Loading…
x
Reference in New Issue
Block a user