Skip to content

Commit 18edba6

Browse files
Enhance macOS compatibility by updating system PATH and improving Docker support for Apple Silicon
1 parent 77fd62e commit 18edba6

3 files changed

Lines changed: 124 additions & 20 deletions

File tree

app_gui.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,31 @@
3333
from version import __version__
3434
from check_app_output import BIDSOutputValidator
3535

36+
def _fix_system_path():
37+
"""Ensure common paths are in PATH, especially when running as a bundled app on macOS."""
38+
extra_paths = [
39+
"/usr/local/bin",
40+
"/opt/homebrew/bin",
41+
"/opt/local/bin",
42+
"/usr/bin",
43+
"/bin",
44+
"/usr/sbin",
45+
"/sbin"
46+
]
47+
current_path = os.environ.get("PATH", "").split(os.pathsep)
48+
path_changed = False
49+
for p in extra_paths:
50+
if p not in current_path and os.path.exists(p):
51+
current_path.append(p)
52+
path_changed = True
53+
54+
if path_changed:
55+
os.environ["PATH"] = os.pathsep.join(current_path)
56+
print(f"[GUI] Updated PATH to include common locations: {os.environ['PATH']}", flush=True)
57+
58+
# Important to fix path before any shutil.which calls
59+
_fix_system_path()
60+
3661
if getattr(sys, 'frozen', False):
3762
# Running in a bundle
3863
BUNDLE_DIR = Path(sys._MEIPASS)
@@ -73,9 +98,10 @@ def check_system_dependencies():
7398
if docker_installed:
7499
try:
75100
# Check if daemon is responsive
76-
subprocess.run(['docker', 'info'], capture_output=True, timeout=2, check=True)
101+
subprocess.run(['docker', 'info'], capture_output=True, timeout=5, check=True)
77102
docker_running = True
78-
except (subprocess.SubprocessError, FileNotFoundError):
103+
except (subprocess.SubprocessError, FileNotFoundError, subprocess.TimeoutExpired) as e:
104+
print(f"[GUI] Docker check failed: {e}")
79105
docker_running = False
80106

81107
return {

check_system_deps.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,30 @@
33
import sys
44
import subprocess
55
import os
6+
import platform
7+
8+
def _fix_system_path():
9+
"""Ensure common paths are in PATH, especially on macOS."""
10+
extra_paths = [
11+
"/usr/local/bin",
12+
"/opt/homebrew/bin",
13+
"/opt/local/bin",
14+
"/usr/bin",
15+
"/bin",
16+
"/usr/sbin",
17+
"/sbin"
18+
]
19+
current_path = os.environ.get("PATH", "").split(os.pathsep)
20+
path_changed = False
21+
for p in extra_paths:
22+
if p not in current_path and os.path.exists(p):
23+
current_path.append(p)
24+
path_changed = True
25+
26+
if path_changed:
27+
os.environ["PATH"] = os.pathsep.join(current_path)
28+
29+
_fix_system_path()
630

731
def check_command(cmd, name):
832
path = shutil.which(cmd)

run_bids_apps.py

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,29 @@
2828
from pathlib import Path
2929
from typing import Set, Optional
3030

31+
def _fix_system_path():
32+
"""Ensure common paths are in PATH, especially on macOS."""
33+
extra_paths = [
34+
"/usr/local/bin",
35+
"/opt/homebrew/bin",
36+
"/opt/local/bin",
37+
"/usr/bin",
38+
"/bin",
39+
"/usr/sbin",
40+
"/sbin"
41+
]
42+
current_path = os.environ.get("PATH", "").split(os.pathsep)
43+
path_changed = False
44+
for p in extra_paths:
45+
if p not in current_path and os.path.exists(p):
46+
current_path.append(p)
47+
path_changed = True
48+
49+
if path_changed:
50+
os.environ["PATH"] = os.pathsep.join(current_path)
51+
52+
_fix_system_path()
53+
3154
# Import validation integration
3255
try:
3356
from bids_validation_integration import (
@@ -1434,27 +1457,58 @@ def process_group(common, app, dry_run=False, debug=False):
14341457
run_datalad_command(cmd, cwd=common["bids_folder"], dry_run=dry_run)
14351458

14361459
# Build container command
1437-
cmd = ["apptainer", "run"]
1460+
engine = common.get("container_engine", "apptainer")
14381461

1439-
# Add app-specific apptainer arguments
1440-
if app.get("apptainer_args"):
1441-
cmd.extend(sanitize_apptainer_args(app["apptainer_args"]))
1462+
if engine == "docker":
1463+
cmd = ["docker", "run", "--rm"]
1464+
1465+
# Apple Silicon support: Add platform flag for standard amd64 containers
1466+
if platform.system() == "Darwin" and platform.machine() == "arm64":
1467+
logging.info("Apple Silicon detected. Adding '--platform linux/amd64' for standard container compatibility.")
1468+
cmd.extend(["--platform", "linux/amd64"])
1469+
1470+
# Add environment variables
1471+
cmd.extend(["-e", "TEMPLATEFLOW_HOME=/templateflow"])
1472+
1473+
# Add bind mounts
1474+
for mnt in build_common_mounts(common, tmp_dir):
1475+
cmd.extend(["-v", mnt])
1476+
1477+
# Add custom mounts
1478+
for mount in app.get("mounts", []):
1479+
if mount.get("source") and mount.get("target"):
1480+
cmd.extend(["-v", f"{mount['source']}:{mount['target']}"])
1481+
1482+
# Add container image name
1483+
cmd.append(common["container"])
14421484
else:
1443-
cmd.append("--containall")
1444-
1445-
# Add bind mounts
1446-
for mnt in build_common_mounts(common, tmp_dir):
1447-
cmd.extend(["-B", mnt])
1448-
1449-
# Add custom mounts
1450-
for mount in app.get("mounts", []):
1451-
if mount.get("source") and mount.get("target"):
1452-
cmd.extend(["-B", f"{mount['source']}:{mount['target']}"])
1453-
1454-
# Add environment and container
1485+
# Default to Apptainer
1486+
cmd = ["apptainer", "run"]
1487+
1488+
# Add app-specific apptainer arguments (only for apptainer)
1489+
if app.get("apptainer_args"):
1490+
safe_args = sanitize_apptainer_args(app["apptainer_args"])
1491+
cmd.extend(safe_args)
1492+
else:
1493+
cmd.append("--containall")
1494+
1495+
# Add bind mounts
1496+
for mnt in build_common_mounts(common, tmp_dir):
1497+
cmd.extend(["-B", mnt])
1498+
1499+
# Add custom mounts
1500+
for mount in app.get("mounts", []):
1501+
if mount.get("source") and mount.get("target"):
1502+
cmd.extend(["-B", f"{mount['source']}:{mount['target']}"])
1503+
1504+
# Add environment variables
1505+
cmd.extend(["--env", "TEMPLATEFLOW_HOME=/templateflow"])
1506+
1507+
# Add container image path
1508+
cmd.append(common["container"])
1509+
1510+
# Add common BIDS app arguments (same for both engines)
14551511
cmd.extend([
1456-
"--env", f"TEMPLATEFLOW_HOME=/templateflow",
1457-
common["container"],
14581512
"/bids", "/output", app.get("analysis_level", "group"),
14591513
"-w", "/tmp"
14601514
])

0 commit comments

Comments
 (0)