Skip to content

Change core search to update indexes only after 24h from last edit #1237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 63 additions & 6 deletions cli/core/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,23 @@ package core
import (
"context"
"os"
"path"
"sort"
"strings"
"time"

"github.com/arduino/arduino-cli/arduino/utils"
"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/globals"
"github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/cli/output"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/core"
"github.com/arduino/arduino-cli/configuration"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/arduino-cli/table"
"github.com/arduino/go-paths-helper"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
Expand All @@ -51,19 +57,24 @@ func initSearchCommand() *cobra.Command {
return searchCommand
}

// indexUpdateInterval specifies the time threshold over which indexes are updated
const indexUpdateInterval = "24h"

func runSearchCommand(cmd *cobra.Command, args []string) {
inst, err := instance.CreateInstance()
if err != nil {
feedback.Errorf("Error searching for platforms: %v", err)
os.Exit(errorcodes.ErrGeneric)
}

_, err = commands.UpdateIndex(context.Background(), &rpc.UpdateIndexRequest{
Instance: inst,
}, output.ProgressBar())
if err != nil {
feedback.Errorf("Error updating index: %v", err)
os.Exit(errorcodes.ErrGeneric)
if indexesNeedUpdating(indexUpdateInterval) {
_, err = commands.UpdateIndex(context.Background(), &rpc.UpdateIndexRequest{
Instance: inst,
}, output.ProgressBar())
if err != nil {
feedback.Errorf("Error updating index: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
}

arguments := strings.ToLower(strings.Join(args, " "))
Expand Down Expand Up @@ -107,3 +118,49 @@ func (sr searchResults) String() string {
}
return "No platforms matching your search."
}

// indexesNeedUpdating returns whether one or more index files need updating.
// A duration string must be provided to calculate the time threshold
// used to update the indexes, if the duration is not valid a default
// of 24 hours is used.
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
func indexesNeedUpdating(duration string) bool {
indexpath := paths.New(configuration.Settings.GetString("directories.Data"))

now := time.Now()
modTimeThreshold, err := time.ParseDuration(duration)
// Not the most elegant way of handling this error
// but it does its job
if err != nil {
modTimeThreshold, _ = time.ParseDuration("24h")
}

urls := []string{globals.DefaultIndexURL}
urls = append(urls, configuration.Settings.GetStringSlice("board_manager.additional_urls")...)
for _, u := range urls {
URL, err := utils.URLParse(u)
if err != nil {
continue
}

if URL.Scheme == "file" {
// No need to update local files
continue
}

coreIndexPath := indexpath.Join(path.Base(URL.Path))
if coreIndexPath.NotExist() {
return true
}

info, err := coreIndexPath.Stat()
if err != nil {
return true
}

if now.After(info.ModTime().Add(modTimeThreshold)) {
return true
}
}
return false
}
35 changes: 29 additions & 6 deletions test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
# software without disclosing the source code of your own applications. To purchase
# a commercial license, send an email to [email protected].
import os
import datetime
import time
import platform
import pytest
import simplejson as json
Expand Down Expand Up @@ -123,9 +125,7 @@ def test_core_search_no_args(run_command, httpserver):
assert result.ok
num_platforms = 0
lines = [l.strip().split() for l in result.stdout.strip().splitlines()]
# Index update output and the header are printed on the first lines
assert ["Updating", "index:", "package_index.json", "downloaded"] in lines
assert ["Updating", "index:", "package_index.json.sig", "downloaded"] in lines
# The header is printed on the first lines
assert ["test:x86", "2.0.0", "test_core"] in lines
header_index = lines.index(["ID", "Version", "Name"])
# We use black to format and flake8 to lint .py files but they disagree on certain
Expand All @@ -147,9 +147,7 @@ def test_core_search_no_args(run_command, httpserver):
assert result.ok
num_platforms = 0
lines = [l.strip().split() for l in result.stdout.strip().splitlines()]
# Index update output and the header are printed on the first lines
assert ["Updating", "index:", "package_index.json", "downloaded"] in lines
assert ["Updating", "index:", "package_index.json.sig", "downloaded"] in lines
# The header is printed on the first lines
assert ["test:x86", "2.0.0", "test_core"] in lines
header_index = lines.index(["ID", "Version", "Name"])
# We use black to format and flake8 to lint .py files but they disagree on certain
Expand Down Expand Up @@ -507,3 +505,28 @@ def test_core_list_with_installed_json(run_command, data_dir):
# platform.txt, turns out that this core has different names used in different files
# thus the change.
assert mapped["adafruit:avr"]["name"] == "Adafruit Boards"


def test_core_search_update_index_delay(run_command, data_dir):
assert run_command("update")

# Verifies index update is not run
res = run_command("core search")
assert res.ok
assert "Updating index" not in res.stdout

# Change edit time of package index file
index_file = Path(data_dir, "package_index.json")
date = datetime.datetime.now() - datetime.timedelta(hours=25)
mod_time = time.mktime(date.timetuple())
os.utime(index_file, (mod_time, mod_time))

# Verifies index update is run
res = run_command("core search")
assert res.ok
assert "Updating index" in res.stdout

# Verifies index update is not run again
res = run_command("core search")
assert res.ok
assert "Updating index" not in res.stdout