Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix relativize paths in Environment generated files #15592

Merged
merged 6 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions conan/tools/env/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from collections import OrderedDict
from contextlib import contextmanager

from conans.client.generators import relativize_generated_file
from conans.client.generators import relativize_paths
from conans.client.subsystems import deduce_subsystem, WINDOWS, subsystem_path
from conan.errors import ConanException
from conans.model.recipe_ref import ref_matches
Expand Down Expand Up @@ -135,12 +135,14 @@ def compose_env_value(self, other):
new_value[index:index + 1] = other._values # replace the placeholder
self._values = new_value

def get_str(self, placeholder, subsystem, pathsep):
def get_str(self, placeholder, subsystem, pathsep, root_path=None, script_path=None):
"""
:param subsystem:
:param placeholder: a OS dependant string pattern of the previous env-var value like
$PATH, %PATH%, et
:param pathsep: The path separator, typically ; or :
:param root_path: To do a relativize of paths, the base root path to be replaced
:param script_path: the replacement instead of the script path
:return: a string representation of the env-var value, including the $NAME-like placeholder
"""
values = []
Expand All @@ -151,6 +153,13 @@ def get_str(self, placeholder, subsystem, pathsep):
else:
if self._path:
v = subsystem_path(subsystem, v)
if root_path is not None:
if v.startswith(root_path): # relativize
v = v.replace(root_path, script_path, 1)
elif os.sep == "\\": # Just in case user specified C:/path/to/somewhere
r = root_path.replace("\\", "/")
if v.startswith(r):
v = v.replace(r, script_path.replace("\\", "/"))
values.append(v)
if self._path:
return pathsep.join(values)
Expand Down Expand Up @@ -329,7 +338,7 @@ class EnvVars:

"""
def __init__(self, conanfile, values, scope):
self._values = values # {var_name: _EnvValue}, just a reference to the Environment
self._values = values # {var_name: _EnvValue}, just a reference to the Environment
self._conanfile = conanfile
self._scope = scope
self._subsystem = deduce_subsystem(conanfile, scope)
Expand Down Expand Up @@ -418,12 +427,13 @@ def save_bat(self, file_location, generate_deactivate=True):
{deactivate}
""").format(deactivate=deactivate if generate_deactivate else "")
result = [capture]
abs_base_path, new_path = relativize_paths(self._conanfile, "%~dp0")
for varname, varvalues in self._values.items():
value = varvalues.get_str("%{name}%", subsystem=self._subsystem, pathsep=self._pathsep)
value = varvalues.get_str("%{name}%", subsystem=self._subsystem, pathsep=self._pathsep,
root_path=abs_base_path, script_path=new_path)
result.append('set "{}={}"'.format(varname, value))

content = "\n".join(result)
content = relativize_generated_file(content, self._conanfile, "%~dp0")
# It is very important to save it correctly with utf-8, the Conan util save() is broken
os.makedirs(os.path.dirname(os.path.abspath(file_location)), exist_ok=True)
open(file_location, "w", encoding="utf-8").write(content)
Expand Down Expand Up @@ -459,24 +469,25 @@ def save_ps1(self, file_location, generate_deactivate=True,):
{deactivate}
""").format(deactivate=deactivate if generate_deactivate else "")
result = [capture]
abs_base_path, new_path = relativize_paths(self._conanfile, "$PSScriptRoot")
for varname, varvalues in self._values.items():
value = varvalues.get_str("$env:{name}", subsystem=self._subsystem, pathsep=self._pathsep)
value = varvalues.get_str("$env:{name}", subsystem=self._subsystem, pathsep=self._pathsep,
root_path=abs_base_path, script_path=new_path)
if value:
value = value.replace('"', '`"') # escape quotes
result.append('$env:{}="{}"'.format(varname, value))
else:
result.append('if (Test-Path env:{0}) {{ Remove-Item env:{0} }}'.format(varname))

content = "\n".join(result)
content = relativize_generated_file(content, self._conanfile, "$PSScriptRoot")
# It is very important to save it correctly with utf-16, the Conan util save() is broken
# and powershell uses utf-16 files!!!
os.makedirs(os.path.dirname(os.path.abspath(file_location)), exist_ok=True)
open(file_location, "w", encoding="utf-16").write(content)

def save_sh(self, file_location, generate_deactivate=True):
filepath, filename = os.path.split(file_location)
deactivate_file = os.path.join(filepath, "deactivate_{}".format(filename))
deactivate_file = os.path.join("$script_folder", "deactivate_{}".format(filename))
deactivate = textwrap.dedent("""\
echo "echo Restoring environment" > "{deactivate_file}"
for v in {vars}
Expand All @@ -495,16 +506,17 @@ def save_sh(self, file_location, generate_deactivate=True):
{deactivate}
""").format(deactivate=deactivate if generate_deactivate else "")
result = [capture]
abs_base_path, new_path = relativize_paths(self._conanfile, "$script_folder")
for varname, varvalues in self._values.items():
value = varvalues.get_str("${name}", self._subsystem, pathsep=self._pathsep)
value = varvalues.get_str("${name}", self._subsystem, pathsep=self._pathsep,
root_path=abs_base_path, script_path=new_path)
value = value.replace('"', '\\"')
if value:
result.append('export {}="{}"'.format(varname, value))
else:
result.append('unset {}'.format(varname))

content = "\n".join(result)
content = relativize_generated_file(content, self._conanfile, "$script_folder")
content = f'script_folder="{os.path.abspath(filepath)}"\n' + content
save(file_location, content)

Expand Down
15 changes: 11 additions & 4 deletions conans/client/generators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,21 @@ def ps1_content(files):


def relativize_generated_file(content, conanfile, placeholder):
abs_base_path, new_path = relativize_paths(conanfile, placeholder)
if abs_base_path is None:
return content
content = content.replace(abs_base_path, new_path)
content = content.replace(abs_base_path.replace("\\", "/"), new_path.replace("\\", "/"))
return content


def relativize_paths(conanfile, placeholder):
abs_base_path = conanfile.folders._base_generators
if not abs_base_path or not os.path.isabs(abs_base_path):
return content
return None, None
abs_base_path = os.path.join(abs_base_path, "") # For the trailing / to dissambiguate matches
generators_folder = conanfile.generators_folder
rel_path = os.path.relpath(abs_base_path, generators_folder)
new_path = placeholder if rel_path == "." else os.path.join(placeholder, rel_path)
new_path = os.path.join(new_path, "") # For the trailing / to dissambiguate matches
content = content.replace(abs_base_path, new_path)
content = content.replace(abs_base_path.replace("\\", "/"), new_path.replace("\\", "/"))
return content
return abs_base_path, new_path
11 changes: 11 additions & 0 deletions conans/test/integration/environment/test_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -841,3 +841,14 @@ def test(self):
c.run("create tool --build-require -s:b build_type=Release -s:h build_type=Debug")
assert "tool/0.1 (test package): Building TEST_PACKAGE IN Debug!!" in c.out
assert "MYLIBVAR=MYLIBVALUE:Release" in c.out


def test_deactivate_relocatable_substitute():
c = TestClient()
# this cannot be tested in CI, because permissions over root folder
# c.current_folder = "/build"
c.save({"conanfile.py": GenConanfile("pkg", "0.1")})
c.run("install . -s os=Linux -s:b os=Linux")
conanbuild = c.load("conanbuildenv.sh")
result = os.path.join("$script_folder", "deactivate_conanbuildenv.sh")
assert f'"{result}"' in conanbuild