From 4a52dac2ab5c03c02cc5c9e11c68b7ea91696140 Mon Sep 17 00:00:00 2001 From: Benjamin Aurich Date: Tue, 26 Mar 2024 14:06:09 +0100 Subject: [PATCH] Allow custom separators for append and prepend from profile --- conan/tools/env/environment.py | 48 +++++++++++++++------ conans/test/unittests/tools/env/test_env.py | 47 ++++++++++++++++---- 2 files changed, 73 insertions(+), 22 deletions(-) diff --git a/conan/tools/env/environment.py b/conan/tools/env/environment.py index ca5d98685fe..3bc94ddc016 100644 --- a/conan/tools/env/environment.py +++ b/conan/tools/env/environment.py @@ -1,5 +1,6 @@ import os import textwrap +import re from collections import OrderedDict from contextlib import contextmanager @@ -81,19 +82,20 @@ def __init__(self, name, value=None, separator=" ", path=False): def dumps(self): result = [] path = "(path)" if self._path else "" + custom_sep = "" if self._sep == " " else "(sep={})".format(self._sep) if not self._values: # Empty means unset result.append("{}=!".format(self._name)) elif _EnvVarPlaceHolder in self._values: index = self._values.index(_EnvVarPlaceHolder) for v in self._values[:index]: - result.append("{}=+{}{}".format(self._name, path, v)) + result.append("{}=+{}{}{}".format(self._name, custom_sep, path, v)) for v in self._values[index+1:]: - result.append("{}+={}{}".format(self._name, path, v)) + result.append("{}+={}{}{}".format(self._name, custom_sep, path, v)) else: append = "" for v in self._values: result.append("{}{}={}{}".format(self._name, append, path, v)) - append = "+" + append = "+{}".format(custom_sep) return "\n".join(result) def copy(self): @@ -604,16 +606,38 @@ def dumps(self): @staticmethod def loads(text): result = ProfileEnvironment() + + operator_pattern_method_mapping = ( + (r"\+=([\s]*)\(sep=([^\)]+)\)", "append"), + (r"=\+([\s]*)\(sep=([^\)]+)\)", "prepend"), + ("+=", "append"), + ("=+", "prepend"), + ("=!", "unset"), + ("=", "define"), + ) + for line in text.splitlines(): line = line.strip() if not line or line.startswith("#"): continue - for op, method in (("+=", "append"), ("=+", "prepend"), - ("=!", "unset"), ("=", "define")): - tokens = line.split(op, 1) - if len(tokens) != 2: - continue - pattern_name, value = tokens + for (op, method) in operator_pattern_method_mapping: + if "sep=" in op: + tokens = re.split(op, line) + if len(tokens) != 4: + continue + pattern_name, _, separator, value = tokens + keyword_args = {"separator": separator} + else: + tokens = line.split(op, 1) + if len(tokens) != 2: + continue + pattern_name, value = tokens + keyword_args = {} + if value.strip().startswith("(path)"): + value = value.strip() + value = value[6:] + method = method + "_path" + pattern_name = pattern_name.split(":", 1) if len(pattern_name) == 2: pattern, name = pattern_name @@ -629,11 +653,7 @@ def loads(text): if method == "unset": env.unset(name) else: - if value.strip().startswith("(path)"): - value = value.strip() - value = value[6:] - method = method + "_path" - getattr(env, method)(name, value) + getattr(env, method)(name, value, **keyword_args) existing = result._environments.get(pattern) if existing is None: diff --git a/conans/test/unittests/tools/env/test_env.py b/conans/test/unittests/tools/env/test_env.py index 37f9fd0205e..aee4de90bc5 100644 --- a/conans/test/unittests/tools/env/test_env.py +++ b/conans/test/unittests/tools/env/test_env.py @@ -155,6 +155,11 @@ def test_profile(): # unset MyPath4=! + # Custom append/prepend + MyCustomList=is;+something + MyCustomList=+(sep=;+)this + MyCustomList+=(sep=;+)weird + # PER-PACKAGE mypkg*:MyVar2=MyValue2 """) @@ -171,6 +176,7 @@ def test_profile(): assert env.get("MyVar3", "$MyVar3") == 'MyValue3 $MyVar3' assert env.get("MyVar4") == "" assert env.get("MyVar5") == '' + assert env.get("MyCustomList") == 'this;+is;+something;+weird' env = profile_env.get_profile_env(RecipeReference.loads("mypkg1/1.0")) env = env.vars(ConanFileMock()) @@ -356,29 +362,46 @@ def test_define(self): def test_append(self): myprofile = textwrap.dedent(""" # define - MyVar1+=MyValue1 - MyPath1 +=(path)/my/path1 + MyVar+=MyValue1 + MyVar+=MyValue2 + MyPath+=(path)/my/path1 + MyPath += (path)/my/path2 + MyList+=(sep=;)item1 + MyList += (sep=;)item2 """) env = ProfileEnvironment.loads(myprofile) text = env.dumps() assert text == textwrap.dedent("""\ - MyVar1+=MyValue1 - MyPath1+=(path)/my/path1 + MyVar+=MyValue1 + MyVar+=MyValue2 + MyPath+=(path)/my/path1 + MyPath+=(path)/my/path2 + MyList+=(sep=;)item1 + MyList+=(sep=;)item2 """) def test_prepend(self): myprofile = textwrap.dedent(""" # define - MyVar1=+MyValue1 - MyPath1=+(path)/my/path1 + MyVar=+MyValue1 + MyVar=+MyValue2 + MyPath =+ (path)/my/path1 + MyPath=+(path)/my/path2 + MyList =+ (sep=++)item1 + MyList=+(sep=++)item2 """) env = ProfileEnvironment.loads(myprofile) text = env.dumps() + # XXX: This seems wrong? assert text == textwrap.dedent("""\ - MyVar1=+MyValue1 - MyPath1=+(path)/my/path1 + MyVar=+MyValue2 + MyVar=+MyValue1 + MyPath=+(path)/my/path2 + MyPath=+(path)/my/path1 + MyList=+(sep=++)item2 + MyList=+(sep=++)item1 """) def test_combined(self): @@ -387,6 +410,8 @@ def test_combined(self): MyVar1+=MyValue12 MyPath1=+(path)/my/path11 MyPath1+=(path)/my/path12 + MyList1=+(sep=;)item11 + MyList1+=(sep=;)item12 """) env = ProfileEnvironment.loads(myprofile) @@ -396,6 +421,8 @@ def test_combined(self): MyVar1+=MyValue12 MyPath1=+(path)/my/path11 MyPath1+=(path)/my/path12 + MyList1=+(sep=;)item11 + MyList1+=(sep=;)item12 """) def test_combined2(self): @@ -404,6 +431,8 @@ def test_combined2(self): MyVar1=+MyValue12 MyPath1+=(path)/my/path11 MyPath1=+(path)/my/path12 + MyList1+=(sep=;)item11 + MyList1=+(sep=;)item12 """) env = ProfileEnvironment.loads(myprofile) @@ -414,6 +443,8 @@ def test_combined2(self): MyVar1+=MyValue11 MyPath1=+(path)/my/path12 MyPath1+=(path)/my/path11 + MyList1=+(sep=;)item12 + MyList1+=(sep=;)item11 """)