From baa2a2902104915fdfbd43d06b0a6a65e7fed954 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Sun, 30 Aug 2026 11:24:42 +0200 Subject: [PATCH 1/2] Metadata: Obtain project URL from package metadata --- pyhope/common/common_vars.py | 37 +++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/pyhope/common/common_vars.py b/pyhope/common/common_vars.py index de0a1de..3e53537 100644 --- a/pyhope/common/common_vars.py +++ b/pyhope/common/common_vars.py @@ -75,6 +75,7 @@ def __init__(self: Self) -> None: self._program: Final[str] = self.__program__ self._version: Final = self.__version__ self._commit: Final = self.__commit__ + self._url: Final = self.__url__ @property def __version__(self) -> Version: @@ -118,6 +119,32 @@ def __commit__(self) -> Optional[str]: return commit + @property + def __url__(self) -> Optional[str]: + # Retrieve repository URL from package metadata + try: + package = pathlib.Path(__file__).parent.parent.name + meta = importlib.metadata.metadata(package) + urls = meta.get_all('Project-URL', []) + for entry in urls: + if ',' in entry: + key, url = entry.split(',', 1) + if key.strip().lower() == 'repository': + return url.strip().rstrip('/') + # Fallback to pyproject.toml + except importlib.metadata.PackageNotFoundError as e: + pyproject = pathlib.Path(__file__).parent.parent.parent / 'pyproject.toml' + if not pyproject.exists(): + raise FileNotFoundError(f'pyproject.toml not found at {pyproject}') from e + + with pyproject.open('r') as p: + match = re.search(r'repository\s*=\s*["\'](.+?)["\']', p.read()) + if not match: + raise ValueError('Version not found in pyproject.toml') from e # noqa: E272 + return match.group(1).rstrip('/') + + return None + @property def __program__(self) -> str: return 'PyHOPE' @@ -134,13 +161,17 @@ def version(self) -> str: def commit(self) -> str: return str(self._commit) + @property + def url(self) -> str: + return str(self._url) + @final class Gitlab: # Gitlab "python-gmsh" access - LIB_GITLAB: tuple[str] = ('gitlab.iag.uni-stuttgart.de', - 'piclas.boltzplatz.eu' , - ) + LIB_HOST: tuple[str] = ('gitlab.iag.uni-stuttgart.de', + 'piclas.boltzplatz.eu' , + ) # LIB_PROJECT = 'libs/python-gmsh' LIB_PROJECT: tuple[int] = (797, 26 , From abc900ff5119081cd9c8a5f389d0df5b216be0c9 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Sun, 30 Aug 2026 12:11:05 +0200 Subject: [PATCH 2/2] Gmsh: Use GitHub release assets --- .github/actions/setup/action.yml | 5 +- .gitlab-ci.yml | 6 +- pyhope/gmsh/gmsh_install.py | 130 ++++++++++++++++++++----------- 3 files changed, 93 insertions(+), 48 deletions(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 4b4bc20..f005943 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -98,7 +98,10 @@ runs: source .venv/bin/activate if [[ "${{ inputs.minimal }}" != "true" ]]; then - - uv pip install --no-cache-dir https://gitlab.iag.uni-stuttgart.de/libs/python-gmsh/-/raw/master/gmsh-${GMSH_VERSION}-py3-none-linux_x86_64.whl || uv pip install https://piclas.boltzplatz.eu/public-libs/python-gmsh/-/raw/master/gmsh-${GMSH_VERSION}-py3-none-linux_x86_64.whl + # Regression checks needs NRG Gmsh, pre-install it (try GitHub latest release asset first, then GitLab mirrors) + uv pip install --no-cache-dir https://github.com/hopr-framework/PyHOPE/releases/latest/download/gmsh-${GMSH_VERSION}-py3-none-linux_x86_64.whl || \ + uv pip install --no-cache-dir https://gitlab.iag.uni-stuttgart.de/libs/python-gmsh/-/raw/master/gmsh-${GMSH_VERSION}-py3-none-linux_x86_64.whl || \ + uv pip install --no-cache-dir https://piclas.boltzplatz.eu/public-libs/python-gmsh/-/raw/master/gmsh-${GMSH_VERSION}-py3-none-linux_x86_64.whl uv pip install --no-cache-dir -e . fi diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dd958d0..d105f5f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -94,8 +94,10 @@ image: registry.iag.uni-stuttgart.de/flexi/codes/pyhope/nrg-python:${PYTHON314_V # Setup Python virtual environment - uv venv .venv - source .venv/bin/activate - # Regression checks needs NRG Gmsh, pre-install it (try two different mirrors for downloading the .whl file) - - uv pip install --no-cache-dir https://gitlab.iag.uni-stuttgart.de/libs/python-gmsh/-/raw/master/gmsh-${GMSH_VERSION}-py3-none-linux_x86_64.whl || uv pip install https://piclas.boltzplatz.eu/public-libs/python-gmsh/-/raw/master/gmsh-${GMSH_VERSION}-py3-none-linux_x86_64.whl + # Regression checks needs NRG Gmsh, pre-install it (try GitHub latest release asset first, then GitLab mirrors) + - uv pip install --no-cache-dir https://github.com/hopr-framework/PyHOPE/releases/latest/download/gmsh-${GMSH_VERSION}-py3-none-linux_x86_64.whl || \ + uv pip install --no-cache-dir https://gitlab.iag.uni-stuttgart.de/libs/python-gmsh/-/raw/master/gmsh-${GMSH_VERSION}-py3-none-linux_x86_64.whl || \ + uv pip install --no-cache-dir https://piclas.boltzplatz.eu/public-libs/python-gmsh/-/raw/master/gmsh-${GMSH_VERSION}-py3-none-linux_x86_64.whl # Install all pre-requisites - uv pip install --no-cache-dir -e . # Install coverage diff --git a/pyhope/gmsh/gmsh_install.py b/pyhope/gmsh/gmsh_install.py index f593586..a0f959d 100644 --- a/pyhope/gmsh/gmsh_install.py +++ b/pyhope/gmsh/gmsh_install.py @@ -138,6 +138,7 @@ def PkgsInstallGmsh(system: str, arch: str, version: str) -> None: import tempfile import requests # Local imports ---------------------------------------- + from pyhope.common.common_vars import Common import pyhope.output.output as hopout from pyhope.common.common_vars import Gitlab from pyhope.common.common_progress import ProgressBar @@ -178,51 +179,90 @@ def PkgsInstallGmsh(system: str, arch: str, version: str) -> None: else: pkgs = os.path.join(path, lib) - # Try the hosts in order, we generally expect the first host to be up and up-to-date - for idGit, (gitURL, gitID) in enumerate(zip(Gitlab.LIB_GITLAB, Gitlab.LIB_PROJECT, strict=True)): - try: - subprocess.check_call(('ping', f'-c{noPing}', f'-w{toPing}', gitURL), - stdout = subprocess.DEVNULL, # noqa: E251 - stderr = subprocess.DEVNULL, # noqa: E251 - timeout = toPing) # noqa: E251 - except subprocess.CalledProcessError: # noqa: PERF203 - continue - - # Host is responding, attempt to get the file - # urllib.request.urlretrieve(url = f'https://{gitURL}/api/v4/projects/{Gitlab.LIB_PROJECT}/repository/files/{lib}/raw?lfs={lfs}', # noqa: E251 - # filename = pkgs # noqa: E251 - # ) - request = requests.get(f'https://{gitURL}/api/v4/projects/{gitID}/repository/files/{lib}/raw?lfs={lfs}', - stream=True) - size = int(request.headers['content-length']) - bar = ProgressBar(title = f'│ Downloading Gmsh [v{Gitlab.LIB_VERSION[system][arch]}] from {gitURL}', # noqa: E251 - value = int(size/1024), # noqa: E251 - threshold = 0) # noqa: E251 - - with open(pkgs, 'wb') as f: - for chunk in request.iter_content(chunk_size=1024*50): - if chunk: # filter out keep-alive new chunks - bar.step(int(len(chunk)/1024)) - f.write(chunk) - - bar.close() - - # Compare the hash - # > Initialize a new sha256 hash - sha256 = hashlib.sha256() - with open(pkgs, 'rb') as f: - # Read and update hash string value in blocks of 4K - for chunk in iter(lambda: f.read(4096), b""): - sha256.update(chunk) - - if sha256.hexdigest() == Gitlab.LIB_SUPPORT[system][arch]: - hopout.info('Hash matches, installing Gmsh wheel...') - break - - if idGit < len(Gitlab.LIB_GITLAB) - 1: - hopout.info('Hash mismatch, trying next mirror...') - - hopout.error('Hash mismatch, exiting...') + download_success = False + + # Try primary download from GitHub release assets first + common = Common() + github_url = f'{common.url}/releases/download/v{common.version}/{lib}' + try: + request = requests.get(github_url, stream=True, timeout=toPing) + if request.status_code == 200: + size = int(request.headers.get('content-length', 0)) + bar = ProgressBar(title = f'│ Downloading Gmsh [v{Gitlab.LIB_VERSION[system][arch]}] from GitHub', # noqa: E251 + value = int(size/1024), # noqa: E251 + threshold = 0) # noqa: E251 + + with open(pkgs, 'wb') as f: + for chunk in request.iter_content(chunk_size=1024*50): + if chunk: + bar.step(int(len(chunk)/1024)) + f.write(chunk) + + bar.close() + + sha256 = hashlib.sha256() + with open(pkgs, 'rb') as f: + for chunk in iter(lambda: f.read(4096), b""): + sha256.update(chunk) + + if sha256.hexdigest() == Gitlab.LIB_SUPPORT[system][arch]: + hopout.info('Hash matches, installing Gmsh wheel...') + download_success = True + else: + hopout.info('GitHub asset hash mismatch, falling back to GitLab...') + except Exception: + hopout.info('GitHub asset download failed, falling back to GitLab...') + + if not download_success: + # Try the fallback hosts in order, we generally expect the first host to be up and up-to-date + for idGit, (gitURL, gitID) in enumerate(zip(Gitlab.LIB_HOST, Gitlab.LIB_PROJECT, strict=True)): + try: + subprocess.check_call(('ping', f'-c{noPing}', f'-w{toPing}', gitURL), + stdout = subprocess.DEVNULL, # noqa: E251 + stderr = subprocess.DEVNULL, # noqa: E251 + timeout = toPing) # noqa: E251 + except subprocess.CalledProcessError: # noqa: PERF203 + continue + + # Host is responding, attempt to get the file + # urllib.request.urlretrieve(url = f'https://{gitURL}/api/v4/projects/{Gitlab.LIB_PROJECT}/repository/files/{lib}/raw?lfs={lfs}', # noqa: E251 + # filename = pkgs # noqa: E251 + # ) + request = requests.get(f'https://{gitURL}/api/v4/projects/{gitID}/repository/files/{lib}/raw?lfs={lfs}', + stream=True) + size = int(request.headers['content-length']) + bar = ProgressBar(title = f'│ Downloading Gmsh [v{Gitlab.LIB_VERSION[system][arch]}] from {gitURL}', # noqa: E251 + value = int(size/1024), # noqa: E251 + threshold = 0) # noqa: E251 + + with open(pkgs, 'wb') as f: + for chunk in request.iter_content(chunk_size=1024*50): + if chunk: # filter out keep-alive new chunks + bar.step(int(len(chunk)/1024)) + f.write(chunk) + + bar.close() + + # Compare the hash + # > Initialize a new sha256 hash + sha256 = hashlib.sha256() + with open(pkgs, 'rb') as f: + # Read and update hash string value in blocks of 4K + for chunk in iter(lambda: f.read(4096), b""): + sha256.update(chunk) + + if sha256.hexdigest() == Gitlab.LIB_SUPPORT[system][arch]: + hopout.info('Hash matches, installing Gmsh wheel...') + download_success = True + break + + if idGit < len(Gitlab.LIB_HOST) - 1: + hopout.info('Gitlab asset hash mismatch, trying next mirror...') + + hopout.warning('Gitlab asset hash mismatch, not updating Gmsh...') + + if not download_success: + return None # Remove the old version try: