Compare commits

...

92 Commits

Author SHA1 Message Date
Bradley Cicenas
be23d85eda Merge remote-tracking branch 'stokito/browser' 2021-10-24 10:40:43 -04:00
bradley
2047e3fa52 Merge pull request #272 from bcicen/dependabot/go_modules/github.com/opencontainers/runc-1.0.0-rc95
Bump github.com/opencontainers/runc from 1.0.0-rc93 to 1.0.0-rc95
2021-10-24 10:35:37 -04:00
dependabot[bot]
4b653e71f6 Bump github.com/opencontainers/runc from 1.0.0-rc93 to 1.0.0-rc95
Bumps [github.com/opencontainers/runc](https://github.com/opencontainers/runc) from 1.0.0-rc93 to 1.0.0-rc95.
- [Release notes](https://github.com/opencontainers/runc/releases)
- [Commits](https://github.com/opencontainers/runc/compare/v1.0.0-rc93...v1.0.0-rc95)

---
updated-dependencies:
- dependency-name: github.com/opencontainers/runc
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-27 17:42:05 +00:00
Bradley Cicenas
c145cf404a match release tag to title 2021-07-01 19:32:32 +00:00
bradley
52f52a1163 Merge pull request #268 from neikei/patch-1
Added support for ppc64le
2021-06-13 10:25:11 -04:00
bradley
94f1f3f558 Merge pull request #269 from Quintenps/master
Update README.md (Fixed release download url)
2021-06-13 10:23:07 -04:00
Quinten Peels
3d5a1c0682 Update README.md
Fixed release download url in readme
2021-06-13 16:07:58 +02:00
neikei
1c3577ad4e Added support for ppc64le 2021-06-13 15:12:27 +02:00
Bradley Cicenas
b48a5cf2f9 go mod tidy 2021-06-11 18:07:31 +00:00
Bradley Cicenas
9f8f38f9d7 Merge remote-tracking branch 'remotes/stokito/events_filter' 2021-06-11 14:04:53 -04:00
bradley
2b898fb216 Merge pull request #267 from frol-kr/bugfix/issue-254-crushes-when-container-logs-opened
#254-handling-with-wrong-log-format
2021-06-11 13:46:42 -04:00
Frol Kryuchkov
99be3b979e #254-handling-with-wrong-log-format 2021-06-11 17:22:34 +03:00
bradley
29f9abf35c Merge pull request #236 from stokito/status_unicode
Use more clear status marks
2021-06-10 22:06:40 -04:00
bradley
82e731e577 Merge pull request #239 from stokito/cpu_color
CPU upper: > 70% yellow/warn and > 90% is red/danger
2021-06-10 22:04:54 -04:00
Bradley Cicenas
a603c1b58c Merge remote-tracking branch 'remotes/stokito/uptime' 2021-06-10 22:01:45 -04:00
Bradley Cicenas
8f0c9f5048 v0.7.6 2021-06-11 01:23:43 +00:00
bradley
15708224a7 Merge pull request #262 from judaew/patch-1
Add install variant via MacPorts
2021-06-10 21:19:16 -04:00
bradley
442e70b8df Merge pull request #264 from garsue/use-runewidth-to-increment-textview-x
Use go-runewidth to increment x in TextView
2021-06-10 21:18:33 -04:00
garsue
c58a609349 Update go.sum 2021-05-29 22:01:26 +09:00
garsue
78b038e687 Use runewidth to increment x in TextView 2021-05-29 19:48:02 +09:00
Vadim-Valdis Yudaev
2d937aca08 Add install variant via MacPorts 2021-05-20 17:09:14 +03:00
Sergey Ponomarev
77c9001ed1 optimize health_status event handling 2021-02-04 09:37:44 +02:00
Sergey Ponomarev
d98ce102b1 Filter events 2021-02-04 09:22:57 +02:00
Sergey Ponomarev
cfa43f809e Update go-dockerclient and opencontainers/runc
The go-dockerclient v1.7.0 now has an ability to specify events filter. But it's dependencies are also updated.
One of those dependencies is mountinfo and the same dependency is used by opencontainers/runc.
The problem is that mountinfo changed it's API and if we just update dockerclient then build is broken.
So we have to update both opencontainers/runc and go-dockerclient
2021-02-04 08:59:06 +02:00
bradley
0094cba5ea Merge pull request #244 from stokito/fix_243
#243 Fix bug: show ENV variables
2020-12-14 12:29:25 -05:00
bradley
537bb2adfa Merge pull request #247 from stokito/more_columns
More columns
2020-12-14 12:25:17 -05:00
Sergey Ponomarev
8dce3ece2b Open in browser: show menu item only if web port is published 2020-12-12 21:50:08 +02:00
Sergey Ponomarev
dd92e85d45 Open in browser
Most containers expose some http port. We can open it in browser.
For simplicity we can just open first container's published port.
We'll determine the ip:port on container creation and store to meta "Web Port".
To open browser on any platform was added a new dependency github.com/pkg/browser which is very small
2020-12-12 21:21:53 +02:00
Sergey Ponomarev
491cd85b4d Additional columns 2020-12-11 21:58:37 +02:00
Sergey Ponomarev
9545dfba31 Extract MetaCol 2020-12-11 20:59:35 +02:00
Sergey Ponomarev
cdcb8b6d99 columns.go: remove redundant type 2020-12-11 20:32:22 +02:00
bradley
b562c923b3 Merge pull request #242 from stokito/awesome
Add Alternatives section
2020-12-09 16:10:09 -05:00
Sergey Ponomarev
f2c28c5fb0 #243 Fix bug: show ENV variables
Previously only last env variable is shown
2020-12-09 23:06:14 +02:00
Sergey Ponomarev
ac76b2eac1 Add Alternatives section
This may help users to find more specific tool than ctop
2020-11-30 17:25:40 +02:00
bradley
b32f90fa4a Merge pull request #240 from stokito/name_width
#128 Set column Name to fixed width 30
2020-11-29 09:19:07 -05:00
bradley
bec78c90b5 Merge pull request #238 from stokito/leftovers
Use standard Go functions
2020-11-29 09:06:13 -05:00
Bradley Cicenas
043f4bd3f3 update dockerfile to go 1.15 2020-11-28 20:30:02 +00:00
Sergey Ponomarev
c2401cb33a #128 Set column Name to fixed width 30 2020-11-27 23:12:16 +02:00
Sergey Ponomarev
fa254c652c Columns settings: add hint for re-order columns 2020-11-27 22:34:55 +02:00
Sergey Ponomarev
a59c7aab3c Fix: enable pause [p] only for running or paused container 2020-11-27 22:28:58 +02:00
Sergey Ponomarev
4e44c9d5f7 file.go use filepath.Dir() 2020-11-26 12:08:55 +02:00
Sergey Ponomarev
948e7cc9d0 docker_logs.go use SplitN(2) 2020-11-26 12:08:36 +02:00
Sergey Ponomarev
4850f817f3 status.go: use more clear status marks 2020-11-25 22:29:10 +02:00
Sergey Ponomarev
10c49018a6 status.go: make logic more explicit 2020-11-25 22:21:19 +02:00
Sergey Ponomarev
6c662d91fb docker.go shortName() use TrimPrefix() 2020-11-25 19:17:07 +02:00
Sergey Ponomarev
b4a63f8c60 docker_logs.go: use time.RFC3339Nano constant 2020-11-24 22:19:29 +02:00
Sergey Ponomarev
4973bc83ff cpu color: make threshold upper: > 70% warn and > 90% is danger 2020-11-24 00:51:09 +02:00
Bradley Cicenas
87d135909f rename cpus column 2020-11-23 17:48:56 -05:00
Sergey Ponomarev
7632420ecc cpu color: check lower values first
this is simpler to understand and faster for usual containers
2020-11-24 00:22:25 +02:00
Sergey Ponomarev
4fbc998a41 status.go: simplify Buffer()
s.health and s.status are always have only one element with a single char length
2020-11-23 15:23:07 +02:00
bradley
117c3bc7b5 Merge pull request #234 from stokito/refresh
docker connector: refresh() delete container only if it not found but keep on failures
2020-11-22 19:00:31 -05:00
bradley
b1171f6c3e Merge pull request #235 from stokito/cpu_scale
#207 Replace scaleCpu option with dedicated column CPU Scaled
2020-11-21 12:19:43 -05:00
Sergey Ponomarev
9a41252764 #207 CPU unscaled column changes color according to system total usage
If container uses two cores then CPU column will be always red even if we have dozens of other free cores and CPUS is 1%
2020-11-20 23:24:13 +02:00
Sergey Ponomarev
f377dcaee2 #207 Replace scaleCpu option with dedicated column CPU Scaled
The new column is disabled by default.
2020-11-20 23:08:19 +02:00
Sergey Ponomarev
65e9c6dff6 docker connector: refresh() delete container only if it not found but keep on failures
If inspect() call was failed due to connection problems then container will be removed anyway as like ot wasn't found.
This is probably almost never happens in real life but still some missed logic bug
2020-11-20 19:44:09 +02:00
Sergey Ponomarev
df0d8b7892 #187 "created" action is handled separately in watchEvents() 2020-11-20 19:26:02 +02:00
bradley
2792e72d18 Merge pull request #233 from stokito/exec_shell
Exec shell config
2020-11-20 11:22:59 -05:00
bradley
68d6da5c61 Merge pull request #231 from stokito/log_file
Log to file
2020-11-20 08:30:13 -05:00
Sergey Ponomarev
53a6b36bf5 exec shell: detect default shell
Instead of using configured shell (e.g. bash) we can autodetect default container user's shell and execute it.
This is much safer because not all containers may have installed shell that is configured in ctop.
2020-11-20 10:42:52 +02:00
Sergey Ponomarev
5ec02f760e exec shell: remove shell config or option
The option is never worked and can't properly work because almost all containers anyway using Ash/Dash from /bin/sh
2020-11-20 10:39:28 +02:00
Sergey Ponomarev
83a422933a exec shell: on error show a status message instead of fatal exit 2020-11-20 10:33:44 +02:00
Sergey Ponomarev
7679d4a7fd exec shell: fix shell config
Currently each time when ctop started it overwrites "shell" config with default value of program argument.
This means that in fact default shell config is never worked at all.
2020-11-20 10:31:00 +02:00
Sergey Ponomarev
e34afceb5f logging: log to file
New env var CTOP_DEBUG_FILE to specify a path to log file
2020-11-19 20:11:46 +02:00
bradley
ddfff03c05 Merge pull request #229 from stokito/events
Improve docker events handling
2020-11-19 11:27:09 -05:00
Sergey Ponomarev
29d90cfdd9 logging: start server after log is configured
Without this "logging server started" is written to stderr
2020-11-19 11:21:27 +02:00
Sergey Ponomarev
ba126e6e7c events handling: early skipping of extremely frequent exec_* events
The exec_create, exec_start, exec_die and other events are generated by health checks
2020-11-18 23:04:29 +02:00
Sergey Ponomarev
009201ed0c actionToStatus: catch more generic die instead of kill 2020-11-18 23:04:29 +02:00
Sergey Ponomarev
2c07cab59c logging: skip timer events e.g. /timer/1s
Each second we receive the timer event which makes little sense but log is bloated with the event.
To make logs more readable we can disable logging of this event
2020-11-18 23:04:29 +02:00
bradley
fd06992236 Merge pull request #230 from stokito/skip_timer_logging
logging: skip timer events e.g. /timer/1s
2020-11-18 09:40:33 -05:00
Sergey Ponomarev
e64edbdc36 logging: skip timer events e.g. /timer/1s
Each second we receive the timer event which makes little sense but log is bloated with the event.
To make logs more readable we can disable logging of this event
2020-11-18 11:25:20 +02:00
Sergey Ponomarev
4c280cee56 Improve docker events handling: separate channel for status updates
Instead of calling a heavy inspect api call we can easily changing status just by knowing an action.
Let's do this in a separate channel decouple UI update from basic event loop.
2020-11-17 22:00:03 +02:00
Sergey Ponomarev
b65e970a83 Improve docker events handling
Firstly check health updates because it will be a lot of them especially when a container is unstable.
Clearly handle create event to create a container even if it wasn't started.
Instead of die event handle more precise events like oom, kill and only then trigger refresh.
Lookup the state from a map.
2020-11-17 21:50:25 +02:00
Sergey Ponomarev
957cabba2d docker.go: watchEvents() optimize actionName extraction
Split(e.Action, ":") creates and array but we can avoid this.
2020-11-17 12:06:34 +02:00
Sergey Ponomarev
5aacdc3772 docker.go: logging of events
Add log.IsEnabledFor(logging.DEBUG) guard to avoid unnecessary memory allocations. Debug level is usually disabled.
Inline "destroy"
2020-11-17 11:42:45 +02:00
Bradley Cicenas
99d9aeec98 set running = false when mock,runc collectors stopped 2020-11-13 21:43:11 +00:00
bradley
44600fca45 Merge pull request #201 from vcmkrtchyan/master
Fix freeze when container is started/stopped multiple times
2020-11-13 16:42:16 -05:00
bradley
9aaba5dfca Merge pull request #223 from stokito/trim
file.go: remove duplicated trim
2020-11-13 15:40:01 -05:00
Bradley Cicenas
0bd8efe800 fix makefile release 2020-11-13 20:35:40 +00:00
Sergey Ponomarev
3a29c94833 Use percent() function to calc CPU usage 2020-11-13 11:02:14 +02:00
Sergey Ponomarev
a22d99fefb file.go: remove duplicated trim
The s var was already trimmed on line 67
2020-11-12 21:23:18 +02:00
Bradley Cicenas
c971d26d42 v0.7.5 2020-11-06 16:59:24 +00:00
Bradley Cicenas
de380ff810 add arch section to readme 2020-11-06 16:56:17 +00:00
bradley
e7e2478468 Merge pull request #222 from azlux/master
Readme : fix link
2020-11-05 13:44:35 -05:00
azlux
42c80c2395 fix link 2020-11-05 19:24:50 +01:00
bradley
d22bbc3420 Merge pull request #221 from azlux/master
Add apt azlux's repository
2020-11-05 13:16:22 -05:00
azlux
bdfb98265d Add apt azlux's repository 2020-11-05 10:54:10 +01:00
Bradley Cicenas
af1908fb27 update make release to use ghub cli 2020-11-03 07:55:39 -05:00
bradley
73a976c6fe Merge pull request #220 from stokito/single_view_trunc_id
Single Container View: truncate ID
2020-11-03 07:55:00 -05:00
Sergey Ponomarev
2bcfc365f7 Single Container View: truncate ID
Truncation Id inside of NewSingle() doesn't work.
It even doesn't have any effect.
Instead truncate the ID inside of NewMeta() call
2020-11-03 14:11:58 +02:00
bradley
ecc7bf4081 Merge pull request #219 from bcicen/text-col-setter
add textcol setter, static CID column width
2020-10-31 10:53:42 -04:00
Sergey Ponomarev
c984b270db #135 Add uptime column 2020-10-26 16:32:51 +02:00
Vahe Mkrtchyan
4a0e80ffdf Fix freeze when container is started/stopped multiple times 2020-07-23 15:23:19 +04:00
34 changed files with 526 additions and 296 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,4 @@
ctop ctop
.idea .idea
/vendor/ /vendor/
*.log

View File

@@ -1,4 +1,4 @@
FROM quay.io/vektorcloud/go:1.13 FROM quay.io/vektorcloud/go:1.15
RUN apk add --no-cache make RUN apk add --no-cache make

View File

@@ -12,11 +12,12 @@ build:
build-all: build-all:
mkdir -p _build mkdir -p _build
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-darwin-amd64 GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-darwin-amd64
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-linux-amd64 GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-linux-amd64
GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-linux-arm GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-linux-arm
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-linux-arm64 GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-linux-arm64
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-windows-amd64 GOOS=linux GOARCH=ppc64le CGO_ENABLED=0 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-linux-ppc64le
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-windows-amd64
cd _build; sha256sum * > sha256sums.txt cd _build; sha256sum * > sha256sums.txt
run-dev: run-dev:
@@ -29,10 +30,8 @@ image:
release: release:
mkdir release mkdir release
go get github.com/progrium/gh-release/...
cp _build/* release cp _build/* release
cd release; sha256sum --quiet --check sha256sums.txt cd release; sha256sum --quiet --check sha256sums.txt && \
gh-release create bcicen/$(NAME) $(VERSION) \ gh release create v$(VERSION) -d -t v$(VERSION) *
$(shell git rev-parse --abbrev-ref HEAD) $(VERSION)
.PHONY: build .PHONY: build

View File

@@ -2,7 +2,7 @@
# #
![release][release] ![homebrew][homebrew] ![release][release] ![homebrew][homebrew] ![macports][macports]
Top-like interface for container metrics Top-like interface for container metrics
@@ -17,10 +17,24 @@ as well as a [single container view][single_view] for inspecting a specific cont
Fetch the [latest release](https://github.com/bcicen/ctop/releases) for your platform: Fetch the [latest release](https://github.com/bcicen/ctop/releases) for your platform:
#### Linux #### Debian/Ubuntu
Maintained by a [third party](https://packages.azlux.fr/)
```bash
echo "deb http://packages.azlux.fr/debian/ buster main" | sudo tee /etc/apt/sources.list.d/azlux.list
wget -qO - https://azlux.fr/repo.gpg.key | sudo apt-key add -
sudo apt update
sudo apt install docker-ctop
```
#### Arch
`ctop` is available for Arch in the [AUR](https://aur.archlinux.org/packages/ctop-bin/)
#### Linux (Generic)
```bash ```bash
sudo wget https://github.com/bcicen/ctop/releases/download/v0.7.4/ctop-0.7.4-linux-amd64 -O /usr/local/bin/ctop sudo wget https://github.com/bcicen/ctop/releases/download/0.7.6/ctop-0.7.6-linux-amd64 -O /usr/local/bin/ctop
sudo chmod +x /usr/local/bin/ctop sudo chmod +x /usr/local/bin/ctop
``` ```
@@ -31,7 +45,11 @@ brew install ctop
``` ```
or or
```bash ```bash
sudo curl -Lo /usr/local/bin/ctop https://github.com/bcicen/ctop/releases/download/v0.7.4/ctop-0.7.4-darwin-amd64 sudo port install ctop
```
or
```bash
sudo curl -Lo /usr/local/bin/ctop https://github.com/bcicen/ctop/releases/download/0.7.6/ctop-0.7.6-darwin-amd64
sudo chmod +x /usr/local/bin/ctop sudo chmod +x /usr/local/bin/ctop
``` ```
@@ -44,8 +62,6 @@ docker run --rm -ti \
quay.io/vektorlab/ctop:latest quay.io/vektorlab/ctop:latest
``` ```
`ctop` is also available for Arch in the [AUR](https://aur.archlinux.org/packages/ctop-bin/)
## Building ## Building
Build steps can be found [here][build]. Build steps can be found [here][build].
@@ -70,9 +86,7 @@ Option | Description
`-i` | invert default colors `-i` | invert default colors
`-r` | reverse container sort order `-r` | reverse container sort order
`-s` | select initial container sort field `-s` | select initial container sort field
`-scale-cpu` | show cpu as % of system total
`-v` | output version information and exit `-v` | output version information and exit
`-shell` | exec shell to use (default: sh)
### Keybindings ### Keybindings
@@ -97,3 +111,8 @@ Option | Description
[single_view]: _docs/single.md [single_view]: _docs/single.md
[release]: https://img.shields.io/github/release/bcicen/ctop.svg "ctop" [release]: https://img.shields.io/github/release/bcicen/ctop.svg "ctop"
[homebrew]: https://img.shields.io/homebrew/v/ctop.svg "ctop" [homebrew]: https://img.shields.io/homebrew/v/ctop.svg "ctop"
[macports]: https://repology.org/badge/version-for-repo/macports/ctop.svg?header=macports "ctop"
## Alternatives
See [Awesome Docker list](https://github.com/veggiemonk/awesome-docker/blob/master/README.md#terminal) for similar tools to work with Docker.

View File

@@ -1 +1 @@
0.7.4 0.7.6

View File

@@ -54,3 +54,18 @@ CTOP_DEBUG=1 CTOP_DEBUG_TCP=1 ./ctop
``` ```
A TCP listener for streaming log messages will be started on the default listen address(`0.0.0.0:9000`) A TCP listener for streaming log messages will be started on the default listen address(`0.0.0.0:9000`)
## Log to file
You can also log to a file by specifying `CTOP_DEBUG_FILE=/path/to/ctop.log` environment variable:
```sh
CTOP_DEBUG=1 CTOP_DEBUG_FILE=ctop.log ./ctop
```
This is useful for GoLand to see logs right in debug panel:
* Edit Run configuration
* Go to Logs tab
* Specify this log file in "Log file to be shown in console".
Then during debugging you'll see the log tab in debug panel:
![Debug in GoLand](img/goland_debug.png)

BIN
_docs/img/goland_debug.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

View File

@@ -6,46 +6,76 @@ import (
// defaults // defaults
var defaultColumns = []Column{ var defaultColumns = []Column{
Column{ {
Name: "status", Name: "status",
Label: "Status Indicator", Label: "Status Indicator",
Enabled: true, Enabled: true,
}, },
Column{ {
Name: "name", Name: "name",
Label: "Container Name", Label: "Container Name",
Enabled: true, Enabled: true,
}, },
Column{ {
Name: "id", Name: "id",
Label: "Container ID", Label: "Container ID",
Enabled: true, Enabled: true,
}, },
Column{ {
Name: "image",
Label: "Image name",
Enabled: false,
},
{
Name: "ports",
Label: "Exposed ports",
Enabled: false,
},
{
Name: "IPs",
Label: "Exposed IPs",
Enabled: false,
},
{
Name: "created",
Label: "Date created",
Enabled: false,
},
{
Name: "cpu", Name: "cpu",
Label: "CPU Usage", Label: "CPU Usage",
Enabled: true, Enabled: true,
}, },
Column{ {
Name: "cpus",
Label: "CPU Usage (% of system total)",
Enabled: false,
},
{
Name: "mem", Name: "mem",
Label: "Memory Usage", Label: "Memory Usage",
Enabled: true, Enabled: true,
}, },
Column{ {
Name: "net", Name: "net",
Label: "Network RX/TX", Label: "Network RX/TX",
Enabled: true, Enabled: true,
}, },
Column{ {
Name: "io", Name: "io",
Label: "Disk IO Read/Write", Label: "Disk IO Read/Write",
Enabled: true, Enabled: true,
}, },
Column{ {
Name: "pids", Name: "pids",
Label: "Container PID Count", Label: "Container PID Count",
Enabled: true, Enabled: true,
}, },
Column{
Name: "uptime",
Label: "Running uptime duration",
Enabled: true,
},
} }
type Column struct { type Column struct {

View File

@@ -3,6 +3,7 @@ package config
import ( import (
"fmt" "fmt"
"os" "os"
"path/filepath"
"regexp" "regexp"
"strings" "strings"
@@ -66,7 +67,7 @@ func Read() error {
for _, s := range strings.Split(colStr, ",") { for _, s := range strings.Split(colStr, ",") {
s = strings.TrimSpace(s) s = strings.TrimSpace(s)
if s != "" { if s != "" {
colNames = append(colNames, strings.TrimSpace(s)) colNames = append(colNames, s)
} }
} }
SetColumns(colNames) SetColumns(colNames)
@@ -81,7 +82,7 @@ func Write() (path string, err error) {
return path, err return path, err
} }
cfgdir := basedir(path) cfgdir := filepath.Dir(path)
// create config dir if not exist // create config dir if not exist
if _, err := os.Stat(cfgdir); err != nil { if _, err := os.Stat(cfgdir); err != nil {
err = os.MkdirAll(cfgdir, 0755) err = os.MkdirAll(cfgdir, 0755)
@@ -141,8 +142,3 @@ func xdgSupport() bool {
} }
return false return false
} }
func basedir(path string) string {
parts := strings.Split(path, "/")
return strings.Join((parts[0 : len(parts)-1]), "/")
}

View File

@@ -12,14 +12,9 @@ var defaultParams = []*Param{
Val: "state", Val: "state",
Label: "Container Sort Field", Label: "Container Sort Field",
}, },
&Param{
Key: "shell",
Val: "sh",
Label: "Shell",
},
&Param{ &Param{
Key: "columns", Key: "columns",
Val: "status,name,id,cpu,mem,net,io,pids", Val: "status,name,id,cpu,mem,net,io,pids,uptime",
Label: "Enabled Columns", Label: "Enabled Columns",
}, },
} }

View File

@@ -22,11 +22,6 @@ var defaultSwitches = []*Switch{
Val: true, Val: true,
Label: "Enable status header", Label: "Enable status header",
}, },
&Switch{
Key: "scaleCpu",
Val: false,
Label: "Show CPU as %% of system total",
},
} }
type Switch struct { type Switch struct {

View File

@@ -1,7 +1,6 @@
package collector package collector
import ( import (
"github.com/bcicen/ctop/config"
"github.com/bcicen/ctop/models" "github.com/bcicen/ctop/models"
api "github.com/fsouza/go-dockerclient" api "github.com/fsouza/go-dockerclient"
) )
@@ -16,15 +15,13 @@ type Docker struct {
done chan bool done chan bool
lastCpu float64 lastCpu float64
lastSysCpu float64 lastSysCpu float64
scaleCpu bool
} }
func NewDocker(client *api.Client, id string) *Docker { func NewDocker(client *api.Client, id string) *Docker {
return &Docker{ return &Docker{
Metrics: models.Metrics{}, Metrics: models.Metrics{},
id: id, id: id,
client: client, client: client,
scaleCpu: config.GetSwitchVal("scaleCpu"),
} }
} }
@@ -74,22 +71,20 @@ func (c *Docker) Logs() LogCollector {
// Stop collector // Stop collector
func (c *Docker) Stop() { func (c *Docker) Stop() {
c.running = false
c.done <- true c.done <- true
} }
func (c *Docker) ReadCPU(stats *api.Stats) { func (c *Docker) ReadCPU(stats *api.Stats) {
ncpus := float64(len(stats.CPUStats.CPUUsage.PercpuUsage)) ncpus := uint8(len(stats.CPUStats.CPUUsage.PercpuUsage))
total := float64(stats.CPUStats.CPUUsage.TotalUsage) total := float64(stats.CPUStats.CPUUsage.TotalUsage)
system := float64(stats.CPUStats.SystemCPUUsage) system := float64(stats.CPUStats.SystemCPUUsage)
cpudiff := total - c.lastCpu cpudiff := total - c.lastCpu
syscpudiff := system - c.lastSysCpu syscpudiff := system - c.lastSysCpu
if c.scaleCpu { c.NCpus = ncpus
c.CPUUtil = round((cpudiff / syscpudiff * 100)) c.CPUUtil = percent(cpudiff, syscpudiff)
} else {
c.CPUUtil = round((cpudiff / syscpudiff * 100) * ncpus)
}
c.lastCpu = total c.lastCpu = total
c.lastSysCpu = system c.lastSysCpu = system
c.Pids = int(stats.PidsStats.Current) c.Pids = int(stats.PidsStats.Current)

View File

@@ -47,9 +47,15 @@ func (l *DockerLogs) Stream() chan models.Log {
go func() { go func() {
scanner := bufio.NewScanner(r) scanner := bufio.NewScanner(r)
for scanner.Scan() { for scanner.Scan() {
parts := strings.Split(scanner.Text(), " ") parts := strings.SplitN(scanner.Text(), " ", 2)
ts := l.parseTime(parts[0]) if len(parts) == 0 {
logCh <- models.Log{Timestamp: ts, Message: strings.Join(parts[1:], " ")} continue
}
if len(parts) < 2 {
logCh <- models.Log{Timestamp: l.parseTime(""), Message: parts[0]}
} else {
logCh <- models.Log{Timestamp: l.parseTime(parts[0]), Message: parts[1]}
}
} }
}() }()
@@ -74,12 +80,12 @@ func (l *DockerLogs) Stream() chan models.Log {
func (l *DockerLogs) Stop() { l.done <- true } func (l *DockerLogs) Stop() { l.done <- true }
func (l *DockerLogs) parseTime(s string) time.Time { func (l *DockerLogs) parseTime(s string) time.Time {
ts, err := time.Parse("2006-01-02T15:04:05.000000000Z", s) ts, err := time.Parse(time.RFC3339Nano, s)
if err == nil { if err == nil {
return ts return ts
} }
ts, err2 := time.Parse("2006-01-02T15:04:05.000000000Z", l.stripPfx(s)) ts, err2 := time.Parse(time.RFC3339Nano, l.stripPfx(s))
if err2 == nil { if err2 == nil {
return ts return ts
} }

View File

@@ -38,6 +38,7 @@ func (c *Mock) Start() {
} }
func (c *Mock) Stop() { func (c *Mock) Stop() {
c.running = false
c.done = true c.done = true
} }

View File

@@ -9,7 +9,6 @@ import (
"github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/types" "github.com/opencontainers/runc/types"
"github.com/bcicen/ctop/config"
"github.com/bcicen/ctop/models" "github.com/bcicen/ctop/models"
) )
@@ -24,7 +23,6 @@ type Runc struct {
interval int // collection interval, in seconds interval int // collection interval, in seconds
lastCpu float64 lastCpu float64
lastSysCpu float64 lastSysCpu float64
scaleCpu bool
} }
func NewRunc(libc libcontainer.Container) *Runc { func NewRunc(libc libcontainer.Container) *Runc {
@@ -33,7 +31,6 @@ func NewRunc(libc libcontainer.Container) *Runc {
id: libc.ID(), id: libc.ID(),
libc: libc, libc: libc,
interval: 1, interval: 1,
scaleCpu: config.GetSwitchVal("scaleCpu"),
} }
return c return c
} }
@@ -49,6 +46,7 @@ func (c *Runc) Start() {
} }
func (c *Runc) Stop() { func (c *Runc) Stop() {
c.running = false
c.done = true c.done = true
} }
@@ -88,18 +86,15 @@ func (c *Runc) run() {
func (c *Runc) ReadCPU(stats *cgroups.Stats) { func (c *Runc) ReadCPU(stats *cgroups.Stats) {
u := stats.CpuStats.CpuUsage u := stats.CpuStats.CpuUsage
ncpus := float64(len(u.PercpuUsage)) ncpus := uint8(len(u.PercpuUsage))
total := float64(u.TotalUsage) total := float64(u.TotalUsage)
system := float64(getSysCPUUsage()) system := float64(getSysCPUUsage())
cpudiff := total - c.lastCpu cpudiff := total - c.lastCpu
syscpudiff := system - c.lastSysCpu syscpudiff := system - c.lastSysCpu
if c.scaleCpu { c.NCpus = ncpus
c.CPUUtil = round((cpudiff / syscpudiff * 100)) c.CPUUtil = percent(cpudiff, syscpudiff)
} else {
c.CPUUtil = round((cpudiff / syscpudiff * 100) * ncpus)
}
c.lastCpu = total c.lastCpu = total
c.lastSysCpu = system c.lastSysCpu = system
c.Pids = int(stats.PidsStats.Current) c.Pids = int(stats.PidsStats.Current)

View File

@@ -4,6 +4,9 @@ import (
"fmt" "fmt"
"strings" "strings"
"sync" "sync"
"time"
"github.com/op/go-logging"
"github.com/bcicen/ctop/connector/collector" "github.com/bcicen/ctop/connector/collector"
"github.com/bcicen/ctop/connector/manager" "github.com/bcicen/ctop/connector/manager"
@@ -13,10 +16,25 @@ import (
func init() { enabled["docker"] = NewDocker } func init() { enabled["docker"] = NewDocker }
var actionToStatus = map[string]string{
"start": "running",
"die": "exited",
"stop": "exited",
"pause": "paused",
"unpause": "running",
}
type StatusUpdate struct {
Cid string
Field string // "status" or "health"
Status string
}
type Docker struct { type Docker struct {
client *api.Client client *api.Client
containers map[string]*container.Container containers map[string]*container.Container
needsRefresh chan string // container IDs requiring refresh needsRefresh chan string // container IDs requiring refresh
statuses chan StatusUpdate
closed chan struct{} closed chan struct{}
lock sync.RWMutex lock sync.RWMutex
} }
@@ -31,6 +49,7 @@ func NewDocker() (Connector, error) {
client: client, client: client,
containers: make(map[string]*container.Container), containers: make(map[string]*container.Container),
needsRefresh: make(chan string, 60), needsRefresh: make(chan string, 60),
statuses: make(chan StatusUpdate, 60),
closed: make(chan struct{}), closed: make(chan struct{}),
lock: sync.RWMutex{}, lock: sync.RWMutex{},
} }
@@ -48,6 +67,7 @@ func NewDocker() (Connector, error) {
log.Debugf("docker-connector ServerVersion: %s", info.ServerVersion) log.Debugf("docker-connector ServerVersion: %s", info.ServerVersion)
go cm.Loop() go cm.Loop()
go cm.LoopStatuses()
cm.refreshAll() cm.refreshAll()
go cm.watchEvents() go cm.watchEvents()
return cm, nil return cm, nil
@@ -60,22 +80,43 @@ func (cm *Docker) Wait() struct{} { return <-cm.closed }
func (cm *Docker) watchEvents() { func (cm *Docker) watchEvents() {
log.Info("docker event listener starting") log.Info("docker event listener starting")
events := make(chan *api.APIEvents) events := make(chan *api.APIEvents)
cm.client.AddEventListener(events) opts := api.EventsOptions{Filters: map[string][]string{
"type": {"container"},
"event": {"create", "start", "health_status", "pause", "unpause", "stop", "die", "destroy"},
},
}
cm.client.AddEventListenerWithOptions(opts, events)
for e := range events { for e := range events {
if e.Type != "container" { actionName := e.Action
continue
}
actionName := strings.Split(e.Action, ":")[0]
switch actionName { switch actionName {
case "start", "die", "pause", "unpause", "health_status": // most frequent event is a health checks
log.Debugf("handling docker event: action=%s id=%s", e.Action, e.ID) case "health_status: healthy", "health_status: unhealthy":
sepIdx := strings.Index(actionName, ": ")
healthStatus := e.Action[sepIdx+2:]
if log.IsEnabledFor(logging.DEBUG) {
log.Debugf("handling docker event: action=health_status id=%s %s", e.ID, healthStatus)
}
cm.statuses <- StatusUpdate{e.ID, "health", healthStatus}
case "create":
if log.IsEnabledFor(logging.DEBUG) {
log.Debugf("handling docker event: action=create id=%s", e.ID)
}
cm.needsRefresh <- e.ID cm.needsRefresh <- e.ID
case "destroy": case "destroy":
log.Debugf("handling docker event: action=%s id=%s", e.Action, e.ID) if log.IsEnabledFor(logging.DEBUG) {
log.Debugf("handling docker event: action=destroy id=%s", e.ID)
}
cm.delByID(e.ID) cm.delByID(e.ID)
default:
// check if this action changes status e.g. start -> running
status := actionToStatus[actionName]
if status != "" {
if log.IsEnabledFor(logging.DEBUG) {
log.Debugf("handling docker event: action=%s id=%s %s", actionName, e.ID, status)
}
cm.statuses <- StatusUpdate{e.ID, "status", status}
}
} }
} }
log.Info("docker event listener exited") log.Info("docker event listener exited")
@@ -100,6 +141,23 @@ func portsFormat(ports map[api.Port][]api.PortBinding) string {
return strings.Join(append(exposed, published...), "\n") return strings.Join(append(exposed, published...), "\n")
} }
func webPort(ports map[api.Port][]api.PortBinding) string {
for _, v := range ports {
if len(v) == 0 {
continue
}
for _, binding := range v {
publishedIp := binding.HostIP
if publishedIp == "0.0.0.0" {
publishedIp = "localhost"
}
publishedWebPort := fmt.Sprintf("%s:%s", publishedIp, binding.HostPort)
return publishedWebPort
}
}
return ""
}
func ipsFormat(networks map[string]api.ContainerNetwork) string { func ipsFormat(networks map[string]api.ContainerNetwork) string {
var ips []string var ips []string
@@ -112,9 +170,12 @@ func ipsFormat(networks map[string]api.ContainerNetwork) string {
} }
func (cm *Docker) refresh(c *container.Container) { func (cm *Docker) refresh(c *container.Container) {
insp := cm.inspect(c.Id) insp, found, failed := cm.inspect(c.Id)
if failed {
return
}
// remove container if no longer exists // remove container if no longer exists
if insp == nil { if !found {
cm.delByID(c.Id) cm.delByID(c.Id)
return return
} }
@@ -122,22 +183,37 @@ func (cm *Docker) refresh(c *container.Container) {
c.SetMeta("image", insp.Config.Image) c.SetMeta("image", insp.Config.Image)
c.SetMeta("IPs", ipsFormat(insp.NetworkSettings.Networks)) c.SetMeta("IPs", ipsFormat(insp.NetworkSettings.Networks))
c.SetMeta("ports", portsFormat(insp.NetworkSettings.Ports)) c.SetMeta("ports", portsFormat(insp.NetworkSettings.Ports))
c.SetMeta("created", insp.Created.Format("Mon Jan 2 15:04:05 2006")) webPort := webPort(insp.NetworkSettings.Ports)
c.SetMeta("health", insp.State.Health.Status) if webPort != "" {
for _, env := range insp.Config.Env { c.SetMeta("Web Port", webPort)
c.SetMeta("[ENV-VAR]", env)
} }
c.SetMeta("created", insp.Created.Format("Mon Jan 2 15:04:05 2006"))
c.SetMeta("uptime", calcUptime(insp))
c.SetMeta("health", insp.State.Health.Status)
c.SetMeta("[ENV-VAR]", strings.Join(insp.Config.Env, ";"))
c.SetState(insp.State.Status) c.SetState(insp.State.Status)
} }
func (cm *Docker) inspect(id string) *api.Container { func (cm *Docker) inspect(id string) (insp *api.Container, found bool, failed bool) {
c, err := cm.client.InspectContainer(id) c, err := cm.client.InspectContainer(id)
if err != nil { if err != nil {
if _, ok := err.(*api.NoSuchContainer); !ok { if _, notFound := err.(*api.NoSuchContainer); notFound {
log.Errorf("%s (%T)", err.Error(), err) return c, false, false
} }
// other error e.g. connection failed
log.Errorf("%s (%T)", err.Error(), err)
return c, false, true
} }
return c return c, true, false
}
func calcUptime(insp *api.Container) string {
endTime := insp.State.FinishedAt
if endTime.IsZero() {
endTime = time.Now()
}
uptime := endTime.Sub(insp.State.StartedAt)
return uptime.Truncate(time.Second).String()
} }
// Mark all container IDs for refresh // Mark all container IDs for refresh
@@ -169,6 +245,24 @@ func (cm *Docker) Loop() {
} }
} }
func (cm *Docker) LoopStatuses() {
for {
select {
case statusUpdate := <-cm.statuses:
c, _ := cm.Get(statusUpdate.Cid)
if c != nil {
if statusUpdate.Field == "health" {
c.SetMeta("health", statusUpdate.Status)
} else {
c.SetState(statusUpdate.Status)
}
}
case <-cm.closed:
return
}
}
}
// MustGet gets a single container, creating one anew if not existing // MustGet gets a single container, creating one anew if not existing
func (cm *Docker) MustGet(id string) *container.Container { func (cm *Docker) MustGet(id string) *container.Container {
c, ok := cm.Get(id) c, ok := cm.Get(id)
@@ -218,5 +312,5 @@ func (cm *Docker) All() (containers container.Containers) {
// use primary container name // use primary container name
func shortName(name string) string { func shortName(name string) string {
return strings.Replace(name, "/", "", 1) return strings.TrimPrefix(name, "/")
} }

View File

@@ -34,7 +34,7 @@ func New(id string, collector collector.Collector, manager manager.Manager) *Con
return &Container{ return &Container{
Metrics: models.NewMetrics(), Metrics: models.NewMetrics(),
Id: id, Id: id,
Meta: models.NewMeta("id", id), Meta: models.NewMeta("id", id[:12]),
Widgets: widgets, Widgets: widgets,
updater: widgets, updater: widgets,
collector: collector, collector: collector,

View File

@@ -79,6 +79,15 @@ var Sorters = map[string]sortMethod{
} }
return stateMap[c1state] > stateMap[c2state] return stateMap[c1state] > stateMap[c2state]
}, },
"uptime": func(c1, c2 *Container) bool {
// Use secondary sort method if equal values
c1Uptime := c1.GetMeta("uptime")
c2Uptime := c2.GetMeta("uptime")
if c1Uptime == c2Uptime {
return nameSorter(c1, c2)
}
return c1Uptime > c2Uptime
},
} }
func SortFields() (fields []string) { func SortFields() (fields []string) {

View File

@@ -9,14 +9,20 @@ import (
var ( var (
allCols = map[string]NewCompactColFn{ allCols = map[string]NewCompactColFn{
"status": NewStatus, "status": NewStatus,
"name": NewNameCol, "name": NewNameCol,
"id": NewCIDCol, "id": NewCIDCol,
"cpu": NewCPUCol, "image": NewImageCol,
"mem": NewMemCol, "ports": NewPortsCol,
"net": NewNetCol, "IPs": NewIpsCol,
"io": NewIOCol, "created": NewCreatedCol,
"pids": NewPIDCol, "cpu": NewCPUCol,
"cpus": NewCpuScaledCol,
"mem": NewMemCol,
"net": NewNetCol,
"io": NewIOCol,
"pids": NewPIDCol,
"uptime": NewUptimeCol,
} }
) )

View File

@@ -11,15 +11,23 @@ import (
type CPUCol struct { type CPUCol struct {
*GaugeCol *GaugeCol
scaleCpu bool
} }
func NewCPUCol() CompactCol { func NewCPUCol() CompactCol {
return &CPUCol{NewGaugeCol("CPU")} return &CPUCol{NewGaugeCol("CPU"), false}
}
func NewCpuScaledCol() CompactCol {
return &CPUCol{NewGaugeCol("CPUS"), true}
} }
func (w *CPUCol) SetMetrics(m models.Metrics) { func (w *CPUCol) SetMetrics(m models.Metrics) {
val := m.CPUUtil val := m.CPUUtil
w.BarColor = colorScale(val) w.BarColor = colorScale(val)
if !w.scaleCpu {
val = val * int(m.NCpus)
}
w.Label = fmt.Sprintf("%d%%", val) w.Label = fmt.Sprintf("%d%%", val)
if val > 100 { if val > 100 {
@@ -92,11 +100,11 @@ func (w *GaugeCol) UnHighlight() {
} }
func colorScale(n int) ui.Attribute { func colorScale(n int) ui.Attribute {
if n > 70 { if n <= 70 {
return ui.ThemeAttr("status.danger") return ui.ThemeAttr("status.ok")
} }
if n > 30 { if n <= 90 {
return ui.ThemeAttr("status.warn") return ui.ThemeAttr("status.warn")
} }
return ui.ThemeAttr("status.ok") return ui.ThemeAttr("status.danger")
} }

View File

@@ -6,12 +6,6 @@ import (
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
) )
const (
mark = "◉"
healthMark = "✚"
vBar = string('\u25AE') + string('\u25AE')
)
// Status indicator // Status indicator
type Status struct { type Status struct {
*ui.Block *ui.Block
@@ -22,26 +16,18 @@ type Status struct {
func NewStatus() CompactCol { func NewStatus() CompactCol {
s := &Status{ s := &Status{
Block: ui.NewBlock(), Block: ui.NewBlock(),
status: []ui.Cell{{Ch: ' '}},
health: []ui.Cell{{Ch: ' '}}, health: []ui.Cell{{Ch: ' '}},
} }
s.Height = 1 s.Height = 1
s.Border = false s.Border = false
s.setState("")
return s return s
} }
func (s *Status) Buffer() ui.Buffer { func (s *Status) Buffer() ui.Buffer {
buf := s.Block.Buffer() buf := s.Block.Buffer()
x := 0 buf.Set(s.InnerX(), s.InnerY(), s.health[0])
for _, c := range s.health { buf.Set(s.InnerX()+2, s.InnerY(), s.status[0])
buf.Set(s.InnerX()+x, s.InnerY(), c)
x += c.Width()
}
x += 1
for _, c := range s.status {
buf.Set(s.InnerX()+x, s.InnerY(), c)
x += c.Width()
}
return buf return buf
} }
@@ -59,36 +45,48 @@ func (s *Status) Header() string { return "" }
func (s *Status) FixedWidth() int { return 3 } func (s *Status) FixedWidth() int { return 3 }
func (s *Status) setState(val string) { func (s *Status) setState(val string) {
// defaults
text := mark
color := ui.ColorDefault color := ui.ColorDefault
var mark string
switch val { switch val {
case "":
return
case "created":
mark = "◉"
case "running": case "running":
mark = "⏵"
color = ui.ThemeAttr("status.ok") color = ui.ThemeAttr("status.ok")
case "exited": case "exited":
mark = "⏹"
color = ui.ThemeAttr("status.danger") color = ui.ThemeAttr("status.danger")
case "paused": case "paused":
text = vBar mark = "⏸"
default:
mark = " "
log.Warningf("unknown status string: \"%v\"", val)
} }
s.status = ui.TextCells(text, color, ui.ColorDefault) s.status = ui.TextCells(mark, color, ui.ColorDefault)
} }
func (s *Status) setHealth(val string) { func (s *Status) setHealth(val string) {
color := ui.ColorDefault color := ui.ColorDefault
mark := healthMark var mark string
switch val { switch val {
case "": case "":
return return
case "healthy": case "healthy":
mark = "☼"
color = ui.ThemeAttr("status.ok") color = ui.ThemeAttr("status.ok")
case "unhealthy": case "unhealthy":
mark = "⚠"
color = ui.ThemeAttr("status.danger") color = ui.ThemeAttr("status.danger")
case "starting": case "starting":
mark = "◌"
color = ui.ThemeAttr("status.warn") color = ui.ThemeAttr("status.warn")
default: default:
mark = " "
log.Warningf("unknown health state string: \"%v\"", val) log.Warningf("unknown health state string: \"%v\"", val)
} }

View File

@@ -9,30 +9,44 @@ import (
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
) )
type NameCol struct { // Column that shows container's meta property i.e. name, id, image tc.
type MetaCol struct {
*TextCol *TextCol
metaName string
}
func (w *MetaCol) SetMeta(m models.Meta) {
w.setText(m.Get(w.metaName))
} }
func NewNameCol() CompactCol { func NewNameCol() CompactCol {
return &NameCol{NewTextCol("NAME")} c := &MetaCol{NewTextCol("NAME"), "name"}
} c.fWidth = 30
return c
func (w *NameCol) SetMeta(m models.Meta) {
w.setText(m.Get("name"))
}
type CIDCol struct {
*TextCol
} }
func NewCIDCol() CompactCol { func NewCIDCol() CompactCol {
c := &CIDCol{NewTextCol("CID")} c := &MetaCol{NewTextCol("CID"), "id"}
c.fWidth = 12 c.fWidth = 12
return c return c
} }
func (w *CIDCol) SetMeta(m models.Meta) { func NewImageCol() CompactCol {
w.setText(m.Get("id")) return &MetaCol{NewTextCol("IMAGE"), "image"}
}
func NewPortsCol() CompactCol {
return &MetaCol{NewTextCol("PORTS"), "ports"}
}
func NewIpsCol() CompactCol {
return &MetaCol{NewTextCol("IPs"), "IPs"}
}
func NewCreatedCol() CompactCol {
c := &MetaCol{NewTextCol("CREATED"), "created"}
c.fWidth = 19 // Year will be stripped e.g. "Thu Nov 26 07:44:03" without 2020 at end
return c
} }
type NetCol struct { type NetCol struct {
@@ -75,6 +89,18 @@ func (w *PIDCol) SetMetrics(m models.Metrics) {
w.setText(fmt.Sprintf("%d", m.Pids)) w.setText(fmt.Sprintf("%d", m.Pids))
} }
type UptimeCol struct {
*TextCol
}
func NewUptimeCol() CompactCol {
return &UptimeCol{NewTextCol("UPTIME")}
}
func (w *UptimeCol) SetMeta(m models.Meta) {
w.Text = m.Get("uptime")
}
type TextCol struct { type TextCol struct {
*ui.Par *ui.Par
header string header string

View File

@@ -3,6 +3,7 @@ package single
import ( import (
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
"regexp" "regexp"
"strings"
) )
var envPattern = regexp.MustCompile(`(?P<KEY>[^=]+)=(?P<VALUJE>.*)`) var envPattern = regexp.MustCompile(`(?P<KEY>[^=]+)=(?P<VALUJE>.*)`)
@@ -23,14 +24,16 @@ func NewEnv() *Env {
return i return i
} }
func (w *Env) Set(k, v string) { func (w *Env) Set(allEnvs string) {
match := envPattern.FindStringSubmatch(v) envs := strings.Split(allEnvs, ";")
key := match[1]
value := match[2]
w.data[key] = value
w.Rows = [][]string{} w.Rows = [][]string{}
w.Rows = append(w.Rows, mkInfoRows(key, value)...) for _, env := range envs {
match := envPattern.FindStringSubmatch(env)
key := match[1]
value := match[2]
w.data[key] = value
w.Rows = append(w.Rows, mkInfoRows(key, value)...)
}
w.Height = len(w.Rows) + 2 w.Height = len(w.Rows) + 2
} }

View File

@@ -6,21 +6,20 @@ import (
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
) )
var displayInfo = []string{"id", "name", "image", "ports", "IPs", "state", "created", "health"} var displayInfo = []string{"id", "name", "image", "ports", "IPs", "state", "created", "uptime", "health"}
type Info struct { type Info struct {
*ui.Table *ui.Table
data map[string]string data map[string]string
} }
func NewInfo(id string) *Info { func NewInfo() *Info {
p := ui.NewTable() p := ui.NewTable()
p.Height = 4 p.Height = 4
p.Width = colWidth[0] p.Width = colWidth[0]
p.FgColor = ui.ThemeAttr("par.text.fg") p.FgColor = ui.ThemeAttr("par.text.fg")
p.Separator = false p.Separator = false
i := &Info{p, make(map[string]string)} i := &Info{p, make(map[string]string)}
i.Set("id", id)
return i return i
} }

View File

@@ -23,12 +23,9 @@ type Single struct {
Width int Width int
} }
func NewSingle(id string) *Single { func NewSingle() *Single {
if len(id) > 12 {
id = id[:12]
}
return &Single{ return &Single{
Info: NewInfo(id), Info: NewInfo(),
Net: NewNet(), Net: NewNet(),
Cpu: NewCpu(), Cpu: NewCpu(),
Mem: NewMem(), Mem: NewMem(),
@@ -58,7 +55,7 @@ func (e *Single) SetWidth(w int) { e.Width = w }
func (e *Single) SetMeta(m models.Meta) { func (e *Single) SetMeta(m models.Meta) {
for k, v := range m { for k, v := range m {
if k == "[ENV-VAR]" { if k == "[ENV-VAR]" {
e.Env.Set(k, v) e.Env.Set(v)
} else { } else {
e.Info.Set(k, v) e.Info.Set(k, v)
} }

View File

@@ -12,6 +12,10 @@ import (
var mstats = &runtime.MemStats{} var mstats = &runtime.MemStats{}
func logEvent(e ui.Event) { func logEvent(e ui.Event) {
// skip timer events e.g. /timer/1s
if e.From == "timer" {
return
}
var s string var s string
s += fmt.Sprintf("Type=%s", quote(e.Type)) s += fmt.Sprintf("Type=%s", quote(e.Type))
s += fmt.Sprintf(" Path=%s", quote(e.Path)) s += fmt.Sprintf(" Path=%s", quote(e.Path))

8
go.mod
View File

@@ -3,17 +3,17 @@ module github.com/bcicen/ctop
require ( require (
github.com/BurntSushi/toml v0.3.1 github.com/BurntSushi/toml v0.3.1
github.com/c9s/goprocinfo v0.0.0-20170609001544-b34328d6e0cd github.com/c9s/goprocinfo v0.0.0-20170609001544-b34328d6e0cd
github.com/fsouza/go-dockerclient v1.6.6 github.com/fsouza/go-dockerclient v1.7.0
github.com/gizak/termui v2.3.0+incompatible github.com/gizak/termui v2.3.0+incompatible
github.com/jgautheron/codename-generator v0.0.0-20150829203204-16d037c7cc3c github.com/jgautheron/codename-generator v0.0.0-20150829203204-16d037c7cc3c
github.com/mattn/go-runewidth v0.0.0-20170201023540-14207d285c6c // indirect github.com/mattn/go-runewidth v0.0.0-20170201023540-14207d285c6c
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
github.com/nsf/termbox-go v0.0.0-20180303152453-e2050e41c884 github.com/nsf/termbox-go v0.0.0-20180303152453-e2050e41c884
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d
github.com/op/go-logging v0.0.0-20160211212156-b2cb9fa56473 github.com/op/go-logging v0.0.0-20160211212156-b2cb9fa56473
github.com/opencontainers/runc v1.0.0-rc92 github.com/opencontainers/runc v1.0.0-rc95
github.com/pkg/browser v0.0.0-20201207095918-0426ae3fba23
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.4.0
) )
replace github.com/gizak/termui => github.com/bcicen/termui v0.0.0-20180326052246-4eb80249d3f5 replace github.com/gizak/termui => github.com/bcicen/termui v0.0.0-20180326052246-4eb80249d3f5

206
go.sum
View File

@@ -4,70 +4,65 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7O
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
github.com/Microsoft/go-winio v0.4.15-0.20200113171025-3fe6c5262873 h1:93nQ7k53GjoMQ07HVP8g6Zj1fQZDDj7Xy2VkNNtvX8o= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
github.com/Microsoft/go-winio v0.4.15-0.20200113171025-3fe6c5262873/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
github.com/Microsoft/hcsshim v0.8.9 h1:VrfodqvztU8YSOvygU+DN1BGaSGxmrNfqOv5oOuX2Bk= github.com/Microsoft/hcsshim v0.8.10 h1:k5wTrpnVU2/xv8ZuzGkbXVd3js5zJ8RnumPo5RxiIxU=
github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= github.com/Microsoft/hcsshim v0.8.10/go.mod h1:g5uw8EV2mAlzqe94tfNBNdr89fnbD/n3HV0OhsddkmM=
github.com/bcicen/termui v0.0.0-20180326052246-4eb80249d3f5 h1:2pI3ZsoefWIi++8EqmANoC7Px/v2lRwnleVUcCuFgLg= github.com/bcicen/termui v0.0.0-20180326052246-4eb80249d3f5 h1:2pI3ZsoefWIi++8EqmANoC7Px/v2lRwnleVUcCuFgLg=
github.com/bcicen/termui v0.0.0-20180326052246-4eb80249d3f5/go.mod h1:yIA9ITWZD1p4/DvCQ44xvhyVb9XEUlVnY1rzGSHwbiM= github.com/bcicen/termui v0.0.0-20180326052246-4eb80249d3f5/go.mod h1:yIA9ITWZD1p4/DvCQ44xvhyVb9XEUlVnY1rzGSHwbiM=
github.com/c9s/goprocinfo v0.0.0-20170609001544-b34328d6e0cd h1:xqaBnULC8wEnQpRDXAsDgXkU/STqoluz1REOoegSfNU= github.com/c9s/goprocinfo v0.0.0-20170609001544-b34328d6e0cd h1:xqaBnULC8wEnQpRDXAsDgXkU/STqoluz1REOoegSfNU=
github.com/c9s/goprocinfo v0.0.0-20170609001544-b34328d6e0cd/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE= github.com/c9s/goprocinfo v0.0.0-20170609001544-b34328d6e0cd/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/checkpoint-restore/go-criu/v4 v4.1.0 h1:WW2B2uxx9KWF6bGlHqhm8Okiafwwx7Y2kcpn8lCpjgo= github.com/checkpoint-restore/go-criu/v5 v5.0.0 h1:TW8f/UvntYoVDMN1K2HlT82qH1rb0sOjpGw3m6Ym+i4=
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775 h1:cHzBGGVew0ezFsq2grfy2RsB8hO/eNyBgOLHBCqfR1U= github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= github.com/cilium/ebpf v0.5.0 h1:E1KshmrMEtkMP2UjlWzfmUV1owWY+BnbL5FxxuatnrU=
github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 h1:qWj4qVYZ95vLWwqyNJCQg7rDsG5wPdze0UaPolH7DUk=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v1.0.0 h1:fU3UuQapBs+zLJu82NhR11Rif1ny2zfMMAyPJzSN5tQ= github.com/containerd/console v1.0.2 h1:Pi6D+aZXM+oUw1czuKgH5IJ+y0jhYcwBJfx5/Ghn9dE=
github.com/containerd/console v1.0.0/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.4 h1:3o0smo5SKY7H6AJCmJhsnCjR2/V2T8VmiHt7seN2/kI= github.com/containerd/containerd v1.4.1 h1:pASeJT3R3YyVn+94qEPk0SnU1OQ20Jd/T+SPKy9xehY=
github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb h1:nXPkFq8X1a9ycY3GYQpFNxHh3j2JgY7zDZfq2EXMIzk= github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a h1:jEIoR0aA5GogXZ8pP3DUzE+zrhaF6/1rYZy+7KkYEWM=
github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a/go.mod h1:W0qIOTD7mp2He++YVq+kgfXezRYqzP1uDuMVH1bITDY=
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.1 h1:7OO2CXWMYNDdaAzP51t4lCCZWwpQHmvPbm9sxWjm3So=
github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg= github.com/coreos/go-systemd/v22 v22.3.1/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible h1:lwpV3629md5omgAKjxPWX17shI7vMRpE3nyb9WHn8pA=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v17.12.0-ce-rc1.0.20200505174321-1655290016ac+incompatible h1:ZxJX4ZSNg1LORBsStUojbrLfkrE3Ut122XhzyZnN110=
github.com/docker/docker v17.12.0-ce-rc1.0.20200505174321-1655290016ac+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=
github.com/fsouza/go-dockerclient v1.6.6 h1:9e3xkBrVkPb81gzYq23i7iDUEd6sx2ooeJA/gnYU6R4= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/fsouza/go-dockerclient v1.6.6/go.mod h1:3/oRIWoe7uT6bwtAayj/EmJmepBjeL4pYvt7ZxC7Rnk= github.com/fsouza/go-dockerclient v1.7.0 h1:Ie1/8pAnBHNyCbSIDnYKBdXUEobk4AeJhWZz7k6rWfc=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8= github.com/fsouza/go-dockerclient v1.7.0/go.mod h1:Ny0LfP7OOsYu9nAi4339E4Ifor6nGBFO2M8lnd2nR+c=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -75,36 +70,35 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jgautheron/codename-generator v0.0.0-20150829203204-16d037c7cc3c h1:/hc+TxW4Q1v6aqNPHE5jiaNF2xEK0CzWTgo25RQhQ+U= github.com/jgautheron/codename-generator v0.0.0-20150829203204-16d037c7cc3c h1:/hc+TxW4Q1v6aqNPHE5jiaNF2xEK0CzWTgo25RQhQ+U=
github.com/jgautheron/codename-generator v0.0.0-20150829203204-16d037c7cc3c/go.mod h1:FJRkXmPrkHw0WDjB/LXMUhjWJ112Y6JUYnIVBOy8oH8= github.com/jgautheron/codename-generator v0.0.0-20150829203204-16d037c7cc3c/go.mod h1:FJRkXmPrkHw0WDjB/LXMUhjWJ112Y6JUYnIVBOy8oH8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -112,40 +106,39 @@ github.com/mattn/go-runewidth v0.0.0-20170201023540-14207d285c6c h1:eFzthqtg3W6P
github.com/mattn/go-runewidth v0.0.0-20170201023540-14207d285c6c/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.0-20170201023540-14207d285c6c/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/moby/sys/mount v0.1.0 h1:Ytx78EatgFKtrqZ0BvJ0UtJE472ZvawVmil6pIfuCCU= github.com/moby/sys/mount v0.2.0 h1:WhCW5B355jtxndN5ovugJlMFJawbUODuW8fSnEH6SSM=
github.com/moby/sys/mount v0.1.0/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74= github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM=
github.com/moby/sys/mountinfo v0.1.0/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o= github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
github.com/moby/sys/mountinfo v0.1.3 h1:KIrhRO14+AkwKvG/g2yIpNMOUVZ02xNhOw8KY1WsLOI= github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM=
github.com/moby/sys/mountinfo v0.1.3/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
github.com/moby/term v0.0.0-20200429084858-129dac9f73f6 h1:3Y9aosU6S5Bo8GYH0s+t1ej4m30GuUKvQ3c9ZLqdL28= github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf h1:Un6PNx5oMK6CCwO3QTUyPiK2mtZnPrpDl5UnZ64eCkw=
github.com/moby/term v0.0.0-20200429084858-129dac9f73f6/go.mod h1:or9wGItza1sRcM4Wd3dIv8DsFHYQuFsMHEdxUIlUxms= github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mrunalp/fileutils v0.0.0-20200520151820-abd8a0e76976 h1:aZQToFSLH8ejFeSkTc3r3L4dPImcj7Ib/KgmkQqbGGg= github.com/mrunalp/fileutils v0.5.0 h1:NKzVxiH7eSk+OQ4M+ZYW1K6h27RUV3MI6NUTsHhU6Z4=
github.com/mrunalp/fileutils v0.0.0-20200520151820-abd8a0e76976/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/nsf/termbox-go v0.0.0-20180303152453-e2050e41c884 h1:fcs71SMqqDhUD+PbpIv9xf3EH9F9s6HfiLwr6jKm1VA= github.com/nsf/termbox-go v0.0.0-20180303152453-e2050e41c884 h1:fcs71SMqqDhUD+PbpIv9xf3EH9F9s6HfiLwr6jKm1VA=
github.com/nsf/termbox-go v0.0.0-20180303152453-e2050e41c884/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= github.com/nsf/termbox-go v0.0.0-20180303152453-e2050e41c884/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/op/go-logging v0.0.0-20160211212156-b2cb9fa56473 h1:J1QZwDXgZ4dJD2s19iqR9+U00OWM2kDzbf1O/fmvCWg= github.com/op/go-logging v0.0.0-20160211212156-b2cb9fa56473 h1:J1QZwDXgZ4dJD2s19iqR9+U00OWM2kDzbf1O/fmvCWg=
github.com/op/go-logging v0.0.0-20160211212156-b2cb9fa56473/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/op/go-logging v0.0.0-20160211212156-b2cb9fa56473/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc92 h1:+IczUKCRzDzFDnw99O/PAqrcBBCoRp9xN3cB1SYSNS4= github.com/opencontainers/runc v1.0.0-rc95 h1:RMuWVfY3E1ILlVsC3RhIq38n4sJtlOFwU9gfFZSqrd0=
github.com/opencontainers/runc v1.0.0-rc92/go.mod h1:X1zlU4p7wOlX4+WRCz+hvlRv8phdL7UqbYD+vQwNMmE= github.com/opencontainers/runc v1.0.0-rc95/go.mod h1:z+bZxa/+Tz/FmYVWkhUajJdzFeOqjc5vrqskhVyHGUM=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6 h1:NhsM2gc769rVWDqJvapK37r+7+CBXI8xHhnfnt8uQsg= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/selinux v1.6.0 h1:+bIAS/Za3q5FTwWym4fTB0vObnfCf3G/NC7K6Jx62mY= github.com/opencontainers/selinux v1.8.0 h1:+77ba4ar4jsCbL1GLbFL8fFM57w6suPfSS9PDLDY7KM=
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/pkg/browser v0.0.0-20201207095918-0426ae3fba23 h1:dofHuld+js7eKSemxqTVIo8yRlpRw+H1SdpzZxWruBc=
github.com/pkg/browser v0.0.0-20201207095918-0426ae3fba23/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -154,43 +147,36 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo= github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243 h1:R43TdZy32XXSXjJn7M/HhALJ9imq6ztLnChfYJpVDnM= github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE=
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -200,10 +186,10 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -212,25 +198,28 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEha
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 h1:sIky/MyNRSHTrdxfsiUSS4WIAMvInbeXljJz+jDjeYE= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201113234701-d7a72108b828/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -245,36 +234,33 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -83,7 +83,7 @@ func SingleView() MenuFn {
ui.DefaultEvtStream.ResetHandlers() ui.DefaultEvtStream.ResetHandlers()
defer ui.DefaultEvtStream.ResetHandlers() defer ui.DefaultEvtStream.ResetHandlers()
ex := single.NewSingle(c.Id) ex := single.NewSingle()
c.SetUpdater(ex) c.SetUpdater(ex)
ex.Align() ex.Align()
@@ -162,6 +162,9 @@ func Display() bool {
menu = ExecShell menu = ExecShell
ui.StopLoop() ui.StopLoop()
}) })
ui.Handle("/sys/kbd/w", func(ui.Event) {
menu = OpenInBrowser()
})
ui.Handle("/sys/kbd/o", func(ui.Event) { ui.Handle("/sys/kbd/o", func(ui.Event) {
menu = SingleView menu = SingleView
ui.StopLoop() ui.StopLoop()

View File

@@ -29,6 +29,7 @@ type statusMsg struct {
type CTopLogger struct { type CTopLogger struct {
*logging.Logger *logging.Logger
backend *logging.MemoryBackend backend *logging.MemoryBackend
logFile *os.File
sLog []statusMsg sLog []statusMsg
} }
@@ -58,18 +59,37 @@ func Init() *CTopLogger {
Log = &CTopLogger{ Log = &CTopLogger{
logging.MustGetLogger("ctop"), logging.MustGetLogger("ctop"),
logging.NewMemoryBackend(size), logging.NewMemoryBackend(size),
nil,
[]statusMsg{}, []statusMsg{},
} }
if debugMode() { debugMode := debugMode()
if debugMode {
level = logging.DEBUG level = logging.DEBUG
StartServer()
} }
backendLvl := logging.AddModuleLevel(Log.backend) backendLvl := logging.AddModuleLevel(Log.backend)
backendLvl.SetLevel(level, "") backendLvl.SetLevel(level, "")
logging.SetBackend(backendLvl) logFilePath := debugModeFile()
if logFilePath == "" {
logging.SetBackend(backendLvl)
} else {
logFile, err := os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
logging.SetBackend(backendLvl)
Log.Error("Unable to create log file: %s", err.Error())
} else {
backendFile := logging.NewLogBackend(logFile, "", 0)
backendFileLvl := logging.AddModuleLevel(backendFile)
backendFileLvl.SetLevel(level, "")
logging.SetBackend(backendLvl, backendFileLvl)
Log.logFile = logFile
}
}
if debugMode {
StartServer()
}
Log.Notice("logger initialized") Log.Notice("logger initialized")
} }
return Log return Log
@@ -102,8 +122,12 @@ func (log *CTopLogger) tail() chan string {
func (log *CTopLogger) Exit() { func (log *CTopLogger) Exit() {
exited = true exited = true
if log.logFile != nil {
_ = log.logFile.Close()
}
StopServer() StopServer()
} }
func debugMode() bool { return os.Getenv("CTOP_DEBUG") == "1" } func debugMode() bool { return os.Getenv("CTOP_DEBUG") == "1" }
func debugModeTCP() bool { return os.Getenv("CTOP_DEBUG_TCP") == "1" } func debugModeTCP() bool { return os.Getenv("CTOP_DEBUG_TCP") == "1" }
func debugModeFile() string { return os.Getenv("CTOP_DEBUG_FILE") }

10
main.go
View File

@@ -44,9 +44,7 @@ func main() {
sortFieldFlag = flag.String("s", "", "select container sort field") sortFieldFlag = flag.String("s", "", "select container sort field")
reverseSortFlag = flag.Bool("r", false, "reverse container sort order") reverseSortFlag = flag.Bool("r", false, "reverse container sort order")
invertFlag = flag.Bool("i", false, "invert default colors") invertFlag = flag.Bool("i", false, "invert default colors")
scaleCpu = flag.Bool("scale-cpu", false, "show cpu as % of system total")
connectorFlag = flag.String("connector", "docker", "container connector to use") connectorFlag = flag.String("connector", "docker", "container connector to use")
defaultShell = flag.String("shell", "sh", "exec shell to use")
) )
flag.Parse() flag.Parse()
@@ -87,14 +85,6 @@ func main() {
config.Toggle("sortReversed") config.Toggle("sortReversed")
} }
if *scaleCpu {
config.Toggle("scaleCpu")
}
if *defaultShell != "" {
config.Update("shell", *defaultShell)
}
// init ui // init ui
if *invertFlag { if *invertFlag {
InvertColorMap() InvertColorMap()

View File

@@ -10,6 +10,7 @@ import (
"github.com/bcicen/ctop/widgets" "github.com/bcicen/ctop/widgets"
"github.com/bcicen/ctop/widgets/menu" "github.com/bcicen/ctop/widgets/menu"
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
"github.com/pkg/browser"
) )
// MenuFn executes a menu window, returning the next menu or nil // MenuFn executes a menu window, returning the next menu or nil
@@ -27,6 +28,7 @@ var helpDialog = []menu.Item{
{"[o] - open single view", ""}, {"[o] - open single view", ""},
{"[l] - view container logs ([t] to toggle timestamp when open)", ""}, {"[l] - view container logs ([t] to toggle timestamp when open)", ""},
{"[e] - exec shell", ""}, {"[e] - exec shell", ""},
{"[w] - open browser (first port is http)", ""},
{"[c] - configure columns", ""}, {"[c] - configure columns", ""},
{"[S] - save current configuration to file", ""}, {"[S] - save current configuration to file", ""},
{"[q] - exit ctop", ""}, {"[q] - exit ctop", ""},
@@ -130,7 +132,7 @@ func ColumnsMenu() MenuFn {
m.Selectable = true m.Selectable = true
m.SortItems = false m.SortItems = false
m.BorderLabel = "Columns" m.BorderLabel = "Columns"
//m.SubText = "Enabled Columns" m.SubText = "Re-order: <Page Up> / <Page Down>"
rebuild := func() { rebuild := func() {
// get padding for right alignment of enabled status // get padding for right alignment of enabled status
@@ -221,6 +223,9 @@ func ContainerMenu() MenuFn {
items = append(items, menu.Item{Val: "pause", Label: "[p] pause"}) items = append(items, menu.Item{Val: "pause", Label: "[p] pause"})
items = append(items, menu.Item{Val: "restart", Label: "[r] restart"}) items = append(items, menu.Item{Val: "restart", Label: "[r] restart"})
items = append(items, menu.Item{Val: "exec", Label: "[e] exec shell"}) items = append(items, menu.Item{Val: "exec", Label: "[e] exec shell"})
if c.Meta["Web Port"] != "" {
items = append(items, menu.Item{Val: "browser", Label: "[w] open in browser"})
}
} }
if c.Meta["state"] == "exited" || c.Meta["state"] == "created" { if c.Meta["state"] == "exited" || c.Meta["state"] == "created" {
items = append(items, menu.Item{Val: "start", Label: "[s] start"}) items = append(items, menu.Item{Val: "start", Label: "[s] start"})
@@ -258,7 +263,7 @@ func ContainerMenu() MenuFn {
ui.StopLoop() ui.StopLoop()
}) })
} }
if c.Meta["state"] != "exited" || c.Meta["state"] != "created" { if c.Meta["state"] != "exited" && c.Meta["state"] != "created" {
ui.Handle("/sys/kbd/p", func(ui.Event) { ui.Handle("/sys/kbd/p", func(ui.Event) {
if c.Meta["state"] == "paused" { if c.Meta["state"] == "paused" {
selected = "unpause" selected = "unpause"
@@ -277,6 +282,11 @@ func ContainerMenu() MenuFn {
selected = "restart" selected = "restart"
ui.StopLoop() ui.StopLoop()
}) })
if c.Meta["Web Port"] != "" {
ui.Handle("/sys/kbd/w", func(ui.Event) {
selected = "browser"
})
}
} }
ui.Handle("/sys/kbd/R", func(ui.Event) { ui.Handle("/sys/kbd/R", func(ui.Event) {
selected = "remove" selected = "remove"
@@ -303,6 +313,8 @@ func ContainerMenu() MenuFn {
nextMenu = LogMenu nextMenu = LogMenu
case "exec": case "exec":
nextMenu = ExecShell nextMenu = ExecShell
case "browser":
nextMenu = OpenInBrowser
case "start": case "start":
nextMenu = Confirm(confirmTxt("start", c.GetMeta("name")), c.Start) nextMenu = Confirm(confirmTxt("start", c.GetMeta("name")), c.Start)
case "stop": case "stop":
@@ -358,15 +370,37 @@ func ExecShell() MenuFn {
ui.DefaultEvtStream.ResetHandlers() ui.DefaultEvtStream.ResetHandlers()
defer ui.DefaultEvtStream.ResetHandlers() defer ui.DefaultEvtStream.ResetHandlers()
// Detect and execute default shell in container.
shell := config.Get("shell") // Execute Ash shell command: /bin/sh -c
if err := c.Exec([]string{shell.Val, "-c", "printf '\\e[0m\\e[?25h' && clear && " + shell.Val}); err != nil { // Reset colors: printf '\e[0m\e[?25h'
log.Fatal(err) // Clear screen
// Run default shell for the user. It's configured in /etc/passwd and looks like root:x:0:0:root:/root:/bin/bash:
// 1. Get current user id: id -un
// 2. Find user's line in /etc/passwd by grep
// 3. Extract default user's shell by cutting seven's column separated by :
// 4. Execute the shell path with eval
if err := c.Exec([]string{"/bin/sh", "-c", "printf '\\e[0m\\e[?25h' && clear && eval `grep ^$(id -un): /etc/passwd | cut -d : -f 7-`"}); err != nil {
log.StatusErr(err)
} }
return nil return nil
} }
func OpenInBrowser() MenuFn {
c := cursor.Selected()
if c == nil {
return nil
}
webPort := c.Meta.Get("Web Port")
if webPort == "" {
return nil
}
link := "http://" + webPort + "/"
browser.OpenURL(link)
return nil
}
// Create a confirmation dialog with a given description string and // Create a confirmation dialog with a given description string and
// func to perform if confirmed // func to perform if confirmed
func Confirm(txt string, fn func()) MenuFn { func Confirm(txt string, fn func()) MenuFn {

View File

@@ -31,6 +31,7 @@ func (m Meta) Get(k string) string {
} }
type Metrics struct { type Metrics struct {
NCpus uint8
CPUUtil int CPUUtil int
NetTx int64 NetTx int64
NetRx int64 NetRx int64

View File

@@ -2,6 +2,7 @@ package widgets
import ( import (
ui "github.com/gizak/termui" ui "github.com/gizak/termui"
"github.com/mattn/go-runewidth"
) )
type ToggleText interface { type ToggleText interface {
@@ -70,7 +71,7 @@ func (t *TextView) Buffer() ui.Buffer {
for _, ch := range line { for _, ch := range line {
cell = ui.Cell{Ch: ch, Fg: t.TextFgColor, Bg: t.TextBgColor} cell = ui.Cell{Ch: ch, Fg: t.TextFgColor, Bg: t.TextBgColor}
buf.Set(x, y, cell) buf.Set(x, y, cell)
x++ x = x + runewidth.RuneWidth(ch)
} }
x = t.Block.X + t.padding[0] x = t.Block.X + t.padding[0]
y++ y++