mirror of
https://github.com/Flowseal/tg-ws-proxy.git
synced 2026-09-05 18:16:11 +03:00
fix linux build
This commit is contained in:
@@ -395,6 +395,8 @@ jobs:
|
|||||||
python3-venv \
|
python3-venv \
|
||||||
python3-dev \
|
python3-dev \
|
||||||
python3-gi \
|
python3-gi \
|
||||||
|
python3-gi-cairo \
|
||||||
|
gir1.2-appindicator3-0.1 \
|
||||||
gir1.2-ayatanaappindicator3-0.1 \
|
gir1.2-ayatanaappindicator3-0.1 \
|
||||||
python3-tk
|
python3-tk
|
||||||
|
|
||||||
|
|||||||
@@ -310,7 +310,47 @@ def run_tray() -> None:
|
|||||||
log.info("Tray app exited")
|
log.info("Tray app exited")
|
||||||
|
|
||||||
|
|
||||||
|
def _smoke_test() -> None:
|
||||||
|
"""Exercise the frozen GUI stack without starting the proxy or writing config."""
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version('AppIndicator3', '0.1')
|
||||||
|
gi.require_version('AyatanaAppIndicator3', '0.1')
|
||||||
|
from gi.repository import AppIndicator3, AyatanaAppIndicator3
|
||||||
|
|
||||||
|
# Namespace imports alone do not resolve app_indicator_new: call it too.
|
||||||
|
indicators = [
|
||||||
|
namespace.Indicator.new(
|
||||||
|
'tg-ws-proxy-smoke-test', '', namespace.IndicatorCategory.APPLICATION_STATUS,
|
||||||
|
)
|
||||||
|
for namespace in (AppIndicator3, AyatanaAppIndicator3)
|
||||||
|
]
|
||||||
|
icon = pystray.Icon('tg-ws-proxy-smoke-test', Image.new('RGB', (16, 16)))
|
||||||
|
root = ctk.CTk()
|
||||||
|
root.withdraw()
|
||||||
|
root.update_idletasks()
|
||||||
|
root.destroy()
|
||||||
|
|
||||||
|
# A successful constructor on the build host can hide missing bundled
|
||||||
|
# libraries. Check where the dynamic loader actually obtained them.
|
||||||
|
bundle_dir = os.path.realpath(sys._MEIPASS) + os.sep
|
||||||
|
prefixes = ('libglib-', 'libgobject-', 'libgio-', 'libgtk-',
|
||||||
|
'libappindicator', 'libayatana-', 'libdbusmenu-')
|
||||||
|
with open('/proc/self/maps', encoding='utf-8') as maps:
|
||||||
|
paths = {line.split(maxsplit=5)[-1].strip() for line in maps}
|
||||||
|
for path in sorted(paths):
|
||||||
|
if os.path.basename(path).startswith(prefixes):
|
||||||
|
if not os.path.realpath(path).startswith(bundle_dir):
|
||||||
|
raise RuntimeError('GUI library loaded outside the bundle: ' + path)
|
||||||
|
print(path)
|
||||||
|
assert icon is not None and all(indicators)
|
||||||
|
print('Linux bundle smoke test passed')
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
if sys.argv[1:] == ['--smoke-test']:
|
||||||
|
_smoke_test()
|
||||||
|
return
|
||||||
if not acquire_lock():
|
if not acquire_lock():
|
||||||
_show_info(t("dialog.already_running"), os.path.basename(sys.argv[0]))
|
_show_info(t("dialog.already_running"), os.path.basename(sys.argv[0]))
|
||||||
return
|
return
|
||||||
|
|||||||
+40
-16
@@ -1,10 +1,9 @@
|
|||||||
# -*- mode: python ; coding: utf-8 -*-
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
import glob
|
import glob
|
||||||
|
|
||||||
from PyInstaller.utils.hooks import collect_submodules, collect_data_files
|
from PyInstaller.utils.hooks import collect_data_files
|
||||||
|
|
||||||
block_cipher = None
|
block_cipher = None
|
||||||
|
|
||||||
@@ -15,21 +14,18 @@ certifi_datas = collect_data_files('certifi')
|
|||||||
|
|
||||||
_i18n_path = os.path.join(os.path.dirname(SPEC), os.pardir, 'ui', 'i18n')
|
_i18n_path = os.path.join(os.path.dirname(SPEC), os.pardir, 'ui', 'i18n')
|
||||||
|
|
||||||
# Collect gi (PyGObject) submodules and data so pystray._appindicator works
|
appindicator_binaries = [
|
||||||
gi_hiddenimports = collect_submodules('gi')
|
(path, '.')
|
||||||
gi_datas = collect_data_files('gi')
|
for pattern in ('/usr/lib/*/libappindicator3.so.1',
|
||||||
|
'/usr/lib/libappindicator3.so.1', '/usr/lib64/libappindicator3.so.1')
|
||||||
# Collect GObject typelib files from the system
|
for path in glob.glob(pattern)
|
||||||
typelib_dirs = glob.glob('/usr/lib/*/girepository-1.0')
|
]
|
||||||
typelib_datas = []
|
|
||||||
for d in typelib_dirs:
|
|
||||||
typelib_datas.append((d, 'gi_typelibs'))
|
|
||||||
|
|
||||||
a = Analysis(
|
a = Analysis(
|
||||||
[os.path.join(os.path.dirname(SPEC), os.pardir, 'linux.py')],
|
[os.path.join(os.path.dirname(SPEC), os.pardir, 'linux.py')],
|
||||||
pathex=[],
|
pathex=[],
|
||||||
binaries=[],
|
binaries=appindicator_binaries,
|
||||||
datas=[(ctk_path, 'customtkinter/'), (_i18n_path, 'ui/i18n')] + certifi_datas + gi_datas + typelib_datas,
|
datas=[(ctk_path, 'customtkinter/'), (_i18n_path, 'ui/i18n')] + certifi_datas,
|
||||||
hiddenimports=[
|
hiddenimports=[
|
||||||
'pystray._appindicator',
|
'pystray._appindicator',
|
||||||
'PIL._tkinter_finder',
|
'PIL._tkinter_finder',
|
||||||
@@ -39,15 +35,22 @@ a = Analysis(
|
|||||||
'cryptography.hazmat.primitives.ciphers.modes',
|
'cryptography.hazmat.primitives.ciphers.modes',
|
||||||
'cryptography.hazmat.backends.openssl',
|
'cryptography.hazmat.backends.openssl',
|
||||||
'gi',
|
'gi',
|
||||||
'_gi',
|
|
||||||
'gi.repository.GLib',
|
'gi.repository.GLib',
|
||||||
'gi.repository.GObject',
|
'gi.repository.GObject',
|
||||||
'gi.repository.Gtk',
|
'gi.repository.Gtk',
|
||||||
'gi.repository.Gdk',
|
'gi.repository.Gdk',
|
||||||
|
'gi.repository.DBus',
|
||||||
|
'gi.repository.AppIndicator3',
|
||||||
'gi.repository.AyatanaAppIndicator3',
|
'gi.repository.AyatanaAppIndicator3',
|
||||||
] + gi_hiddenimports,
|
],
|
||||||
hookspath=[],
|
hookspath=[],
|
||||||
hooksconfig={},
|
hooksconfig={
|
||||||
|
'gi': {
|
||||||
|
'icons': [],
|
||||||
|
'themes': [],
|
||||||
|
'languages': ['en', 'ru'],
|
||||||
|
},
|
||||||
|
},
|
||||||
runtime_hooks=[],
|
runtime_hooks=[],
|
||||||
excludes=[
|
excludes=[
|
||||||
'PIL._avif',
|
'PIL._avif',
|
||||||
@@ -58,6 +61,27 @@ a = Analysis(
|
|||||||
cipher=block_cipher,
|
cipher=block_cipher,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_required_libraries = {
|
||||||
|
'libglib-2.0.so.0', 'libgobject-2.0.so.0', 'libgio-2.0.so.0',
|
||||||
|
'libgtk-3.so.0', 'libappindicator3.so.1',
|
||||||
|
'libayatana-appindicator3.so.1',
|
||||||
|
}
|
||||||
|
_required_typelibs = {
|
||||||
|
'AppIndicator3-0.1.typelib', 'AyatanaAppIndicator3-0.1.typelib', 'DBus-1.0.typelib',
|
||||||
|
}
|
||||||
|
_bundled_libraries = {
|
||||||
|
os.path.basename(name)
|
||||||
|
for name, _, kind in a.binaries + a.datas
|
||||||
|
if kind in ('BINARY', 'SYMLINK')
|
||||||
|
}
|
||||||
|
_missing = (
|
||||||
|
_required_libraries - _bundled_libraries
|
||||||
|
) | (
|
||||||
|
_required_typelibs - {os.path.basename(name) for name, _, _ in a.datas}
|
||||||
|
)
|
||||||
|
if _missing:
|
||||||
|
raise RuntimeError('Incomplete Linux GI bundle: ' + ', '.join(sorted(_missing)))
|
||||||
|
|
||||||
_PIL_EXCLUDE_PYDS = {
|
_PIL_EXCLUDE_PYDS = {
|
||||||
'_avif', '_webp', '_imagingtk',
|
'_avif', '_webp', '_imagingtk',
|
||||||
'FpxImagePlugin', 'MicImagePlugin',
|
'FpxImagePlugin', 'MicImagePlugin',
|
||||||
|
|||||||
Reference in New Issue
Block a user