Skip to content

Commit fafaab1

Browse files
committed
Add pip_installer.py and uv.lock to version control
1 parent d093c14 commit fafaab1

2 files changed

Lines changed: 87 additions & 1 deletion

File tree

pip_installer.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#!/usr/bin/env python3
2+
"""Runtime pip installer for QGIS plugin dependencies."""
3+
4+
from __future__ import annotations
5+
6+
import os
7+
import subprocess
8+
import sys
9+
from pathlib import Path
10+
11+
12+
def _bundled_pip_root() -> Path | None:
13+
"""Return bundled pip root (vendor/pip) if present."""
14+
plugin_root = Path(__file__).resolve().parent
15+
candidate = plugin_root / "virtughan_qgis" / "vendor" / "pip"
16+
if (candidate / "pip").is_dir():
17+
return candidate
18+
19+
# Also support running from plugin folder directly
20+
candidate_alt = plugin_root / "vendor" / "pip"
21+
if (candidate_alt / "pip").is_dir():
22+
return candidate_alt
23+
24+
return None
25+
26+
27+
def install_dependencies(target_dir: Path | str, package_specs: list[str], verbose: bool = False) -> bool:
28+
"""Install packages to target directory using bundled pip when available."""
29+
target_dir = Path(target_dir)
30+
target_dir.mkdir(parents=True, exist_ok=True)
31+
32+
env = os.environ.copy()
33+
pip_root = _bundled_pip_root()
34+
if pip_root:
35+
existing_pythonpath = env.get("PYTHONPATH", "")
36+
env["PYTHONPATH"] = str(pip_root) + (os.pathsep + existing_pythonpath if existing_pythonpath else "")
37+
38+
cmd = [
39+
sys.executable,
40+
"-m",
41+
"pip",
42+
"install",
43+
"--disable-pip-version-check",
44+
"--upgrade",
45+
"--target",
46+
str(target_dir),
47+
*package_specs,
48+
]
49+
50+
if verbose:
51+
print(f"Running: {' '.join(cmd)}", file=sys.stderr)
52+
53+
try:
54+
subprocess.run(
55+
cmd,
56+
check=True,
57+
capture_output=not verbose,
58+
text=True,
59+
env=env,
60+
)
61+
return True
62+
except subprocess.CalledProcessError as exc:
63+
if verbose:
64+
print(f"pip install failed: {exc}", file=sys.stderr)
65+
if exc.stdout:
66+
print(exc.stdout, file=sys.stderr)
67+
if exc.stderr:
68+
print(exc.stderr, file=sys.stderr)
69+
return False
70+
except Exception as exc:
71+
if verbose:
72+
print(f"Error running pip: {exc}", file=sys.stderr)
73+
return False
74+
75+
76+
if __name__ == "__main__":
77+
import argparse
78+
79+
parser = argparse.ArgumentParser(description="Runtime pip installer for plugin dependencies")
80+
parser.add_argument("--target", required=True, help="Target directory for pip install --target")
81+
parser.add_argument("--packages", nargs="+", required=True, help="Package specs to install")
82+
parser.add_argument("--verbose", action="store_true", help="Show pip output")
83+
84+
args = parser.parse_args()
85+
success = install_dependencies(args.target, args.packages, args.verbose)
86+
sys.exit(0 if success else 1)

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)