forked from platformio/platformio-core
Allow to skip saving of package dependencies to the "platformio.ini" // Issue #3373
This commit is contained in:
2
docs
2
docs
Submodule docs updated: 0c41108fe3...4c8e6f1fbf
@ -21,7 +21,9 @@ from platformio import fs
|
|||||||
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
|
||||||
|
from platformio.package.meta import PackageSpec
|
||||||
from platformio.project.config import ProjectConfig
|
from platformio.project.config import ProjectConfig
|
||||||
|
from platformio.project.savedeps import save_project_dependencies
|
||||||
|
|
||||||
|
|
||||||
@click.command(
|
@click.command(
|
||||||
@ -37,13 +39,18 @@ from platformio.project.config import ProjectConfig
|
|||||||
@click.option("-p", "--platform", "platforms", multiple=True)
|
@click.option("-p", "--platform", "platforms", multiple=True)
|
||||||
@click.option("-t", "--tool", "tools", multiple=True)
|
@click.option("-t", "--tool", "tools", multiple=True)
|
||||||
@click.option("-l", "--library", "libraries", multiple=True)
|
@click.option("-l", "--library", "libraries", multiple=True)
|
||||||
|
@click.option(
|
||||||
|
"--no-save",
|
||||||
|
is_flag=True,
|
||||||
|
help="Prevent saving specified packages to `platformio.ini`",
|
||||||
|
)
|
||||||
@click.option("--skip-dependencies", is_flag=True, help="Skip package dependencies")
|
@click.option("--skip-dependencies", is_flag=True, help="Skip package dependencies")
|
||||||
@click.option("-g", "--global", is_flag=True, help="Install package globally")
|
@click.option("-g", "--global", is_flag=True, help="Install package globally")
|
||||||
@click.option(
|
@click.option(
|
||||||
"--storage-dir",
|
"--storage-dir",
|
||||||
default=None,
|
default=None,
|
||||||
type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True),
|
type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True),
|
||||||
help="Custom package storage directory",
|
help="Custom Package Manager storage for global packages",
|
||||||
)
|
)
|
||||||
@click.option("-f", "--force", is_flag=True, help="Reinstall package if it exists")
|
@click.option("-f", "--force", is_flag=True, help="Reinstall package if it exists")
|
||||||
@click.option("-s", "--silent", is_flag=True, help="Suppress progress reporting")
|
@click.option("-s", "--silent", is_flag=True, help="Suppress progress reporting")
|
||||||
@ -168,21 +175,33 @@ def _install_project_env_libraries(project_env, options):
|
|||||||
if options.get("libraries"):
|
if options.get("libraries"):
|
||||||
if not options.get("silent"):
|
if not options.get("silent"):
|
||||||
lm.set_log_level(logging.DEBUG)
|
lm.set_log_level(logging.DEBUG)
|
||||||
for spec in options.get("libraries", []):
|
specs_to_save = []
|
||||||
lm.install(
|
for library in options.get("libraries", []):
|
||||||
|
spec = PackageSpec(library)
|
||||||
|
pkg = lm.install(
|
||||||
spec,
|
spec,
|
||||||
skip_dependencies=options.get("skip_dependencies"),
|
skip_dependencies=options.get("skip_dependencies"),
|
||||||
force=options.get("force"),
|
force=options.get("force"),
|
||||||
)
|
)
|
||||||
|
specs_to_save.append(_pkg_to_save_spec(pkg, spec))
|
||||||
|
if not options.get("no_save") and specs_to_save:
|
||||||
|
save_project_dependencies(
|
||||||
|
os.getcwd(),
|
||||||
|
specs_to_save,
|
||||||
|
scope="lib_deps",
|
||||||
|
action="add",
|
||||||
|
environments=[project_env],
|
||||||
|
)
|
||||||
return not already_up_to_date
|
return not already_up_to_date
|
||||||
|
|
||||||
if options.get("platforms") or options.get("tools"):
|
if options.get("platforms") or options.get("tools"):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# if not custom platforms/tools, install declared libraries
|
# if not custom platforms/tools, install declared libraries
|
||||||
for spec in config.get(f"env:{project_env}", "lib_deps"):
|
for library in config.get(f"env:{project_env}", "lib_deps"):
|
||||||
|
spec = PackageSpec(library)
|
||||||
# skip built-in dependencies
|
# skip built-in dependencies
|
||||||
if "/" not in spec:
|
if not spec.external and not spec.owner:
|
||||||
continue
|
continue
|
||||||
if not lm.get_package(spec):
|
if not lm.get_package(spec):
|
||||||
already_up_to_date = False
|
already_up_to_date = False
|
||||||
@ -192,3 +211,19 @@ def _install_project_env_libraries(project_env, options):
|
|||||||
force=options.get("force"),
|
force=options.get("force"),
|
||||||
)
|
)
|
||||||
return not already_up_to_date
|
return not already_up_to_date
|
||||||
|
|
||||||
|
|
||||||
|
def _pkg_to_save_spec(pkg, user_spec):
|
||||||
|
assert isinstance(user_spec, PackageSpec)
|
||||||
|
if user_spec.external:
|
||||||
|
return user_spec
|
||||||
|
return PackageSpec(
|
||||||
|
owner=pkg.metadata.spec.owner,
|
||||||
|
name=pkg.metadata.spec.name,
|
||||||
|
requirements=user_spec.requirements
|
||||||
|
or (
|
||||||
|
("^%s" % pkg.metadata.version)
|
||||||
|
if not pkg.metadata.version.build
|
||||||
|
else pkg.metadata.version
|
||||||
|
),
|
||||||
|
)
|
||||||
|
71
platformio/project/savedeps.py
Normal file
71
platformio/project/savedeps.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from platformio.compat import ci_strings_are_equal
|
||||||
|
from platformio.package.meta import PackageSpec
|
||||||
|
from platformio.project.config import ProjectConfig
|
||||||
|
from platformio.project.exception import InvalidProjectConfError
|
||||||
|
|
||||||
|
|
||||||
|
def save_project_dependencies(
|
||||||
|
project_dir, specs, scope, action="add", environments=None
|
||||||
|
):
|
||||||
|
config = ProjectConfig.get_instance(os.path.join(project_dir, "platformio.ini"))
|
||||||
|
config.validate(environments)
|
||||||
|
for env in config.envs():
|
||||||
|
if environments and env not in environments:
|
||||||
|
continue
|
||||||
|
config.expand_interpolations = False
|
||||||
|
candidates = []
|
||||||
|
try:
|
||||||
|
candidates = ignore_deps_by_specs(config.get("env:" + env, scope), specs)
|
||||||
|
except InvalidProjectConfError:
|
||||||
|
pass
|
||||||
|
if action == "add":
|
||||||
|
candidates.extend(spec.as_dependency() for spec in specs)
|
||||||
|
if candidates:
|
||||||
|
result = []
|
||||||
|
for item in candidates:
|
||||||
|
item = item.strip()
|
||||||
|
if item and item not in result:
|
||||||
|
result.append(item)
|
||||||
|
config.set("env:" + env, scope, result)
|
||||||
|
elif config.has_option("env:" + env, scope):
|
||||||
|
config.remove_option("env:" + env, scope)
|
||||||
|
config.save()
|
||||||
|
|
||||||
|
|
||||||
|
def ignore_deps_by_specs(deps, specs):
|
||||||
|
result = []
|
||||||
|
for dep in deps:
|
||||||
|
ignore_conditions = []
|
||||||
|
depspec = PackageSpec(dep)
|
||||||
|
if depspec.external:
|
||||||
|
ignore_conditions.append(depspec in specs)
|
||||||
|
else:
|
||||||
|
for spec in specs:
|
||||||
|
if depspec.owner:
|
||||||
|
ignore_conditions.append(
|
||||||
|
ci_strings_are_equal(depspec.owner, spec.owner)
|
||||||
|
and ci_strings_are_equal(depspec.name, spec.name)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
ignore_conditions.append(
|
||||||
|
ci_strings_are_equal(depspec.name, spec.name)
|
||||||
|
)
|
||||||
|
if not any(ignore_conditions):
|
||||||
|
result.append(dep)
|
||||||
|
return result
|
@ -89,14 +89,18 @@ def test_project(clirunner, validate_cliresult, isolated_pio_core, tmp_path):
|
|||||||
)
|
)
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
with fs.cd(str(project_dir)):
|
with fs.cd(str(project_dir)):
|
||||||
|
config = ProjectConfig()
|
||||||
lm = LibraryPackageManager(
|
lm = LibraryPackageManager(
|
||||||
os.path.join(ProjectConfig().get("platformio", "libdeps_dir"), "devkit")
|
os.path.join(config.get("platformio", "libdeps_dir"), "devkit")
|
||||||
)
|
)
|
||||||
assert pkgs_to_names(lm.get_installed()) == ["DallasTemperature", "OneWire"]
|
assert pkgs_to_names(lm.get_installed()) == ["DallasTemperature", "OneWire"]
|
||||||
assert pkgs_to_names(ToolPackageManager().get_installed()) == [
|
assert pkgs_to_names(ToolPackageManager().get_installed()) == [
|
||||||
"framework-arduino-avr-attiny",
|
"framework-arduino-avr-attiny",
|
||||||
"toolchain-atmelavr",
|
"toolchain-atmelavr",
|
||||||
]
|
]
|
||||||
|
assert config.get("env:devkit", "lib_deps") == [
|
||||||
|
"milesburton/DallasTemperature@^3.9.1"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_unknown_project_dependencies(
|
def test_unknown_project_dependencies(
|
||||||
@ -175,6 +179,25 @@ def test_custom_project_libraries(
|
|||||||
# do not expect any platforms/tools
|
# do not expect any platforms/tools
|
||||||
assert not os.path.exists(config.get("platformio", "platforms_dir"))
|
assert not os.path.exists(config.get("platformio", "platforms_dir"))
|
||||||
assert not os.path.exists(config.get("platformio", "packages_dir"))
|
assert not os.path.exists(config.get("platformio", "packages_dir"))
|
||||||
|
# check saved deps
|
||||||
|
assert config.get("env:devkit", "lib_deps") == [
|
||||||
|
"bblanchon/ArduinoJson@^6.19.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
# install library without saving to config
|
||||||
|
result = clirunner.invoke(
|
||||||
|
package_install_cmd,
|
||||||
|
["-e", "devkit", "-l", "nanopb/Nanopb@^0.4.6", "--no-save"],
|
||||||
|
)
|
||||||
|
validate_cliresult(result)
|
||||||
|
config = ProjectConfig()
|
||||||
|
lm = LibraryPackageManager(
|
||||||
|
os.path.join(config.get("platformio", "libdeps_dir"), "devkit")
|
||||||
|
)
|
||||||
|
assert pkgs_to_names(lm.get_installed()) == ["ArduinoJson", "Nanopb"]
|
||||||
|
assert config.get("env:devkit", "lib_deps") == [
|
||||||
|
"bblanchon/ArduinoJson@^6.19.2",
|
||||||
|
]
|
||||||
|
|
||||||
# unknown libraries
|
# unknown libraries
|
||||||
result = clirunner.invoke(
|
result = clirunner.invoke(
|
||||||
|
120
tests/project/test_savedeps.py
Normal file
120
tests/project/test_savedeps.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
from platformio.package.meta import PackageSpec
|
||||||
|
from platformio.project.config import ProjectConfig
|
||||||
|
from platformio.project.savedeps import save_project_dependencies
|
||||||
|
|
||||||
|
PROJECT_CONFIG_TPL = """
|
||||||
|
[env]
|
||||||
|
board = uno
|
||||||
|
framework = arduino
|
||||||
|
|
||||||
|
[env:bare]
|
||||||
|
|
||||||
|
[env:release]
|
||||||
|
platform = platformio/atmelavr
|
||||||
|
lib_deps =
|
||||||
|
milesburton/DallasTemperature@^3.8
|
||||||
|
|
||||||
|
[env:debug]
|
||||||
|
platform = platformio/atmelavr@^3.4.0
|
||||||
|
lib_deps =
|
||||||
|
milesburton/DallasTemperature@^3.9.1
|
||||||
|
bblanchon/ArduinoJson
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_save_libraries(tmp_path):
|
||||||
|
project_dir = tmp_path / "project"
|
||||||
|
project_dir.mkdir()
|
||||||
|
(project_dir / "platformio.ini").write_text(PROJECT_CONFIG_TPL)
|
||||||
|
specs = [
|
||||||
|
PackageSpec("milesburton/DallasTemperature@^3.9"),
|
||||||
|
PackageSpec("adafruit/Adafruit GPS Library@^1.6.0"),
|
||||||
|
PackageSpec("https://github.com/nanopb/nanopb.git"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# add to the sepcified environment
|
||||||
|
save_project_dependencies(
|
||||||
|
str(project_dir), specs, scope="lib_deps", action="add", environments=["debug"]
|
||||||
|
)
|
||||||
|
config = ProjectConfig.get_instance(str(project_dir / "platformio.ini"))
|
||||||
|
assert config.get("env:debug", "lib_deps") == [
|
||||||
|
"bblanchon/ArduinoJson",
|
||||||
|
"milesburton/DallasTemperature@^3.9",
|
||||||
|
"adafruit/Adafruit GPS Library@^1.6.0",
|
||||||
|
"https://github.com/nanopb/nanopb.git",
|
||||||
|
]
|
||||||
|
assert config.get("env:bare", "lib_deps") == []
|
||||||
|
assert config.get("env:release", "lib_deps") == [
|
||||||
|
"milesburton/DallasTemperature@^3.8"
|
||||||
|
]
|
||||||
|
|
||||||
|
# add to the the all environments
|
||||||
|
save_project_dependencies(str(project_dir), specs, scope="lib_deps", action="add")
|
||||||
|
config = ProjectConfig.get_instance(str(project_dir / "platformio.ini"))
|
||||||
|
assert config.get("env:debug", "lib_deps") == [
|
||||||
|
"bblanchon/ArduinoJson",
|
||||||
|
"milesburton/DallasTemperature@^3.9",
|
||||||
|
"adafruit/Adafruit GPS Library@^1.6.0",
|
||||||
|
"https://github.com/nanopb/nanopb.git",
|
||||||
|
]
|
||||||
|
assert config.get("env:bare", "lib_deps") == [
|
||||||
|
"milesburton/DallasTemperature@^3.9",
|
||||||
|
"adafruit/Adafruit GPS Library@^1.6.0",
|
||||||
|
"https://github.com/nanopb/nanopb.git",
|
||||||
|
]
|
||||||
|
assert config.get("env:release", "lib_deps") == [
|
||||||
|
"milesburton/DallasTemperature@^3.9",
|
||||||
|
"adafruit/Adafruit GPS Library@^1.6.0",
|
||||||
|
"https://github.com/nanopb/nanopb.git",
|
||||||
|
]
|
||||||
|
|
||||||
|
# remove deps from env
|
||||||
|
save_project_dependencies(
|
||||||
|
str(project_dir),
|
||||||
|
[PackageSpec("milesburton/DallasTemperature")],
|
||||||
|
scope="lib_deps",
|
||||||
|
action="remove",
|
||||||
|
environments=["release"],
|
||||||
|
)
|
||||||
|
config = ProjectConfig.get_instance(str(project_dir / "platformio.ini"))
|
||||||
|
assert config.get("env:release", "lib_deps") == [
|
||||||
|
"adafruit/Adafruit GPS Library@^1.6.0",
|
||||||
|
"https://github.com/nanopb/nanopb.git",
|
||||||
|
]
|
||||||
|
# invalid requirements
|
||||||
|
save_project_dependencies(
|
||||||
|
str(project_dir),
|
||||||
|
[PackageSpec("adafruit/Adafruit GPS Library@^9.9.9")],
|
||||||
|
scope="lib_deps",
|
||||||
|
action="remove",
|
||||||
|
environments=["release"],
|
||||||
|
)
|
||||||
|
config = ProjectConfig.get_instance(str(project_dir / "platformio.ini"))
|
||||||
|
assert config.get("env:release", "lib_deps") == [
|
||||||
|
"https://github.com/nanopb/nanopb.git",
|
||||||
|
]
|
||||||
|
|
||||||
|
# remove deps from all envs
|
||||||
|
save_project_dependencies(
|
||||||
|
str(project_dir), specs, scope="lib_deps", action="remove"
|
||||||
|
)
|
||||||
|
config = ProjectConfig.get_instance(str(project_dir / "platformio.ini"))
|
||||||
|
assert config.get("env:debug", "lib_deps") == [
|
||||||
|
"bblanchon/ArduinoJson",
|
||||||
|
]
|
||||||
|
assert config.get("env:bare", "lib_deps") == []
|
||||||
|
assert config.get("env:release", "lib_deps") == []
|
Reference in New Issue
Block a user