diff --git a/arduino/libraries/librariesindex/index.go b/arduino/libraries/librariesindex/index.go index b21506a197e..85c3bbba472 100644 --- a/arduino/libraries/librariesindex/index.go +++ b/arduino/libraries/librariesindex/index.go @@ -136,7 +136,9 @@ func (idx *Index) FindLibraryUpdate(lib *libraries.Library) *Release { if indexLib == nil { return nil } - if indexLib.Latest.Version.GreaterThan(lib.Version) { + // If a library.properties has an invalid version property, usually empty or malformed, + // the latest available version is returned + if lib.Version == nil || indexLib.Latest.Version.GreaterThan(lib.Version) { return indexLib.Latest } return nil diff --git a/arduino/libraries/librariesindex/index_test.go b/arduino/libraries/librariesindex/index_test.go index cc6f9928c89..097d7adec51 100644 --- a/arduino/libraries/librariesindex/index_test.go +++ b/arduino/libraries/librariesindex/index_test.go @@ -78,6 +78,10 @@ func TestIndexer(t *testing.T) { require.NotNil(t, rtcUpdate) require.Equal(t, "RTCZero@1.6.0", rtcUpdate.String()) + rtcUpdateNoVersion := index.FindLibraryUpdate(&libraries.Library{Name: "RTCZero", Version: nil}) + require.NotNil(t, rtcUpdateNoVersion) + require.Equal(t, "RTCZero@1.6.0", rtcUpdateNoVersion.String()) + rtcNoUpdate := index.FindLibraryUpdate(&libraries.Library{Name: "RTCZero", Version: semver.MustParse("3.0.0")}) require.Nil(t, rtcNoUpdate) diff --git a/arduino/libraries/librariesmanager/install.go b/arduino/libraries/librariesmanager/install.go index 9132d68099f..1a7dcfff0ac 100644 --- a/arduino/libraries/librariesmanager/install.go +++ b/arduino/libraries/librariesmanager/install.go @@ -50,7 +50,7 @@ func (lm *LibrariesManager) InstallPrerequisiteCheck(indexLibrary *librariesinde if installedLib.Location != libraries.User { continue } - if installedLib.Version.Equal(indexLibrary.Version) { + if installedLib.Version != nil && installedLib.Version.Equal(indexLibrary.Version) { return installedLib.InstallDir, nil, ErrAlreadyInstalled } replaced = installedLib diff --git a/test/test_lib.py b/test/test_lib.py index 034ae172c3c..e5d8fb35092 100644 --- a/test/test_lib.py +++ b/test/test_lib.py @@ -703,3 +703,65 @@ def test_lib_examples_with_case_mismatch(run_command, data_dir): # Verifies sketches with wrong casing are not returned assert str(examples_path / "NonBlocking" / "OnDemandNonBlocking") not in examples assert str(examples_path / "OnDemand" / "OnDemandWebPortal") not in examples + + +def test_lib_list_using_library_with_invalid_version(run_command, data_dir): + assert run_command("update") + + # Install a library + assert run_command("lib install WiFi101@0.16.1") + + # Verifies library is correctly returned + res = run_command("lib list --format json") + assert res.ok + data = json.loads(res.stdout) + assert len(data) == 1 + assert "0.16.1" == data[0]["library"]["version"] + + # Changes the version of the currently installed library so that it's + # invalid + lib_path = Path(data_dir, "libraries", "WiFi101") + Path(lib_path, "library.properties").write_text("version=1.0001") + + # Verifies version is now empty + res = run_command("lib list --format json") + assert res.ok + data = json.loads(res.stdout) + assert len(data) == 1 + assert "version" not in data[0]["library"] + + +def test_lib_upgrade_using_library_with_invalid_version(run_command, data_dir): + assert run_command("update") + + # Install a library + assert run_command("lib install WiFi101@0.16.1") + + # Verifies library is correctly returned + res = run_command("lib list --format json") + assert res.ok + data = json.loads(res.stdout) + assert len(data) == 1 + assert "0.16.1" == data[0]["library"]["version"] + + # Changes the version of the currently installed library so that it's + # invalid + lib_path = Path(data_dir, "libraries", "WiFi101") + Path(lib_path, "library.properties").write_text("version=1.0001") + + # Verifies version is now empty + res = run_command("lib list --format json") + assert res.ok + data = json.loads(res.stdout) + assert len(data) == 1 + assert "version" not in data[0]["library"] + + # Upgrade library + assert run_command("lib upgrade WiFi101") + + # Verifies library has been updated + res = run_command("lib list --format json") + assert res.ok + data = json.loads(res.stdout) + assert len(data) == 1 + assert "" != data[0]["library"]["version"] diff --git a/test/test_outdated.py b/test/test_outdated.py index d9ef406851c..878ea87f1cb 100644 --- a/test/test_outdated.py +++ b/test/test_outdated.py @@ -13,6 +13,8 @@ # software without disclosing the source code of your own applications. To purchase # a commercial license, send an email to license@arduino.cc. +from pathlib import Path + def test_outdated(run_command): # Updates index for cores and libraries @@ -33,3 +35,26 @@ def test_outdated(run_command): lines = [l.strip() for l in result.stdout.splitlines()] assert lines[1].startswith("Arduino AVR Boards") assert lines[4].startswith("USBHost") + + +def test_outdated_using_library_with_invalid_version(run_command, data_dir): + assert run_command("update") + + # Install latest version of a library library + assert run_command("lib install WiFi101") + + # Verifies library is correctly returned + res = run_command("outdated") + assert res.ok + assert "WiFi101" not in res.stdout + + # Changes the version of the currently installed library so that it's + # invalid + lib_path = Path(data_dir, "libraries", "WiFi101") + Path(lib_path, "library.properties").write_text("version=1.0001") + + # Verifies library is correctly returned + res = run_command("outdated") + assert res.ok + lines = [l.strip().split() for l in res.stdout.splitlines()] + assert "WiFi101" == lines[1][0] diff --git a/test/test_update.py b/test/test_update.py index 2550e0dd4f9..d35f7831930 100644 --- a/test/test_update.py +++ b/test/test_update.py @@ -13,6 +13,8 @@ # software without disclosing the source code of your own applications. To purchase # a commercial license, send an email to license@arduino.cc. +from pathlib import Path + def test_update(run_command): res = run_command("update") @@ -73,3 +75,25 @@ def test_update_with_url_internal_server_error(run_command, httpserver): assert res.failed lines = [l.strip() for l in res.stderr.splitlines()] assert f"Error updating core and libraries index: downloading index {url}: 500 INTERNAL SERVER ERROR" in lines + + +def test_update_showing_outdated_using_library_with_invalid_version(run_command, data_dir): + assert run_command("update") + + # Install latest version of a library + assert run_command("lib install WiFi101") + + # Verifies library doesn't get updated + res = run_command("update --show-outdated") + assert res.ok + assert "WiFi101" not in res.stdout + + # Changes the version of the currently installed library so that it's + # invalid + lib_path = Path(data_dir, "libraries", "WiFi101") + Path(lib_path, "library.properties").write_text("version=1.0001") + + # Verifies library gets updated + res = run_command("update --show-outdated") + assert res.ok + assert "WiFi101" in res.stdout diff --git a/test/test_upgrade.py b/test/test_upgrade.py index e4c67678c9e..f5c3d691e7f 100644 --- a/test/test_upgrade.py +++ b/test/test_upgrade.py @@ -13,6 +13,8 @@ # software without disclosing the source code of your own applications. To purchase # a commercial license, send an email to license@arduino.cc. +from pathlib import Path + def test_upgrade(run_command): # Updates index for cores and libraries @@ -41,3 +43,25 @@ def test_upgrade(run_command): result = run_command("outdated") assert result.ok assert result.stdout == "" + + +def test_upgrade_using_library_with_invalid_version(run_command, data_dir): + assert run_command("update") + + # Install latest version of a library + assert run_command("lib install WiFi101") + + # Verifies library is not shown + res = run_command("outdated") + assert res.ok + assert "WiFi101" not in res.stdout + + # Changes the version of the currently installed library so that it's + # invalid + lib_path = Path(data_dir, "libraries", "WiFi101") + Path(lib_path, "library.properties").write_text("version=1.0001") + + # Verifies library gets upgraded + res = run_command("upgrade") + assert res.ok + assert "WiFi101" in res.stdout