diff --git a/compilesketches/compilesketches.py b/compilesketches/compilesketches.py index 678ae7b..5b8a81b 100644 --- a/compilesketches/compilesketches.py +++ b/compilesketches/compilesketches.py @@ -15,6 +15,7 @@ import git import gitdb.exc import github +import semver import yaml import yaml.parser @@ -527,13 +528,15 @@ def __init__(self): command_data = self.run_arduino_cli_command(command=["core", "list", "--format", "json"]) installed_platform_list = json.loads(command_data.stdout) for installed_platform in installed_platform_list: - if installed_platform["ID"] == platform[self.dependency_name_key]: + if installed_platform[self.cli_json_key("core list", "ID")] == platform[self.dependency_name_key]: # The platform has been installed via Board Manager, so do an overwrite platform_installation_path.path = ( - self.board_manager_platforms_path.joinpath(platform_vendor, - "hardware", - platform_architecture, - installed_platform["Installed"]) + self.board_manager_platforms_path.joinpath( + platform_vendor, + "hardware", + platform_architecture, + installed_platform[self.cli_json_key("core list", "Installed")] + ) ) platform_installation_path.is_overwrite = True @@ -1413,6 +1416,91 @@ def create_sketches_report_file(self, sketches_report): encoding="utf-8") as report_file: json.dump(obj=sketches_report, fp=report_file, indent=2) + def cli_json_key(self, command, original_key_name): + """Return the appropriate JSON output key name for the Arduino CLI version in use. + + Keyword arguments: + command -- Arduino CLI command (e.g., "core list") + original_key_name -- key name used by the original Arduino CLI JSON interface + """ + final_original_interface_version = "0.17.0" # Interface was changed in the next Arduino CLI release + + key_translation = { + "board details": { + "identification_pref": "identification_prefs", + "usbID": "usb_id", + "PID": "pid", + "VID": "vid", + "websiteURL": "website_url", + "archiveFileName": "archive_filename", + "propertiesId": "properties_id", + "toolsDependencies": "tools_dependencies" + }, + "board list": { + "FQBN": "fqbn", + "VID": "vid", + "PID": "pid" + }, + "board listall": { + "FQBN": "fqbn", + "Email": "email", + "ID": "id", + "Installed": "installed", + "Latest": "latest", + "Name": "name", + "Maintainer": "maintainer", + "Website": "website" + }, + "board search": { + "FQBN": "fqbn", + "Email": "email", + "ID": "id", + "Installed": "installed", + "Latest": "latest", + "Name": "name", + "Maintainer": "maintainer", + "Website": "website" + }, + "core list": { + "Boards": "boards", + "Email": "email", + "ID": "id", + "Installed": "installed", + "Latest": "latest", + "Maintainer": "maintainer", + "Name": "name", + "Website": "website" + }, + "core search": { + "Boards": "boards", + "Email": "email", + "ID": "id", + "Latest": "latest", + "Maintainer": "maintainer", + "Name": "name", + "Website": "website" + }, + "lib deps": { + "versionRequired": "version_required", + "versionInstalled": "version_installed" + }, + "lib search": { + "archivefilename": "archive_filename", + "cachepath": "cache_path" + } + } + + if ( + ( + not semver.VersionInfo.isvalid(version=self.cli_version) + or semver.compare(ver1=self.cli_version, ver2=final_original_interface_version) > 0 + ) + and (command in key_translation and original_key_name in key_translation[command]) + ): + return key_translation[command][original_key_name] + + return original_key_name + def parse_list_input(list_input): """Parse a space separated list and return the equivalent Python list diff --git a/compilesketches/requirements.txt b/compilesketches/requirements.txt index f3a619c..6b8da46 100644 --- a/compilesketches/requirements.txt +++ b/compilesketches/requirements.txt @@ -1,3 +1,4 @@ GitPython==3.1.2 PyGithub==1.51 PyYAML==5.3.1 +semver==2.13.0 diff --git a/compilesketches/tests/test_compilesketches.py b/compilesketches/tests/test_compilesketches.py index f9bebf7..e19b8e3 100644 --- a/compilesketches/tests/test_compilesketches.py +++ b/compilesketches/tests/test_compilesketches.py @@ -20,7 +20,7 @@ def get_compilesketches_object( - cli_version=unittest.mock.sentinel.cli_version, + cli_version="0.12.3", fqbn_arg="foo fqbn_arg", platforms="- name: FooVendor:BarArchitecture", libraries="foo libraries", @@ -2578,6 +2578,19 @@ def test_create_sketches_report_file(monkeypatch, tmp_path): assert json.load(sketch_report_file) == sketches_report +@pytest.mark.parametrize("cli_version, command, original_key, expected_key", + [("latest", "core list", "ID", "id"), # Non-semver + ("1.0.0", "core list", "ID", "id"), # > + ("0.17.0", "core list", "ID", "ID"), # == + ("0.14.0-rc2", "core list", "ID", "ID"), # < + ("1.0.0", "foo", "ID", "ID"), # Command has no translation + ("1.0.0", "core list", "foo", "foo")]) # Key has no translation +def test_cli_json_key(cli_version, command, original_key, expected_key): + compile_sketches = get_compilesketches_object(cli_version=cli_version) + + assert compile_sketches.cli_json_key(command, original_key) == expected_key + + @pytest.mark.parametrize("verbose", ["true", "false"]) def test_verbose_print(capsys, verbose): string_print_argument = "foo string argument"