Compare commits
2
Commits
f0f50381ec
...
6a49f47a5b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a49f47a5b | ||
|
|
b40e802627 |
@@ -4,6 +4,8 @@ from pathlib import Path
|
|||||||
import PyInstaller.__main__
|
import PyInstaller.__main__
|
||||||
import typer
|
import typer
|
||||||
from rich import print
|
from rich import print
|
||||||
|
import time
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
app = typer.Typer()
|
app = typer.Typer()
|
||||||
@@ -70,17 +72,62 @@ def build(build: bool = True, copy: bool = True, test: bool = False, dest: str |
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Warning: couldn't locate pythonnet runtime: {e}")
|
print(f"Warning: couldn't locate pythonnet runtime: {e}")
|
||||||
|
|
||||||
|
# Ensure dist/work/spec directories exist
|
||||||
|
dist_dir = project_root / "dist" / "test"
|
||||||
|
work_dir = project_root / "build" / "test"
|
||||||
|
spec_dir = project_root / "build" / "specs"
|
||||||
|
dist_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
work_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
spec_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Decide build name and try to remove any locked previous artifact.
|
||||||
|
base_name = "Uploader_test"
|
||||||
|
output_exe = dist_dir / f"{base_name}.exe"
|
||||||
|
|
||||||
|
def try_remove_with_retries(path: Path, retries: int = 5, delay: float = 0.5) -> bool:
|
||||||
|
"""Try to remove a file with retries and backoff. Returns True if removed or not present."""
|
||||||
|
if not path.exists():
|
||||||
|
return True
|
||||||
|
for attempt in range(retries):
|
||||||
|
try:
|
||||||
|
path.unlink()
|
||||||
|
print(f"Removed existing file: {path}")
|
||||||
|
return True
|
||||||
|
except PermissionError:
|
||||||
|
# Try to move/rename it out of the way
|
||||||
|
try:
|
||||||
|
backup = path.with_suffix(f".old.{int(time.time())}")
|
||||||
|
path.rename(backup)
|
||||||
|
print(f"Renamed locked file to: {backup}")
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
print(f"File locked, retrying in {delay} seconds ({attempt+1}/{retries})")
|
||||||
|
time.sleep(delay)
|
||||||
|
delay *= 1.5
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to remove existing file {path}: {e}")
|
||||||
|
return False
|
||||||
|
return False
|
||||||
|
|
||||||
|
name_used = base_name
|
||||||
|
if not try_remove_with_retries(output_exe):
|
||||||
|
# If the previous artifact is locked, fall back to a unique name to avoid build failure
|
||||||
|
ts = datetime.now().strftime("%Y%m%dT%H%M%S")
|
||||||
|
name_used = f"{base_name}_{ts}"
|
||||||
|
print(f"Previous artifact appears locked; building as {name_used} to avoid PermissionError")
|
||||||
|
|
||||||
PyInstaller.__main__.run([
|
PyInstaller.__main__.run([
|
||||||
str(project_root / "nice.py"),
|
str(project_root / "nice.py"),
|
||||||
"--onefile",
|
"--onefile",
|
||||||
"--name",
|
"--name",
|
||||||
"Uploader_test",
|
name_used,
|
||||||
"--distpath",
|
"--distpath",
|
||||||
str(project_root / "dist" / "test"),
|
str(dist_dir),
|
||||||
"--workpath",
|
"--workpath",
|
||||||
str(project_root / "build" / "test"),
|
str(work_dir),
|
||||||
"--specpath",
|
"--specpath",
|
||||||
str(project_root / "build" / "specs"),
|
str(spec_dir),
|
||||||
] + add_data_args + add_binary_args + [
|
] + add_data_args + add_binary_args + [
|
||||||
# add some common hidden imports that PyInstaller sometimes misses
|
# add some common hidden imports that PyInstaller sometimes misses
|
||||||
"--hidden-import",
|
"--hidden-import",
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ async def read_nng_messages():
|
|||||||
# This shouldn't be necessary
|
# This shouldn't be necessary
|
||||||
global SHUTDOWN
|
global SHUTDOWN
|
||||||
SHUTDOWN = True
|
SHUTDOWN = True
|
||||||
|
logger.debug("Triggering shutdown due to socket in use")
|
||||||
return
|
return
|
||||||
|
|
||||||
# asyncio.create_task(read_nng_messages())
|
# asyncio.create_task(read_nng_messages())
|
||||||
@@ -752,8 +753,56 @@ def launch_app(
|
|||||||
port = native.find_open_port()
|
port = native.find_open_port()
|
||||||
#port = 8001
|
#port = 8001
|
||||||
logger.debug(f"Run on port {port}")
|
logger.debug(f"Run on port {port}")
|
||||||
#ui.run(reload=False, show=True, port=port, native=native_mode, favicon="icon/icon1.ico")
|
|
||||||
ui.run(reload=False, show=True, port=port, native=native_mode)
|
# If native mode was requested, ensure pywebview has a usable GUI
|
||||||
|
# backend (Qt or GTK). If not present, disable native mode to avoid
|
||||||
|
# runtime WebViewException errors when webview.initialize() runs.
|
||||||
|
if native_mode:
|
||||||
|
try:
|
||||||
|
import webview
|
||||||
|
|
||||||
|
backend_available = False
|
||||||
|
# Check common backends: PyQt5/PySide6 or GTK (gi)
|
||||||
|
try:
|
||||||
|
import PyQt5 # type: ignore
|
||||||
|
backend_available = True
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
import PySide6 # type: ignore
|
||||||
|
backend_available = True
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not backend_available:
|
||||||
|
try:
|
||||||
|
# GTK
|
||||||
|
from gi.repository import Gtk # type: ignore
|
||||||
|
|
||||||
|
backend_available = True
|
||||||
|
except Exception:
|
||||||
|
backend_available = False
|
||||||
|
|
||||||
|
if not backend_available:
|
||||||
|
logger.debug(
|
||||||
|
"pywebview backend (Qt/GTK) not available; disabling native mode"
|
||||||
|
)
|
||||||
|
native_mode = False
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"pywebview import/check failed: {e}; disabling native mode")
|
||||||
|
native_mode = False
|
||||||
|
|
||||||
|
# Try to run with the requested mode. If native startup fails at
|
||||||
|
# runtime, catch and fall back to browser mode so the app stays usable.
|
||||||
|
try:
|
||||||
|
ui.run(reload=False, show=True, port=port, native=native_mode)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to start UI in native mode: {e}")
|
||||||
|
if native_mode:
|
||||||
|
logger.debug("Retrying without native mode (browser fallback)")
|
||||||
|
try:
|
||||||
|
ui.run(reload=False, show=True, port=port, native=False)
|
||||||
|
except Exception as e2:
|
||||||
|
logger.error(f"Fallback to browser mode failed: {e2}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import webview
|
||||||
|
webview.create_window('Hello world', 'https://pywebview.flowrl.com/hello')
|
||||||
|
webview.start()
|
||||||
Reference in New Issue
Block a user