|
1 | 1 | import argparse |
| 2 | +import contextlib |
2 | 3 | import hashlib |
3 | 4 | import json |
4 | 5 | import os |
| 6 | +import platform |
5 | 7 | import re |
6 | 8 | import shutil |
| 9 | +import subprocess |
7 | 10 | import sys |
8 | 11 | import urllib.request |
9 | 12 | from pathlib import Path |
|
28 | 31 | Path.mkdir(ARTIFACTS_DIR, parents=True, exist_ok=True) |
29 | 32 |
|
30 | 33 |
|
| 34 | +def get_arch() -> str: |
| 35 | + """Get the current system architecture.""" |
| 36 | + machine = platform.machine().lower() |
| 37 | + if machine in ["x86_64", "amd64"]: |
| 38 | + return "amd64" |
| 39 | + elif machine in ["aarch64", "arm64"]: |
| 40 | + return "arm64" |
| 41 | + elif machine in ["i386", "i686"]: |
| 42 | + return "386" |
| 43 | + return machine |
| 44 | + |
| 45 | + |
| 46 | +def check_emulation_available() -> bool: |
| 47 | + """Check if x86_64 emulation is available.""" |
| 48 | + if get_arch() != "arm64": |
| 49 | + return False |
| 50 | + |
| 51 | + # On macOS, check for Rosetta 2 |
| 52 | + if sys.platform == "darwin": |
| 53 | + # Check if we can run x86_64 binaries |
| 54 | + try: |
| 55 | + result = subprocess.run(["arch", "-x86_64", "true"], capture_output=True, check=False) |
| 56 | + return result.returncode == 0 |
| 57 | + except (FileNotFoundError, OSError): |
| 58 | + return False |
| 59 | + |
| 60 | + # On Linux, check for qemu-x86_64 |
| 61 | + try: |
| 62 | + result = subprocess.run( |
| 63 | + ["which", "qemu-x86_64"], capture_output=True, text=True, check=False |
| 64 | + ) |
| 65 | + return result.returncode == 0 |
| 66 | + except (FileNotFoundError, OSError): |
| 67 | + return False |
| 68 | + |
| 69 | + |
| 70 | +def get_emulation_prefix() -> list: |
| 71 | + """Get the command prefix for emulation if needed.""" |
| 72 | + if get_arch() != "arm64": |
| 73 | + return [] |
| 74 | + |
| 75 | + # On macOS, use arch command for Rosetta 2 |
| 76 | + if sys.platform == "darwin" and check_emulation_available(): |
| 77 | + return ["arch", "-x86_64"] |
| 78 | + |
| 79 | + # On Linux, use qemu |
| 80 | + if sys.platform.startswith("linux") and check_emulation_available(): |
| 81 | + return ["qemu-x86_64"] |
| 82 | + |
| 83 | + return [] |
| 84 | + |
| 85 | + |
| 86 | +def warn_about_arm64(force: bool = False) -> None: |
| 87 | + """Warn ARM64 users about compatibility and suggest solutions.""" |
| 88 | + if get_arch() != "arm64": |
| 89 | + return |
| 90 | + |
| 91 | + # Check if we've already warned |
| 92 | + warning_file = SOLC_SELECT_DIR.joinpath(".arm64_warning_shown") |
| 93 | + if not force and warning_file.exists(): |
| 94 | + return |
| 95 | + |
| 96 | + print("\n⚠️ WARNING: ARM64 Architecture Detected", file=sys.stderr) |
| 97 | + print("=" * 50, file=sys.stderr) |
| 98 | + |
| 99 | + if check_emulation_available(): |
| 100 | + if sys.platform == "darwin": |
| 101 | + print("✓ Rosetta 2 detected - will use emulation for x86 binaries", file=sys.stderr) |
| 102 | + else: |
| 103 | + print("✓ qemu-x86_64 detected - will use emulation for x86 binaries", file=sys.stderr) |
| 104 | + print(" Note: Performance will be slower than native execution", file=sys.stderr) |
| 105 | + else: |
| 106 | + if sys.platform == "darwin": |
| 107 | + print( |
| 108 | + "✗ solc binaries are x86_64 only, and Rosetta 2 is not available", file=sys.stderr |
| 109 | + ) |
| 110 | + else: |
| 111 | + print("✗ solc binaries are x86_64 only, and qemu is not installed", file=sys.stderr) |
| 112 | + print("\nTo use solc-select on ARM64, you can:", file=sys.stderr) |
| 113 | + print(" 1. Install qemu for x86_64 emulation:", file=sys.stderr) |
| 114 | + if sys.platform.startswith("linux"): |
| 115 | + print(" sudo apt-get install qemu-user-static # Debian/Ubuntu", file=sys.stderr) |
| 116 | + print(" sudo dnf install qemu-user-static # Fedora", file=sys.stderr) |
| 117 | + print(" sudo pacman -S qemu-user-static # Arch", file=sys.stderr) |
| 118 | + elif sys.platform == "darwin": |
| 119 | + print(" Use Rosetta 2 (installed automatically on Apple Silicon)", file=sys.stderr) |
| 120 | + print(" 2. Use an x86_64 Docker container", file=sys.stderr) |
| 121 | + print(" 3. Use a cloud-based development environment", file=sys.stderr) |
| 122 | + print("=" * 50, file=sys.stderr) |
| 123 | + print(file=sys.stderr) |
| 124 | + |
| 125 | + # Mark that we've shown the warning |
| 126 | + with contextlib.suppress(OSError): |
| 127 | + warning_file.touch() |
| 128 | + |
| 129 | + |
31 | 130 | def validate_url_scheme(url: str) -> None: |
32 | 131 | """Validate that URL uses a safe scheme (http or https only).""" |
33 | 132 | parsed = urlparse(url) |
@@ -107,6 +206,10 @@ def artifact_path(version: str) -> Path: |
107 | 206 |
|
108 | 207 |
|
109 | 208 | def install_artifacts(versions: [str], silent: bool = False) -> bool: |
| 209 | + # Warn ARM64 users about compatibility on first install |
| 210 | + if get_arch() == "arm64" and not silent: |
| 211 | + warn_about_arm64() |
| 212 | + |
110 | 213 | releases = get_available_versions() |
111 | 214 | versions = [get_latest_release() if ver == "latest" else ver for ver in versions] |
112 | 215 |
|
|
0 commit comments