mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2026-02-04 13:25:13 +00:00
215 lines
7.7 KiB
Python
215 lines
7.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Development installation script for UniLabOS.
|
|
Auto-detects Chinese locale and uses appropriate mirror.
|
|
|
|
Usage:
|
|
python scripts/dev_install.py
|
|
python scripts/dev_install.py --no-mirror # Force no mirror
|
|
python scripts/dev_install.py --china # Force China mirror
|
|
python scripts/dev_install.py --skip-deps # Skip pip dependencies installation
|
|
|
|
Flow:
|
|
1. pip install -e . (install unilabos in editable mode)
|
|
2. Detect Chinese locale
|
|
3. Use uv to install pip dependencies from requirements.txt
|
|
4. Special packages (like pylabrobot) are handled by environment_check.py at runtime
|
|
"""
|
|
|
|
import locale
|
|
import subprocess
|
|
import sys
|
|
import argparse
|
|
from pathlib import Path
|
|
|
|
# Tsinghua mirror URL
|
|
TSINGHUA_MIRROR = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"
|
|
|
|
|
|
def is_chinese_locale() -> bool:
|
|
"""
|
|
Detect if system is in Chinese locale.
|
|
Same logic as EnvironmentChecker._is_chinese_locale()
|
|
"""
|
|
try:
|
|
lang = locale.getdefaultlocale()[0]
|
|
if lang and ("zh" in lang.lower() or "chinese" in lang.lower()):
|
|
return True
|
|
except Exception:
|
|
pass
|
|
return False
|
|
|
|
|
|
def run_command(cmd: list, description: str, retry: int = 2) -> bool:
|
|
"""Run command with retry support."""
|
|
print(f"[INFO] {description}")
|
|
print(f"[CMD] {' '.join(cmd)}")
|
|
|
|
for attempt in range(retry + 1):
|
|
try:
|
|
result = subprocess.run(cmd, check=True, timeout=600)
|
|
print(f"[OK] {description}")
|
|
return True
|
|
except subprocess.CalledProcessError as e:
|
|
if attempt < retry:
|
|
print(f"[WARN] Attempt {attempt + 1} failed, retrying...")
|
|
else:
|
|
print(f"[ERROR] {description} failed: {e}")
|
|
return False
|
|
except subprocess.TimeoutExpired:
|
|
print(f"[ERROR] {description} timed out")
|
|
return False
|
|
return False
|
|
|
|
|
|
def install_editable(project_root: Path, use_mirror: bool) -> bool:
|
|
"""Install unilabos in editable mode using pip."""
|
|
cmd = [sys.executable, "-m", "pip", "install", "-e", str(project_root)]
|
|
if use_mirror:
|
|
cmd.extend(["-i", TSINGHUA_MIRROR])
|
|
|
|
return run_command(cmd, "Installing unilabos in editable mode")
|
|
|
|
|
|
def install_requirements_uv(requirements_file: Path, use_mirror: bool) -> bool:
|
|
"""Install pip dependencies using uv (installed via conda-forge::uv)."""
|
|
cmd = ["uv", "pip", "install", "-r", str(requirements_file)]
|
|
if use_mirror:
|
|
cmd.extend(["-i", TSINGHUA_MIRROR])
|
|
|
|
return run_command(cmd, "Installing pip dependencies with uv", retry=2)
|
|
|
|
|
|
def install_requirements_pip(requirements_file: Path, use_mirror: bool) -> bool:
|
|
"""Fallback: Install pip dependencies using pip."""
|
|
cmd = [sys.executable, "-m", "pip", "install", "-r", str(requirements_file)]
|
|
if use_mirror:
|
|
cmd.extend(["-i", TSINGHUA_MIRROR])
|
|
|
|
return run_command(cmd, "Installing pip dependencies with pip", retry=2)
|
|
|
|
|
|
def check_uv_available() -> bool:
|
|
"""Check if uv is available (installed via conda-forge::uv)."""
|
|
try:
|
|
subprocess.run(["uv", "--version"], capture_output=True, check=True)
|
|
return True
|
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
return False
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Development installation script for UniLabOS")
|
|
parser.add_argument("--china", action="store_true", help="Force use China mirror (Tsinghua)")
|
|
parser.add_argument("--no-mirror", action="store_true", help="Force use default PyPI (no mirror)")
|
|
parser.add_argument(
|
|
"--skip-deps", action="store_true", help="Skip pip dependencies installation (only install unilabos)"
|
|
)
|
|
parser.add_argument("--use-pip", action="store_true", help="Use pip instead of uv for dependencies")
|
|
args = parser.parse_args()
|
|
|
|
# Determine project root
|
|
script_dir = Path(__file__).parent
|
|
project_root = script_dir.parent
|
|
requirements_file = project_root / "unilabos" / "utils" / "requirements.txt"
|
|
|
|
if not (project_root / "setup.py").exists():
|
|
print(f"[ERROR] setup.py not found in {project_root}")
|
|
sys.exit(1)
|
|
|
|
print("=" * 60)
|
|
print("UniLabOS Development Installation")
|
|
print("=" * 60)
|
|
print(f"Project root: {project_root}")
|
|
print()
|
|
|
|
# Determine mirror usage based on locale
|
|
if args.no_mirror:
|
|
use_mirror = False
|
|
print("[INFO] Mirror disabled by --no-mirror flag")
|
|
elif args.china:
|
|
use_mirror = True
|
|
print("[INFO] China mirror enabled by --china flag")
|
|
else:
|
|
use_mirror = is_chinese_locale()
|
|
if use_mirror:
|
|
print("[INFO] Chinese locale detected, using Tsinghua mirror")
|
|
else:
|
|
print("[INFO] Non-Chinese locale detected, using default PyPI")
|
|
|
|
print()
|
|
|
|
# Step 1: Install unilabos in editable mode
|
|
print("[STEP 1] Installing unilabos in editable mode...")
|
|
if not install_editable(project_root, use_mirror):
|
|
print("[ERROR] Failed to install unilabos")
|
|
print()
|
|
print("Manual fallback:")
|
|
if use_mirror:
|
|
print(f" pip install -e {project_root} -i {TSINGHUA_MIRROR}")
|
|
else:
|
|
print(f" pip install -e {project_root}")
|
|
sys.exit(1)
|
|
|
|
print()
|
|
|
|
# Step 2: Install pip dependencies
|
|
if args.skip_deps:
|
|
print("[INFO] Skipping pip dependencies installation (--skip-deps)")
|
|
else:
|
|
print("[STEP 2] Installing pip dependencies...")
|
|
|
|
if not requirements_file.exists():
|
|
print(f"[WARN] Requirements file not found: {requirements_file}")
|
|
print("[INFO] Skipping dependencies installation")
|
|
else:
|
|
# Try uv first (faster), fallback to pip
|
|
if args.use_pip:
|
|
print("[INFO] Using pip (--use-pip flag)")
|
|
success = install_requirements_pip(requirements_file, use_mirror)
|
|
elif check_uv_available():
|
|
print("[INFO] Using uv (installed via conda-forge::uv)")
|
|
success = install_requirements_uv(requirements_file, use_mirror)
|
|
if not success:
|
|
print("[WARN] uv failed, falling back to pip...")
|
|
success = install_requirements_pip(requirements_file, use_mirror)
|
|
else:
|
|
print("[WARN] uv not available (should be installed via: mamba install conda-forge::uv)")
|
|
print("[INFO] Falling back to pip...")
|
|
success = install_requirements_pip(requirements_file, use_mirror)
|
|
|
|
if not success:
|
|
print()
|
|
print("[WARN] Failed to install some dependencies automatically.")
|
|
print("You can manually install them:")
|
|
if use_mirror:
|
|
print(f" uv pip install -r {requirements_file} -i {TSINGHUA_MIRROR}")
|
|
print(" or:")
|
|
print(f" pip install -r {requirements_file} -i {TSINGHUA_MIRROR}")
|
|
else:
|
|
print(f" uv pip install -r {requirements_file}")
|
|
print(" or:")
|
|
print(f" pip install -r {requirements_file}")
|
|
|
|
print()
|
|
print("=" * 60)
|
|
print("Installation complete!")
|
|
print("=" * 60)
|
|
print()
|
|
print("Note: Some special packages (like pylabrobot) are installed")
|
|
print("automatically at runtime by unilabos if needed.")
|
|
print()
|
|
print("Verify installation:")
|
|
print(' python -c "import unilabos; print(unilabos.__version__)"')
|
|
print()
|
|
print("If you encounter issues, you can manually install dependencies:")
|
|
if use_mirror:
|
|
print(f" uv pip install -r unilabos/utils/requirements.txt -i {TSINGHUA_MIRROR}")
|
|
else:
|
|
print(" uv pip install -r unilabos/utils/requirements.txt")
|
|
print()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|