Compare commits

..
2 Commits
Author SHA1 Message Date
thePR0M3TH3ANandClaude Opus 4.6 35069e24c5 fix(install): remove flask/werkzeug pins, clean stale pip packages (v0.2.18)
Previous pip --user installs left werkzeug 2.0.3 in ~/.local which
shadows the system werkzeug and breaks the system onionshare-cli
(Flask 2.2.2 requires werkzeug >= 2.2 for LocalProxy.unbound_message).

Changes:
- Remove flask, werkzeug, and onionshare-cli from voxvera's own
  dependencies — they are onionshare's transitive deps, not ours
- Install script now cleans up stale user-local packages (werkzeug,
  flask, flask-socketio, onionshare-cli, voxvera) before installing
- Prevents pip --user packages from poisoning system Python environment

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-16 10:06:17 -04:00
thePR0M3TH3ANandClaude Opus 4.6 51ab72239f fix(cli): always use system onionshare-cli binary, even in PyInstaller builds (v0.2.17)
The previous fix only used the system binary for non-frozen (pip/pipx)
installs.  But the PyInstaller binary also needs this — it downloads
successfully but its bundled onionshare_cli import still crashes on
'No module named pkg_resources'.

Now both serve() and _internal_onionshare() unconditionally prefer the
system onionshare-cli/onionshare binary via shutil.which(), falling
back to the Python import only if no system binary exists.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-16 09:51:44 -04:00
4 changed files with 41 additions and 25 deletions

No files matched your search

+22
View File
@@ -96,6 +96,28 @@ else
msg "onionshare-cli found (system package), skipping pipx install. Run 'pipx install --force ...' if you want the latest git version."
fi
# Clean up stale user-local packages from prior pip --user installs of voxvera.
# These can shadow system packages (e.g. Werkzeug) and break onionshare-cli.
msg "Cleaning up stale user-local packages that may conflict with system onionshare-cli..."
PIP_CLEANUP_OPTS=""
if [ -f /etc/debian_version ]; then
DEB_VER=$(cat /etc/debian_version | cut -d. -f1)
if [[ "$DEB_VER" =~ ^[0-9]+$ ]] && [ "$DEB_VER" -ge 12 ]; then
PIP_CLEANUP_OPTS="--break-system-packages"
fi
fi
for pkg in werkzeug flask flask-socketio onionshare-cli; do
if pip3 show --quiet "$pkg" 2>/dev/null && \
pip3 show "$pkg" 2>/dev/null | grep -q "Location.*\.local"; then
pip3 uninstall -y $PIP_CLEANUP_OPTS "$pkg" 2>/dev/null || true
fi
done
# Also uninstall any previous pip --user install of voxvera itself
if pip3 show --quiet voxvera 2>/dev/null && \
pip3 show voxvera 2>/dev/null | grep -q "Location.*\.local"; then
pip3 uninstall -y $PIP_CLEANUP_OPTS voxvera 2>/dev/null || true
fi
download_binary() {
local url=$1
local dest=$2
+1 -4
View File
@@ -14,7 +14,7 @@ voxvera = ["templates/**", "src/**", "resources/**", "locales/**", "resources/bi
[project]
name = "voxvera"
version = "0.2.16"
version = "0.2.18"
description = "VoxVera CLI utilities"
readme = "README.md"
authors = [{name = "VoxVera"}]
@@ -28,10 +28,7 @@ dependencies = [
"htmlmin2",
"pypdf",
"wcwidth",
"onionshare-cli",
"setuptools",
"flask<2.3.0",
"werkzeug<3.0.0",
]
[project.optional-dependencies]
test = [
+1 -1
View File
@@ -1,7 +1,7 @@
import sys
from pathlib import Path
__version__ = "0.2.16"
__version__ = "0.2.18"
# Add the vendor directory to sys.path ONLY for PyInstaller (frozen) builds.
# For pip/pipx installs the system/venv packages are correct and the vendored
+17 -20
View File
@@ -673,15 +673,15 @@ def _internal_onionshare():
onionshare_args = sys.argv[2:] # strip 'voxvera _internal_onionshare'
# For non-frozen installs (pip/pipx), prefer the system onionshare-cli
# binary to avoid dependency-isolation issues with pkg_resources etc.
if not getattr(sys, 'frozen', False):
onionshare_bin = shutil.which("onionshare-cli") or shutil.which("onionshare")
if onionshare_bin:
os.execvp(onionshare_bin, [onionshare_bin] + onionshare_args)
# execvp replaces the process; if we reach here something went wrong
# Fall through to Python import as last resort
# Always prefer the system onionshare-cli binary. This avoids
# pkg_resources / setuptools isolation issues in both PyInstaller
# builds and pipx venvs.
onionshare_bin = shutil.which("onionshare-cli") or shutil.which("onionshare")
if onionshare_bin:
os.execvp(onionshare_bin, [onionshare_bin] + onionshare_args)
# execvp replaces the process; unreachable unless execvp itself fails
# Last resort: try to import onionshare_cli as a Python module
try:
from onionshare_cli import main
sys.argv = ["onionshare-cli"] + onionshare_args
@@ -719,19 +719,16 @@ def serve(config_path: str) -> str | None:
str(dir_path),
]
if getattr(sys, 'frozen', False):
# PyInstaller build: route through our hidden subcommand
cmd = [sys.argv[0], "_internal_onionshare"] + onionshare_args
# Always prefer the system onionshare-cli binary to avoid pkg_resources
# and dependency-isolation issues inside both PyInstaller and pipx.
onionshare_bin = shutil.which("onionshare-cli") or shutil.which("onionshare")
if onionshare_bin:
cmd = [onionshare_bin] + onionshare_args
else:
# pip/pipx install: call the system onionshare-cli binary directly
onionshare_bin = shutil.which("onionshare-cli") or shutil.which("onionshare")
if onionshare_bin:
cmd = [onionshare_bin] + onionshare_args
else:
# Last resort: route through our subcommand (will try Python import)
cmd = [sys.argv[0], "_internal_onionshare"] + onionshare_args
if sys.argv[0].endswith('.py'):
cmd = [sys.executable] + cmd
# Fallback: route through our hidden subcommand
cmd = [sys.argv[0], "_internal_onionshare"] + onionshare_args
if not getattr(sys, 'frozen', False) and sys.argv[0].endswith('.py'):
cmd = [sys.executable] + cmd
log_fh = open(logfile, "w")
proc = subprocess.Popen(cmd, stdout=log_fh, stderr=subprocess.STDOUT, env=env)