diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml new file mode 100644 index 0000000..5857db9 --- /dev/null +++ b/.github/workflows/build_test.yml @@ -0,0 +1,50 @@ +on: [push, pull_request] +name: Build Test +jobs: + build_test_v2: + env: + GOPATH: ${{ github.workspace }} + GO111MODULE: off + strategy: + matrix: + go-version: [1.16.x, 1.17.x] + runs-on: ubuntu-20.04 + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + - name: Checkout code + uses: actions/checkout@v2 + with: + path: ${{ github.workspace }}/src/github.com/shirou/gopsutil + - name: Get dependencies + if: runner.os != 'Windows' + run: | + if ! command -v dep &>/dev/null; then + mkdir -p $GOPATH/bin + curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh + echo "PATH=$GOPATH/bin:$PATH" >> $GITHUB_PATH + fi + cd $GOPATH/src/github.com/shirou/gopsutil + dep ensure + # exclude v3 from being run with ./... + rm -rf $GOPATH/src/github.com/shirou/gopsutil/v3 + - name: Build Test v2 + run: | + cd $GOPATH/src/github.com/shirou/gopsutil && make build_test + build_test_v3: + strategy: + matrix: + go-version: [1.16.x, 1.17.x] + runs-on: ubuntu-20.04 + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + - name: Checkout code + uses: actions/checkout@v2 + - name: Build Test v3 + run: | + cd v3 && make build_test \ No newline at end of file diff --git a/mem/mem_solaris.go b/mem/mem_solaris.go index 0c58314..4cacde1 100644 --- a/mem/mem_solaris.go +++ b/mem/mem_solaris.go @@ -122,7 +122,7 @@ func nonGlobalZoneMemoryCapacity() (uint64, error) { return memSizeBytes, nil } -const swapsCommand = "swap" +const swapCommand = "swap" // The blockSize as reported by `swap -l`. See https://docs.oracle.com/cd/E23824_01/html/821-1459/fsswap-52195.html const blockSize = 512 @@ -141,13 +141,13 @@ func SwapDevices() ([]*SwapDevice, error) { } func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) { - swapsCommandPath, err := exec.LookPath(swapsCommand) + swapCommandPath, err := exec.LookPath(swapCommand) if err != nil { return nil, fmt.Errorf("could not find command %q: %w", swapCommand, err) } - output, err := invoke.CommandWithContext(swapsCommandPath, "-l") + output, err := invoke.CommandWithContext(ctx, swapCommandPath, "-l") if err != nil { - return nil, fmt.Errorf("could not execute %q: %w", swapsCommand, err) + return nil, fmt.Errorf("could not execute %q: %w", swapCommand, err) } return parseSwapsCommandOutput(string(output)) @@ -156,22 +156,22 @@ func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) { func parseSwapsCommandOutput(output string) ([]*SwapDevice, error) { lines := strings.Split(output, "\n") if len(lines) == 0 { - return nil, fmt.Errorf("could not parse output of %q: no lines in %q", swapsCommand, output) + return nil, fmt.Errorf("could not parse output of %q: no lines in %q", swapCommand, output) } // Check header headerFields are as expected. headerFields := strings.Fields(lines[0]) if len(headerFields) < freeBlocksCol { - return nil, fmt.Errorf("couldn't parse %q: too few fields in header %q", swapsCommand, lines[0]) + return nil, fmt.Errorf("couldn't parse %q: too few fields in header %q", swapCommand, lines[0]) } if headerFields[nameCol] != "swapfile" { - return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsCommand, headerFields[nameCol], "swapfile") + return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[nameCol], "swapfile") } if headerFields[totalBlocksCol] != "blocks" { - return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsCommand, headerFields[totalBlocksCol], "blocks") + return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[totalBlocksCol], "blocks") } if headerFields[freeBlocksCol] != "free" { - return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsCommand, headerFields[freeBlocksCol], "free") + return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[freeBlocksCol], "free") } var swapDevices []*SwapDevice @@ -181,17 +181,17 @@ func parseSwapsCommandOutput(output string) ([]*SwapDevice, error) { } fields := strings.Fields(line) if len(fields) < freeBlocksCol { - return nil, fmt.Errorf("couldn't parse %q: too few fields", swapsCommand) + return nil, fmt.Errorf("couldn't parse %q: too few fields", swapCommand) } totalBlocks, err := strconv.ParseUint(fields[totalBlocksCol], 10, 64) if err != nil { - return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapsCommand, err) + return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapCommand, err) } freeBlocks, err := strconv.ParseUint(fields[freeBlocksCol], 10, 64) if err != nil { - return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapsCommand, err) + return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapCommand, err) } swapDevices = append(swapDevices, &SwapDevice{ diff --git a/v3/mem/mem_solaris.go b/v3/mem/mem_solaris.go index 11a9cef..99f5975 100644 --- a/v3/mem/mem_solaris.go +++ b/v3/mem/mem_solaris.go @@ -122,7 +122,7 @@ func nonGlobalZoneMemoryCapacity() (uint64, error) { return memSizeBytes, nil } -const swapsCommand = "swap" +const swapCommand = "swap" // The blockSize as reported by `swap -l`. See https://docs.oracle.com/cd/E23824_01/html/821-1459/fsswap-52195.html const blockSize = 512 @@ -141,13 +141,13 @@ func SwapDevices() ([]*SwapDevice, error) { } func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) { - swapsCommandPath, err := exec.LookPath(swapsCommand) + swapCommandPath, err := exec.LookPath(swapCommand) if err != nil { - return nil, fmt.Errorf("could not find command %q: %w", swapsCommand, err) + return nil, fmt.Errorf("could not find command %q: %w", swapCommand, err) } - output, err := invoke.CommandWithContext(ctx, swapsCommandPath, "-l") + output, err := invoke.CommandWithContext(ctx, swapCommandPath, "-l") if err != nil { - return nil, fmt.Errorf("could not execute %q: %w", swapsCommand, err) + return nil, fmt.Errorf("could not execute %q: %w", swapCommand, err) } return parseSwapsCommandOutput(string(output)) @@ -156,22 +156,22 @@ func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) { func parseSwapsCommandOutput(output string) ([]*SwapDevice, error) { lines := strings.Split(output, "\n") if len(lines) == 0 { - return nil, fmt.Errorf("could not parse output of %q: no lines in %q", swapsCommand, output) + return nil, fmt.Errorf("could not parse output of %q: no lines in %q", swapCommand, output) } // Check header headerFields are as expected. headerFields := strings.Fields(lines[0]) if len(headerFields) < freeBlocksCol { - return nil, fmt.Errorf("couldn't parse %q: too few fields in header %q", swapsCommand, lines[0]) + return nil, fmt.Errorf("couldn't parse %q: too few fields in header %q", swapCommand, lines[0]) } if headerFields[nameCol] != "swapfile" { - return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsCommand, headerFields[nameCol], "swapfile") + return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[nameCol], "swapfile") } if headerFields[totalBlocksCol] != "blocks" { - return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsCommand, headerFields[totalBlocksCol], "blocks") + return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[totalBlocksCol], "blocks") } if headerFields[freeBlocksCol] != "free" { - return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsCommand, headerFields[freeBlocksCol], "free") + return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[freeBlocksCol], "free") } var swapDevices []*SwapDevice @@ -181,17 +181,17 @@ func parseSwapsCommandOutput(output string) ([]*SwapDevice, error) { } fields := strings.Fields(line) if len(fields) < freeBlocksCol { - return nil, fmt.Errorf("couldn't parse %q: too few fields", swapsCommand) + return nil, fmt.Errorf("couldn't parse %q: too few fields", swapCommand) } totalBlocks, err := strconv.ParseUint(fields[totalBlocksCol], 10, 64) if err != nil { - return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapsCommand, err) + return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapCommand, err) } freeBlocks, err := strconv.ParseUint(fields[freeBlocksCol], 10, 64) if err != nil { - return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapsCommand, err) + return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapCommand, err) } swapDevices = append(swapDevices, &SwapDevice{ diff --git a/v3/process/process_fallback.go b/v3/process/process_fallback.go index ee35306..2638d8c 100644 --- a/v3/process/process_fallback.go +++ b/v3/process/process_fallback.go @@ -1,15 +1,18 @@ -// +build !darwin,!linux,!freebsd,!openbsd,!windows,!solaris +// +build !darwin,!linux,!freebsd,!openbsd,!windows,!solaris,!plan9 package process import ( "context" + "syscall" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/net" ) +type Signal = syscall.Signal + type MemoryMapsStat struct { Path string `json:"path"` Rss uint64 `json:"rss"` diff --git a/v3/process/process_plan9.go b/v3/process/process_plan9.go index 53a0291..ff4a5cf 100644 --- a/v3/process/process_plan9.go +++ b/v3/process/process_plan9.go @@ -3,7 +3,205 @@ package process import ( + "context" "syscall" + + "github.com/shirou/gopsutil/v3/cpu" + "github.com/shirou/gopsutil/v3/internal/common" + "github.com/shirou/gopsutil/v3/net" ) type Signal = syscall.Note + +type MemoryMapsStat struct { + Path string `json:"path"` + Rss uint64 `json:"rss"` + Size uint64 `json:"size"` + Pss uint64 `json:"pss"` + SharedClean uint64 `json:"sharedClean"` + SharedDirty uint64 `json:"sharedDirty"` + PrivateClean uint64 `json:"privateClean"` + PrivateDirty uint64 `json:"privateDirty"` + Referenced uint64 `json:"referenced"` + Anonymous uint64 `json:"anonymous"` + Swap uint64 `json:"swap"` +} + +type MemoryInfoExStat struct { +} + +func pidsWithContext(ctx context.Context) ([]int32, error) { + return nil, common.ErrNotImplementedError +} + +func ProcessesWithContext(ctx context.Context) ([]*Process, error) { + return nil, common.ErrNotImplementedError +} + +func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) { + return false, common.ErrNotImplementedError +} + +func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { + return 0, common.ErrNotImplementedError +} + +func (p *Process) NameWithContext(ctx context.Context) (string, error) { + return "", common.ErrNotImplementedError +} + +func (p *Process) TgidWithContext(ctx context.Context) (int32, error) { + return 0, common.ErrNotImplementedError +} + +func (p *Process) ExeWithContext(ctx context.Context) (string, error) { + return "", common.ErrNotImplementedError +} + +func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { + return "", common.ErrNotImplementedError +} + +func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { + return 0, common.ErrNotImplementedError +} + +func (p *Process) CwdWithContext(ctx context.Context) (string, error) { + return "", common.ErrNotImplementedError +} + +func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) { + return []string{""}, common.ErrNotImplementedError +} + +func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { + return false, common.ErrNotImplementedError +} + +func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { + return "", common.ErrNotImplementedError +} + +func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { + return 0, common.ErrNotImplementedError +} + +func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) { + return 0, common.ErrNotImplementedError +} + +func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) { + return 0, common.ErrNotImplementedError +} + +func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { + return 0, common.ErrNotImplementedError +} + +func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) { + return nil, common.ErrNotImplementedError +} + +func (p *Process) SendSignalWithContext(ctx context.Context, sig Signal) error { + return common.ErrNotImplementedError +} + +func (p *Process) SuspendWithContext(ctx context.Context) error { + return common.ErrNotImplementedError +} + +func (p *Process) ResumeWithContext(ctx context.Context) error { + return common.ErrNotImplementedError +} + +func (p *Process) TerminateWithContext(ctx context.Context) error { + return common.ErrNotImplementedError +} + +func (p *Process) KillWithContext(ctx context.Context) error { + return common.ErrNotImplementedError +} + +func (p *Process) UsernameWithContext(ctx context.Context) (string, error) { + return "", common.ErrNotImplementedError +} + +func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) { + return nil, common.ErrNotImplementedError +} diff --git a/v3/process/process_posix.go b/v3/process/process_posix.go index fa38759..2e4a04e 100644 --- a/v3/process/process_posix.go +++ b/v3/process/process_posix.go @@ -82,7 +82,7 @@ func isMount(path string) bool { if err != nil { return false } - if fileInfo.Mode() & os.ModeSymlink != 0 { + if fileInfo.Mode()&os.ModeSymlink != 0 { return false } var stat1 unix.Stat_t