ethanolivertroy_obsidian-ma.../python/install_package.py
Ethan Troy d6fa068498
Rewrite plugin v2: fix shell injection, modularize, add features (ENG-533)
## Summary
- **Security**: Replaced shell injection-vulnerable `exec()` calls with `spawn()` using argument arrays and `shell: false`, bundling Python wrapper scripts that use `argparse`
- **Architecture**: Decomposed monolithic 735-line `main.ts` into 12 focused modules across `src/` and `python/`
- **Features**: Added image extraction from PDFs, plugin arguments editor, context menu conversion, batch progress indicators, setup wizard, and Unicode support via `PYTHONUTF8=1`
- **Compatibility**: Reverted minAppVersion to 0.15.0, python3 fallback for macOS/Linux

Closes ENG-533
2026-02-17 01:08:20 -05:00

60 lines
1.5 KiB
Python

#!/usr/bin/env python3
"""Install a Python package using pip with progress output.
Usage:
python install_package.py --package "markitdown[all]"
Output:
Streams pip output line by line to stdout.
Final line is JSON: {"success": true} or {"success": false, "error": "message"}
"""
import argparse
import json
import subprocess
import sys
def main():
parser = argparse.ArgumentParser(description="Install a Python package via pip")
parser.add_argument(
"--package",
required=True,
help="Package specification (e.g., 'markitdown[all]')",
)
args = parser.parse_args()
try:
process = subprocess.Popen(
[sys.executable, "-m", "pip", "install", args.package],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
)
for line in process.stdout:
print(line, end="", flush=True)
process.wait()
if process.returncode == 0:
print(json.dumps({"success": True}))
else:
print(
json.dumps(
{
"success": False,
"error": f"pip exited with code {process.returncode}",
}
)
)
sys.exit(1)
except Exception as e:
print(json.dumps({"success": False, "error": str(e)}))
sys.exit(1)
if __name__ == "__main__":
main()