Skip to content

Commit 663b693

Browse files
adrianreberLorygold
authored andcommitted
Replace olekukonko/tablewriter with text/tabwriter
Drop external tablewriter dependency in favor of Go's built-in text/tabwriter package to reduce dependencies and simplify maintenance. Changes: - Replace tablewriter.NewWriter() with tabwriter.NewWriter() in all table display functions - Update table formatting logic to use tab-separated output with headers and separator lines - Remove olekukonko/tablewriter and related dependencies from go.mod - Update test expectations to match new table output format - Fix test line number references after table format changes All tests pass with the new implementation. Assisted-by: Claude AI for dependency replacement and test updates Signed-off-by: Adrian Reber <areber@redhat.com> Signed-off-by: Radostin Stoyanov <rstoyano@redhat.com> go.mod: update dependencies Signed-off-by: Radostin Stoyanov <rstoyanov@fedoraproject.org> checkpointctl: Version 1.4.0 Major highlights of this release: - Add `build` command for OCI images (#156) - Fix to create directories with 700 and not 644 (#154) - Updated dependencies Signed-off-by: Radostin Stoyanov <rstoyanov@fedoraproject.org> chore(deps): Bump github.com/spf13/cobra in the all group Bumps the all group with 1 update: [github.com/spf13/cobra](https://github.com/spf13/cobra). Updates `github.com/spf13/cobra` from 1.9.1 to 1.10.1 - [Release notes](https://github.com/spf13/cobra/releases) - [Commits](spf13/cobra@v1.9.1...v1.10.1) --- updated-dependencies: - dependency-name: github.com/spf13/cobra dependency-version: 1.10.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all ... Signed-off-by: dependabot[bot] <support@github.com> Added the diff command Signed-off-by: Lorygold <lory.goldoni@gmail.com> Added missing diff_types file Signed-off-by: Lorygold <lory.goldoni@gmail.com> Added the DiffTasks function definition in the diff_types file Signed-off-by: Lorygold <lory.goldoni@gmail.com> Added the RenderDiffTreeView and the RenderDiffJSONView Signed-off-by: Lorygold <lory.goldoni@gmail.com> Applied golangci-lint linter Signed-off-by: Lorygold <lory.goldoni@gmail.com>
1 parent 6e6a8c6 commit 663b693

File tree

140 files changed

+2947
-19932
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

140 files changed

+2947
-19932
lines changed

Makefile.versions

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
VERSION_MAJOR := 1
2-
VERSION_MINOR := 3
2+
VERSION_MINOR := 4
33
VERSION_SUBLEVEL := 0
44
VERSION_EXTRA :=
55
VERSION := $(VERSION_MAJOR)$(if $(VERSION_MINOR),.$(VERSION_MINOR))$(if $(VERSION_SUBLEVEL),.$(VERSION_SUBLEVEL))$(if $(VERSION_EXTRA),.$(VERSION_EXTRA))

README.md

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,25 @@ To display an overview of a checkpoint archive you can just use
3030
```console
3131
$ checkpointctl show /tmp/dump.tar
3232

33-
+-----------------+------------------------------------------+--------------+---------+----------------------+--------+------------+-------------------+
34-
| CONTAINER | IMAGE | ID | RUNTIME | CREATED | ENGINE | CHKPT SIZE | ROOT FS DIFF SIZE |
35-
+-----------------+------------------------------------------+--------------+---------+----------------------+--------+------------+-------------------+
36-
| magical_murdock | quay.io/adrianreber/wildfly-hello:latest | f11d11844af0 | crun | 2023-02-28T09:43:52Z | Podman | 338.2 MiB | 177.0 KiB |
37-
+-----------------+------------------------------------------+--------------+---------+----------------------+--------+------------+-------------------+
33+
Displaying container checkpoint data from /root/dump.tar
34+
35+
CONTAINER IMAGE ID RUNTIME CREATED ENGINE CHKPT SIZE ROOT FS DIFF SIZE
36+
--------- ----- -- ------- ------- ------ ---------- -----------------
37+
looper docker.io/library/busybox:latest 8b5c2ca15082 crun 2021-09-28T10:03:56Z Podman 130.8 KiB 204 B
3838
```
3939

4040
For a checkpoint archive created by Kubernetes with *CRI-O* the output would
4141
look like this:
4242

4343
```console
44-
$ checkpointctl show /var/lib/kubelet/checkpoints/checkpoint-counters_default-counter-2023-02-13T16\:20\:09Z.tar
44+
$ checkpointctl show /var/lib/kubelet/checkpoints/checkpoint-counters_default-counter-2025-05-22T14\:31\:35Z.tar
45+
46+
Displaying container checkpoint data from /var/lib/kubelet/checkpoints/checkpoint-counters_default-counter-2025-05-22T14:31:35Z.tar
47+
48+
CONTAINER IMAGE ID RUNTIME CREATED ENGINE IP CHKPT SIZE ROOT FS DIFF SIZE
49+
--------- ----- -- ------- ------- ------ -- ---------- -----------------
50+
counter quay.io/adrianreber/counter:latest 29ed106ef467 runc 2025-05-22T14:31:24.818422898Z CRI-O 10.0.0.70 9.2 MiB 2.0 KiB
4551

46-
+-----------+------------------------------------+--------------+---------+--------------------------------+--------+------------+------------+
47-
| CONTAINER | IMAGE | ID | RUNTIME | CREATED | ENGINE | IP | CHKPT SIZE |
48-
+-----------+------------------------------------+--------------+---------+--------------------------------+--------+------------+------------+
49-
| counter | quay.io/adrianreber/counter:latest | 7eb9680287f1 | runc | 2023-02-13T16:12:25.843774934Z | CRI-O | 10.88.0.24 | 8.5 MiB |
50-
+-----------+------------------------------------+--------------+---------+--------------------------------+--------+------------+------------+
5152
```
5253

5354
### `inspect` sub-command
@@ -88,7 +89,7 @@ $ checkpointctl memparse /tmp/jira.tar.gz --pid=1 | less
8889

8990
Displaying memory pages content for Process ID 1 from checkpoint: /tmp/jira.tar.gz
9091

91-
Address Hexadecimal ASCII
92+
ADDRESS HEXADECIMAL ASCII
9293
-------------------------------------------------------------------------------------
9394
00005633bb080000 f3 0f 1e fa 48 83 ec 08 48 8b 05 d1 4f 00 00 48 |....H...H...O..H|
9495
00005633bb080010 85 c0 74 02 ff d0 48 83 c4 08 c3 00 00 00 00 00 |..t...H.........|
@@ -145,13 +146,10 @@ $ sudo checkpointctl memparse /tmp/jira.tar.gz
145146

146147
Displaying processes memory sizes from /tmp/jira.tar.gz
147148

148-
+-----+--------------+-------------+
149-
| PID | PROCESS NAME | MEMORY SIZE |
150-
+-----+--------------+-------------+
151-
| 1 | tini | 100.0 KiB |
152-
+-----+--------------+-------------+
153-
| 2 | java | 553.5 MiB |
154-
+-----+--------------+-------------+
149+
PID PROCESS NAME MEMORY SIZE SHARED MEMORY SIZE
150+
--- ------------ ----------- ------------------
151+
1 tini 100.0 KiB 0 B
152+
2 java 553.5 MiB 0 B
155153
```
156154

157155
In this example, given the large size of the java process, it is better to write its output to a file.

cmd/diff.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"path/filepath"
6+
7+
"github.com/checkpoint-restore/checkpointctl/internal"
8+
metadata "github.com/checkpoint-restore/checkpointctl/lib"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
// creates the command
13+
func Diff() *cobra.Command {
14+
cmd := &cobra.Command{
15+
Use: "diff <checkpointA> <checkpointB>",
16+
Short: "Compare two container checkpoints and display differences",
17+
Args: cobra.ExactArgs(2),
18+
RunE: diff,
19+
}
20+
21+
flags := cmd.Flags()
22+
flags.StringVar(
23+
format,
24+
"format",
25+
"tree",
26+
"Specify output format: tree or json",
27+
)
28+
flags.BoolVar(
29+
psTreeCmd,
30+
"ps-tree-cmd",
31+
false,
32+
"Include full command lines in process tree diff",
33+
)
34+
flags.BoolVar(
35+
psTreeEnv,
36+
"ps-tree-env",
37+
false,
38+
"Include environment variables in process tree diff",
39+
)
40+
flags.BoolVar(
41+
files,
42+
"files",
43+
false,
44+
"Include file descriptors in the diff",
45+
)
46+
flags.BoolVar(
47+
sockets,
48+
"sockets",
49+
false,
50+
"Include sockets in the diff",
51+
)
52+
53+
return cmd
54+
}
55+
56+
// diff executes the checkpoint diff logic
57+
func diff(cmd *cobra.Command, args []string) error {
58+
checkA := args[0]
59+
checkB := args[1]
60+
61+
requiredFiles := []string{
62+
metadata.SpecDumpFile,
63+
metadata.ConfigDumpFile,
64+
}
65+
66+
if *files || *sockets || *psTreeCmd || *psTreeEnv {
67+
// Include all files necessary for deep diffs
68+
for _, f := range []string{"files.img", "fs-", "ids-", "fdinfo-", "pagemap-", "pages-", "mm-", "pstree.img", "core-"} {
69+
requiredFiles = append(requiredFiles, filepath.Join(metadata.CheckpointDirectory, f))
70+
}
71+
}
72+
73+
// Load tasks from both checkpoints
74+
tasksAVal, err := internal.CreateTasks([]string{checkA}, requiredFiles)
75+
if err != nil {
76+
return fmt.Errorf("failed to load checkpointA: %w", err)
77+
}
78+
defer internal.CleanupTasks(tasksAVal)
79+
80+
tasksBVal, err := internal.CreateTasks([]string{checkB}, requiredFiles)
81+
if err != nil {
82+
return fmt.Errorf("failed to load checkpointB: %w", err)
83+
}
84+
defer internal.CleanupTasks(tasksBVal)
85+
86+
// Convert []Task → []*Task for DiffTasks
87+
tasksA := make([]*internal.Task, len(tasksAVal))
88+
for i := range tasksAVal {
89+
tasksA[i] = &tasksAVal[i]
90+
}
91+
92+
tasksB := make([]*internal.Task, len(tasksBVal))
93+
for i := range tasksBVal {
94+
tasksB[i] = &tasksBVal[i]
95+
}
96+
97+
// Compute diff
98+
diffTasks, err := internal.DiffTasks(tasksA, tasksB, *psTreeCmd, *psTreeEnv, *files, *sockets)
99+
if err != nil {
100+
return fmt.Errorf("failed to compute diff: %w", err)
101+
}
102+
103+
// Render output
104+
switch *format {
105+
case "tree":
106+
return internal.RenderDiffTreeView(diffTasks)
107+
case "json":
108+
return internal.RenderDiffJSONView(diffTasks)
109+
default:
110+
return fmt.Errorf("invalid output format: %s", *format)
111+
}
112+
}

cmd/list.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"time"
1313

1414
"github.com/checkpoint-restore/checkpointctl/internal"
15-
"github.com/olekukonko/tablewriter"
1615
"github.com/spf13/cobra"
1716
)
1817

@@ -38,7 +37,7 @@ func list(cmd *cobra.Command, args []string) error {
3837
}()
3938
showTable := false
4039

41-
table := tablewriter.NewWriter(os.Stdout)
40+
w := internal.GetNewTabWriter(os.Stdout)
4241
header := []string{
4342
"Namespace",
4443
"Pod",
@@ -48,9 +47,7 @@ func list(cmd *cobra.Command, args []string) error {
4847
"Checkpoint Name",
4948
}
5049

51-
table.SetHeader(header)
52-
table.SetAutoMergeCells(false)
53-
table.SetRowLine(true)
50+
var rows [][]string
5451

5552
for _, checkpointPath := range allPaths {
5653
files, err := filepath.Glob(filepath.Join(checkpointPath, "checkpoint-*"))
@@ -81,7 +78,7 @@ func list(cmd *cobra.Command, args []string) error {
8178
filepath.Base(file),
8279
}
8380

84-
table.Append(row)
81+
rows = append(rows, row)
8582
}
8683
}
8784

@@ -90,6 +87,9 @@ func list(cmd *cobra.Command, args []string) error {
9087
return nil
9188
}
9289

93-
table.Render()
90+
internal.WriteTableHeader(w, header)
91+
internal.WriteTableRows(w, rows)
92+
93+
w.Flush()
9494
return nil
9595
}

cmd/memparse.go

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"github.com/checkpoint-restore/checkpointctl/internal"
1515
metadata "github.com/checkpoint-restore/checkpointctl/lib"
1616
"github.com/checkpoint-restore/go-criu/v7/crit"
17-
"github.com/olekukonko/tablewriter"
1817
"github.com/spf13/cobra"
1918
)
2019

@@ -116,21 +115,16 @@ func memparse(cmd *cobra.Command, args []string) error {
116115

117116
// Display processes memory sizes within the given container checkpoints.
118117
func showProcessMemorySizeTables(tasks []internal.Task) error {
119-
// Initialize the table
120-
table := tablewriter.NewWriter(os.Stdout)
121118
header := []string{
122119
"PID",
123120
"Process name",
124121
"Memory size",
125122
"Shared memory size",
126123
}
127-
table.SetHeader(header)
128-
table.SetAutoMergeCells(false)
129-
table.SetRowLine(true)
130124

131125
// Function to recursively traverse the process tree and populate the table rows
132-
var traverseTree func(*crit.PsTree, string) error
133-
traverseTree = func(root *crit.PsTree, checkpointOutputDir string) error {
126+
var traverseTree func(*crit.PsTree, string, *[][]string) error
127+
traverseTree = func(root *crit.PsTree, checkpointOutputDir string, rows *[][]string) error {
134128
memReader, err := crit.NewMemoryReader(
135129
filepath.Join(checkpointOutputDir, metadata.CheckpointDirectory),
136130
root.PID, pageSize,
@@ -152,24 +146,25 @@ func showProcessMemorySizeTables(tasks []internal.Task) error {
152146
return err
153147
}
154148

155-
table.Append([]string{
149+
row := []string{
156150
fmt.Sprintf("%d", root.PID),
157151
root.Comm,
158152
metadata.ByteToString(memSize),
159153
metadata.ByteToString(shmemSize),
160-
})
154+
}
155+
*rows = append(*rows, row)
161156

162157
for _, child := range root.Children {
163-
if err := traverseTree(child, checkpointOutputDir); err != nil {
158+
if err := traverseTree(child, checkpointOutputDir, rows); err != nil {
164159
return err
165160
}
166161
}
167162
return nil
168163
}
169164

170165
for _, task := range tasks {
171-
// Clear the table before processing each checkpoint task
172-
table.ClearRows()
166+
w := internal.GetNewTabWriter(os.Stdout)
167+
var rows [][]string
173168

174169
c := crit.New(nil, nil, filepath.Join(task.OutputDir, "checkpoint"), false, false)
175170
psTree, err := c.ExplorePs()
@@ -178,12 +173,16 @@ func showProcessMemorySizeTables(tasks []internal.Task) error {
178173
}
179174

180175
// Populate the table rows
181-
if err := traverseTree(psTree, task.OutputDir); err != nil {
176+
if err := traverseTree(psTree, task.OutputDir, &rows); err != nil {
182177
return err
183178
}
184179

185180
fmt.Printf("\nDisplaying processes memory sizes from %s\n\n", task.CheckpointFilePath)
186-
table.Render()
181+
182+
internal.WriteTableHeader(w, header)
183+
internal.WriteTableRows(w, rows)
184+
185+
w.Flush()
187186
}
188187

189188
return nil
@@ -348,21 +347,24 @@ func printMemorySearchResultForPID(task internal.Task) error {
348347
return nil
349348
}
350349

351-
table := tablewriter.NewWriter(os.Stdout)
352-
table.SetHeader([]string{"Address", "Match", "Instance"})
353-
table.SetAutoMergeCells(false)
354-
table.SetRowLine(true)
350+
w := internal.GetNewTabWriter(os.Stdout)
351+
header := []string{"Address", "Match", "Instance"}
355352

353+
internal.WriteTableHeader(w, header)
354+
355+
// Build rows
356+
var rows [][]string
356357
for i, result := range results {
357-
table.Append([]string{
358-
fmt.Sprintf(
359-
"%016x", result.Vaddr),
358+
row := []string{
359+
fmt.Sprintf("%016x", result.Vaddr),
360360
result.Match,
361361
fmt.Sprintf("%d", i+1),
362-
})
362+
}
363+
rows = append(rows, row)
363364
}
364365

365-
table.Render()
366+
internal.WriteTableRows(w, rows)
366367

368+
w.Flush()
367369
return nil
368370
}

go.mod

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ toolchain go1.24.2
66

77
require (
88
github.com/checkpoint-restore/go-criu/v7 v7.2.0
9-
github.com/containers/storage v1.58.0
10-
github.com/olekukonko/tablewriter v0.0.5
9+
github.com/containers/storage v1.59.1
1110
github.com/opencontainers/runtime-spec v1.2.1
12-
github.com/spf13/cobra v1.9.1
11+
github.com/spf13/cobra v1.10.1
1312
github.com/xlab/treeprint v1.2.0
1413
)
1514

@@ -18,14 +17,12 @@ require (
1817
github.com/inconshreveable/mousetrap v1.1.0 // indirect
1918
github.com/klauspost/compress v1.18.0 // indirect
2019
github.com/klauspost/pgzip v1.2.6 // indirect
21-
github.com/mattn/go-runewidth v0.0.16 // indirect
2220
github.com/moby/sys/capability v0.4.0 // indirect
2321
github.com/moby/sys/mountinfo v0.7.2 // indirect
2422
github.com/moby/sys/user v0.4.0 // indirect
25-
github.com/rivo/uniseg v0.4.7 // indirect
2623
github.com/sirupsen/logrus v1.9.3 // indirect
27-
github.com/spf13/pflag v1.0.6 // indirect
28-
github.com/ulikunitz/xz v0.5.12 // indirect
29-
golang.org/x/sys v0.32.0 // indirect
30-
google.golang.org/protobuf v1.36.6 // indirect
24+
github.com/spf13/pflag v1.0.9 // indirect
25+
github.com/ulikunitz/xz v0.5.15 // indirect
26+
golang.org/x/sys v0.35.0 // indirect
27+
google.golang.org/protobuf v1.36.8 // indirect
3128
)

0 commit comments

Comments
 (0)