Skip to content

Commit 899a74d

Browse files
authored
Define syntax for env-vars custom separators in profile files (#17781)
* force cygpath for path variables * wip * wip * comment
1 parent 9eb72c8 commit 899a74d

File tree

3 files changed

+83
-3
lines changed

3 files changed

+83
-3
lines changed

conan/tools/env/environment.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -84,18 +84,19 @@ def __init__(self, name, value=None, separator=" ", path=False):
8484
def dumps(self):
8585
result = []
8686
path = "(path)" if self._path else ""
87+
sep = f"(sep={self._sep})" if self._sep != " " and not self._path else ""
8788
if not self._values: # Empty means unset
8889
result.append("{}=!".format(self._name))
8990
elif _EnvVarPlaceHolder in self._values:
9091
index = self._values.index(_EnvVarPlaceHolder)
9192
for v in self._values[:index]:
92-
result.append("{}=+{}{}".format(self._name, path, v))
93+
result.append("{}=+{}{}{}".format(self._name, path, sep, v))
9394
for v in self._values[index+1:]:
94-
result.append("{}+={}{}".format(self._name, path, v))
95+
result.append("{}+={}{}{}".format(self._name, path, sep, v))
9596
else:
9697
append = ""
9798
for v in self._values:
98-
result.append("{}{}={}{}".format(self._name, append, path, v))
99+
result.append("{}{}={}{}{}".format(self._name, append, path, sep, v))
99100
append = "+"
100101
return "\n".join(result)
101102

@@ -644,6 +645,14 @@ def loads(text):
644645
env = Environment()
645646
if method == "unset":
646647
env.unset(name)
648+
elif value.strip().startswith("(sep="):
649+
value = value.strip()
650+
sep = value[5]
651+
value = value[7:]
652+
if value.strip().startswith("(path)"):
653+
msg = f"Cannot use (sep) and (path) qualifiers simultaneously: {line}"
654+
raise ConanException(msg)
655+
getattr(env, method)(name, value, separator=sep)
647656
else:
648657
if value.strip().startswith("(path)"):
649658
value = value.strip()

test/functional/subsystems_build_test.py

+47
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def test_tool_not_available(self):
8383
client.run_command('uname', assert_error=True)
8484
assert "'uname' is not recognized as an internal or external command" in client.out
8585

86+
8687
@pytest.mark.skipif(platform.system() != "Windows", reason="Tests Windows Subsystems")
8788
class TestSubsystemsBuild:
8889

@@ -512,3 +513,49 @@ def test_vs_clang(self):
512513
self._build(client, generator="Visual Studio 17 2022", toolset="ClangCL")
513514
check_exe_run(client.out, "main", "clang", None, "Debug", "x86_64", None, subsystem=None)
514515
check_vs_runtime("Debug/app.exe", client, "15", "Debug", subsystem=None)
516+
517+
518+
@pytest.mark.tool("msys2")
519+
def test_msys2_env_vars_paths():
520+
c = TestClient()
521+
# A tool-requires injecting PATHs for native, should not use "_path" calls, and use
522+
# 'separator=;' explicitly
523+
tool = textwrap.dedent("""
524+
from conan import ConanFile
525+
class HelloConan(ConanFile):
526+
name = "tool"
527+
version = "0.1"
528+
def package_info(self):
529+
self.buildenv_info.append("INCLUDE", "C:/mytool/path", separator=";")
530+
""")
531+
conanfile = textwrap.dedent("""
532+
from conan import ConanFile
533+
class HelloConan(ConanFile):
534+
win_bash = True
535+
tool_requires = "tool/0.1"
536+
537+
def build(self):
538+
self.run('echo "INCLUDE=$INCLUDE"')
539+
""")
540+
profile = textwrap.dedent("""
541+
[conf]
542+
tools.microsoft.bash:subsystem=msys2
543+
tools.microsoft.bash:path=bash
544+
545+
[buildenv]
546+
INCLUDE=+(sep=;)C:/prepended/path
547+
INCLUDE+=(sep=;)C:/appended/path
548+
""")
549+
c.save({"tool/conanfile.py": tool,
550+
"consumer/conanfile.py": conanfile,
551+
"profile": profile})
552+
c.run("create tool")
553+
with environment_update({"INCLUDE": "C:/my/abs path/folder;C:/other path/subfolder"}):
554+
c.run("build consumer -pr=profile")
555+
556+
# Check the profile is outputed correctly
557+
assert "INCLUDE=+(sep=;)C:/prepended/path" in c.out
558+
assert "INCLUDE+=(sep=;)C:/appended/path" in c.out
559+
# check the composition is correct
560+
assert "INCLUDE=C:/prepended/path;C:/my/abs path/folder;C:/other path/subfolder;" \
561+
"C:/mytool/path;C:/appended/path" in c.out

test/unittests/tools/env/test_env.py

+24
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import pytest
77

8+
from conan.errors import ConanException
89
from conan.tools.env import Environment
910
from conan.tools.env.environment import ProfileEnvironment
1011
from conans.client.subsystems import WINDOWS
@@ -426,3 +427,26 @@ def test_custom_placeholder():
426427
f"$penv{{MyVar}}:MyValue"
427428
items = {k: v for k, v in env.items(variable_reference="$penv{{{name}}}")}
428429
assert items == {"MyVar": f"$penv{{MyVar}}:MyValue"}
430+
431+
432+
class TestProfileSeparators:
433+
434+
def test_define(self):
435+
myprofile = "MyPath1 = (sep=@)/my/path1"
436+
env = ProfileEnvironment.loads(myprofile).get_profile_env(ref="")
437+
assert env.dumps() == "MyPath1=(sep=@)/my/path1"
438+
env.append("MyPath1", "/other/value")
439+
assert env.vars(ConanFileMock()).get("MyPath1") == "/my/path1@/other/value"
440+
441+
def test_append(self):
442+
myprofile = "MyPath1 +=(sep=@)/my/path1"
443+
env = ProfileEnvironment.loads(myprofile).get_profile_env(ref="")
444+
assert env.dumps() == "MyPath1+=(sep=@)/my/path1"
445+
env.append("MyPath1", "/other/value")
446+
assert env.vars(ConanFileMock()).get("MyPath1") == "/my/path1@/other/value"
447+
448+
def test_error(self):
449+
myprofile = "MyPath1 = (sep=@) (path)/my/path1"
450+
with pytest.raises(ConanException) as e:
451+
ProfileEnvironment.loads(myprofile)
452+
assert "Cannot use (sep) and (path) qualifiers simultaneously" in str(e.value)

0 commit comments

Comments
 (0)