From 374433d6fc32866f631568ee8efd38446a0d7ed1 Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 10 Jan 2024 23:40:56 +0100 Subject: [PATCH 1/5] poc for --global-conf in cli --- conan/cli/command.py | 9 ++++++++- conan/cli/commands/config.py | 2 +- conans/test/integration/configuration/conf/test_conf.py | 9 +++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/conan/cli/command.py b/conan/cli/command.py index 05bda22eebc..d9d4d149300 100644 --- a/conan/cli/command.py +++ b/conan/cli/command.py @@ -50,6 +50,8 @@ def _init_log_levels(parser): help="Level of detail of the output. Valid options from less verbose " "to more verbose: -vquiet, -verror, -vwarning, -vnotice, -vstatus, " "-v or -vverbose, -vv or -vdebug, -vvv or -vtrace") + parser.add_argument("-gc", "--global-conf", action="append", + help="Global configuration for Conan") @property def _help_formatters(self): @@ -100,9 +102,14 @@ class ConanArgumentParser(argparse.ArgumentParser): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - def parse_args(self, args=None, namespace=None): + def parse_args(self, args=None, namespace=None, conan_api=None): args = super().parse_args(args) ConanOutput.define_log_level(os.getenv("CONAN_LOG_LEVEL", args.v)) + if conan_api and args.global_conf: + from conans.model.conf import ConfDefinition + confs = ConfDefinition() + confs.loads("\n".join(args.global_conf)) + conan_api.config.global_conf.update_conf_definition(confs) return args diff --git a/conan/cli/commands/config.py b/conan/cli/commands/config.py index 045c31643e6..75522983b61 100644 --- a/conan/cli/commands/config.py +++ b/conan/cli/commands/config.py @@ -73,6 +73,6 @@ def config_show(conan_api, parser, subparser, *args): Get the value of the specified conf """ subparser.add_argument('pattern', help='Conf item(s) pattern for which to query their value') - args = parser.parse_args(*args) + args = parser.parse_args(*args, conan_api=conan_api) return conan_api.config.show(args.pattern) diff --git a/conans/test/integration/configuration/conf/test_conf.py b/conans/test/integration/configuration/conf/test_conf.py index 50aa689999c..2acdc66136b 100644 --- a/conans/test/integration/configuration/conf/test_conf.py +++ b/conans/test/integration/configuration/conf/test_conf.py @@ -307,6 +307,15 @@ def test_global_conf_auto_created(): assert "# core:non_interactive = True" in global_conf +def test_command_line_core_conf(): + c = TestClient() + c.run("config show * -gc core:default_profile=potato") + assert "core:default_profile: potato" in c.out + c.run("config show * -gc core:default_profile=potato -gc core:default_build_profile=orange") + assert "core:default_profile: potato" in c.out + assert "core:default_build_profile: orange" in c.out + + def test_build_test_consumer_only(): c = TestClient() dep = textwrap.dedent(""" From 0bfd3d90746e2ba527babf75b6eb235a7cafac47 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 11 Jan 2024 11:30:04 +0100 Subject: [PATCH 2/5] add test storage_path --- conan/cli/commands/list.py | 2 +- .../test/integration/configuration/conf/test_conf.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/conan/cli/commands/list.py b/conan/cli/commands/list.py index 61b067a766d..29be0aa80f2 100644 --- a/conan/cli/commands/list.py +++ b/conan/cli/commands/list.py @@ -223,7 +223,7 @@ def list(conan_api: ConanAPI, parser, *args): " time limit like --lru=5d (days) or --lru=4w (weeks)," " h (hours), m(minutes)") - args = parser.parse_args(*args) + args = parser.parse_args(*args, conan_api=conan_api) if args.pattern is None and args.graph is None: raise ConanException("Missing pattern or graph json file") diff --git a/conans/test/integration/configuration/conf/test_conf.py b/conans/test/integration/configuration/conf/test_conf.py index 2acdc66136b..921937f28a3 100644 --- a/conans/test/integration/configuration/conf/test_conf.py +++ b/conans/test/integration/configuration/conf/test_conf.py @@ -8,6 +8,7 @@ from conan import conan_version from conan.internal.api import detect_api from conans.test.assets.genconanfile import GenConanfile +from conans.test.utils.test_files import temp_folder from conans.util.files import save, load from conans.test.utils.tools import TestClient @@ -315,6 +316,16 @@ def test_command_line_core_conf(): assert "core:default_profile: potato" in c.out assert "core:default_build_profile: orange" in c.out + c.save({"conanfile.py": GenConanfile("pkg", "0.1")}) + c.run("export .") + + tfolder = temp_folder() + c.run(f'list * -gc core.cache:storage_path="{tfolder}"') + assert "WARN: There are no matching recipe references" in c.out + c.run(f'list *') + assert "WARN: There are no matching recipe references" not in c.out + assert "pkg/0.1" in c.out + def test_build_test_consumer_only(): c = TestClient() From c446aafc971bdbeb532e5675b22c5272077f174e Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 17 Jan 2024 17:51:24 +0100 Subject: [PATCH 3/5] no need to inject conan_api to every parse --- conan/cli/command.py | 20 +++++++++++--------- conan/cli/commands/config.py | 2 +- conan/cli/commands/list.py | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/conan/cli/command.py b/conan/cli/command.py index d9d4d149300..c4947b59cad 100644 --- a/conan/cli/command.py +++ b/conan/cli/command.py @@ -99,17 +99,18 @@ def _format(self, parser, info, *args): class ConanArgumentParser(argparse.ArgumentParser): - def __init__(self, *args, **kwargs): + def __init__(self, conan_api, *args, **kwargs): + self._conan_api = conan_api super().__init__(*args, **kwargs) - def parse_args(self, args=None, namespace=None, conan_api=None): + def parse_args(self, args=None, namespace=None): args = super().parse_args(args) ConanOutput.define_log_level(os.getenv("CONAN_LOG_LEVEL", args.v)) - if conan_api and args.global_conf: + if args.global_conf: from conans.model.conf import ConfDefinition confs = ConfDefinition() confs.loads("\n".join(args.global_conf)) - conan_api.config.global_conf.update_conf_definition(confs) + self._conan_api.config.global_conf.update_conf_definition(confs) return args @@ -125,7 +126,8 @@ def add_subcommand(self, subcommand): self._subcommands[subcommand.name] = subcommand def run(self, conan_api, *args): - parser = ConanArgumentParser(description=self._doc, prog="conan {}".format(self._name), + parser = ConanArgumentParser(conan_api, description=self._doc, + prog="conan {}".format(self._name), formatter_class=SmartFormatter) self._init_log_levels(parser) self._init_formatters(parser) @@ -142,10 +144,10 @@ def run(self, conan_api, *args): sub = self._subcommands[args[0][0]] except (KeyError, IndexError): # display help for sub in self._subcommands.values(): - sub.set_parser(subcommand_parser) + sub.set_parser(subcommand_parser, conan_api) parser.parse_args(*args) else: - sub.set_parser(subcommand_parser) + sub.set_parser(subcommand_parser, conan_api) sub.run(conan_api, parser, *args) @property @@ -167,8 +169,8 @@ def run(self, conan_api, parent_parser, *args): def set_name(self, parent_name): self._name = self._subcommand_name.replace(f'{parent_name}-', '', 1) - def set_parser(self, subcommand_parser): - self._parser = subcommand_parser.add_parser(self._name, help=self._doc) + def set_parser(self, subcommand_parser, conan_api): + self._parser = subcommand_parser.add_parser(self._name, conan_api=conan_api, help=self._doc) self._parser.description = self._doc self._init_formatters(self._parser) self._init_log_levels(self._parser) diff --git a/conan/cli/commands/config.py b/conan/cli/commands/config.py index 75522983b61..045c31643e6 100644 --- a/conan/cli/commands/config.py +++ b/conan/cli/commands/config.py @@ -73,6 +73,6 @@ def config_show(conan_api, parser, subparser, *args): Get the value of the specified conf """ subparser.add_argument('pattern', help='Conf item(s) pattern for which to query their value') - args = parser.parse_args(*args, conan_api=conan_api) + args = parser.parse_args(*args) return conan_api.config.show(args.pattern) diff --git a/conan/cli/commands/list.py b/conan/cli/commands/list.py index 29be0aa80f2..61b067a766d 100644 --- a/conan/cli/commands/list.py +++ b/conan/cli/commands/list.py @@ -223,7 +223,7 @@ def list(conan_api: ConanAPI, parser, *args): " time limit like --lru=5d (days) or --lru=4w (weeks)," " h (hours), m(minutes)") - args = parser.parse_args(*args, conan_api=conan_api) + args = parser.parse_args(*args) if args.pattern is None and args.graph is None: raise ConanException("Missing pattern or graph json file") From 55b66826c3ddbced0051fc01e2d9d2863826d343 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 18 Jan 2024 14:49:47 +0100 Subject: [PATCH 4/5] review --- conan/cli/command.py | 11 ++++++++--- .../test/integration/configuration/conf/test_conf.py | 9 ++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/conan/cli/command.py b/conan/cli/command.py index c4947b59cad..a924dda9b74 100644 --- a/conan/cli/command.py +++ b/conan/cli/command.py @@ -4,6 +4,7 @@ from conan.api.output import ConanOutput from conan.errors import ConanException +from conans.model.conf import CORE_CONF_PATTERN class OnceArgument(argparse.Action): @@ -50,7 +51,7 @@ def _init_log_levels(parser): help="Level of detail of the output. Valid options from less verbose " "to more verbose: -vquiet, -verror, -vwarning, -vnotice, -vstatus, " "-v or -vverbose, -vv or -vdebug, -vvv or -vtrace") - parser.add_argument("-gc", "--global-conf", action="append", + parser.add_argument("-cc", "--core-conf", action="append", help="Global configuration for Conan") @property @@ -106,10 +107,14 @@ def __init__(self, conan_api, *args, **kwargs): def parse_args(self, args=None, namespace=None): args = super().parse_args(args) ConanOutput.define_log_level(os.getenv("CONAN_LOG_LEVEL", args.v)) - if args.global_conf: + if args.core_conf: from conans.model.conf import ConfDefinition confs = ConfDefinition() - confs.loads("\n".join(args.global_conf)) + for c in args.core_conf: + if not CORE_CONF_PATTERN.match(c): + raise ConanException(f"Only core. values are allowed in --core-conf. Got {c}") + confs.loads("\n".join(args.core_conf)) + confs.validate() self._conan_api.config.global_conf.update_conf_definition(confs) return args diff --git a/conans/test/integration/configuration/conf/test_conf.py b/conans/test/integration/configuration/conf/test_conf.py index 921937f28a3..5a4ee37d7ae 100644 --- a/conans/test/integration/configuration/conf/test_conf.py +++ b/conans/test/integration/configuration/conf/test_conf.py @@ -310,9 +310,9 @@ def test_global_conf_auto_created(): def test_command_line_core_conf(): c = TestClient() - c.run("config show * -gc core:default_profile=potato") + c.run("config show * -cc core:default_profile=potato") assert "core:default_profile: potato" in c.out - c.run("config show * -gc core:default_profile=potato -gc core:default_build_profile=orange") + c.run("config show * -cc core:default_profile=potato -cc core:default_build_profile=orange") assert "core:default_profile: potato" in c.out assert "core:default_build_profile: orange" in c.out @@ -320,12 +320,15 @@ def test_command_line_core_conf(): c.run("export .") tfolder = temp_folder() - c.run(f'list * -gc core.cache:storage_path="{tfolder}"') + c.run(f'list * -cc core.cache:storage_path="{tfolder}"') assert "WARN: There are no matching recipe references" in c.out c.run(f'list *') assert "WARN: There are no matching recipe references" not in c.out assert "pkg/0.1" in c.out + c.run("list * -cc user.xxx:yyy=zzz", assert_error=True) + assert "ERROR: Only core. values are allowed in --core-conf. Got user.xxx:yyy=zzz" in c.out + def test_build_test_consumer_only(): c = TestClient() From a44b61e77b3e0191dcdb40ba67c22617a41c4e1c Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 18 Jan 2024 15:30:45 +0100 Subject: [PATCH 5/5] fix test --- .../graph/version_ranges/version_ranges_diamond_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/test/integration/graph/version_ranges/version_ranges_diamond_test.py b/conans/test/integration/graph/version_ranges/version_ranges_diamond_test.py index 9a648cd075e..0a6b11cdcac 100644 --- a/conans/test/integration/graph/version_ranges/version_ranges_diamond_test.py +++ b/conans/test/integration/graph/version_ranges/version_ranges_diamond_test.py @@ -56,7 +56,7 @@ def test_update(self): client.run("remove pkg/1.3* -c") # removes remote - client.run("remove pkg* -r=default --c") + client.run("remove pkg* -r=default -c") # Resolves to local package client.run("install app") assert "pkg/1.1" not in client.out