Skip to content

Commit 1c761ff

Browse files
authored
Download correct CmdStan tarball on non-x86 linux (#616)
* Resolve download URL for non-x86 linux OSes * Add doc * Typo fix * Refactor to avoid shell=True * Fix CI issue
1 parent e885cb0 commit 1c761ff

File tree

4 files changed

+57
-9
lines changed

4 files changed

+57
-9
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ jobs:
3939
strategy:
4040
matrix:
4141
os: [ubuntu-latest, macos-latest, windows-latest]
42-
python-version: [3.7, 3.8, 3.9, "3.10"]
42+
python-version: [3.7, 3.8, 3.9, "3.10.6"]
43+
# more specific version of 3.10 due to https://github.com/python/mypy/issues/13627
4344
env:
4445
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
4546
steps:

cmdstanpy/install_cmdstan.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
validate_dir,
4242
wrap_url_progress_hook,
4343
)
44+
from cmdstanpy.utils.cmdstan import get_download_url
4445

4546
from . import progress as progbar
4647

@@ -426,10 +427,7 @@ def install_version(
426427

427428
def is_version_available(version: str) -> bool:
428429
is_available = True
429-
url = (
430-
'https://github.com/stan-dev/cmdstan/releases/download/'
431-
'v{0}/cmdstan-{0}.tar.gz'.format(version)
432-
)
430+
url = get_download_url(version)
433431
for i in range(6):
434432
try:
435433
urllib.request.urlopen(url)
@@ -458,10 +456,7 @@ def retrieve_version(version: str, progress: bool = True) -> None:
458456
if version is None or version == '':
459457
raise ValueError('Argument "version" unspecified.')
460458
print('Downloading CmdStan version {}'.format(version))
461-
url = (
462-
'https://github.com/stan-dev/cmdstan/releases/download/'
463-
'v{0}/cmdstan-{0}.tar.gz'.format(version)
464-
)
459+
url = get_download_url(version)
465460
for i in range(6): # always retry to allow for transient URLErrors
466461
try:
467462
if progress and progbar.allow_show_progress():

cmdstanpy/utils/cmdstan.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44
import os
55
import platform
6+
import subprocess
67
import sys
78
from collections import OrderedDict
89
from typing import Callable, Dict, Optional, Tuple, Union
@@ -17,6 +18,46 @@
1718
EXTENSION = '.exe' if platform.system() == 'Windows' else ''
1819

1920

21+
def determine_linux_arch() -> str:
22+
machine = platform.machine()
23+
arch = ""
24+
if machine == "aarch64":
25+
arch = "arm64"
26+
elif machine == "armv7l":
27+
# Telling armel and armhf apart is nontrivial
28+
# c.f. https://forums.raspberrypi.com/viewtopic.php?t=20873
29+
readelf = subprocess.run(
30+
["readelf", "-A", "/proc/self/exe"],
31+
check=True,
32+
stdout=subprocess.PIPE,
33+
text=True,
34+
)
35+
if "Tag_ABI_VFP_args" in readelf.stdout:
36+
arch = "armel"
37+
else:
38+
arch = "armhf"
39+
elif machine == "mips64":
40+
arch = "mips64el"
41+
elif machine == "ppc64el":
42+
arch = "ppc64le"
43+
elif machine == "s390x":
44+
arch = "s390x"
45+
return arch
46+
47+
48+
def get_download_url(version: str) -> str:
49+
arch = os.environ.get("CMDSTAN_ARCH", "")
50+
if not arch and platform.system() == "Linux":
51+
arch = determine_linux_arch()
52+
53+
if arch and arch.lower() != "false":
54+
url_end = f'v{version}/cmdstan-{version}-linux-{arch}.tar.gz'
55+
else:
56+
url_end = f'v{version}/cmdstan-{version}.tar.gz'
57+
58+
return f'https://github.com/stan-dev/cmdstan/releases/download/{url_end}'
59+
60+
2061
def validate_dir(install_dir: str) -> None:
2162
"""Check that specified install directory exists, can write."""
2263
if not os.path.exists(install_dir):

docsrc/installation.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,17 @@ can be used to override these defaults:
209209
install_cmdstan -d my_local_cmdstan -v 2.27.0
210210
ls -F my_local_cmdstan
211211
212+
Alternate Linux Architectures
213+
.............................
214+
215+
CmdStan can be installed on Linux for the following non-x86 architectures:
216+
``arm64``, ``armel``, ``armhf``, ``mips64el``, ``ppc64el`` and ``s390x``.
217+
218+
CmdStanPy will do its best to determine which of these is applicable for your
219+
machine when running ``install_cmdstan``. If the wrong choice is made, or if you
220+
need to manually override this, you can set the ``CMDSTAN_ARCH`` environment variable
221+
to one of the above options, or to "false" to use the standard x86 download.
222+
212223
DIY Installation
213224
^^^^^^^^^^^^^^^^
214225

0 commit comments

Comments
 (0)