Fixed an issue when manually removed dependencies were not uninstalled from the storage // Resolve #3076

This commit is contained in:
Ivan Kravets
2022-04-02 22:30:35 +03:00
parent cdd63dec65
commit 71f9401e23
4 changed files with 86 additions and 5 deletions

View File

@@ -30,6 +30,7 @@ PlatformIO Core 5
- Ignore files according to the patterns declared in ".gitignore" when using the `pio package pack <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_pack.html>`__ command (`issue #4188 <https://github.com/platformio/platformio-core/issues/4188>`_) - Ignore files according to the patterns declared in ".gitignore" when using the `pio package pack <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_pack.html>`__ command (`issue #4188 <https://github.com/platformio/platformio-core/issues/4188>`_)
- Dropped automatic updates of global libraries and development platforms (`issue #4179 <https://github.com/platformio/platformio-core/issues/4179>`_) - Dropped automatic updates of global libraries and development platforms (`issue #4179 <https://github.com/platformio/platformio-core/issues/4179>`_)
- Dropped support for the "pythonPackages" field in "platform.json" manifest in favor of `Extra Python Dependencies <https://docs.platformio.org/en/latest/scripting/examples/extra_python_packages.html>`__ - Dropped support for the "pythonPackages" field in "platform.json" manifest in favor of `Extra Python Dependencies <https://docs.platformio.org/en/latest/scripting/examples/extra_python_packages.html>`__
- Fixed an issue when manually removed dependencies from the `"platformio.ini" <https://docs.platformio.org/en/latest/projectconf.html>`__ configuration file were not uninstalled from the storage (`issue #3076 <https://github.com/platformio/platformio-core/issues/3076>`_)
* **Static Code Analysis** * **Static Code Analysis**
@@ -38,9 +39,9 @@ PlatformIO Core 5
* **Miscellaneous** * **Miscellaneous**
* Show project dependency licenses when building in the verbose mode - Show project dependency licenses when building in the verbose mode
* Improved PIO Remote setup on credit-card sized computers (Raspberry Pi, BeagleBon, etc) (`issue #3865 <https://github.com/platformio/platformio-core/issues/3865>`_) - Improved PIO Remote setup on credit-card sized computers (Raspberry Pi, BeagleBon, etc) (`issue #3865 <https://github.com/platformio/platformio-core/issues/3865>`_)
* Better handling of the failed tests using the `Unit Testing <https://docs.platformio.org/en/latest/plus/unit-testing.html>`__ solution. - Better handling of the failed tests using the `Unit Testing <https://docs.platformio.org/en/latest/plus/unit-testing.html>`__ solution.
5.2.5 (2022-02-10) 5.2.5 (2022-02-10)
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~

View File

@@ -14,10 +14,12 @@
import logging import logging
import os import os
from pathlib import Path
import click import click
from platformio import fs from platformio import fs
from platformio.package.exception import UnknownPackageError
from platformio.package.manager.library import LibraryPackageManager from platformio.package.manager.library import LibraryPackageManager
from platformio.package.manager.platform import PlatformPackageManager from platformio.package.manager.platform import PlatformPackageManager
from platformio.package.manager.tool import ToolPackageManager from platformio.package.manager.tool import ToolPackageManager
@@ -197,6 +199,7 @@ def _install_project_env_custom_tools(project_env, options):
def _install_project_env_libraries(project_env, options): def _install_project_env_libraries(project_env, options):
_uninstall_project_unused_libdeps(project_env, options)
already_up_to_date = not options.get("force") already_up_to_date = not options.get("force")
config = ProjectConfig.get_instance() config = ProjectConfig.get_instance()
env_lm = LibraryPackageManager( env_lm = LibraryPackageManager(
@@ -220,12 +223,37 @@ def _install_project_env_libraries(project_env, options):
skip_dependencies=options.get("skip_dependencies"), skip_dependencies=options.get("skip_dependencies"),
force=options.get("force"), force=options.get("force"),
) )
# install dependencies from the priate libraries # install dependencies from the private libraries
for pkg in private_lm.get_installed(): for pkg in private_lm.get_installed():
_install_project_private_library_deps(pkg, private_lm, env_lm, options) _install_project_private_library_deps(pkg, private_lm, env_lm, options)
return not already_up_to_date return not already_up_to_date
def _uninstall_project_unused_libdeps(project_env, options):
config = ProjectConfig.get_instance()
lib_deps = set(config.get(f"env:{project_env}", "lib_deps"))
if not lib_deps:
return
storage_dir = Path(config.get("platformio", "libdeps_dir"), project_env)
integrity_dat = storage_dir / "integrity.dat"
if integrity_dat.is_file():
prev_lib_deps = set(integrity_dat.read_text().strip().split("\n"))
if lib_deps == prev_lib_deps:
return
lm = LibraryPackageManager(str(storage_dir))
if options.get("silent"):
lm.set_log_level(logging.WARN)
else:
click.secho("Removing unused dependencies...")
for spec in set(prev_lib_deps) - set(lib_deps):
try:
lm.uninstall(spec)
except UnknownPackageError:
pass
storage_dir.mkdir(parents=True, exist_ok=True)
integrity_dat.write_text("\n".join(lib_deps), encoding="utf-8")
def _install_project_private_library_deps(private_pkg, private_lm, env_lm, options): def _install_project_private_library_deps(private_pkg, private_lm, env_lm, options):
for dependency in private_lm.get_pkg_dependencies(private_pkg) or []: for dependency in private_lm.get_pkg_dependencies(private_pkg) or []:
spec = private_lm.dependency_to_spec(dependency) spec = private_lm.dependency_to_spec(dependency)

View File

@@ -58,7 +58,9 @@ def package_list_cmd(**options):
def humanize_package(pkg, spec=None, verbose=False): def humanize_package(pkg, spec=None, verbose=False):
if spec and not isinstance(spec, PackageSpec): if spec and not isinstance(spec, PackageSpec):
spec = PackageSpec(spec) spec = PackageSpec(spec)
data = [click.style("{name}@{version}".format(**pkg.metadata.as_dict()), fg="cyan")] data = [
click.style("{name} @ {version}".format(**pkg.metadata.as_dict()), fg="cyan")
]
extra_data = ["required: %s" % (spec.humanize() if spec else "Any")] extra_data = ["required: %s" % (spec.humanize() if spec else "Any")]
if verbose: if verbose:
extra_data.append(pkg.path) extra_data.append(pkg.path)

View File

@@ -253,6 +253,56 @@ platform = native
] ]
def test_remove_project_unused_libdeps(
clirunner, validate_cliresult, isolated_pio_core, tmp_path
):
project_dir = tmp_path / "project"
project_dir.mkdir()
(project_dir / "platformio.ini").write_text(PROJECT_CONFIG_TPL)
result = clirunner.invoke(
package_install_cmd,
["-d", str(project_dir), "-e", "baremetal"],
)
validate_cliresult(result)
with fs.cd(str(project_dir)):
config = ProjectConfig()
storage_dir = os.path.join(config.get("platformio", "libdeps_dir"), "baremetal")
lm = LibraryPackageManager(storage_dir)
assert pkgs_to_specs(lm.get_installed()) == [
PackageSpec("DallasTemperature@3.9.1"),
PackageSpec("OneWire@2.3.6"),
]
# add new deps
lib_deps = config.get("env:baremetal", "lib_deps")
config.set(
"env:baremetal", "lib_deps", lib_deps + ["bblanchon/ArduinoJson@^6.19.2"]
)
config.save()
result = clirunner.invoke(
package_install_cmd,
["-e", "baremetal"],
)
validate_cliresult(result)
lm = LibraryPackageManager(storage_dir)
assert pkgs_to_specs(lm.get_installed()) == [
PackageSpec("ArduinoJson@6.19.3"),
PackageSpec("DallasTemperature@3.9.1"),
PackageSpec("OneWire@2.3.6"),
]
# manually remove from cofiguration file
config.set("env:baremetal", "lib_deps", ["bblanchon/ArduinoJson@^6.19.2"])
config.save()
result = clirunner.invoke(
package_install_cmd,
["-e", "baremetal"],
)
validate_cliresult(result)
lm = LibraryPackageManager(storage_dir)
assert pkgs_to_specs(lm.get_installed()) == [PackageSpec("ArduinoJson@6.19.3")]
def test_unknown_project_dependencies( def test_unknown_project_dependencies(
clirunner, validate_cliresult, isolated_pio_core, tmp_path clirunner, validate_cliresult, isolated_pio_core, tmp_path
): ):