pyappify 0.0.2__tar.gz → 0.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyappify-0.0.2 → pyappify-0.0.4}/PKG-INFO +1 -1
- pyappify-0.0.4/pyappify/__init__.py +146 -0
- {pyappify-0.0.2 → pyappify-0.0.4}/pyappify.egg-info/PKG-INFO +1 -1
- {pyappify-0.0.2 → pyappify-0.0.4}/pyproject.toml +1 -1
- pyappify-0.0.2/pyappify/__init__.py +0 -0
- {pyappify-0.0.2 → pyappify-0.0.4}/pyappify/main.py +0 -0
- {pyappify-0.0.2 → pyappify-0.0.4}/pyappify.egg-info/SOURCES.txt +0 -0
- {pyappify-0.0.2 → pyappify-0.0.4}/pyappify.egg-info/dependency_links.txt +0 -0
- {pyappify-0.0.2 → pyappify-0.0.4}/pyappify.egg-info/entry_points.txt +0 -0
- {pyappify-0.0.2 → pyappify-0.0.4}/pyappify.egg-info/requires.txt +0 -0
- {pyappify-0.0.2 → pyappify-0.0.4}/pyappify.egg-info/top_level.txt +0 -0
- {pyappify-0.0.2 → pyappify-0.0.4}/setup.cfg +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# pyappify/__init__.py
|
|
2
|
+
import os
|
|
3
|
+
import signal
|
|
4
|
+
import hashlib
|
|
5
|
+
import shutil
|
|
6
|
+
import urllib.request
|
|
7
|
+
import zipfile
|
|
8
|
+
import threading
|
|
9
|
+
|
|
10
|
+
app_version = os.environ.get("PYAPPIFY_APP_VERSION")
|
|
11
|
+
app_profile = os.environ.get("PYAPPIFY_APP_PROFILE")
|
|
12
|
+
pyappify_version = os.environ.get("PYAPPIFY_VERSION")
|
|
13
|
+
pyappify_executable = os.environ.get("PYAPPIFY_EXECUTABLE")
|
|
14
|
+
|
|
15
|
+
pyappify_upgradeable = os.environ.get("PYAPPIFY_UPGRADEABLE") == '1'
|
|
16
|
+
logger = None
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
pid = int(os.environ.get("PYAPPIFY_PID"))
|
|
20
|
+
except (ValueError, TypeError):
|
|
21
|
+
pid = None
|
|
22
|
+
|
|
23
|
+
import sys
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
import ctypes
|
|
27
|
+
except ImportError:
|
|
28
|
+
ctypes = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def minimize_window_by_pid(pid):
|
|
32
|
+
if not ctypes or sys.platform != "win32":
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
found_hwnd = []
|
|
36
|
+
EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
|
|
37
|
+
|
|
38
|
+
def enum_windows_callback(hwnd, lParam):
|
|
39
|
+
owner_pid = ctypes.c_ulong()
|
|
40
|
+
ctypes.windll.user32.GetWindowThreadProcessId(hwnd, ctypes.byref(owner_pid))
|
|
41
|
+
if owner_pid.value == pid and ctypes.windll.user32.IsWindowVisible(hwnd):
|
|
42
|
+
found_hwnd.append(hwnd)
|
|
43
|
+
return False
|
|
44
|
+
return True
|
|
45
|
+
|
|
46
|
+
ctypes.windll.user32.EnumWindows(EnumWindowsProc(enum_windows_callback), 0)
|
|
47
|
+
|
|
48
|
+
if found_hwnd:
|
|
49
|
+
ctypes.windll.user32.ShowWindow(found_hwnd[0], 6)
|
|
50
|
+
return True
|
|
51
|
+
|
|
52
|
+
return False
|
|
53
|
+
|
|
54
|
+
def kill_pyappify():
|
|
55
|
+
if pid:
|
|
56
|
+
if logger:
|
|
57
|
+
logger.info(f"Attempting to terminate process with PID: {pid}")
|
|
58
|
+
try:
|
|
59
|
+
os.kill(pid, signal.SIGTERM)
|
|
60
|
+
except Exception as e:
|
|
61
|
+
if logger:
|
|
62
|
+
logger.error(f"Failed to terminate process with PID {pid}: {e}")
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
def hide_pyappify():
|
|
66
|
+
if pid:
|
|
67
|
+
if logger:
|
|
68
|
+
logger.info(f"Attempting to minimize window for process with PID: {pid}")
|
|
69
|
+
try:
|
|
70
|
+
minimize_window_by_pid(pid)
|
|
71
|
+
except Exception as e:
|
|
72
|
+
if logger:
|
|
73
|
+
logger.error(f"Failed to minimize window for process with PID {pid}: {e}")
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
def upgrade(to_version, executable_sha256, executable_zip_urls, stop_event=None):
|
|
77
|
+
if not pyappify_upgradeable or to_version == pyappify_version:
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
def _do_upgrade():
|
|
81
|
+
tmp_dir = os.path.join(os.getcwd(), "tmp")
|
|
82
|
+
try:
|
|
83
|
+
os.makedirs(tmp_dir, exist_ok=True)
|
|
84
|
+
downloaded_zip_path = None
|
|
85
|
+
for url in executable_zip_urls:
|
|
86
|
+
try:
|
|
87
|
+
local_zip_path = os.path.join(tmp_dir, os.path.basename(url))
|
|
88
|
+
with urllib.request.urlopen(url) as response, open(local_zip_path, 'wb') as out_file:
|
|
89
|
+
while True:
|
|
90
|
+
if stop_event and stop_event.is_set():
|
|
91
|
+
if logger:
|
|
92
|
+
logger.info("Upgrade download cancelled by stop event.")
|
|
93
|
+
return
|
|
94
|
+
chunk = response.read(8192)
|
|
95
|
+
if not chunk:
|
|
96
|
+
break
|
|
97
|
+
out_file.write(chunk)
|
|
98
|
+
downloaded_zip_path = local_zip_path
|
|
99
|
+
break
|
|
100
|
+
except Exception as e:
|
|
101
|
+
if logger:
|
|
102
|
+
logger.warning(f"Failed to download from {url}: {e}")
|
|
103
|
+
continue
|
|
104
|
+
|
|
105
|
+
if not downloaded_zip_path:
|
|
106
|
+
if logger:
|
|
107
|
+
logger.error("Failed to download upgrade.")
|
|
108
|
+
return
|
|
109
|
+
|
|
110
|
+
with zipfile.ZipFile(downloaded_zip_path, 'r') as zip_ref:
|
|
111
|
+
zip_ref.extractall(tmp_dir)
|
|
112
|
+
|
|
113
|
+
new_executable_name = os.path.basename(pyappify_executable)
|
|
114
|
+
found_executable_path = None
|
|
115
|
+
for root, _, files in os.walk(tmp_dir):
|
|
116
|
+
if new_executable_name in files:
|
|
117
|
+
found_executable_path = os.path.join(root, new_executable_name)
|
|
118
|
+
break
|
|
119
|
+
|
|
120
|
+
if not found_executable_path:
|
|
121
|
+
if logger:
|
|
122
|
+
logger.error("Executable not found in zip.")
|
|
123
|
+
return
|
|
124
|
+
|
|
125
|
+
sha256_hash = hashlib.sha256()
|
|
126
|
+
with open(found_executable_path, "rb") as f:
|
|
127
|
+
for byte_block in iter(lambda: f.read(4096), b""):
|
|
128
|
+
sha256_hash.update(byte_block)
|
|
129
|
+
|
|
130
|
+
if sha256_hash.hexdigest() != executable_sha256:
|
|
131
|
+
if logger:
|
|
132
|
+
logger.error("SHA256 checksum mismatch.")
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
kill_pyappify()
|
|
136
|
+
shutil.move(found_executable_path, pyappify_executable)
|
|
137
|
+
except Exception as e:
|
|
138
|
+
if logger:
|
|
139
|
+
logger.error(f"Upgrade failed: {e}")
|
|
140
|
+
finally:
|
|
141
|
+
if os.path.exists(tmp_dir):
|
|
142
|
+
shutil.rmtree(tmp_dir)
|
|
143
|
+
|
|
144
|
+
thread = threading.Thread(target=_do_upgrade)
|
|
145
|
+
thread.daemon = True
|
|
146
|
+
thread.start()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|