@@ -21,14 +21,17 @@ import (
21
21
"os"
22
22
"sort"
23
23
"strings"
24
+ "time"
24
25
25
26
"github.com/arduino/arduino-cli/cli/errorcodes"
26
27
"github.com/arduino/arduino-cli/cli/feedback"
27
28
"github.com/arduino/arduino-cli/cli/instance"
28
29
"github.com/arduino/arduino-cli/cli/output"
29
30
"github.com/arduino/arduino-cli/commands"
30
31
"github.com/arduino/arduino-cli/commands/lib"
32
+ "github.com/arduino/arduino-cli/configuration"
31
33
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
34
+ "github.com/arduino/go-paths-helper"
32
35
"github.com/sirupsen/logrus"
33
36
"github.com/spf13/cobra"
34
37
semver "go.bug.st/relaxed-semver"
@@ -51,6 +54,9 @@ func initSearchCommand() *cobra.Command {
51
54
return searchCommand
52
55
}
53
56
57
+ // indexUpdateInterval specifies the time threshold over which indexes are updated
58
+ const indexUpdateInterval = "60m"
59
+
54
60
func runSearchCommand (cmd * cobra.Command , args []string ) {
55
61
inst , status := instance .Create ()
56
62
logrus .Info ("Executing `arduino-cli lib search`" )
@@ -60,13 +66,15 @@ func runSearchCommand(cmd *cobra.Command, args []string) {
60
66
os .Exit (errorcodes .ErrGeneric )
61
67
}
62
68
63
- if err := commands .UpdateLibrariesIndex (
64
- context .Background (),
65
- & rpc.UpdateLibrariesIndexRequest {Instance : inst },
66
- output .ProgressBar (),
67
- ); err != nil {
68
- feedback .Errorf (tr ("Error updating library index: %v" ), err )
69
- os .Exit (errorcodes .ErrGeneric )
69
+ if indexNeedsUpdating (indexUpdateInterval ) {
70
+ if err := commands .UpdateLibrariesIndex (
71
+ context .Background (),
72
+ & rpc.UpdateLibrariesIndexRequest {Instance : inst },
73
+ output .ProgressBar (),
74
+ ); err != nil {
75
+ feedback .Errorf (tr ("Error updating library index: %v" ), err )
76
+ os .Exit (errorcodes .ErrGeneric )
77
+ }
70
78
}
71
79
72
80
for _ , err := range instance .Init (inst ) {
@@ -193,3 +201,38 @@ func versionsFromSearchedLibrary(library *rpc.SearchedLibrary) []*semver.Version
193
201
sort .Sort (semver .List (res ))
194
202
return res
195
203
}
204
+
205
+ // indexNeedsUpdating returns whether library_index.json need updating.
206
+ // A positive duration string must be provided to calculate the time threshold
207
+ // used to update the index (default: +24 hours).
208
+ // Valid duration units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
209
+ // Use a duration of 0 to always update the index.
210
+ func indexNeedsUpdating (duration string ) bool {
211
+ // Library index path is constant (relative to the data directory).
212
+ // It does not depend on board manager URLs or any other configuration.
213
+ dataDir := configuration .Settings .GetString ("directories.Data" )
214
+ indexPath := paths .New (dataDir ).Join ("library_index.json" )
215
+ // Verify the index file exists and we can read its fstat attrs.
216
+ if indexPath .NotExist () {
217
+ return true
218
+ }
219
+ info , err := indexPath .Stat ()
220
+ if err != nil {
221
+ return true
222
+ }
223
+ // Sanity check the given threshold duration string.
224
+ now := time .Now ()
225
+ modTimeThreshold , err := time .ParseDuration (duration )
226
+ if err != nil {
227
+ feedback .Error (tr ("Invalid timeout: %s" , err ))
228
+ os .Exit (errorcodes .ErrBadArgument )
229
+ }
230
+ // The behavior of now.After(T) is confusing if T < 0 and MTIME in the future,
231
+ // and is probably not what the user intended. Disallow negative T and inform
232
+ // the user that positive thresholds are expected.
233
+ if modTimeThreshold < 0 {
234
+ feedback .Error (tr ("Timeout must be non-negative: %dns (%s)" , modTimeThreshold , duration ))
235
+ os .Exit (errorcodes .ErrBadArgument )
236
+ }
237
+ return modTimeThreshold == 0 || now .After (info .ModTime ().Add (modTimeThreshold ))
238
+ }
0 commit comments