From 98b498c671fe4cec0c3b1ecfc09fa959faa713bd Mon Sep 17 00:00:00 2001
From: Peter Josef Scheibel <scheibel1@llnl.gov>
Date: Tue, 26 Nov 2019 18:50:32 -0800
Subject: [PATCH] Mirrors: fix cosmetic symlink targets

The targets for the cosmetic paths in mirrrors were being calculated
incorrectly as of fb3a3ba: the symlinks used relative paths as targets,
and the relative path was computed relative to the wrong directory.
---
 lib/spack/spack/caches.py      |  3 ++-
 lib/spack/spack/test/mirror.py | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/lib/spack/spack/caches.py b/lib/spack/spack/caches.py
index 61a47eaa6e..ce2f8a6371 100644
--- a/lib/spack/spack/caches.py
+++ b/lib/spack/spack/caches.py
@@ -67,8 +67,9 @@ def symlink(self, mirror_ref):
         storage location."""
 
         cosmetic_path = os.path.join(self.root, mirror_ref.cosmetic_path)
+        storage_path = os.path.join(self.root, mirror_ref.storage_path)
         relative_dst = os.path.relpath(
-            mirror_ref.storage_path,
+            storage_path,
             start=os.path.dirname(cosmetic_path))
 
         if not os.path.exists(cosmetic_path):
diff --git a/lib/spack/spack/test/mirror.py b/lib/spack/spack/test/mirror.py
index 9068db7193..e1b31695e3 100644
--- a/lib/spack/spack/test/mirror.py
+++ b/lib/spack/spack/test/mirror.py
@@ -14,6 +14,8 @@
 from spack.stage import Stage
 from spack.util.executable import which
 
+from llnl.util.filesystem import resolve_link_target_relative_to_the_link
+
 pytestmark = pytest.mark.usefixtures('config', 'mutable_mock_packages')
 
 # paths in repos that shouldn't be in the mirror tarballs.
@@ -192,3 +194,33 @@ def successful_apply(*args, **kwargs):
             'abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234',
             'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd.gz'  # NOQA: ignore=E501
         ]) - files_cached_in_mirror)
+
+
+class MockFetcher(object):
+    """Mock fetcher object which implements the necessary functionality for
+       testing MirrorCache
+    """
+    @staticmethod
+    def archive(dst):
+        with open(dst, 'w'):
+            pass
+
+
+@pytest.mark.regression('14067')
+def test_mirror_cache_symlinks(tmpdir):
+    """Confirm that the cosmetic symlink created in the mirror cache (which may
+       be relative) targets the storage path correctly.
+    """
+    cosmetic_path = 'zlib/zlib-1.2.11.tar.gz'
+    global_path = '_source-cache/archive/c3/c3e5.tar.gz'
+    cache = spack.caches.MirrorCache(str(tmpdir))
+    reference = spack.mirror.MirrorReference(cosmetic_path, global_path)
+
+    cache.store(MockFetcher(), reference.storage_path)
+    cache.symlink(reference)
+
+    link_target = resolve_link_target_relative_to_the_link(
+        os.path.join(cache.root, reference.cosmetic_path))
+    assert os.path.exists(link_target)
+    assert (os.path.normpath(link_target) ==
+            os.path.join(cache.root, reference.storage_path))
-- 
GitLab