Repository: conan-io/conan
Pull request #12876 (2023-01-10 13:07:33)

fix remove_broken_symlinks
Changelog: Bugfix: Fix ``remove_broken_symlinks`` failing at relative paths symlinks
Docs: Omit

Fix https://github.com/conan-io/conan/issues/12629


Patch:
diff --git a/conan/tools/cmake/presets.py b/conan/tools/cmake/presets.py
index 306b811d3..11a443a62 100644
--- a/conan/tools/cmake/presets.py
+++ b/conan/tools/cmake/presets.py
@@ -117,7 +117,7 @@ def _configure_preset(conanfile, generator, cache_variables, toolchain_file, mul
 
 
 def _insert_preset(data, preset_name, preset):
-    position = _get_already_existing_preset_index(preset["name"], data[preset_name])
+    position = _get_already_existing_preset_index(preset["name"], data.setdefault(preset_name, []))
     if position is not None:
         data[preset_name][position] = preset
     else:
diff --git a/conan/tools/files/symlinks/symlinks.py b/conan/tools/files/symlinks/symlinks.py
index 98c4b2040..7700e8713 100644
--- a/conan/tools/files/symlinks/symlinks.py
+++ b/conan/tools/files/symlinks/symlinks.py
@@ -37,7 +37,7 @@ def remove_external_symlinks(conanfile, base_folder=None):
     for fullpath in get_symlinks(base_folder):
         link_target = os.readlink(fullpath)
         if not os.path.isabs(link_target):
-            link_target = os.path.join(base_folder, link_target)
+            link_target = os.path.join(os.path.dirname(fullpath), link_target)
         if not _path_inside(base_folder, link_target):
             os.unlink(fullpath)
 
@@ -47,6 +47,6 @@ def remove_broken_symlinks(conanfile, base_folder=None):
     for fullpath in get_symlinks(base_folder):
         link_target = os.readlink(fullpath)
         if not os.path.isabs(link_target):
-            link_target = os.path.join(base_folder, link_target)
+            link_target = os.path.join(os.path.dirname(fullpath), link_target)
         if not os.path.exists(link_target):
             os.unlink(fullpath)


Test patch:
diff --git a/conans/test/functional/command/test_command_test.py b/conans/test/functional/command/test_command_test.py
index 970e50aaf..c34fddfff 100644
--- a/conans/test/functional/command/test_command_test.py
+++ b/conans/test/functional/command/test_command_test.py
@@ -1,4 +1,5 @@
 import os
+import platform
 import time
 import unittest
 
@@ -26,5 +27,6 @@ class ConanTestTest(unittest.TestCase):
         client.run("test test_package hello/0.1@lasote/stable -s hello:build_type=Debug "
                    "--build missing")
         self.assertIn('hello/0.1: Hello World Debug!', client.out)
+        subfolder = "Release" if platform.system() != "Windows" else ""
         assert os.path.exists(os.path.join(client.current_folder, "test_package",
-                                           "build", "generators", "conaninfo.txt"))
+                                           "build", subfolder, "generators", "conaninfo.txt"))
diff --git a/conans/test/unittests/tools/files/test_symlinks.py b/conans/test/unittests/tools/files/test_symlinks.py
index 83433228a..3a2fd174f 100644
--- a/conans/test/unittests/tools/files/test_symlinks.py
+++ b/conans/test/unittests/tools/files/test_symlinks.py
@@ -17,7 +17,7 @@ def folders():
         (os.path.join(tmp, "foo/var/file.txt"), "foo/var/other/absolute.txt"),  # Absolute link
         (os.path.join(tmp, "foo/var"), "foo/var/other/other/myfolder"),  # Absolute link folder
         (os.path.join(tmp, "foo/var/file.txt"), "foo/absolute.txt"),  # Absolute link
-        ("foo/var/file.txt", "foo/var/other/relative.txt"),  # Relative link
+        ("../file.txt", "foo/var/other/relative.txt"),  # Relative link
         ("missing.txt", "foo/var/other/broken.txt"),  # Broken link
         (outside_folder, "foo/var/other/absolute_outside"),  # Absolute folder outside the folder
         ("../../../../../outside", "foo/absolute_outside"),  # Relative folder outside the folder
@@ -54,7 +54,7 @@ def test_absolute_to_relative_symlinks(folders):
     assert linked_to == "var/file.txt"
 
     linked_to = os.readlink(os.path.join(folder, "foo/var/other/relative.txt")).replace("\\", "/")
-    assert linked_to == "foo/var/file.txt"
+    assert linked_to == "../file.txt"
 
     linked_to = os.readlink(os.path.join(folder, "foo/var/other/broken.txt"))
     assert linked_to == "missing.txt"
@@ -81,7 +81,7 @@ def test_remove_external_symlinks(folders):
     assert linked_to == os.path.join(folder, "foo/var/file.txt")
 
     linked_to = os.readlink(os.path.join(folder, "foo/var/other/relative.txt"))
-    assert linked_to == "foo/var/file.txt"
+    assert linked_to == "../file.txt"
 
     linked_to = os.readlink(os.path.join(folder, "foo/var/other/broken.txt"))
     assert linked_to == "missing.txt"
@@ -112,7 +112,7 @@ def test_remove_broken_symlinks(folders):
     assert linked_to == os.path.join(folder, "foo/var/file.txt")
 
     linked_to = os.readlink(os.path.join(folder, "foo/var/other/relative.txt"))
-    assert linked_to == "foo/var/file.txt"
+    assert linked_to == "../file.txt"
 
     # This one is removed
     assert not os.path.islink(os.path.join(folder, "foo/var/other/broken.txt"))