k
This commit is contained in:
@@ -303,6 +303,11 @@ def main() -> int:
|
|||||||
script_dir = Path(__file__).resolve().parent
|
script_dir = Path(__file__).resolve().parent
|
||||||
repo_root = script_dir.parent
|
repo_root = script_dir.parent
|
||||||
|
|
||||||
|
if not args.quiet:
|
||||||
|
print(f"Bootstrap script location: {script_dir}")
|
||||||
|
print(f"Detected project root: {repo_root}")
|
||||||
|
print(f"Current working directory: {Path.cwd()}")
|
||||||
|
|
||||||
# Helpers for interactive menu and uninstall detection
|
# Helpers for interactive menu and uninstall detection
|
||||||
def _venv_python_path(p: Path) -> Path | None:
|
def _venv_python_path(p: Path) -> Path | None:
|
||||||
"""Return the path to a python executable inside a venv directory if present."""
|
"""Return the path to a python executable inside a venv directory if present."""
|
||||||
@@ -555,6 +560,14 @@ def main() -> int:
|
|||||||
# Opinionated: always create or use a local venv at the project root (.venv)
|
# Opinionated: always create or use a local venv at the project root (.venv)
|
||||||
venv_dir = repo_root / ".venv"
|
venv_dir = repo_root / ".venv"
|
||||||
|
|
||||||
|
# Validate that venv_dir is where we expect it to be
|
||||||
|
if not args.quiet:
|
||||||
|
print(f"Planned venv location: {venv_dir}")
|
||||||
|
if venv_dir.parent != repo_root:
|
||||||
|
print(f"WARNING: venv parent is {venv_dir.parent}, expected {repo_root}", file=sys.stderr)
|
||||||
|
if "scripts" in str(venv_dir).lower():
|
||||||
|
print(f"WARNING: venv path contains 'scripts': {venv_dir}", file=sys.stderr)
|
||||||
|
|
||||||
def _venv_python(p: Path) -> Path:
|
def _venv_python(p: Path) -> Path:
|
||||||
if platform.system().lower() == "windows":
|
if platform.system().lower() == "windows":
|
||||||
return p / "Scripts" / "python.exe"
|
return p / "Scripts" / "python.exe"
|
||||||
@@ -834,22 +847,25 @@ if (Test-Path (Join-Path $repo 'CLI.py')) {
|
|||||||
user_bin = Path(os.environ.get("USERPROFILE", str(home))) / "bin"
|
user_bin = Path(os.environ.get("USERPROFILE", str(home))) / "bin"
|
||||||
user_bin.mkdir(parents=True, exist_ok=True)
|
user_bin.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Convert repo path to string with proper escaping
|
||||||
|
repo_str = str(repo).replace("\\", "\\\\")
|
||||||
|
|
||||||
# Write mm.ps1 (PowerShell shim)
|
# Write mm.ps1 (PowerShell shim)
|
||||||
mm_ps1 = user_bin / "mm.ps1"
|
mm_ps1 = user_bin / "mm.ps1"
|
||||||
ps1_text = (
|
ps1_text = (
|
||||||
"Param([Parameter(ValueFromRemainingArguments=$true)] $args)\n"
|
"Param([Parameter(ValueFromRemainingArguments=$true)] $args)\n"
|
||||||
f'$repo = "{repo}"\n'
|
f'$repo = "{repo_str}"\n'
|
||||||
"$venv = Join-Path $repo '.venv'\n"
|
"$venv = Join-Path $repo '.venv'\n"
|
||||||
"$py = Join-Path $venv 'Scripts\\python.exe'\n"
|
"$py = Join-Path $venv 'Scripts\\python.exe'\n"
|
||||||
"if (Test-Path $py) {\n"
|
"if (Test-Path $py) {\n"
|
||||||
" if ($env:MM_DEBUG) {\n"
|
" if ($env:MM_DEBUG) {\n"
|
||||||
' Write-Host "MM_DEBUG: using venv python at $py" -ForegroundColor Yellow\n'
|
' Write-Host "MM_DEBUG: using venv python at $py" -ForegroundColor Yellow\n'
|
||||||
" & $py -c \"import sys; print('sys.executable:', sys.executable)\"\n"
|
" & $py -c \"import sys; print('sys.executable:', sys.executable); print('sys.path:', sys.path[:5])\"\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
" & $py -m scripts.cli_entry @args; exit $LASTEXITCODE\n"
|
" & $py -m scripts.cli_entry @args; exit $LASTEXITCODE\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"# Fallback to system python if venv doesn't exist\n"
|
"# Fallback to system python if venv doesn't exist\n"
|
||||||
"if ($env:MM_DEBUG) { Write-Host 'MM_DEBUG: venv python not found, trying system python' -ForegroundColor Yellow }\n"
|
"if ($env:MM_DEBUG) { Write-Host 'MM_DEBUG: venv python not found at' $py ', trying system python' -ForegroundColor Yellow }\n"
|
||||||
"python -m scripts.cli_entry @args\n"
|
"python -m scripts.cli_entry @args\n"
|
||||||
)
|
)
|
||||||
if mm_ps1.exists():
|
if mm_ps1.exists():
|
||||||
@@ -859,21 +875,22 @@ if (Test-Path (Join-Path $repo 'CLI.py')) {
|
|||||||
|
|
||||||
# Write mm.bat (CMD shim for better compatibility)
|
# Write mm.bat (CMD shim for better compatibility)
|
||||||
mm_bat = user_bin / "mm.bat"
|
mm_bat = user_bin / "mm.bat"
|
||||||
|
repo_bat_str = str(repo)
|
||||||
bat_text = (
|
bat_text = (
|
||||||
"@echo off\n"
|
"@echo off\n"
|
||||||
"setlocal enabledelayedexpansion\n"
|
"setlocal enabledelayedexpansion\n"
|
||||||
f'set "REPO={repo}"\n'
|
f'set "REPO={repo_bat_str}"\n'
|
||||||
"set \"VENV=!REPO!\\.venv\"\n"
|
"set \"VENV=!REPO!\\.venv\"\n"
|
||||||
"set \"PY=!VENV!\\Scripts\\python.exe\"\n"
|
"set \"PY=!VENV!\\Scripts\\python.exe\"\n"
|
||||||
"if exist \"!PY!\" (\n"
|
"if exist \"!PY!\" (\n"
|
||||||
" if defined MM_DEBUG (\n"
|
" if defined MM_DEBUG (\n"
|
||||||
" echo MM_DEBUG: using venv python at !PY!\n"
|
" echo MM_DEBUG: using venv python at !PY!\n"
|
||||||
" \"!PY!\" -c \"import sys; print('sys.executable:', sys.executable)\"\n"
|
" \"!PY!\" -c \"import sys; print('sys.executable:', sys.executable); print('sys.path:', sys.path[:5])\"\n"
|
||||||
" )\n"
|
" )\n"
|
||||||
" \"!PY!\" -m scripts.cli_entry %*\n"
|
" \"!PY!\" -m scripts.cli_entry %*\n"
|
||||||
" exit /b !ERRORLEVEL!\n"
|
" exit /b !ERRORLEVEL!\n"
|
||||||
")\n"
|
")\n"
|
||||||
"echo MM: venv not found at !VENV!, trying system python\n"
|
"echo MM: venv python not found at !PY!\n"
|
||||||
"if defined MM_DEBUG echo MM_DEBUG: venv python not found, trying system python\n"
|
"if defined MM_DEBUG echo MM_DEBUG: venv python not found, trying system python\n"
|
||||||
"python -m scripts.cli_entry %*\n"
|
"python -m scripts.cli_entry %*\n"
|
||||||
"exit /b !ERRORLEVEL!\n"
|
"exit /b !ERRORLEVEL!\n"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from __future__ import annotations
|
|||||||
from typing import Optional, List, Tuple
|
from typing import Optional, List, Tuple
|
||||||
import importlib
|
import importlib
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import shlex
|
import shlex
|
||||||
@@ -25,7 +26,7 @@ def _ensure_repo_root_on_sys_path(pkg_file: Optional[Path] = None) -> Optional[P
|
|||||||
not necessarily on `sys.path`, which breaks `import CLI`.
|
not necessarily on `sys.path`, which breaks `import CLI`.
|
||||||
|
|
||||||
We infer the repo root by walking up from this package location and looking
|
We infer the repo root by walking up from this package location and looking
|
||||||
for a sibling `CLI.py`.
|
for a sibling `CLI.py` or checking parent directories.
|
||||||
|
|
||||||
`pkg_file` exists for unit tests; production uses this module's `__file__`.
|
`pkg_file` exists for unit tests; production uses this module's `__file__`.
|
||||||
"""
|
"""
|
||||||
@@ -34,6 +35,7 @@ def _ensure_repo_root_on_sys_path(pkg_file: Optional[Path] = None) -> Optional[P
|
|||||||
except Exception:
|
except Exception:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Strategy 1: Look for CLI.py in parent directories (starting from scripts parent)
|
||||||
for parent in pkg_dir.parents:
|
for parent in pkg_dir.parents:
|
||||||
try:
|
try:
|
||||||
if (parent / "CLI.py").exists():
|
if (parent / "CLI.py").exists():
|
||||||
@@ -43,6 +45,22 @@ def _ensure_repo_root_on_sys_path(pkg_file: Optional[Path] = None) -> Optional[P
|
|||||||
return parent
|
return parent
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Strategy 2: If in a venv, check the .venv/.. path (project root)
|
||||||
|
try:
|
||||||
|
# If this file is in .../venv/lib/python3.x/site-packages/scripts/
|
||||||
|
# then we want to go up to find the project root
|
||||||
|
current = pkg_dir.resolve()
|
||||||
|
for _ in range(20): # Safety limit
|
||||||
|
current = current.parent
|
||||||
|
if (current / "CLI.py").exists():
|
||||||
|
parent_str = str(current)
|
||||||
|
if parent_str not in sys.path:
|
||||||
|
sys.path.insert(0, parent_str)
|
||||||
|
return current
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@@ -165,13 +183,35 @@ def _run_cli(clean_args: List[str]) -> int:
|
|||||||
# 2) If no in-memory module provided the class, try importing the repo-root CLI
|
# 2) If no in-memory module provided the class, try importing the repo-root CLI
|
||||||
if MedeiaCLI is None:
|
if MedeiaCLI is None:
|
||||||
try:
|
try:
|
||||||
_ensure_repo_root_on_sys_path()
|
repo_root = _ensure_repo_root_on_sys_path()
|
||||||
from CLI import MedeiaCLI as _M # type: ignore
|
from CLI import MedeiaCLI as _M # type: ignore
|
||||||
MedeiaCLI = _M
|
MedeiaCLI = _M
|
||||||
except Exception:
|
except Exception as exc:
|
||||||
raise ImportError(
|
# Provide diagnostic information
|
||||||
"Could not import 'MedeiaCLI'. This often means the project is not available on sys.path (run 'pip install -e scripts' or re-run the bootstrap script)."
|
import traceback
|
||||||
|
error_msg = (
|
||||||
|
"Could not import 'MedeiaCLI'. This often means the project is not available on sys.path.\n"
|
||||||
|
"Diagnostic info:\n"
|
||||||
|
f" - sys.executable: {sys.executable}\n"
|
||||||
|
f" - sys.path (first 5): {sys.path[:5]}\n"
|
||||||
|
f" - current working directory: {Path.cwd()}\n"
|
||||||
|
f" - this file: {Path(__file__).resolve()}\n"
|
||||||
)
|
)
|
||||||
|
try:
|
||||||
|
repo = _ensure_repo_root_on_sys_path()
|
||||||
|
if repo:
|
||||||
|
error_msg += f" - detected repo root: {repo}\n"
|
||||||
|
cli_path = repo / "CLI.py"
|
||||||
|
error_msg += f" - CLI.py exists at {cli_path}: {cli_path.exists()}\n"
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
error_msg += (
|
||||||
|
"\nRemedy: Run 'pip install -e scripts' from the project root or re-run the bootstrap script.\n"
|
||||||
|
"Set MM_DEBUG=1 to enable detailed diagnostics."
|
||||||
|
)
|
||||||
|
if os.environ.get("MM_DEBUG"):
|
||||||
|
error_msg += f"\n\nTraceback:\n{traceback.format_exc()}"
|
||||||
|
raise ImportError(error_msg) from exc
|
||||||
|
|
||||||
try:
|
try:
|
||||||
app = MedeiaCLI()
|
app = MedeiaCLI()
|
||||||
|
|||||||
Reference in New Issue
Block a user