diff --git a/conan/tools/cmake/toolchain.py b/conan/tools/cmake/toolchain.py index 39994397e37..faed8f5d4a5 100644 --- a/conan/tools/cmake/toolchain.py +++ b/conan/tools/cmake/toolchain.py @@ -245,7 +245,7 @@ class ParallelBlock(Block): def context(self): # TODO: Check this conf - max_cpu_count = self._conanfile.conf["tools.cmake.cmaketoolchain"].msvc_parallel_compile + max_cpu_count = self._conanfile.conf["tools.cmake.cmaketoolchain:msvc_parallel_compile"] if max_cpu_count: return {"parallel": max_cpu_count} @@ -278,7 +278,7 @@ def context(self): libcxx_str = str(self._conanfile.settings.compiler.libcxx) # TODO: Do not use envvar! This has to be provided by the user somehow - android_ndk = self._conanfile.conf["tools.android"].ndk_path + android_ndk = self._conanfile.conf["tools.android:ndk_path"] if not android_ndk: raise ConanException('CMakeToolchain needs tools.android:ndk_path configuration defined') android_ndk = android_ndk.replace("\\", "/") @@ -376,7 +376,7 @@ def context(self): cmake_prefix_path = "${CMAKE_CURRENT_LIST_DIR}" cmake_module_path = "${CMAKE_CURRENT_LIST_DIR}" find_package_prefer_config = "ON" # assume ON by default if not specified in conf - prefer_config = self._conanfile.conf["tools.cmake.cmaketoolchain"].find_package_prefer_config + prefer_config = self._conanfile.conf["tools.cmake.cmaketoolchain:find_package_prefer_config"] if prefer_config is not None and prefer_config.lower() in ("false", "0", "off"): find_package_prefer_config = "OFF" diff --git a/conan/tools/files/files.py b/conan/tools/files/files.py index 86a3855aefb..b1c505e027e 100644 --- a/conan/tools/files/files.py +++ b/conan/tools/files/files.py @@ -123,9 +123,9 @@ def download(conanfile, url, filename, verify=True, out=None, retry=None, retry_ config = conanfile.conf # It might be possible that users provide their own requester - retry = retry if retry is not None else int(config["tools.files.download"].retry) + retry = retry if retry is not None else int(config["tools.files.download:retry"]) retry = retry if retry is not None else 1 - retry_wait = retry_wait if retry_wait is not None else int(config["tools.files.download"].retry_wait) + retry_wait = retry_wait if retry_wait is not None else int(config["tools.files.download:retry_wait"]) retry_wait = retry_wait if retry_wait is not None else 5 checksum = sha256 or sha1 or md5 diff --git a/conan/tools/gnu/autotools.py b/conan/tools/gnu/autotools.py index fd0329e3d1e..93300936075 100644 --- a/conan/tools/gnu/autotools.py +++ b/conan/tools/gnu/autotools.py @@ -63,7 +63,7 @@ def make(self): cpu_count_option]), win_bash=self._win_bash, subsystem=self.subsystem)""" - make_program = self._conanfile.conf["tools.gnu"].make_program + make_program = self._conanfile.conf["tools.gnu:make_program"] if make_program is None: make_program = "mingw32-make" if use_win_mingw(self._conanfile) else "make" # Need to activate the buildenv if existing diff --git a/conan/tools/gnu/make.py b/conan/tools/gnu/make.py index fa48776cab3..8f7fc3729f4 100644 --- a/conan/tools/gnu/make.py +++ b/conan/tools/gnu/make.py @@ -1,5 +1,5 @@ def make_jobs_cmd_line_arg(conanfile): - njobs = conanfile.conf["tools.gnu.make"].jobs or \ - conanfile.conf["tools.build"].processes + njobs = conanfile.conf["tools.gnu.make:jobs"] or \ + conanfile.conf["tools.build:processes"] if njobs: return "-j{}".format(njobs) diff --git a/conan/tools/meson/meson.py b/conan/tools/meson/meson.py index a137e22c9c2..bd982d3d785 100644 --- a/conan/tools/meson/meson.py +++ b/conan/tools/meson/meson.py @@ -5,8 +5,8 @@ def ninja_jobs_cmd_line_arg(conanfile): - njobs = conanfile.conf["tools.ninja"].jobs or \ - conanfile.conf["tools.build"].processes + njobs = conanfile.conf["tools.ninja:jobs"] or \ + conanfile.conf["tools.build:processes"] if njobs: return "-j{}".format(njobs) diff --git a/conan/tools/microsoft/msbuild.py b/conan/tools/microsoft/msbuild.py index 6c799b02880..9ff60ab0985 100644 --- a/conan/tools/microsoft/msbuild.py +++ b/conan/tools/microsoft/msbuild.py @@ -4,7 +4,7 @@ def msbuild_verbosity_cmd_line_arg(conanfile): - verbosity = conanfile.conf["tools.microsoft.msbuild"].verbosity + verbosity = conanfile.conf["tools.microsoft.msbuild:verbosity"] if verbosity: if verbosity not in ("Quiet", "Minimal", "Normal", "Detailed", "Diagnostic"): raise ConanException("Unknown msbuild verbosity: {}".format(verbosity)) @@ -12,8 +12,8 @@ def msbuild_verbosity_cmd_line_arg(conanfile): def msbuild_max_cpu_count_cmd_line_arg(conanfile): - max_cpu_count = conanfile.conf["tools.microsoft.msbuild"].max_cpu_count or \ - conanfile.conf["tools.build"].processes + max_cpu_count = conanfile.conf["tools.microsoft.msbuild:max_cpu_count"] or \ + conanfile.conf["tools.build:processes"] if max_cpu_count: return "/m:{}".format(max_cpu_count) diff --git a/conan/tools/microsoft/msbuilddeps.py b/conan/tools/microsoft/msbuilddeps.py index c8f7cffc1d8..a5714598fd1 100644 --- a/conan/tools/microsoft/msbuilddeps.py +++ b/conan/tools/microsoft/msbuilddeps.py @@ -103,7 +103,7 @@ def __init__(self, conanfile): self.output_path = os.getcwd() # ca_exclude section self.exclude_code_analysis = None - ca_exclude = self._conanfile.conf["tools.microsoft.msbuilddeps"].exclude_code_analysis + ca_exclude = self._conanfile.conf["tools.microsoft.msbuilddeps:exclude_code_analysis"] if ca_exclude is not None: # TODO: Accept single strings, not lists self.exclude_code_analysis = eval(ca_exclude) diff --git a/conan/tools/microsoft/toolchain.py b/conan/tools/microsoft/toolchain.py index da792ea6ab0..b3ea986422b 100644 --- a/conan/tools/microsoft/toolchain.py +++ b/conan/tools/microsoft/toolchain.py @@ -41,7 +41,7 @@ def vs_ide_version(conanfile): compiler_version = (conanfile.settings.get_safe("compiler.base.version") or conanfile.settings.get_safe("compiler.version")) if compiler == "msvc": - toolset_override = conanfile.conf["tools.microsoft.msbuild"].vs_version + toolset_override = conanfile.conf["tools.microsoft.msbuild:vs_version"] if toolset_override: visual_version = toolset_override else: @@ -160,7 +160,7 @@ def format_macro(key, value): cppstd = "stdcpp%s" % self.cppstd if self.cppstd else "" runtime_library = self.runtime_library toolset = self.toolset - compile_options = self._conanfile.conf["tools.microsoft.msbuildtoolchain"].compile_options + compile_options = self._conanfile.conf["tools.microsoft.msbuildtoolchain:compile_options"] if compile_options is not None: compile_options = eval(compile_options) self.compile_options.update(compile_options) diff --git a/conans/client/conf/required_version.py b/conans/client/conf/required_version.py index 24d46ddb3e4..f06342d663c 100644 --- a/conans/client/conf/required_version.py +++ b/conans/client/conf/required_version.py @@ -30,7 +30,7 @@ def check_required_conan_version(cache_folder, out): if required_range: validate_conan_version(required_range) - required_range_new = cache.new_config["core"].required_conan_version + required_range_new = cache.new_config["core:required_conan_version"] if required_range_new: if six.PY2 and not isinstance(required_range_new, str): required_range_new = required_range_new.encode() diff --git a/conans/client/generators/__init__.py b/conans/client/generators/__init__.py index 7c941caf361..03ea1213a47 100644 --- a/conans/client/generators/__init__.py +++ b/conans/client/generators/__init__.py @@ -207,7 +207,7 @@ def write_toolchain(conanfile, path, output): conanfile.generate() # tools.env.virtualenv:auto_use will be always True in Conan 2.0 - if conanfile.conf["tools.env.virtualenv"].auto_use and conanfile.virtualenv: + if conanfile.conf["tools.env.virtualenv:auto_use"] and conanfile.virtualenv: with chdir(path): from conan.tools.env.virtualenv import VirtualEnv env = VirtualEnv(conanfile) diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py index e2bcb8602ba..f9cb92abe2a 100644 --- a/conans/client/graph/graph_binaries.py +++ b/conans/client/graph/graph_binaries.py @@ -340,7 +340,7 @@ def _compute_package_id(self, node, default_package_id_mode, default_python_requ default_python_requires_id_mode= default_python_requires_id_mode) - if not self._cache.new_config["core.package_id"].msvc_visual_incompatible: + if not self._cache.new_config["core.package_id:msvc_visual_incompatible"]: msvc_compatible = conanfile.info.msvc_compatible() if msvc_compatible: conanfile.compatible_packages.append(msvc_compatible) diff --git a/conans/model/conf.py b/conans/model/conf.py index 41fa6b8ed4d..bae38aba373 100644 --- a/conans/model/conf.py +++ b/conans/model/conf.py @@ -4,8 +4,8 @@ DEFAULT_CONFIGURATION = { - "core.required_conan_version": "Will raise if the current Conan version does not match the defined version range.", - "core.package_id.msvc_visual_incompatible": "Allows opting-out the fallback from the new msvc compiler to the Visual Studio compiler existing binaries", + "core:required_conan_version": "Will raise if the current Conan version does not match the defined version range.", + "core.package_id:msvc_visual_incompatible": "Allows opting-out the fallback from the new msvc compiler to the Visual Studio compiler existing binaries", "tools.microsoft.msbuild:verbosity": "Verbosity level for MSBuild: 'Quiet', 'Minimal', 'Normal', 'Detailed', 'Diagnostic'", "tools.microsoft.msbuild:max_cpu_count": "Argument for the /m (/maxCpuCount) when running MSBuild", "tools.microsoft.msbuild:vs_version": "Defines the compiler version when using using the new msvc compiler", @@ -24,35 +24,6 @@ } -class _ConfModule(object): - """ - a dictionary of key: values for each config property of a module - like "tools.cmake.CMake" - """ - def __init__(self): - self._confs = {} # Component => dict {config-name: value} - - def __getattr__(self, item): - return self._confs.get(item) - - def update(self, other): - """ - :type other: _ConfModule - """ - self._confs.update(other._confs) - - def set_value(self, k, v): - if k != k.lower(): - raise ConanException("Conf key '{}' must be lowercase".format(k)) - self._confs[k] = v - - def __repr__(self): - return "_ConfModule: " + repr(self._confs) - - def items(self): - return self._confs.items() - - def _is_profile_module(module_name): # These are the modules that are propagated to profiles and user recipes _user_modules = "tools.", "user." @@ -62,46 +33,40 @@ def _is_profile_module(module_name): class Conf(object): def __init__(self): - self._conf_modules = {} # module_name => _ConfModule + self._values = {} # property: value - def __getitem__(self, module_name): - return self._conf_modules.get(module_name, _ConfModule()) + def __getitem__(self, name): + return self._values.get(name) + + def __setitem__(self, name, value): + if name != name.lower(): + raise ConanException("Conf '{}' must be lowercase".format(name)) + self._values[name] = value def __repr__(self): - return "Conf: " + repr(self._conf_modules) + return "Conf: " + repr(self._values) def items(self): - return self._conf_modules.items() + return self._values.items() def filter_user_modules(self): result = Conf() - for k, v in self._conf_modules.items(): + for k, v in self._values.items(): if _is_profile_module(k): - result._conf_modules[k] = v + result._values[k] = v return result def update(self, other): """ :type other: Conf """ - for module_name, module_conf in other._conf_modules.items(): - existing = self._conf_modules.get(module_name) - if existing: - existing.update(module_conf) - else: - self._conf_modules[module_name] = module_conf - - def set_value(self, module_name, k, v): - if module_name != module_name.lower(): - raise ConanException("Conf module '{}' must be lowercase".format(module_name)) - self._conf_modules.setdefault(module_name, _ConfModule()).set_value(k, v) + self._values.update(other._values) @property def sha(self): result = [] - for name, values in sorted(self.items()): - for k, v in sorted(values.items()): - result.append("{}:{}={}".format(name, k, v)) + for k, v in sorted(self._values.items()): + result.append("{}={}".format(k, v)) return "\n".join(result) @@ -158,12 +123,11 @@ def dumps(self): # It is necessary to convert the None for sorting for pattern, conf in sorted(self._pattern_confs.items(), key=lambda x: ("", x[1]) if x[0] is None else x): - for name, values in sorted(conf.items()): - for k, v in sorted(values.items()): - if pattern: - result.append("{}:{}:{}={}".format(pattern, name, k, v)) - else: - result.append("{}:{}={}".format(name, k, v)) + for name, value in sorted(conf.items()): + if pattern: + result.append("{}:{}={}".format(pattern, name, value)) + else: + result.append("{}={}".format(name, value)) return "\n".join(result) def loads(self, text, profile=False): @@ -174,20 +138,19 @@ def loads(self, text, profile=False): continue try: left, value = line.split("=", 1) + value = value.strip() + left = left.strip() + if left.count(":") >= 2: + pattern, name = left.split(":", 1) + else: + pattern, name = None, left except Exception: raise ConanException("Error while parsing conf value '{}'".format(line)) - value = value.strip() - tokens = left.strip().split(":", 2) - if len(tokens) == 3: - pattern, conf_module, name = tokens - else: - assert len(tokens) == 2 - conf_module, name = tokens - pattern = None - if not _is_profile_module(conf_module): + + if not _is_profile_module(name): if profile: raise ConanException("[conf] '{}' not allowed in profiles".format(line)) if pattern is not None: raise ConanException("Conf '{}' cannot have a package pattern".format(line)) conf = self._pattern_confs.setdefault(pattern, Conf()) - conf.set_value(conf_module, name, value) + conf[name] = value diff --git a/conans/test/integration/configuration/conf/test_conf.py b/conans/test/integration/configuration/conf/test_conf.py index 300c0b0fcb1..dc943a14a4a 100644 --- a/conans/test/integration/configuration/conf/test_conf.py +++ b/conans/test/integration/configuration/conf/test_conf.py @@ -16,9 +16,8 @@ def client(): class Pkg(ConanFile): def generate(self): - for k, conf in self.conf.items(): - for name, value in conf.items(): - self.output.info("{}${}${}".format(k, name, value)) + for k, v in self.conf.items(): + self.output.info("{}${}".format(k, v)) """) client.save({"conanfile.py": conanfile}) return client @@ -40,23 +39,23 @@ def test_basic_composition(client): client.save({"profile1": profile1, "profile2": profile2}) client.run("install . -pr=profile1") - assert "tools.microsoft.msbuild$verbosity$Quiet" in client.out - assert "tools.microsoft.msbuild$performance$Slow" in client.out - assert "tools.cmake.cmake$verbosity$Extra" in client.out + assert "tools.microsoft.msbuild:verbosity$Quiet" in client.out + assert "tools.microsoft.msbuild:performance$Slow" in client.out + assert "tools.cmake.cmake:verbosity$Extra" in client.out client.run("install . -pr=profile1 -pr=profile2") - assert "tools.microsoft.msbuild$verbosity$Minimal" in client.out - assert "tools.microsoft.msbuild$performance$Slow" in client.out - assert "tools.microsoft.msbuild$robustness$High" in client.out - assert "tools.cmake.cmake$verbosity$Extra" in client.out - assert "tools.meson.meson$verbosity$Super" in client.out + assert "tools.microsoft.msbuild:verbosity$Minimal" in client.out + assert "tools.microsoft.msbuild:performance$Slow" in client.out + assert "tools.microsoft.msbuild:robustness$High" in client.out + assert "tools.cmake.cmake:verbosity$Extra" in client.out + assert "tools.meson.meson:verbosity$Super" in client.out client.run("install . -pr=profile2 -pr=profile1") - assert "tools.microsoft.msbuild$verbosity$Quiet" in client.out - assert "tools.microsoft.msbuild$performance$Slow" in client.out - assert "tools.microsoft.msbuild$robustness$High" in client.out - assert "tools.cmake.cmake$verbosity$Extra" in client.out - assert "tools.meson.meson$verbosity$Super" in client.out + assert "tools.microsoft.msbuild:verbosity$Quiet" in client.out + assert "tools.microsoft.msbuild:performance$Slow" in client.out + assert "tools.microsoft.msbuild:robustness$High" in client.out + assert "tools.cmake.cmake:verbosity$Extra" in client.out + assert "tools.meson.meson:verbosity$Super" in client.out def test_basic_inclusion(client): @@ -77,11 +76,11 @@ def test_basic_inclusion(client): "profile2": profile2}) client.run("install . -pr=profile2") - assert "tools.microsoft.msbuild$verbosity$Minimal" in client.out - assert "tools.microsoft.msbuild$performance$Slow" in client.out - assert "tools.microsoft.msbuild$robustness$High" in client.out - assert "tools.cmake.cmake$verbosity$Extra" in client.out - assert "tools.meson.meson$verbosity$Super" in client.out + assert "tools.microsoft.msbuild:verbosity$Minimal" in client.out + assert "tools.microsoft.msbuild:performance$Slow" in client.out + assert "tools.microsoft.msbuild:robustness$High" in client.out + assert "tools.cmake.cmake:verbosity$Extra" in client.out + assert "tools.meson.meson:verbosity$Super" in client.out def test_composition_conan_conf(client): @@ -99,11 +98,11 @@ def test_composition_conan_conf(client): """) client.save({"profile": profile}) client.run("install . -pr=profile") - assert "tools.microsoft.msbuild$verbosity$Minimal" in client.out - assert "tools.microsoft.msbuild$performance$Slow" in client.out - assert "tools.microsoft.msbuild$robustness$High" in client.out - assert "tools.cmake.cmake$verbosity$Extra" in client.out - assert "tools.meson.meson$verbosity$Super" in client.out + assert "tools.microsoft.msbuild:verbosity$Minimal" in client.out + assert "tools.microsoft.msbuild:performance$Slow" in client.out + assert "tools.microsoft.msbuild:robustness$High" in client.out + assert "tools.cmake.cmake:verbosity$Extra" in client.out + assert "tools.meson.meson:verbosity$Super" in client.out def test_new_config_file(client): @@ -116,9 +115,9 @@ def test_new_config_file(client): """) save(client.cache.new_config_path, conf) client.run("install .") - assert "tools.microsoft.msbuild$verbosity$Minimal" in client.out - assert "user.mycompany.myhelper$myconfig$myvalue" in client.out - assert "tools.cmake.cmake$generator$X" in client.out + assert "tools.microsoft.msbuild:verbosity$Minimal" in client.out + assert "user.mycompany.myhelper:myconfig$myvalue" in client.out + assert "tools.cmake.cmake:generator$X" in client.out assert "no_locks" not in client.out assert "read_only" not in client.out diff --git a/conans/test/unittests/model/test_conf.py b/conans/test/unittests/model/test_conf.py index 285362a71a7..f66ac378aa9 100644 --- a/conans/test/unittests/model/test_conf.py +++ b/conans/test/unittests/model/test_conf.py @@ -21,10 +21,10 @@ def test_conf_definition(conf_definition): # Round trip assert c.dumps() == text # access - assert c["tools.microsoft.msbuild"].verbosity == "minimal" - assert c["user.company.toolchain"].flags == "someflags" - assert c["tools.microsoft.msbuild"].nonexist is None - assert c["nonexist"].nonexist is None + assert c["tools.microsoft.msbuild:verbosity"] == "minimal" + assert c["user.company.toolchain:flags"] == "someflags" + assert c["tools.microsoft.msbuild:nonexist"] is None + assert c["nonexist:nonexist"] is None # bool assert bool(c) assert not bool(ConfDefinition()) @@ -71,11 +71,12 @@ def test_conf_error_per_package(): def test_conf_error_uppercase(): text = "tools.something:Verbosity=minimal" c = ConfDefinition() - with pytest.raises(ConanException, match=r"Conf key 'Verbosity' must be lowercase"): + with pytest.raises(ConanException, match=r"Conf 'tools.something:Verbosity' must be lowercase"): c.loads(text) text = "tools.Something:verbosity=minimal" c = ConfDefinition() - with pytest.raises(ConanException, match=r"Conf module 'tools.Something' must be lowercase"): + with pytest.raises(ConanException, + match=r"Conf 'tools.Something:verbosity' must be lowercase"): c.loads(text) @@ -83,4 +84,4 @@ def test_parse_spaces(): text = "core:verbosity = minimal" c = ConfDefinition() c.loads(text) - assert c["core"].verbosity == "minimal" + assert c["core:verbosity"] == "minimal"