aebe5f1aa6
Adds a post-processing step to ensure desktop entry and icon files are correctly placed in DEB packages built via alien, addressing issues where alien may miss proper desktop integration.
312 lines
9.7 KiB
YAML
312 lines
9.7 KiB
YAML
name: Build Linux Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
env:
|
|
PYTHON_VERSION: '3.13.6'
|
|
|
|
jobs:
|
|
build-linux:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Extract version from tag
|
|
id: get_version
|
|
shell: bash
|
|
run: |
|
|
tag="${GITHUB_REF_NAME}"
|
|
version="${tag#v}"
|
|
echo "Extracted version: $version"
|
|
echo "VERSION=$version" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Setup Python
|
|
uses: actions/setup-python@v4
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- name: Cache Python dependencies
|
|
uses: actions/cache@v3
|
|
with:
|
|
path: |
|
|
venv
|
|
~/.cache/pip
|
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-pip-
|
|
|
|
- name: Install system dependencies
|
|
shell: bash
|
|
run: |
|
|
sudo apt-get update -y
|
|
# Tools commonly required by cx_Freeze on Linux packaging
|
|
sudo apt-get install -y --no-install-recommends \
|
|
rpm alien fakeroot patchelf desktop-file-utils file xz-utils zsync
|
|
|
|
- name: Create virtual environment and install dependencies
|
|
shell: bash
|
|
run: |
|
|
python -m venv venv
|
|
source venv/bin/activate
|
|
python -m pip install --upgrade pip
|
|
pip install --no-cache-dir -r requirements.txt
|
|
pip install --no-cache-dir cx_Freeze yt-dlp
|
|
|
|
- name: Prepare build variables
|
|
shell: bash
|
|
run: |
|
|
version="${{ steps.get_version.outputs.VERSION }}"
|
|
echo "VERSION=$version" >> "$GITHUB_ENV"
|
|
arch="$(uname -m)" # x86_64 or aarch64
|
|
echo "ARCH=$arch" >> "$GITHUB_ENV"
|
|
echo "Prepared build variables for version: $version on $(uname -a)"
|
|
|
|
- name: Create cx_Freeze setup script (Linux)
|
|
shell: bash
|
|
run: |
|
|
cat > setup_cxfreeze.py <<'PY'
|
|
import os
|
|
from cx_Freeze import setup, Executable
|
|
|
|
version = os.environ.get("VERSION", "0.0.0")
|
|
|
|
build_exe_options = dict(
|
|
optimize=2,
|
|
packages=[
|
|
"PySide6.QtCore",
|
|
"PySide6.QtGui",
|
|
"PySide6.QtWidgets",
|
|
"requests",
|
|
"PIL",
|
|
"packaging",
|
|
"markdown",
|
|
"pyglet",
|
|
"loguru",
|
|
"setuptools",
|
|
],
|
|
excludes=[
|
|
"PySide6.QtBluetooth",
|
|
"PySide6.QtNetwork",
|
|
"PySide6.QtOpenGL",
|
|
"PySide6.QtPrintSupport",
|
|
"PySide6.QtSvg",
|
|
"PySide6.QtTest",
|
|
"PySide6.QtXml",
|
|
"PySide6.QtSql",
|
|
"PySide6.QtHelp",
|
|
"PySide6.QtMultimedia",
|
|
"PySide6.QtQml",
|
|
"PySide6.QtQuick",
|
|
"PySide6.QtWebEngineCore",
|
|
"PIL.ImageDraw",
|
|
"PIL.ImageFont",
|
|
"numpy",
|
|
"scipy",
|
|
"wx",
|
|
"pandas",
|
|
"tkinter",
|
|
"yt_dlp",
|
|
"unittest",
|
|
"test",
|
|
"tests",
|
|
],
|
|
include_files=[
|
|
("src", "src"),
|
|
("assets", "assets"),
|
|
("ytsage.desktop", "share/applications/ytsage.desktop"),
|
|
("assets/branding/icons/icon.png", "share/pixmaps/ytsage.png"),
|
|
],
|
|
)
|
|
|
|
executables = [
|
|
Executable(
|
|
script="main.py",
|
|
target_name="ytsage",
|
|
icon="assets/branding/icons/icon.png",
|
|
)
|
|
]
|
|
|
|
setup(
|
|
name="ytsage",
|
|
version=version,
|
|
description="YTSage",
|
|
options={
|
|
"build_exe": build_exe_options,
|
|
# AppImage packaging
|
|
"bdist_appimage": {
|
|
# If ends with .AppImage, use verbatim file name
|
|
"target_name": f"ytsage-v{version}.AppImage",
|
|
},
|
|
# RPM packaging metadata
|
|
"bdist_rpm": {
|
|
"release": "1",
|
|
"group": "Applications/Multimedia",
|
|
},
|
|
# DEB packaging wraps alien to convert RPM
|
|
"bdist_deb": {},
|
|
},
|
|
executables=executables,
|
|
)
|
|
PY
|
|
|
|
- name: Create desktop entry
|
|
shell: bash
|
|
run: |
|
|
cat > ytsage.desktop <<'DESKTOP'
|
|
[Desktop Entry]
|
|
Type=Application
|
|
Name=YTSage
|
|
Comment=YouTube downloader
|
|
Exec=ytsage %U
|
|
Icon=ytsage
|
|
Terminal=false
|
|
Categories=AudioVideo;Network;Utility;
|
|
StartupWMClass=YTSage
|
|
DESKTOP
|
|
|
|
- name: Build AppImage, RPM and DEB
|
|
shell: bash
|
|
run: |
|
|
set -e
|
|
source venv/bin/activate
|
|
|
|
# Ensure a clean build and build_exe first
|
|
python setup_cxfreeze.py build_exe
|
|
|
|
# Remove screenshots to reduce size before packaging
|
|
build_dir=$(ls -d build/exe.* 2>/dev/null | head -n1 || true)
|
|
if [ -n "$build_dir" ] && [ -d "$build_dir/assets/branding/screenshots" ]; then
|
|
rm -rf "$build_dir/assets/branding/screenshots"
|
|
echo "Removed screenshots folder from $build_dir"
|
|
fi
|
|
|
|
# Build AppImage
|
|
python setup_cxfreeze.py bdist_appimage
|
|
|
|
# Build RPM
|
|
python setup_cxfreeze.py bdist_rpm
|
|
|
|
# Build DEB (via alien from RPM)
|
|
python setup_cxfreeze.py bdist_deb || echo "bdist_deb completed with warnings (alien)"
|
|
|
|
# Fix DEB desktop integration (alien sometimes misses this)
|
|
deb_file=$(ls dist/ytsage_*.deb 2>/dev/null | head -n1 || true)
|
|
if [ -n "$deb_file" ]; then
|
|
echo "Fixing DEB desktop integration for: $deb_file"
|
|
|
|
# Create temporary directory for DEB extraction
|
|
temp_deb_dir=$(mktemp -d)
|
|
cd "$temp_deb_dir"
|
|
|
|
# Extract the DEB package
|
|
ar x "$GITHUB_WORKSPACE/$deb_file"
|
|
|
|
# Extract the data archive
|
|
mkdir -p data
|
|
cd data
|
|
tar xf ../data.tar.xz
|
|
|
|
# Ensure desktop files are properly placed
|
|
if [ ! -d "usr/share/applications" ]; then
|
|
mkdir -p usr/share/applications
|
|
fi
|
|
if [ ! -d "usr/share/pixmaps" ]; then
|
|
mkdir -p usr/share/pixmaps
|
|
fi
|
|
|
|
# Copy desktop entry if it exists in the package but not in the right place
|
|
if [ -f "usr/lib/ytsage-${version}/share/applications/ytsage.desktop" ] && [ ! -f "usr/share/applications/ytsage.desktop" ]; then
|
|
cp "usr/lib/ytsage-${version}/share/applications/ytsage.desktop" "usr/share/applications/"
|
|
echo "Copied desktop entry to proper location"
|
|
fi
|
|
|
|
# Copy icon if it exists in the package but not in the right place
|
|
if [ -f "usr/lib/ytsage-${version}/share/pixmaps/ytsage.png" ] && [ ! -f "usr/share/pixmaps/ytsage.png" ]; then
|
|
cp "usr/lib/ytsage-${version}/share/pixmaps/ytsage.png" "usr/share/pixmaps/"
|
|
echo "Copied icon to proper location"
|
|
fi
|
|
|
|
# Repackage the data archive
|
|
tar cJf ../data.tar.xz ./*
|
|
cd ..
|
|
|
|
# Create the fixed DEB package
|
|
ar r "${GITHUB_WORKSPACE}/${deb_file}" debian-binary control.tar.xz data.tar.xz
|
|
|
|
# Clean up
|
|
cd "$GITHUB_WORKSPACE"
|
|
rm -rf "$temp_deb_dir"
|
|
|
|
echo "DEB package desktop integration fixed"
|
|
fi
|
|
|
|
echo "Post-build directory listing:"
|
|
echo "-- dist --"; ls -lah dist || true
|
|
echo "-- build --"; ls -lah build || true
|
|
|
|
- name: Package and prepare release artifacts (.AppImage, .rpm, .deb)
|
|
shell: bash
|
|
run: |
|
|
version="${{ steps.get_version.outputs.VERSION }}"
|
|
mkdir -p artifacts
|
|
|
|
# Copy AppImage
|
|
appimage_src=$(ls dist/ytsage-v*.AppImage 2>/dev/null | head -n1 || true)
|
|
if [ -n "$appimage_src" ]; then
|
|
cp "$appimage_src" "artifacts/YTSage-v${version}-${ARCH}.AppImage"
|
|
echo "Copied AppImage: $appimage_src -> artifacts/YTSage-v${version}-${ARCH}.AppImage"
|
|
else
|
|
echo "Warning: No .AppImage found in dist/"
|
|
fi
|
|
|
|
# Copy RPM (normalize name)
|
|
rpm_src=$(ls dist/ytsage-*.rpm 2>/dev/null | head -n1 || true)
|
|
if [ -n "$rpm_src" ]; then
|
|
cp "$rpm_src" "artifacts/YTSage-v${version}-${ARCH}.rpm"
|
|
echo "Copied RPM: $rpm_src -> artifacts/YTSage-v${version}-${ARCH}.rpm"
|
|
else
|
|
echo "Warning: No .rpm found in dist/"
|
|
fi
|
|
|
|
# Copy DEB (normalize name)
|
|
deb_src=$(ls dist/ytsage_*.deb 2>/dev/null | head -n1 || true)
|
|
if [ -n "$deb_src" ]; then
|
|
cp "$deb_src" "artifacts/YTSage-v${version}-${ARCH}.deb"
|
|
echo "Copied DEB: $deb_src -> artifacts/YTSage-v${version}-${ARCH}.deb"
|
|
else
|
|
echo "Warning: No .deb found in dist/"
|
|
fi
|
|
|
|
echo "Final artifacts:"
|
|
ls -lh artifacts || true
|
|
|
|
- name: Create/Update draft release
|
|
uses: softprops/action-gh-release@v1
|
|
with:
|
|
tag_name: ${{ github.ref_name }}
|
|
name: YTSage ${{ github.ref_name }}
|
|
draft: true
|
|
prerelease: false
|
|
append_body: true
|
|
fail_on_unmatched_files: false
|
|
body: |
|
|
# YTSage ${{ github.ref_name }}
|
|
|
|
**Release Date**: ${{ github.event.head_commit.timestamp }}
|
|
|
|
**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ github.ref_name }}
|
|
files: |
|
|
artifacts/*
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|