From d0a57d8fffcb8286c5f4eb220a9590b55002f8b5 Mon Sep 17 00:00:00 2001
From: adrianciu <adrianciu25@gmail.com>
Date: Thu, 6 Feb 2025 10:10:33 +0200
Subject: [PATCH] esd-spack-installation: additional methods

---
 .gitlab-ci.yml                             |  1 +
 dedal/tests/spack_from_scratch_test.py     | 83 +++++++++++++++++-----
 esd/error_handling/exceptions.py           |  9 ++-
 esd/spack_manager/SpackManager.py          | 51 +++++++++----
 esd/spack_manager/wrapper/__init__.py      |  0
 esd/spack_manager/wrapper/spack_wrapper.py | 15 ++++
 6 files changed, 124 insertions(+), 35 deletions(-)
 create mode 100644 esd/spack_manager/wrapper/__init__.py
 create mode 100644 esd/spack_manager/wrapper/spack_wrapper.py

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4f15b9ab..bd5669bd 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -6,6 +6,7 @@ variables:
   BUILD_ENV_DOCKER_IMAGE: docker-registry.ebrains.eu/esd/tmp:latest
 
 
+
 build-wheel:
   stage: build
   tags:
diff --git a/dedal/tests/spack_from_scratch_test.py b/dedal/tests/spack_from_scratch_test.py
index d1aca83c..2131e7df 100644
--- a/dedal/tests/spack_from_scratch_test.py
+++ b/dedal/tests/spack_from_scratch_test.py
@@ -1,14 +1,13 @@
+import os
 from pathlib import Path
-
 import pytest
-
 from esd.error_handling.exceptions import BashCommandException, NoSpackEnvironmentException
 from esd.model.SpackModel import SpackModel
 from esd.spack_manager.enums.SpackManagerEnum import SpackManagerEnum
 from esd.spack_manager.factory.SpackManagerCreator import SpackManagerCreator
-from esd.spack_manager.factory.SpackManagerScratch import SpackManagerScratch
 from esd.utils.utils import file_exists_and_not_empty
 
+SPACK_ENV_ACCESS_TOKEN = os.getenv("SPACK_ENV_ACCESS_TOKEN")
 
 def test_spack_repo_exists_1():
     spack_manager = SpackManagerCreator.get_spack_manger(SpackManagerEnum.FROM_SCRATCH)
@@ -34,9 +33,9 @@ def test_spack_repo_exists_3(tmp_path):
 def test_spack_from_scratch_setup_1(tmp_path):
     install_dir = tmp_path
     env = SpackModel('ebrains-spack-builds', install_dir,
-                     'https://gitlab.ebrains.eu/ri/tech-hub/platform/esd/ebrains-spack-builds.git', )
+                     'https://gitlab.ebrains.eu/ri/tech-hub/platform/esd/ebrains-spack-builds.git')
     spack_manager = SpackManagerCreator.get_spack_manger(SpackManagerEnum.FROM_SCRATCH, env=env,
-                                                                              system_name='ebrainslab')
+                                                         system_name='ebrainslab')
     spack_manager.setup_spack_env()
     assert spack_manager.spack_repo_exists(env.env_name) == False
 
@@ -44,11 +43,11 @@ def test_spack_from_scratch_setup_1(tmp_path):
 def test_spack_from_scratch_setup_2(tmp_path):
     install_dir = tmp_path
     env = SpackModel('ebrains-spack-builds', install_dir,
-                     'https://gitlab.ebrains.eu/ri/tech-hub/platform/esd/ebrains-spack-builds.git', )
+                     'https://gitlab.ebrains.eu/ri/tech-hub/platform/esd/ebrains-spack-builds.git')
     repo = env
     spack_manager = SpackManagerCreator.get_spack_manger(SpackManagerEnum.FROM_SCRATCH, env=env,
-                                                                              repos=[repo, repo],
-                                                                              system_name='ebrainslab')
+                                                         repos=[repo, repo],
+                                                         system_name='ebrainslab')
     spack_manager.setup_spack_env()
     assert spack_manager.spack_repo_exists(env.env_name) == True
 
@@ -58,8 +57,8 @@ def test_spack_from_scratch_setup_3(tmp_path):
     env = SpackModel('new_env1', install_dir)
     repo = env
     spack_manager = SpackManagerCreator.get_spack_manger(SpackManagerEnum.FROM_SCRATCH, env=env,
-                                                                              repos=[repo, repo],
-                                                                              system_name='ebrainslab')
+                                                         repos=[repo, repo],
+                                                         system_name='ebrainslab')
     with pytest.raises(BashCommandException):
         spack_manager.setup_spack_env()
 
@@ -76,8 +75,8 @@ def test_spack_not_a_valid_repo():
     env = SpackModel('ebrains-spack-builds', Path(), None)
     repo = env
     spack_manager = SpackManagerCreator.get_spack_manger(SpackManagerEnum.FROM_SCRATCH, env=env,
-                                                                              repos=[repo],
-                                                                              system_name='ebrainslab')
+                                                         repos=[repo],
+                                                         system_name='ebrainslab')
     with pytest.raises(NoSpackEnvironmentException):
         spack_manager.add_spack_repo(repo.path, repo.env_name)
 
@@ -85,7 +84,7 @@ def test_spack_not_a_valid_repo():
 def test_spack_from_scratch_concretize_1(tmp_path):
     install_dir = tmp_path
     env = SpackModel('ebrains-spack-builds', install_dir,
-                     'https://gitlab.ebrains.eu/ri/tech-hub/platform/esd/ebrains-spack-builds.git', )
+                     'https://gitlab.ebrains.eu/ri/tech-hub/platform/esd/ebrains-spack-builds.git')
     repo = env
     spack_manager = SpackManagerCreator.get_spack_manger(SpackManagerEnum.FROM_SCRATCH, env=env, repos=[repo, repo],
                                                          system_name='ebrainslab')
@@ -98,7 +97,7 @@ def test_spack_from_scratch_concretize_1(tmp_path):
 def test_spack_from_scratch_concretize_2(tmp_path):
     install_dir = tmp_path
     env = SpackModel('ebrains-spack-builds', install_dir,
-                     'https://gitlab.ebrains.eu/ri/tech-hub/platform/esd/ebrains-spack-builds.git', )
+                     'https://gitlab.ebrains.eu/ri/tech-hub/platform/esd/ebrains-spack-builds.git')
     repo = env
     spack_manager = SpackManagerCreator.get_spack_manger(SpackManagerEnum.FROM_SCRATCH, env=env, repos=[repo, repo],
                                                          system_name='ebrainslab')
@@ -111,11 +110,59 @@ def test_spack_from_scratch_concretize_2(tmp_path):
 def test_spack_from_scratch_concretize_3(tmp_path):
     install_dir = tmp_path
     env = SpackModel('ebrains-spack-builds', install_dir,
-                     'https://gitlab.ebrains.eu/ri/tech-hub/platform/esd/ebrains-spack-builds.git', )
+                     'https://gitlab.ebrains.eu/ri/tech-hub/platform/esd/ebrains-spack-builds.git')
     repo = env
-    spack_manager  = SpackManagerCreator.get_spack_manger(SpackManagerEnum.FROM_SCRATCH, env=env,
-                                                                              repos=[repo, repo],
-                                                                              system_name='ebrainslab')
+    spack_manager = SpackManagerCreator.get_spack_manger(SpackManagerEnum.FROM_SCRATCH, env=env,
+                                                         repos=[repo, repo],
+                                                         system_name='ebrainslab')
     spack_manager.setup_spack_env()
     concretization_file_path = spack_manager.env_path / 'spack.lock'
     assert file_exists_and_not_empty(concretization_file_path) == False
+
+
+def test_spack_from_scratch_concretize_4(tmp_path):
+    install_dir = tmp_path
+    env = SpackModel('test-spack-env', install_dir,
+                     f'https://oauth2:{SPACK_ENV_ACCESS_TOKEN}@gitlab.ebrains.eu/ri/projects-and-initiatives/virtualbraintwin/test-spack-env.git')
+    spack_manager = SpackManagerCreator.get_spack_manger(SpackManagerEnum.FROM_SCRATCH, env=env)
+    spack_manager.setup_spack_env()
+    spack_manager.concretize_spack_env(force=False)
+    concretization_file_path = spack_manager.env_path / 'spack.lock'
+    assert file_exists_and_not_empty(concretization_file_path) == True
+
+
+def test_spack_from_scratch_concretize_5(tmp_path):
+    install_dir = tmp_path
+    env = SpackModel('test-spack-env', install_dir,
+                     f'https://oauth2:{SPACK_ENV_ACCESS_TOKEN}@gitlab.ebrains.eu/ri/projects-and-initiatives/virtualbraintwin/test-spack-env.git')
+    spack_manager = SpackManagerCreator.get_spack_manger(SpackManagerEnum.FROM_SCRATCH, env=env)
+    spack_manager.setup_spack_env()
+    spack_manager.concretize_spack_env(force=True)
+    concretization_file_path = spack_manager.env_path / 'spack.lock'
+    assert file_exists_and_not_empty(concretization_file_path) == True
+
+
+def test_spack_from_scratch_concretize_6(tmp_path):
+    install_dir = tmp_path
+    env = SpackModel('test-spack-env', install_dir,
+                     f'https://oauth2:{SPACK_ENV_ACCESS_TOKEN}@gitlab.ebrains.eu/ri/projects-and-initiatives/virtualbraintwin/test-spack-env.git')
+    repo = SpackModel('ebrains-spack-builds', install_dir,
+                      'https://gitlab.ebrains.eu/ri/tech-hub/platform/esd/ebrains-spack-builds.git')
+    spack_manager = SpackManagerCreator.get_spack_manger(SpackManagerEnum.FROM_SCRATCH, env=env, repos=[repo])
+    spack_manager.setup_spack_env()
+    spack_manager.concretize_spack_env(force=False)
+    concretization_file_path = spack_manager.env_path / 'spack.lock'
+    assert file_exists_and_not_empty(concretization_file_path) == True
+
+
+def test_spack_from_scratch_concretize_7(tmp_path):
+    install_dir = tmp_path
+    env = SpackModel('test-spack-env', install_dir,
+                     'https://gitlab.ebrains.eu/ri/projects-and-initiatives/virtualbraintwin/test-spack-env.git')
+    repo = SpackModel('ebrains-spack-builds', install_dir,
+                      'https://gitlab.ebrains.eu/ri/tech-hub/platform/esd/ebrains-spack-builds.git')
+    spack_manager = SpackManagerCreator.get_spack_manger(SpackManagerEnum.FROM_SCRATCH, env=env, repos=[repo])
+    spack_manager.setup_spack_env()
+    spack_manager.concretize_spack_env(force=True)
+    concretization_file_path = spack_manager.env_path / 'spack.lock'
+    assert file_exists_and_not_empty(concretization_file_path) == True
diff --git a/esd/error_handling/exceptions.py b/esd/error_handling/exceptions.py
index d6de666b..9d11b5fa 100644
--- a/esd/error_handling/exceptions.py
+++ b/esd/error_handling/exceptions.py
@@ -14,13 +14,18 @@ class BashCommandException(SpackException):
     """
 
 
-class NoSpackEnvironmentException(SpackException):
+class NoSpackEnvironmentException(BashCommandException):
     """
     To be thrown when an operation on a spack environment is executed without the environment being activated or existent
     """
 
 
-class SpackConcertizeException(SpackException):
+class SpackConcertizeException(BashCommandException):
     """
     To be thrown when the spack concretization step fails
     """
+
+class SpackInstallPackagesException(BashCommandException):
+    """
+    To be thrown when the spack fails to install spack packages
+    """
diff --git a/esd/spack_manager/SpackManager.py b/esd/spack_manager/SpackManager.py
index 340b1b95..a7f46c27 100644
--- a/esd/spack_manager/SpackManager.py
+++ b/esd/spack_manager/SpackManager.py
@@ -1,10 +1,13 @@
 import os
+import re
 from abc import ABC, abstractmethod
 from pathlib import Path
 
-from esd.error_handling.exceptions import BashCommandException, NoSpackEnvironmentException
+from esd.error_handling.exceptions import BashCommandException, NoSpackEnvironmentException, \
+    SpackInstallPackagesException
 from esd.logger.logger_builder import get_logger
 from esd.model.SpackModel import SpackModel
+from esd.spack_manager.wrapper.spack_wrapper import no_spack_env
 from esd.utils.utils import run_command, git_clone_repo
 
 
@@ -103,10 +106,10 @@ class SpackManager(ABC):
         else:
             if self.spack_env_exists():
                 result = run_command("bash", "-c",
-                                 f'source {self.spack_setup_script} && spack env activate -p {self.env_path} && spack repo list',
-                                 check=True,
-                                 capture_output=True, text=True, logger=self.logger,
-                                 debug_msg=f'Checking if repository {repo_name} was added')
+                                     f'source {self.spack_setup_script} && spack env activate -p {self.env_path} && spack repo list',
+                                     check=True,
+                                     capture_output=True, text=True, logger=self.logger,
+                                     debug_msg=f'Checking if repository {repo_name} was added')
             else:
                 self.logger.debug('No spack environment defined')
                 raise NoSpackEnvironmentException('No spack environment defined')
@@ -124,18 +127,35 @@ class SpackManager(ABC):
             return False
         return True
 
+    @no_spack_env
     def add_spack_repo(self, repo_path: Path, repo_name: str):
         """Add the Spack repository if it does not exist."""
-        if self.spack_env_exists():
-            run_command("bash", "-c",
-                        f'source {self.spack_setup_script} && spack env activate -p {self.env_path} && spack repo add {repo_path}/{repo_name}',
-                        check=True, logger=self.logger,
-                        debug_msg=f"Added {repo_name} to spack environment {self.env.env_name}",
-                        exception_msg=f"Failed to add {repo_name} to spack environment {self.env.env_name}",
-                        exception=BashCommandException)
-        else:
-            self.logger.debug('No spack environment defined')
-            raise NoSpackEnvironmentException('No spack environment defined')
+        run_command("bash", "-c",
+                    f'source {self.spack_setup_script} && spack env activate -p {self.env_path} && spack repo add {repo_path}/{repo_name}',
+                    check=True, logger=self.logger,
+                    debug_msg=f"Added {repo_name} to spack environment {self.env.env_name}",
+                    exception_msg=f"Failed to add {repo_name} to spack environment {self.env.env_name}",
+                    exception=BashCommandException)
+
+    @no_spack_env
+    def get_compiler_version(self):
+        result = run_command("bash", "-c",
+                             f'source {self.spack_setup_script} && spack env activate -p {self.env_path} && spack compiler list',
+                             check=True, logger=self.logger,
+                             capture_output=True, text=True,
+                             debug_msg=f"Checking spack environment compiler version for {self.env.env_name}",
+                             exception_msg=f"Failed to checking spack environment compiler version for {self.env.env_name}",
+                             exception=BashCommandException)
+        # todo add error handling and tests
+        if result.stdout is None:
+            self.logger.debug('No gcc found for {self.env.env_name}')
+            return None
+
+        # Find the first occurrence of a GCC compiler using regex
+        match = re.search(r"gcc@([\d\.]+)", result.stdout)
+        gcc_version = match.group(1)
+        self.logger.debug(f'Found gcc for {self.env.env_name}: {gcc_version}')
+        return gcc_version
 
     def get_spack_installed_version(self):
         spack_version = run_command("bash", "-c", f'source {self.spack_setup_script} && spack --version',
@@ -147,6 +167,7 @@ class SpackManager(ABC):
             return spack_version.stdout.strip().split()[0]
         return None
 
+
     def install_spack(self, spack_version="v0.21.1", spack_repo='https://github.com/spack/spack'):
         try:
             user = os.getlogin()
diff --git a/esd/spack_manager/wrapper/__init__.py b/esd/spack_manager/wrapper/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/esd/spack_manager/wrapper/spack_wrapper.py b/esd/spack_manager/wrapper/spack_wrapper.py
new file mode 100644
index 00000000..d075a317
--- /dev/null
+++ b/esd/spack_manager/wrapper/spack_wrapper.py
@@ -0,0 +1,15 @@
+import functools
+
+from esd.error_handling.exceptions import NoSpackEnvironmentException
+
+
+def no_spack_env(method):
+    @functools.wraps(method)
+    def wrapper(self, *args, **kwargs):
+        if self.spack_env_exists():
+            return method(self, *args, **kwargs)  # Call the method with 'self'
+        else:
+            self.logger.debug('No spack environment defined')
+            raise NoSpackEnvironmentException('No spack environment defined')
+
+    return wrapper
-- 
GitLab