updated installer script
This commit is contained in:
@@ -14,22 +14,17 @@ ffmpeg-python is installed as a dependency, but requires ffmpeg itself to be on
|
||||
|
||||
Note: This Python script is the canonical installer for the project — prefer
|
||||
running `python ./scripts/bootstrap.py` locally. The platform scripts
|
||||
(`scripts/bootstrap.ps1` and `scripts/bootstrap.sh`) are now thin wrappers
|
||||
that delegate to this script (they call it with `--no-delegate -q`).
|
||||
(`scripts/bootstrap.ps1` and `scripts/bootstrap.sh`) are thin wrappers
|
||||
that delegate to this script.
|
||||
|
||||
When invoked without any arguments, `bootstrap.py` will automatically select and
|
||||
run the platform-specific bootstrap helper (`scripts/bootstrap.ps1` on Windows
|
||||
or `scripts/bootstrap.sh` on POSIX) in **non-interactive (quiet)** mode so a
|
||||
single `python ./scripts/bootstrap.py` call does the usual bootstrap on your OS.
|
||||
|
||||
The platform bootstrap scripts also attempt (best-effort) to install `mpv` if
|
||||
it is not found on your PATH, since some workflows use it.
|
||||
The install flow is owned here so `bootstrap.py` remains the single global
|
||||
entry point, while platform wrappers only provide shell-specific convenience.
|
||||
|
||||
This file replaces the old `scripts/setup.py` to ensure the repository only has
|
||||
one `setup.py` (at the repository root) for packaging.
|
||||
|
||||
Usage:
|
||||
python ./scripts/bootstrap.py # install deps and playwright browsers (or run platform bootstrap if no args)
|
||||
python ./scripts/bootstrap.py # install deps and playwright browsers
|
||||
python ./scripts/bootstrap.py --skip-deps
|
||||
python ./scripts/bootstrap.py --playwright-only
|
||||
|
||||
@@ -249,10 +244,16 @@ def run_platform_bootstrap(repo_root: Path) -> int:
|
||||
return int(rc.returncode or 0)
|
||||
|
||||
|
||||
def playwright_package_installed() -> bool:
|
||||
def playwright_package_installed(python_path: Optional[Path] = None) -> bool:
|
||||
interpreter = str(python_path or sys.executable)
|
||||
try:
|
||||
|
||||
return True
|
||||
result = subprocess.run(
|
||||
[interpreter, "-c", "import playwright"],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
check=False,
|
||||
)
|
||||
return result.returncode == 0
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@@ -446,7 +447,7 @@ def main() -> int:
|
||||
parser.add_argument(
|
||||
"--no-delegate",
|
||||
action="store_true",
|
||||
help="Do not delegate to platform bootstrap scripts; run the Python bootstrap directly.",
|
||||
help="Legacy no-op retained for wrapper compatibility; Python bootstrap is always the canonical entry point.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-q",
|
||||
@@ -812,7 +813,7 @@ def main() -> int:
|
||||
return False
|
||||
|
||||
def _interactive_menu() -> str | int:
|
||||
"""Show a simple interactive menu to choose install/uninstall or delegate."""
|
||||
"""Show a simple interactive menu to choose install/uninstall tasks."""
|
||||
try:
|
||||
installed = _is_installed()
|
||||
while True:
|
||||
@@ -878,8 +879,7 @@ def main() -> int:
|
||||
if choice in ("q", "quit", "exit"):
|
||||
return 0
|
||||
except EOFError:
|
||||
# Non-interactive, fall back to delegating to platform helper
|
||||
return "delegate"
|
||||
return "install"
|
||||
|
||||
def _prompt_hydrus_install_location() -> tuple[Path, str] | None:
|
||||
"""Ask the user for the Hydrus installation root and folder name."""
|
||||
@@ -907,9 +907,10 @@ def main() -> int:
|
||||
def _clone_repo(url: str, dest: Path, depth: int = 1) -> bool:
|
||||
"""Helper to clone a repository."""
|
||||
try:
|
||||
cmd = ["git", "clone", url, str(dest)]
|
||||
cmd = ["git", "clone"]
|
||||
if depth:
|
||||
cmd.extend(["--depth", str(depth)])
|
||||
cmd.extend([url, str(dest)])
|
||||
subprocess.check_call(cmd)
|
||||
return True
|
||||
except Exception as e:
|
||||
@@ -1318,25 +1319,14 @@ def main() -> int:
|
||||
continue
|
||||
elif sel == "uninstall":
|
||||
return _do_uninstall()
|
||||
elif sel == "delegate":
|
||||
rc = run_platform_bootstrap(repo_root)
|
||||
if rc != 0:
|
||||
return rc
|
||||
if not args.quiet:
|
||||
print("Platform bootstrap completed successfully.")
|
||||
return 0
|
||||
elif sel == 0:
|
||||
return 0
|
||||
elif sel == "menu":
|
||||
continue
|
||||
elif not args.no_delegate and script_path is not None:
|
||||
# Default non-interactive behavior: delegate to platform script
|
||||
rc = run_platform_bootstrap(repo_root)
|
||||
if rc != 0:
|
||||
return rc
|
||||
if not args.quiet:
|
||||
print("Platform bootstrap completed successfully.")
|
||||
return 0
|
||||
|
||||
if not is_in_repo:
|
||||
if not _ensure_repo_available():
|
||||
return 1
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
print("Warning: Python 3.8+ is recommended.", file=sys.stderr)
|
||||
@@ -1360,12 +1350,27 @@ def main() -> int:
|
||||
print("Error: No project repository found. Please ensure you are running this script inside the project folder or follow the interactive install prompts.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Determine total steps for progress bar
|
||||
total_steps = 7 # Base: venv, pip, deps, project, cli, finalize, env
|
||||
if args.upgrade_pip: total_steps += 1
|
||||
if not args.no_playwright: total_steps += 1 # Playwright is combined pkg+browsers
|
||||
if not getattr(args, "no_mpv", False): total_steps += 1
|
||||
if not getattr(args, "no_deno", False): total_steps += 1
|
||||
should_install_deps = not args.skip_deps and not args.playwright_only
|
||||
should_install_playwright = not args.no_playwright
|
||||
should_install_project = not args.playwright_only
|
||||
|
||||
total_steps = 2
|
||||
if args.playwright_only:
|
||||
total_steps += 1
|
||||
else:
|
||||
if args.upgrade_pip:
|
||||
total_steps += 1
|
||||
if should_install_deps:
|
||||
total_steps += 1
|
||||
if should_install_playwright:
|
||||
total_steps += 1
|
||||
if should_install_project:
|
||||
total_steps += 1
|
||||
total_steps += 3
|
||||
if not getattr(args, "no_mpv", False):
|
||||
total_steps += 1
|
||||
if not getattr(args, "no_deno", False):
|
||||
total_steps += 1
|
||||
|
||||
pb = ProgressBar(total_steps, quiet=args.quiet or args.debug)
|
||||
|
||||
@@ -1437,17 +1442,12 @@ def main() -> int:
|
||||
pb.update("Checking for pip...")
|
||||
_ensure_pip_available(venv_python)
|
||||
|
||||
# Enforce opinionated behavior: install deps, playwright, deno, and install project in editable mode.
|
||||
# Ignore `--skip-deps` and `--install-editable` flags to keep the setup deterministic.
|
||||
args.skip_deps = False
|
||||
args.install_editable = True
|
||||
args.no_playwright = False
|
||||
|
||||
try:
|
||||
if args.playwright_only:
|
||||
# Playwright browser install (short-circuit)
|
||||
if not playwright_package_installed():
|
||||
_run_cmd([sys.executable, "-m", "pip", "install", "--no-cache-dir", "playwright"])
|
||||
pb.update("Setting up Playwright and browsers...")
|
||||
if not playwright_package_installed(venv_python):
|
||||
_run_cmd([str(venv_python), "-m", "pip", "install", "--no-cache-dir", "playwright"])
|
||||
|
||||
try:
|
||||
cmd = _build_playwright_install_cmd(args.browsers)
|
||||
@@ -1476,15 +1476,16 @@ def main() -> int:
|
||||
)
|
||||
|
||||
# 4. Core Dependencies
|
||||
pb.update("Installing core dependencies...")
|
||||
req_file = repo_root / "scripts" / "requirements.txt"
|
||||
if req_file.exists():
|
||||
_run_cmd([str(venv_python), "-m", "pip", "install", "--no-cache-dir", "-r", str(req_file)])
|
||||
if should_install_deps:
|
||||
pb.update("Installing core dependencies...")
|
||||
if req_file.exists():
|
||||
_run_cmd([str(venv_python), "-m", "pip", "install", "--no-cache-dir", "-r", str(req_file)])
|
||||
|
||||
# 5. Playwright Setup
|
||||
if not args.no_playwright:
|
||||
if should_install_playwright:
|
||||
pb.update("Setting up Playwright and browsers...")
|
||||
if not playwright_package_installed():
|
||||
if not playwright_package_installed(venv_python):
|
||||
_run_cmd([str(venv_python), "-m", "pip", "install", "--no-cache-dir", "playwright"])
|
||||
|
||||
try:
|
||||
@@ -1495,16 +1496,22 @@ def main() -> int:
|
||||
pass
|
||||
|
||||
# 6. Internal Components
|
||||
pb.update("Installing internal components...")
|
||||
if platform.system() != "Windows":
|
||||
old_mm = venv_dir / "bin" / "mm"
|
||||
if old_mm.exists():
|
||||
try:
|
||||
old_mm.unlink()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
_run_cmd([str(venv_python), "-m", "pip", "install", "--no-cache-dir", "-e", str(repo_root / "scripts")])
|
||||
if should_install_project:
|
||||
pb.update("Installing internal components...")
|
||||
if platform.system() != "Windows":
|
||||
old_mm = venv_dir / "bin" / "mm"
|
||||
if old_mm.exists():
|
||||
try:
|
||||
old_mm.unlink()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
project_cmd = [str(venv_python), "-m", "pip", "install", "--no-cache-dir"]
|
||||
if args.install_editable:
|
||||
project_cmd.extend(["-e", str(repo_root / "scripts")])
|
||||
else:
|
||||
project_cmd.append(str(repo_root / "scripts"))
|
||||
_run_cmd(project_cmd)
|
||||
|
||||
# 7. CLI Verification
|
||||
pb.update("Verifying CLI configuration...")
|
||||
|
||||
Reference in New Issue
Block a user