Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better linux build support #617

Merged
merged 5 commits into from
Dec 31, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ jobs:
- name: Install system dependencies
run: |
sudo apt update
sudo apt install gir1.2-appindicator3-0.1 libgirepository1.0-dev python3-tk
sudo apt install libgirepository1.0-dev gir1.2-ayatanaappindicator3-0.1 libayatana-appindicator3-1 python3-tk

- name: Install project dependencies
run: |
Expand Down Expand Up @@ -198,7 +198,7 @@ jobs:
- name: Install system dependencies
run: |
sudo apt update
sudo apt install libgirepository1.0-dev python3-testresources
sudo apt install libgirepository1.0-dev gir1.2-ayatanaappindicator3-0.1 libayatana-appindicator3-1 python3-testresources

- name: Download AppImage Builder
run: |
Expand Down
2 changes: 1 addition & 1 deletion appimage/AppImageBuilder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ AppDir:
key_url: http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x871920D1991BC93C

include:
- gir1.2-appindicator3-0.1
- gir1.2-ayatanaappindicator3-0.1
- python3-tk

exclude:
Expand Down
55 changes: 37 additions & 18 deletions build.bat
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,18 +1,37 @@
@echo off
cls
set dirpath=%~dp0
if "%dirpath:~-1%" == "\" set dirpath=%dirpath:~0,-1%

if not exist "%dirpath%\env" (
echo:
echo No virtual environment found! Run setup_env.bat to set it up first.
echo:
pause
exit
)

if not exist "%dirpath%\env\scripts\pyinstaller.exe" (
"%dirpath%\env\scripts\pip" install pyinstaller
"%dirpath%\env\scripts\python" "%dirpath%\env\scripts\pywin32_postinstall.py" -install -silent
)
"%dirpath%/env/scripts/pyinstaller" "%dirpath%\build.spec"
@echo off

REM Get the directory path of the script
set "dirpath=%~dp0"
if "%dirpath:~-1%" == "\" set "dirpath=%dirpath:~0,-1%"

REM Check if the virtual environment exists
if not exist "%dirpath%\env" (
echo:
echo No virtual environment found! Run setup_env.bat to set it up first.
echo:
pause
exit /b 1
)

REM Check if pyinstaller and pywin32 is installed in the virtual environment
if not exist "%dirpath%\env\scripts\pyinstaller.exe" (
"%dirpath%\env\scripts\pip" install pyinstaller
biast12 marked this conversation as resolved.
Show resolved Hide resolved
if errorlevel 1 (
echo Failed to install pyinstaller.
biast12 marked this conversation as resolved.
Show resolved Hide resolved
exit /b 1
)
"%dirpath%\env\scripts\python" "%dirpath%\env\scripts\pywin32_postinstall.py" -install -silent
if errorlevel 1 (
echo Failed to run pywin32_postinstall.py.
biast12 marked this conversation as resolved.
Show resolved Hide resolved
exit /b 1
)
)

REM Run pyinstaller with the specified build spec file
"%dirpath%\env\scripts\pyinstaller" "%dirpath%\build.spec"
biast12 marked this conversation as resolved.
Show resolved Hide resolved
if errorlevel 1 (
echo PyInstaller build failed.
biast12 marked this conversation as resolved.
Show resolved Hide resolved
exit /b 1
)

echo Build completed successfully.
36 changes: 36 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash

dirpath=$(dirname "$(readlink -f "$0")")

# Check if the virtual environment exists
if [ ! -d "$dirpath/env" ]; then
echo
echo "No virtual environment found! Run setup_env.sh to set it up first."
echo
read -p "Press any key to continue..."
biast12 marked this conversation as resolved.
Show resolved Hide resolved
exit 1
fi

# Check if pyinstaller is installed in the virtual environment
if [ ! -f "$dirpath/env/bin/pyinstaller" ]; then
echo
echo "Installing pyinstaller..."
biast12 marked this conversation as resolved.
Show resolved Hide resolved
"$dirpath/env/bin/pip" install pyinstaller
if [ $? -ne 0 ]; then
echo "Failed to install pyinstaller."
biast12 marked this conversation as resolved.
Show resolved Hide resolved
exit 1
fi
fi

# Run pyinstaller with the specified build spec file
echo
echo "Running pyinstaller..."
biast12 marked this conversation as resolved.
Show resolved Hide resolved
"$dirpath/env/bin/pyinstaller" "$dirpath/build.spec"
if [ $? -ne 0 ]; then
echo "PyInstaller build failed."
exit 1
fi

echo
echo "Build completed successfully."
read -p "Press any key to continue..."
231 changes: 117 additions & 114 deletions build.spec
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,114 +1,117 @@
# -*- mode: python ; coding: utf-8 -*-
from __future__ import annotations

import sys
from pathlib import Path
from typing import Any, TYPE_CHECKING

SELF_PATH = str(Path(".").resolve())
if SELF_PATH not in sys.path:
sys.path.insert(0, SELF_PATH)

from constants import WORKING_DIR, SITE_PACKAGES_PATH, DEFAULT_LANG

if TYPE_CHECKING:
from PyInstaller.building.api import PYZ, EXE
from PyInstaller.building.build_main import Analysis

# (source_path, dest_path, required)
to_add: list[tuple[Path, str, bool]] = [
# icon files
(Path("icons/pickaxe.ico"), "./icons", True),
(Path("icons/active.ico"), "./icons", True),
(Path("icons/idle.ico"), "./icons", True),
(Path("icons/error.ico"), "./icons", True),
(Path("icons/maint.ico"), "./icons", True),
# SeleniumWire HTTPS/SSL cert file and key
(Path(SITE_PACKAGES_PATH, "seleniumwire/ca.crt"), "./seleniumwire", False),
(Path(SITE_PACKAGES_PATH, "seleniumwire/ca.key"), "./seleniumwire", False),
]
for lang_filepath in WORKING_DIR.joinpath("lang").glob("*.json"):
if lang_filepath.stem != DEFAULT_LANG:
to_add.append((lang_filepath, "lang", True))

# ensure the required to-be-added data exists
datas: list[tuple[Path, str]] = []
for source_path, dest_path, required in to_add:
if source_path.exists():
datas.append((source_path, dest_path))
elif required:
raise FileNotFoundError(str(source_path))

hooksconfig: dict[str, Any] = {}
binaries: list[tuple[Path, str]] = []
hiddenimports: list[str] = [
"PIL._tkinter_finder",
"setuptools._distutils.log",
"setuptools._distutils.dir_util",
"setuptools._distutils.file_util",
"setuptools._distutils.archive_util",
]

if sys.platform == "linux":
# Needed files for better system tray support on Linux via pystray (AppIndicator backend).
biast12 marked this conversation as resolved.
Show resolved Hide resolved
datas.append((Path("/usr/lib/girepository-1.0/AppIndicator3-0.1.typelib"), "gi_typelibs"))
binaries.append((Path("/lib/x86_64-linux-gnu/libappindicator3.so.1"), "."))
hiddenimports.extend([
"gi.repository.Gtk",
"gi.repository.GObject",
])
hooksconfig = {
"gi": {
"icons": [],
"themes": [],
"languages": ["en_US"]
}
}

block_cipher = None
a = Analysis(
["main.py"],
pathex=[],
datas=datas,
excludes=[],
hookspath=[],
noarchive=False,
runtime_hooks=[],
binaries=binaries,
cipher=block_cipher,
hooksconfig=hooksconfig,
hiddenimports=hiddenimports,
win_private_assemblies=False,
win_no_prefer_redirects=False,
)

# Exclude unneeded Linux libraries
excluded_binaries = [
"libicudata.so.66",
"libicuuc.so.66",
"librsvg-2.so.2"
]
a.binaries = [b for b in a.binaries if b[0] not in excluded_binaries]

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
upx=True,
debug=False,
strip=False,
console=False,
upx_exclude=[],
target_arch=None,
runtime_tmpdir=None,
codesign_identity=None,
entitlements_file=None,
icon="icons/pickaxe.ico",
bootloader_ignore_signals=False,
disable_windowed_traceback=False,
name="Twitch Drops Miner (by DevilXD)",
)
# -*- mode: python ; coding: utf-8 -*-
from __future__ import annotations

import sys
import platform
from pathlib import Path
from typing import Any, TYPE_CHECKING

SELF_PATH = str(Path(".").resolve())
if SELF_PATH not in sys.path:
sys.path.insert(0, SELF_PATH)

from constants import WORKING_DIR, SITE_PACKAGES_PATH, DEFAULT_LANG

if TYPE_CHECKING:
from PyInstaller.building.api import PYZ, EXE
from PyInstaller.building.build_main import Analysis

# (source_path, dest_path, required)
to_add: list[tuple[Path, str, bool]] = [
# icon files
(Path("icons/pickaxe.ico"), "./icons", True),
(Path("icons/active.ico"), "./icons", True),
(Path("icons/idle.ico"), "./icons", True),
(Path("icons/error.ico"), "./icons", True),
(Path("icons/maint.ico"), "./icons", True),
# SeleniumWire HTTPS/SSL cert file and key
(Path(SITE_PACKAGES_PATH, "seleniumwire/ca.crt"), "./seleniumwire", False),
(Path(SITE_PACKAGES_PATH, "seleniumwire/ca.key"), "./seleniumwire", False),
]
for lang_filepath in WORKING_DIR.joinpath("lang").glob("*.json"):
if lang_filepath.stem != DEFAULT_LANG:
to_add.append((lang_filepath, "lang", True))

# Ensure the required to-be-added data exists
datas: list[tuple[Path, str]] = []
for source_path, dest_path, required in to_add:
if source_path.exists():
datas.append((source_path, dest_path))
elif required:
raise FileNotFoundError(str(source_path))

hooksconfig: dict[str, Any] = {}
binaries: list[tuple[Path, str]] = []
hiddenimports: list[str] = [
"PIL._tkinter_finder",
"setuptools._distutils.log",
"setuptools._distutils.dir_util",
"setuptools._distutils.file_util",
"setuptools._distutils.archive_util",
]

if sys.platform == "linux":
# Needed files for better system tray support on Linux via pystray (AppIndicator backend).
arch = platform.machine()
datas.append((Path(f"/usr/lib/{arch}-linux-gnu/girepository-1.0/AyatanaAppIndicator3-0.1.typelib"), "gi_typelibs"))
binaries.append((Path(f"/usr/lib/{arch}-linux-gnu/libayatana-appindicator3.so.1"), "."))

hiddenimports.extend([
"gi.repository.Gtk",
"gi.repository.GObject",
])
hooksconfig = {
"gi": {
"icons": [],
"themes": [],
"languages": ["en_US"]
}
}

block_cipher = None
a = Analysis(
["main.py"],
pathex=[],
datas=datas,
excludes=[],
hookspath=[],
noarchive=False,
runtime_hooks=[],
binaries=binaries,
cipher=block_cipher,
hooksconfig=hooksconfig,
hiddenimports=hiddenimports,
win_private_assemblies=False,
win_no_prefer_redirects=False,
)

# Exclude unneeded Linux libraries
excluded_binaries = [
"libicudata.so.66",
"libicuuc.so.66",
"librsvg-2.so.2"
]
a.binaries = [b for b in a.binaries if b[0] not in excluded_binaries]

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
upx=True,
debug=False,
strip=False,
console=False,
upx_exclude=[],
target_arch=None,
runtime_tmpdir=None,
codesign_identity=None,
entitlements_file=None,
icon="icons/pickaxe.ico",
bootloader_ignore_signals=False,
disable_windowed_traceback=False,
name="Twitch Drops Miner (by DevilXD)",
)
Loading