Skip to content

Commit

Permalink
Better linux build support
Browse files Browse the repository at this point in the history
  • Loading branch information
JourneyOver committed Dec 31, 2024
1 parent a09c033 commit d55f371
Show file tree
Hide file tree
Showing 8 changed files with 310 additions and 171 deletions.
4 changes: 3 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ log.txt
lock.file

# Ignore Python-related files
build.spec
.mypy_cache/
__pycache__/

Expand All @@ -43,8 +42,11 @@ manual.txt
# Ignore specific development and build scripts
run_dev.bat
build.bat
build.sh
build.spec
pack.bat
setup_env.bat
setup_env.sh

# Docker-specific files
Dockerfile
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/dev-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,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 @@ -201,7 +201,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
69 changes: 51 additions & 18 deletions build.bat
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,18 +1,51 @@
@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" (
echo Installing PyInstaller...
"%dirpath%\env\scripts\pip" install pyinstaller
if errorlevel 1 (
echo:
echo Failed to install PyInstaller.
echo:
pause
exit /b 1
)
"%dirpath%\env\scripts\python" "%dirpath%\env\scripts\pywin32_postinstall.py" -install -silent
if errorlevel 1 (
echo:
echo Failed to run pywin32_postinstall.py.
echo:
pause
exit /b 1
)
)

REM Run PyInstaller with the specified build spec file
echo Building...
"%dirpath%\env\scripts\pyinstaller" "%dirpath%\build.spec"
if errorlevel 1 (
echo:
echo PyInstaller build failed.
echo:
pause
exit /b 1
)

echo:
echo Build completed successfully.
echo:
pause
43 changes: 43 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/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..."
exit 1
fi

# Check if PyInstaller is installed in the virtual environment
if [ ! -f "$dirpath/env/bin/pyinstaller" ]; then
echo
echo "Installing PyInstaller..."
"$dirpath/env/bin/pip" install pyinstaller
if [ $? -ne 0 ]; then
echo
echo "Failed to install PyInstaller."
echo
read -p "Press any key to continue..."
exit 1
fi
fi

# Run PyInstaller with the specified build spec file
echo
echo "Running PyInstaller..."
"$dirpath/env/bin/pyinstaller" "$dirpath/build.spec"
if [ $? -ne 0 ]; then
echo
echo "PyInstaller build failed."
echo
read -p "Press any key to continue..."
exit 1
fi

echo
echo "Build completed successfully."
echo
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).
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

0 comments on commit d55f371

Please sign in to comment.