From 0e28ff8ef0c6ca4329395407d9aed49826d7ccee Mon Sep 17 00:00:00 2001 From: "diegor@jfrog.com" Date: Mon, 28 Nov 2022 12:53:44 +0100 Subject: [PATCH 1/2] [develop2] simplify loading conaninfo.txt for search results --- conans/client/loader_txt.py | 2 +- conans/client/profile_loader.py | 1 + conans/model/info.py | 46 +++++++-------------------------- conans/util/config_parser.py | 23 ++++++++--------- 4 files changed, 22 insertions(+), 50 deletions(-) diff --git a/conans/client/loader_txt.py b/conans/client/loader_txt.py index b94ffaa113e..0e915dfe8a2 100644 --- a/conans/client/loader_txt.py +++ b/conans/client/loader_txt.py @@ -9,7 +9,7 @@ def __init__(self, input_text): # Prefer composition over inheritance, the __getattr__ was breaking things self._config_parser = ConfigParser(input_text, ["requires", "generators", "options", "imports", "tool_requires", "layout"], - parse_lines=True) + strip_comments=True) @property def layout(self): diff --git a/conans/client/profile_loader.py b/conans/client/profile_loader.py index 4a8db07f196..8f61f5ef23c 100644 --- a/conans/client/profile_loader.py +++ b/conans/client/profile_loader.py @@ -251,6 +251,7 @@ class _ProfileValueParser(object): """ @staticmethod def get_profile(profile_text, base_profile=None): + # Trying to strip comments might be problematic if things contain # doc = ConfigParser(profile_text, allowed_fields=["tool_requires", "settings", "options", "conf", "buildenv", "runenv"]) diff --git a/conans/model/info.py b/conans/model/info.py index a245dfff5c3..0c2de46340b 100644 --- a/conans/model/info.py +++ b/conans/model/info.py @@ -1,7 +1,5 @@ -from conans.client.graph.graph import BINARY_INVALID from conans.errors import ConanException from conans.model.dependencies import UserRequirementsDict -from conans.model.options import Options from conans.model.package_ref import PkgReference from conans.model.recipe_ref import RecipeReference, Version from conans.util.config_parser import ConfigParser @@ -291,41 +289,15 @@ def full_mode(self): def load_binary_info(text): # This is used for search functionality, search prints info from this file - # TODO: Generalize - parser = ConfigParser(text, ["settings", "settings_target", "options", "requires", "conf", - "python_requires", "build_requires"], - raise_unexpected_field=False) - - def _loads_settings(settings_text): - settings_result = [] - for line in settings_text.splitlines(): - if not line.strip(): - continue - name, value = line.split("=", 1) - settings_result.append((name.strip(), value.strip())) - return settings_result - - settings = _loads_settings(parser.settings) - settings_target = _loads_settings(parser.settings_target) - options = Options.loads(parser.options) - - def parse_list(lines): - ret = lines.splitlines() if lines else [] - return [r for r in ret if r] - - requires = parse_list(parser.requires) - conf = parse_list(parser.conf) - python_requires = parse_list(parser.python_requires) - build_requires = parse_list(parser.build_requires) - - conan_info_json = {"settings": dict(settings), - "options": options.serialize(), - "requires": requires, - "settings_target": dict(settings_target), - "conf": conf, - "python_requires": python_requires, - "build_requires": build_requires, - } + parser = ConfigParser(text) + conan_info_json = {} + for section, lines in parser.line_items(): + try: + items = [line.split("=", 1) for line in lines] + conan_info_json[section] = {item[0].strip(): item[1].strip() for item in items} + except IndexError: + conan_info_json[section] = lines + return conan_info_json diff --git a/conans/util/config_parser.py b/conans/util/config_parser.py index b8ce8ac9071..2b24c474be1 100644 --- a/conans/util/config_parser.py +++ b/conans/util/config_parser.py @@ -27,7 +27,7 @@ class ConfigParser(object): as parser.section Currently used in ConanInfo and ConanFileTextLoader """ - def __init__(self, text, allowed_fields=None, parse_lines=False, raise_unexpected_field=True): + def __init__(self, text, allowed_fields=None, strip_comments=False): self._sections = {} self._allowed_fields = allowed_fields or [] pattern = re.compile(r"^\[([a-z_]{2,50})]") @@ -36,29 +36,28 @@ def __init__(self, text, allowed_fields=None, parse_lines=False, raise_unexpecte line = line.strip() if not line or line[0] == '#': continue - field = None if line[0] == '[': m = pattern.match(line) - if m: - field = m.group(1) - else: + if not m: raise ConanException("ConfigParser: Bad syntax '%s'" % line) - if field: - if (self._allowed_fields and field not in self._allowed_fields and - raise_unexpected_field): + field = m.group(1) + if self._allowed_fields and field not in self._allowed_fields: raise ConanException("ConfigParser: Unrecognized field '%s'" % field) - else: - current_lines = [] - self._sections[field] = current_lines + current_lines = [] + self._sections[field] = current_lines else: if current_lines is None: raise ConanException("ConfigParser: Unexpected line '%s'" % line) - if parse_lines: + if strip_comments: line = line.split(' #', 1)[0] line = line.split(' #', 1)[0] line = line.strip() current_lines.append(line) + def line_items(self): + # Used atm by load_binary_info() + return self._sections.items() + def __getattr__(self, name): if name in self._sections: return "\n".join(self._sections[name]) From d4ab322174b7fe0fdefa3ba5e2a4c598dbb98435 Mon Sep 17 00:00:00 2001 From: "diegor@jfrog.com" Date: Mon, 28 Nov 2022 14:23:12 +0100 Subject: [PATCH 2/2] fixes --- conans/test/unittests/model/other_settings_test.py | 4 ++-- conans/test/unittests/server/conf_test.py | 6 ++---- conans/util/config_parser.py | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/conans/test/unittests/model/other_settings_test.py b/conans/test/unittests/model/other_settings_test.py index 8b055a5303c..7aaf90baf70 100644 --- a/conans/test/unittests/model/other_settings_test.py +++ b/conans/test/unittests/model/other_settings_test.py @@ -241,7 +241,7 @@ class SayConan(ConanFile): client.run("create . --build missing") self.assertIn('Generated conaninfo.txt', client.out) conan_info = self._get_conaninfo("say/0.1", client) - self.assertEqual(conan_info["settings"], {}) + self.assertEqual(conan_info.get("settings"), None) # Settings is {} content = """ @@ -259,4 +259,4 @@ class SayConan(ConanFile): conan_info = self._get_conaninfo("say/0.1", client) - self.assertEqual(conan_info["settings"], {}) + self.assertEqual(conan_info.get("settings"), None) diff --git a/conans/test/unittests/server/conf_test.py b/conans/test/unittests/server/conf_test.py index 4c0d9e3b900..27710ceaf2e 100644 --- a/conans/test/unittests/server/conf_test.py +++ b/conans/test/unittests/server/conf_test.py @@ -55,20 +55,18 @@ def test_unexpected_section(self): """ self.assertRaises(ConanException, ConfigParser, text, ["one", "two", "three"]) - conf = ConfigParser(text, ["one", "two", "three"], raise_unexpected_field=False) + conf = ConfigParser(text) self.assertEqual(conf.one, "text=value") self.assertEqual(conf.two, "other=var") self.assertEqual(conf.three, "var") self.assertEqual(conf.moon, "var=walker") - with self.assertRaisesRegex(ConanException, "Unrecognized field 'NOEXIST'"): - conf.NOEXIST # IF an old config file is readed but the section is in the list, just return it empty text = """ [one] text=value """ - conf = ConfigParser(text, ["one", "two", "three"], raise_unexpected_field=False) + conf = ConfigParser(text) self.assertEqual(conf.two, "") def test_values(self): diff --git a/conans/util/config_parser.py b/conans/util/config_parser.py index 2b24c474be1..75d4ad93a74 100644 --- a/conans/util/config_parser.py +++ b/conans/util/config_parser.py @@ -62,7 +62,6 @@ def __getattr__(self, name): if name in self._sections: return "\n".join(self._sections[name]) else: - if self._allowed_fields and name in self._allowed_fields: - return "" - else: + if self._allowed_fields and name not in self._allowed_fields: raise ConanException("ConfigParser: Unrecognized field '%s'" % name) + return ""