refactor: move `ipfs stat provide/reprovide` to `ipfs provide stat` (#10896)
- Move `ipfs stat reprovide` to `ipfs provide stat` - Mark `ipfs stat provide` as deprecated and replaces by `ipfs provide stat` - Mark `ipfs stat reprovide` as deprecated and replaces by `ipfs provide stat` - Remove redundant code from deprecated subcommands Closes #10869
Andrew Gillis committed
Aug 7, 2025 at 17:17 UTC
918aa07c9ee64500f57eab8b8e12e9a4c727a94e
5 files changed
+124
-144
core/commands/commands_test.go
+1
@@ -165,6 +165,7 @@ func TestCommands(t *testing.T) {
165
"/ping",
166
"/provide",
167
"/provide/clear",
168
+ "/provide/stat",
169
"/pubsub",
170
"/pubsub/ls",
171
"/pubsub/peers",
core/commands/provide.go
+99
-3
@@ -3,9 +3,15 @@ package commands
3
import (
4
"fmt"
5
"io"
6
+ "text/tabwriter"
7
+ "time"
8
9
+ humanize "github.com/dustin/go-humanize"
10
+ "github.com/ipfs/boxo/provider"
11
cmds "github.com/ipfs/go-ipfs-cmds"
8
- cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
12
+ "github.com/ipfs/kubo/core/commands/cmdenv"
13
+ "github.com/libp2p/go-libp2p-kad-dht/fullrt"
14
+ "golang.org/x/exp/constraints"
15
)
16
17
const (
@@ -28,11 +34,12 @@ reprovide' provides statistics. Additionally, 'ipfs bitswap reprovide' and
34
},
35
36
Subcommands: map[string]*cmds.Command{
31
- "clear": ProvideClearCmd,
37
+ "clear": provideClearCmd,
38
+ "stat": provideStatCmd,
39
},
40
}
41
35
-var ProvideClearCmd = &cmds.Command{
42
+var provideClearCmd = &cmds.Command{
43
Status: cmds.Experimental,
44
Helptext: cmds.HelpText{
45
Tagline: "Clear all CIDs from the provide queue.",
@@ -80,3 +87,92 @@ https://github.com/ipfs/kubo/blob/master/docs/config.md#reproviderstrategy
87
}),
88
},
89
}
90
+
91
+type provideStats struct {
92
+ provider.ReproviderStats
93
+ fullRT bool
94
+}
95
+
96
+var provideStatCmd = &cmds.Command{
97
+ Status: cmds.Experimental,
98
+ Helptext: cmds.HelpText{
99
+ Tagline: "Returns statistics about the node's provider system.",
100
+ ShortDescription: `
101
+Returns statistics about the content the node is reproviding every
102
+Reprovider.Interval according to Reprovider.Strategy:
103
+https://github.com/ipfs/kubo/blob/master/docs/config.md#reprovider
104
+
105
+This interface is not stable and may change from release to release.
106
+
107
+`,
108
+ },
109
+ Arguments: []cmds.Argument{},
110
+ Options: []cmds.Option{},
111
+ Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
112
+ nd, err := cmdenv.GetNode(env)
113
+ if err != nil {
114
+ return err
115
+ }
116
+
117
+ if !nd.IsOnline {
118
+ return ErrNotOnline
119
+ }
120
+
121
+ stats, err := nd.Provider.Stat()
122
+ if err != nil {
123
+ return err
124
+ }
125
+ _, fullRT := nd.DHTClient.(*fullrt.FullRT)
126
+
127
+ if err := res.Emit(provideStats{stats, fullRT}); err != nil {
128
+ return err
129
+ }
130
+
131
+ return nil
132
+ },
133
+ Encoders: cmds.EncoderMap{
134
+ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, s provideStats) error {
135
+ wtr := tabwriter.NewWriter(w, 1, 2, 1, ' ', 0)
136
+ defer wtr.Flush()
137
+
138
+ fmt.Fprintf(wtr, "TotalReprovides:\t%s\n", humanNumber(s.TotalReprovides))
139
+ fmt.Fprintf(wtr, "AvgReprovideDuration:\t%s\n", humanDuration(s.AvgReprovideDuration))
140
+ fmt.Fprintf(wtr, "LastReprovideDuration:\t%s\n", humanDuration(s.LastReprovideDuration))
141
+ if !s.LastRun.IsZero() {
142
+ fmt.Fprintf(wtr, "LastReprovide:\t%s\n", humanTime(s.LastRun))
143
+ if s.fullRT {
144
+ fmt.Fprintf(wtr, "NextReprovide:\t%s\n", humanTime(s.LastRun.Add(s.ReprovideInterval)))
145
+ }
146
+ }
147
+ return nil
148
+ }),
149
+ },
150
+ Type: provideStats{},
151
+}
152
+
153
+func humanDuration(val time.Duration) string {
154
+ return val.Truncate(time.Microsecond).String()
155
+}
156
+
157
+func humanTime(val time.Time) string {
158
+ return val.Format("2006-01-02 15:04:05")
159
+}
160
+
161
+func humanNumber[T constraints.Float | constraints.Integer](n T) string {
162
+ nf := float64(n)
163
+ str := humanSI(nf, 0)
164
+ fullStr := humanFull(nf, 0)
165
+ if str != fullStr {
166
+ return fmt.Sprintf("%s\t(%s)", str, fullStr)
167
+ }
168
+ return str
169
+}
170
+
171
+func humanSI(val float64, decimals int) string {
172
+ v, unit := humanize.ComputeSI(val)
173
+ return fmt.Sprintf("%s%s", humanFull(v, decimals), unit)
174
+}
175
+
176
+func humanFull(val float64, decimals int) string {
177
+ return humanize.CommafWithDigits(val, decimals)
178
+}
core/commands/stat_provide.go
+6
-49
@@ -1,65 +1,22 @@
1
package commands
2
3
import (
4
- "fmt"
5
- "io"
6
- "text/tabwriter"
7
-
4
cmds "github.com/ipfs/go-ipfs-cmds"
9
- "github.com/ipfs/kubo/core/commands/cmdenv"
10
- "github.com/libp2p/go-libp2p-kad-dht/fullrt"
5
)
6
7
var statProvideCmd = &cmds.Command{
8
Status: cmds.Deprecated,
9
Helptext: cmds.HelpText{
16
- Tagline: "Deprecated command, use 'ipfs stats reprovide' instead.",
10
+ Tagline: "Deprecated command, use 'ipfs provide stat' instead.",
11
ShortDescription: `
12
'ipfs stats provide' is deprecated because provide and reprovide operations
13
are now distinct. This command may be replaced by provide only stats in the
14
future.
15
`,
16
},
23
- Arguments: []cmds.Argument{},
24
- Options: []cmds.Option{},
25
- Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
26
- nd, err := cmdenv.GetNode(env)
27
- if err != nil {
28
- return err
29
- }
30
-
31
- if !nd.IsOnline {
32
- return ErrNotOnline
33
- }
34
-
35
- stats, err := nd.Provider.Stat()
36
- if err != nil {
37
- return err
38
- }
39
- _, fullRT := nd.DHTClient.(*fullrt.FullRT)
40
-
41
- if err := res.Emit(reprovideStats{stats, fullRT}); err != nil {
42
- return err
43
- }
44
-
45
- return nil
46
- },
47
- Encoders: cmds.EncoderMap{
48
- cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, s reprovideStats) error {
49
- wtr := tabwriter.NewWriter(w, 1, 2, 1, ' ', 0)
50
- defer wtr.Flush()
51
-
52
- fmt.Fprintf(wtr, "TotalProvides:\t%s\n", humanNumber(s.TotalReprovides))
53
- fmt.Fprintf(wtr, "AvgProvideDuration:\t%s\n", humanDuration(s.AvgReprovideDuration))
54
- fmt.Fprintf(wtr, "LastReprovideDuration:\t%s\n", humanDuration(s.LastReprovideDuration))
55
- if !s.LastRun.IsZero() {
56
- fmt.Fprintf(wtr, "LastRun:\t%s\n", humanTime(s.LastRun))
57
- if s.fullRT {
58
- fmt.Fprintf(wtr, "NextRun:\t%s\n", humanTime(s.LastRun.Add(s.ReprovideInterval)))
59
- }
60
- }
61
- return nil
62
- }),
63
- },
64
- Type: reprovideStats{},
17
+ Arguments: provideStatCmd.Arguments,
18
+ Options: provideStatCmd.Options,
19
+ Run: provideStatCmd.Run,
20
+ Encoders: provideStatCmd.Encoders,
21
+ Type: provideStatCmd.Type,
22
}
core/commands/stat_reprovide.go
+9
-92
@@ -1,104 +1,21 @@
1
package commands
2
3
import (
4
- "fmt"
5
- "io"
6
- "text/tabwriter"
7
- "time"
8
-
9
- humanize "github.com/dustin/go-humanize"
10
- "github.com/ipfs/boxo/provider"
4
cmds "github.com/ipfs/go-ipfs-cmds"
12
- "github.com/ipfs/kubo/core/commands/cmdenv"
13
- "github.com/libp2p/go-libp2p-kad-dht/fullrt"
14
- "golang.org/x/exp/constraints"
5
)
6
17
-type reprovideStats struct {
18
- provider.ReproviderStats
19
- fullRT bool
20
-}
21
-
7
var statReprovideCmd = &cmds.Command{
23
- Status: cmds.Experimental,
8
+ Status: cmds.Deprecated,
9
Helptext: cmds.HelpText{
25
- Tagline: "Returns statistics about the node's reprovider system.",
10
+ Tagline: "Deprecated command, use 'ipfs provide stat' instead.",
11
ShortDescription: `
27
-Returns statistics about the content the node is reproviding every
28
-Reprovider.Interval according to Reprovider.Strategy:
29
-https://github.com/ipfs/kubo/blob/master/docs/config.md#reprovider
30
-
31
-This interface is not stable and may change from release to release.
32
-
12
+'ipfs stats reprovide' is deprecated because provider stats are now
13
+available fomr 'ipfs provide stat'.
14
`,
15
},
35
- Arguments: []cmds.Argument{},
36
- Options: []cmds.Option{},
37
- Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
38
- nd, err := cmdenv.GetNode(env)
39
- if err != nil {
40
- return err
41
- }
42
-
43
- if !nd.IsOnline {
44
- return ErrNotOnline
45
- }
46
-
47
- stats, err := nd.Provider.Stat()
48
- if err != nil {
49
- return err
50
- }
51
- _, fullRT := nd.DHTClient.(*fullrt.FullRT)
52
-
53
- if err := res.Emit(reprovideStats{stats, fullRT}); err != nil {
54
- return err
55
- }
56
-
57
- return nil
58
- },
59
- Encoders: cmds.EncoderMap{
60
- cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, s reprovideStats) error {
61
- wtr := tabwriter.NewWriter(w, 1, 2, 1, ' ', 0)
62
- defer wtr.Flush()
63
-
64
- fmt.Fprintf(wtr, "TotalReprovides:\t%s\n", humanNumber(s.TotalReprovides))
65
- fmt.Fprintf(wtr, "AvgReprovideDuration:\t%s\n", humanDuration(s.AvgReprovideDuration))
66
- fmt.Fprintf(wtr, "LastReprovideDuration:\t%s\n", humanDuration(s.LastReprovideDuration))
67
- if !s.LastRun.IsZero() {
68
- fmt.Fprintf(wtr, "LastReprovide:\t%s\n", humanTime(s.LastRun))
69
- if s.fullRT {
70
- fmt.Fprintf(wtr, "NextReprovide:\t%s\n", humanTime(s.LastRun.Add(s.ReprovideInterval)))
71
- }
72
- }
73
- return nil
74
- }),
75
- },
76
- Type: reprovideStats{},
77
-}
78
-
79
-func humanDuration(val time.Duration) string {
80
- return val.Truncate(time.Microsecond).String()
81
-}
82
-
83
-func humanTime(val time.Time) string {
84
- return val.Format("2006-01-02 15:04:05")
85
-}
86
-
87
-func humanNumber[T constraints.Float | constraints.Integer](n T) string {
88
- nf := float64(n)
89
- str := humanSI(nf, 0)
90
- fullStr := humanFull(nf, 0)
91
- if str != fullStr {
92
- return fmt.Sprintf("%s\t(%s)", str, fullStr)
93
- }
94
- return str
95
-}
96
-
97
-func humanSI(val float64, decimals int) string {
98
- v, unit := humanize.ComputeSI(val)
99
- return fmt.Sprintf("%s%s", humanFull(v, decimals), unit)
100
-}
101
-
102
-func humanFull(val float64, decimals int) string {
103
- return humanize.CommafWithDigits(val, decimals)
16
+ Arguments: provideStatCmd.Arguments,
17
+ Options: provideStatCmd.Options,
18
+ Run: provideStatCmd.Run,
19
+ Encoders: provideStatCmd.Encoders,
20
+ Type: provideStatCmd.Type,
21
}
docs/changelogs/v0.37.md
+9
@@ -13,6 +13,7 @@ This release was brought to you by the [Interplanetary Shipyard](https://ipship
13
- [Clear provide queue when reprovide strategy changes](#clear-provide-queue-when-reprovide-strategy-changes)
14
- [Named pins in `ipfs add` command](#-named-pins-in-ipfs-add-command)
15
- [Removed unnecessary dependencies](#removed-unnecessary-dependencies)
16
+ - [Deprecated `ipfs stats reprovide`](#deprecated-ipfs-stats-reprovide)
17
- [📦️ Important dependency updates](#-important-dependency-updates)
18
- [📝 Changelog](#-changelog)
19
- [👨👩👧👦 Contributors](#-contributors)
@@ -55,6 +56,14 @@ Kubo has been cleaned up by removing unnecessary dependencies and packages:
56
57
These changes reduce the dependency footprint while improving code maintainability and following Go best practices.
58
59
+#### Deprecated `ipfs stats reprovide`
60
+
61
+The `ipfs stats reprovide` command has moved to `ipfs provide stat`. This was done to organize provider commands in one location.
62
+
63
+> [!NOTE]
64
+> `ipfs stats reprovide` still works, but is marked as deprecated and will be removed in a future release.
65
+
66
+
67
#### 📦️ Important dependency updates
68
69
- update `go-libp2p` to [v0.42.1](https://github.com/libp2p/go-libp2p/releases/tag/v0.42.1)