diff --git a/.github/workflows/simple-release.yml b/.github/workflows/simple-release.yml index c9f0d1c..8146ef7 100644 --- a/.github/workflows/simple-release.yml +++ b/.github/workflows/simple-release.yml @@ -11,6 +11,19 @@ name: Build Multi-Platform Binaries on: workflow_dispatch: + inputs: + jobs: + description: "Comma-separated jobs to run (e.g., build-windows,build-debian,build-arch,build-rhel)" + required: true + default: "build-windows,build-debian,build-arch,build-rhel" + DO_RELEASE: + description: "Set to 'true' to create a GitHub release after successful builds" + required: false + default: "false" + UPLOAD_S3: + description: "Set to 'true' to upload build artifacts to S3 after builds" + required: false + default: "false" permissions: contents: write @@ -20,9 +33,11 @@ env: FPM_VERSION: "1.16.0" # Personal Access Token for HTTPS git operations (populate in repository secrets) CI_CD_PAT: ${{ secrets.CI_CD_PAT }} + CI_CD: true jobs: build-windows: + if: contains(github.event.inputs.jobs, 'build-windows') runs-on: windows-latest steps: - name: Checkout code @@ -60,18 +75,26 @@ jobs: uses: actions/upload-artifact@v4 with: name: windows-binary - path: dist/android-file-handler.exe - + path: | + dist/**/android-file-handler*.exe + dist/android-file-handler.exe + build-debian: + if: contains(github.event.inputs.jobs, 'build-debian') + env: + DISTRO_TYPE: debian runs-on: ubuntu-latest container: image: python:3.12-slim steps: - - name: Install system dependencies & gem fpm + - name: Install system dependencies & gem fpm (include Tcl/Tk) run: | set -euo pipefail apt-get update - apt-get install -y --no-install-recommends curl git build-essential ruby ruby-dev gcc make zlib1g-dev ca-certificates + # Install Tcl/Tk runtimes, dev headers and common X libraries required by tkinter + apt-get install -y --no-install-recommends \ + curl git build-essential ruby ruby-dev gcc make zlib1g-dev ca-certificates python3-tk \ + tcl8.6 tk8.6 tcl8.6-dev tk8.6-dev libx11-6 libxext6 libxrender1 libxcb1 # install pinned fpm to the system gem dir (will be available under gem env's EXECUTABLE DIRECTORY or /usr/local/bin) gem install --no-document -v "${FPM_VERSION}" fpm @@ -101,27 +124,49 @@ jobs: run: | export PATH="$HOME/.local/bin:$PATH" poetry env use python3.12 || true - poetry install - # Use the Linux spec file for reproducible builds - poetry run pyinstaller scripts/spec_scripts/android-file-handler-linux.spec + # Debug: show tkinter/_tkinter and Tcl library discovery in the Poetry venv + poetry run python -c 'import tkinter, _tkinter, sys; print("tkinter=", getattr(tkinter, "__file__", None)); print("_tkinter=", getattr(_tkinter, "__file__", None)); import tkinter as tk; print("TCL_LIBRARY=", tk.Tcl().eval("info library"))' + + # Build distro-specific package layout using the build script via Poetry + poetry run python scripts/build_package_linux.py - name: Package .deb (fpm) + shell: bash run: | set -euo pipefail export PATH="$HOME/.local/bin:$PATH" VERSION="$(poetry version -s)" + PKG_DIR="pkg_dist_debian" mkdir -p dist - chmod +x dist/android-file-handler - # explicit filename into dist/ - fpm -s dir -t deb -n android-file-handler -v "$VERSION" --architecture amd64 --prefix /usr/local/bin -p "dist/android-file-handler_${VERSION}_amd64.deb" dist/android-file-handler + # Debug listing + echo "Packaging from $PKG_DIR" + ls -la "$PKG_DIR" || true + + ICON_PATH="$PKG_DIR/usr/share/icons/hicolor/256x256/apps/android-file-handler.png" + PKG_ITEMS=( "usr/local/bin/android-file-handler" "usr/share/applications/android-file-handler.desktop" ) + if [ -f "$ICON_PATH" ]; then + PKG_ITEMS+=( "usr/share/icons/hicolor/256x256/apps/android-file-handler.png" ) + else + echo "Note: icon not present, packaging without icon" + fi + + fpm -s dir -t deb -n android-file-handler -v "$VERSION" \ + --architecture amd64 --prefix /usr/local/bin --deb-user root --deb-group root \ + --after-install scripts/debian_postinst.sh \ + -p "dist/android-file-handler_${VERSION}_amd64.deb" -C "$PKG_DIR" "${PKG_ITEMS[@]}" - name: Upload Debian .deb uses: actions/upload-artifact@v4 with: name: debian-package - path: dist/android-file-handler_*.deb + path: | + dist/android-file-handler_*.deb + pkg_dist_debian/** build-arch: + if: contains(github.event.inputs.jobs, 'build-arch') + env: + DISTRO_TYPE: arch runs-on: ubuntu-latest container: image: archlinux:latest @@ -130,10 +175,10 @@ jobs: run: | set -euo pipefail pacman -Syu --noconfirm - pacman -S --noconfirm ruby base-devel curl git tar ca-certificates - # Install fpm system-wide and pin version so fpm will be in /usr/local/bin + pacman -S --noconfirm ruby base-devel curl git tar ca-certificates tk tcl libx11 libxext libxrender libxcb + # Install fpm system-wide and pin version so fpm will be in /usr/in gem install --no-document erb - gem install --no-document -v "${FPM_VERSION}" fpm --bindir /usr/local/bin + gem install --no-document -v "${FPM_VERSION}" fpm --bindir /usr/bin # persist system bindir to subsequent steps (usually already on PATH) echo "/usr/local/bin" >> $GITHUB_PATH @@ -154,36 +199,148 @@ jobs: - name: Configure Poetry run: | - echo 'export PATH="$HOME/.local/bin:$PATH"' >> $GITHUB_ENV - export PATH="$HOME/.local/bin:$PATH" + echo 'export PATH="$HOME/bin:$PATH"' >> $GITHUB_ENV + export PATH="$HOME/bin:$PATH" - name: Install dependencies & build executable run: | - export PATH="$HOME/.local/bin:/usr/local/bin:$PATH" - poetry install - # Use the Linux spec file for reproducible builds on Arch - poetry run pyinstaller scripts/spec_scripts/android-file-handler-linux.spec + export PATH="$HOME/bin:/usr/bin:$PATH" + # Use unified build script to produce pkg_dist_arch layout via Poetry + poetry run python scripts/build_package_linux.py - name: Package pacman (fpm) + shell: bash run: | set -euo pipefail - export PATH="$HOME/.local/bin:/usr/local/bin:$PATH" + export PATH="$HOME/.local/bin:/usr/bin:$PATH" VERSION="$(poetry version -s)" + PKG_DIR="pkg_dist_arch" mkdir -p dist - chmod +x dist/android-file-handler - # explicit filename into dist/ - fpm -s dir -t pacman -n android-file-handler -v "$VERSION" --architecture x86_64 --prefix /usr/local/bin -p "dist/android-file-handler-${VERSION}-1-x86_64.pkg.tar.zst" dist/android-file-handler + echo "Packaging from $PKG_DIR" + ls -la "$PKG_DIR" || true + + ICON_PATH="$PKG_DIR/usr/share/icons/hicolor/256x256/apps/android-file-handler.png" + PKG_ITEMS=( "usr/bin/android-file-handler" "usr/share/applications/android-file-handler.desktop" ) + if [ -f "$ICON_PATH" ]; then + PKG_ITEMS+=( "usr/share/icons/hicolor/256x256/apps/android-file-handler.png" ) + else + echo "Note: icon not present, packaging without icon" + fi + + fpm -s dir -t pacman -n android-file-handler -v "$VERSION" \ + --architecture x86_64 --prefix /usr/bin \ + -p "dist/android-file-handler-${VERSION}-1-x86_64.pkg.tar.zst" -C "$PKG_DIR" "${PKG_ITEMS[@]}" - name: Upload Arch package uses: actions/upload-artifact@v4 with: name: arch-package - path: dist/*.pkg.tar.* + path: | + dist/*.pkg.tar.* + pkg_dist_arch/** + + + build-rhel: + if: contains(github.event.inputs.jobs, 'build-rhel') + env: + DISTRO_TYPE: rhel + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Update OS and install Docker + run: | + set -euo pipefail + sudo apt-get update + # Remove possible conflicting containerd packages that can block docker.io installation + sudo apt-get remove -y --purge containerd containerd.io || true + sudo apt-get autoremove -y || true + # Try installing docker.io from distro packages + if ! sudo apt-get install -y --no-install-recommends ca-certificates curl gnupg lsb-release docker.io git build-essential; then + echo "apt install docker.io failed; falling back to Docker convenience script" + # Fallback: use Docker's official convenience script + curl -fsSL https://get.docker.com | sudo sh + fi + sudo usermod -aG docker $USER || true + + - name: Pull Fedora container image + run: | + docker pull fedora:latest + + - name: Start Fedora container (background) and mount repo + run: | + # Run container with workspace mounted + docker run -d --name rhel-build -v "$PWD":/workspace -w /workspace fedora:latest sleep infinity + + - name: Prepare container build environment (dnf, pyenv, python, poetry, fpm) + run: | + set -euo pipefail + # Update the Fedora image and install build deps + docker exec rhel-build bash -lc "dnf -y update && dnf -y install gcc make zlib-devel bzip2 bzip2-devel readline-devel sqlite-devel openssl-devel libffi-devel wget tar git curl ruby rubygems rpm-build redhat-rpm-config gcc-c++ patch which xz-devel" + + # Install pyenv into the container (if not present) + docker exec rhel-build bash -lc "[ -d \"/root/.pyenv\" ] || git clone https://github.com/pyenv/pyenv.git /root/.pyenv && mkdir -p /root/.pyenv/plugins && [ -d \"/root/.pyenv/plugins/python-build\" ] || git clone https://github.com/pyenv/pyenv-build.git /root/.pyenv/plugins/python-build" + + # Install Python 3.12 via pyenv and set global using explicit pyenv binary path + # Use single quotes so $PYENV_ROOT and $PATH are expanded inside the container's shell + docker exec rhel-build bash -lc 'export PYENV_ROOT="/root/.pyenv"; export PATH="$PYENV_ROOT/bin:$PATH"; /root/.pyenv/bin/pyenv install -s 3.12.0; /root/.pyenv/bin/pyenv global 3.12.0; /root/.pyenv/bin/pyenv rehash' + + # Install Poetry inside the container using the official installer (install to /root/.local/bin) + # Use single quotes so PATH is evaluated inside the container shell rather than the runner + docker exec rhel-build bash -lc 'export PATH="/root/.pyenv/shims:/root/.pyenv/bin:$PATH"; curl -sSL https://install.python-poetry.org | python3 - --yes' + + # Verify Poetry is available via explicit path if not on PATH + docker exec rhel-build bash -lc "/root/.local/bin/poetry --version || echo 'Poetry not found in /root/.local/bin'" + + # Install fpm (Ruby gem) and ensure rpm build tools exist + docker exec rhel-build bash -lc "dnf -y install ruby rubygems make && gem install --no-document -v \"${FPM_VERSION}\" fpm" + + - name: Build inside container using Poetry + run: | + set -euo pipefail + # Use poetry inside the container to build package layouts. Use explicit paths so the runner shell + # doesn't expand $HOME; expansion should occur inside the container. + docker exec rhel-build bash -lc 'export PATH="/root/.local/bin:/root/.pyenv/shims:/root/.pyenv/bin:$PATH"; export CI_CD=true; export DISTRO_TYPE=rhel; cd /workspace && /root/.local/bin/poetry install --no-interaction && /root/.local/bin/poetry run python scripts/build_package_linux.py' + + - name: Package RHEL (fpm) inside container + shell: bash + run: | + # Run the entire packaging flow inside the Fedora container so Poetry, PATH and arrays are evaluated in-container. + docker exec rhel-build bash -lc ' + set -euo pipefail + VERSION="$(/root/.local/bin/poetry version -s)" + PKG_DIR="pkg_dist_rhel" + mkdir -p dist || true + echo "Packaging from $PKG_DIR (version=$VERSION)" + ls -la "$PKG_DIR" || true + + ICON_PATH="$PKG_DIR/usr/share/icons/hicolor/256x256/apps/android-file-handler.png" + PKG_ITEMS=( "usr/bin/android-file-handler" "usr/share/applications/android-file-handler.desktop" ) + if [ -f "$ICON_PATH" ]; then + PKG_ITEMS+=( "usr/share/icons/hicolor/256x256/apps/android-file-handler.png" ) + else + echo "Note: icon not present, packaging without icon" + fi + + # Run fpm inside the container to produce an RPM + cd /workspace + exec fpm -s dir -t rpm -n android-file-handler -v "$VERSION" --architecture x86_64 --prefix /usr/bin --after-install scripts/rhel_postinst.sh -p "dist/android-file-handler-${VERSION}.x86_64.rpm" -C "$PKG_DIR" "${PKG_ITEMS[@]}" + ' + + - name: Upload RHEL artifacts + uses: actions/upload-artifact@v4 + with: + name: rhel-package + path: | + dist/*.rpm + pkg_dist_rhel/** create-release: - needs: [build-windows, build-debian, build-arch] + needs: [build-windows, build-debian, build-arch, build-rhel] + if: ${{ github.event.inputs.DO_RELEASE == 'true' && needs.build-windows.result == 'success' && needs.build-debian.result == 'success' && needs.build-arch.result == 'success' && needs.build-rhel.result == 'success' }} runs-on: ubuntu-latest steps: - name: Checkout code @@ -219,4 +376,77 @@ jobs: draft: false prerelease: false env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + upload-s3: + needs: [build-windows, build-debian, build-arch, build-rhel] + if: ${{ github.event.inputs.UPLOAD_S3 == 'true' || contains(github.event.inputs.jobs, 'upload-s3') }} + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install AWS CLI + run: | + python -m pip install --upgrade pip awscli + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + merge-multiple: true + path: ./binaries + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Upload artifacts to S3 + run: | + set -euo pipefail + if [ -z "${{ secrets.S3_BUCKET }}" ]; then + echo "S3_BUCKET secret not set; skipping upload" + exit 0 + fi + aws s3 sync ./binaries s3://${{ secrets.S3_BUCKET }}/builds/${{ github.run_id }}/ --acl private + env: + AWS_PAGER: "" + + sync-wiki: + needs: create-release + runs-on: ubuntu-latest + steps: + - name: Checkout main repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Checkout wiki repo + run: | + git clone "https://github.com/${GITHUB_REPOSITORY}.wiki.git" wiki + + - name: Sync WIKI.md to Wiki/Home.md + run: | + set -e + SRC_FILE="WIKI.md" + DEST_FILE="wiki/Home.md" + + if [ ! -f "$SRC_FILE" ]; then + echo "No $SRC_FILE in main repo; skipping." + exit 0 + fi + + if ! cmp -s "$SRC_FILE" "$DEST_FILE"; then + echo "Changes found, updating wiki..." + cp "$SRC_FILE" "$DEST_FILE" + cd wiki + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add Home.md + git commit -m "Sync WIKI.md from main repo [skip ci]" || echo "No changes to commit" + git push + else + echo "No changes in $SRC_FILE; wiki is up to date." + fi \ No newline at end of file diff --git a/.gitignore b/.gitignore index 84cba60..a91cd38 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ platform-tools** -dist/ +dist* build_temp/ build *.ini @@ -7,7 +7,7 @@ build .actrc bin/ test-act.yml -pkg_dist +pkg_dist* # Python cache files __pycache__/ diff --git a/scripts/build_package_linux.py b/scripts/build_package_linux.py new file mode 100755 index 0000000..add07a6 --- /dev/null +++ b/scripts/build_package_linux.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python3 + +import os +import subprocess +import shutil +import sys +from pathlib import Path +from enum import Enum +from typing import List + + +class DistroType(Enum): + DEBIAN = "debian" + ARCH = "arch" + RHEL = "rhel" + + +def run_command(cmd: list[str], check: bool = True) -> subprocess.CompletedProcess: + """Run command and handle errors.""" + print(f"Running: {' '.join(cmd)}") + try: + return subprocess.run(cmd, check=check, capture_output=False) + except subprocess.CalledProcessError as e: + print(f"Command failed with exit code {e.returncode}: {' '.join(cmd)}") + sys.exit(e.returncode) + + +def get_distro_config(distro_type: DistroType) -> dict: + """Get configuration for specific distro type.""" + configs = { + DistroType.DEBIAN: { + "name": "Debian", + "bin_path": "usr/local/bin", + "pkg_suffix": "debian", + "spec_file": "scripts/spec_scripts/android-file-handler-debian.spec" + }, + DistroType.ARCH: { + "name": "Arch", + "bin_path": "usr/bin", + "pkg_suffix": "arch", + "spec_file": "scripts/spec_scripts/android-file-handler-arch.spec" + }, + DistroType.RHEL: { + "name": "RHEL", + "bin_path": "usr/bin", + "pkg_suffix": "rhel", + "spec_file": "scripts/spec_scripts/android-file-handler-rhel.spec" + } + } + return configs[distro_type] + + +def prompt_distro_selection() -> List[DistroType]: + """Prompt user for distro selection.""" + print("Select distribution(s) to build for:") + print("1. Debian") + print("2. Arch") + print("3. RHEL") + print("4. All distributions") + + while True: + choice = input("Enter choice (1-4): ").strip() + if choice == "1": + return [DistroType.DEBIAN] + elif choice == "2": + return [DistroType.ARCH] + elif choice == "3": + return [DistroType.RHEL] + elif choice == "4": + return [DistroType.DEBIAN, DistroType.ARCH, DistroType.RHEL] + else: + print("Invalid choice. Please enter 1, 2, 3, or 4.") + + +def build_for_distro(distro_type: DistroType, version: str) -> None: + """Build package for specific distro type.""" + config = get_distro_config(distro_type) + print(f"\n=== Building for {config['name']} ===") + + # Build with distro-specific spec file + print(f"Building binary using {config['spec_file']}") + run_command([ + "poetry", "run", "pyinstaller", + config['spec_file'], + "--distpath", f"dist_{config['pkg_suffix']}" + ]) + + # Make binary executable + binary_path = Path(f"dist_{config['pkg_suffix']}/android-file-handler") + binary_path.chmod(0o755) + + # Package preparation + pkg_dir = Path(f"pkg_dist_{config['pkg_suffix']}") + + # Clean and create package structure + if pkg_dir.exists(): + shutil.rmtree(pkg_dir) + + directories = [ + config["bin_path"], + "usr/share/applications", + "usr/share/icons/hicolor/256x256/apps" + ] + + for directory in directories: + (pkg_dir / directory).mkdir(parents=True, exist_ok=True) + + # Copy built binary + binary_dst = pkg_dir / config["bin_path"] / "android-file-handler" + shutil.copy2(f"dist_{config['pkg_suffix']}/android-file-handler", binary_dst) + binary_dst.chmod(0o755) + + # Handle icon + icon_src = Path("icon_media/robot_files_256.png") + icon_dst = pkg_dir / "usr/share/icons/hicolor/256x256/apps/android-file-handler.png" + icon_included = False + + if icon_src.exists(): + shutil.copy2(icon_src, icon_dst) + icon_dst.chmod(0o644) + icon_included = True + else: + print(f"Warning: icon not found at {icon_src}; packaging without icon") + + # Create .desktop file with correct exec path + exec_path = f"/{config['bin_path']}/android-file-handler" + desktop_content = f"""[Desktop Entry] +Type=Application +Name=Android File Handler +Comment=Manage Android device files via ADB +Exec={exec_path} %U +Icon=android-file-handler +Terminal=false +Categories=Utility;Development; +StartupNotify=true +""" + + desktop_path = pkg_dir / "usr/share/applications/android-file-handler.desktop" + desktop_path.write_text(desktop_content) + desktop_path.chmod(0o644) + + # Build package items list + pkg_items = [ + f"{config['bin_path']}/android-file-handler", + "usr/share/applications/android-file-handler.desktop" + ] + + if icon_included: + pkg_items.append("usr/share/icons/hicolor/256x256/apps/android-file-handler.png") + + # Debug listing + print(f"Packaging the following items for {config['name']} (relative to {pkg_dir}):") + for item in pkg_items: + print(f" - {item}") + item_path = pkg_dir / item + if item_path.exists(): + stat = item_path.stat() + print(f" {oct(stat.st_mode)[-3:]} {stat.st_size:>8} {item_path}") + else: + print(f" (missing) {item_path}") + + +def main(): + # Check if running in CI/CD mode + is_ci_cd = os.environ.get("CI_CD", "false").lower() == "true" + + if is_ci_cd: + distro_env = os.environ.get("DISTRO_TYPE", "").lower() + if distro_env == "debian": + selected_distros = [DistroType.DEBIAN] + print("CI/CD mode detected - building for Debian") + elif distro_env == "arch": + selected_distros = [DistroType.ARCH] + print("CI/CD mode detected - building for Arch") + elif distro_env == "rhel": + selected_distros = [DistroType.RHEL] + print("CI/CD mode detected - building for RHEL") + else: + print(f"Error: Invalid or missing DISTRO_TYPE environment variable: '{distro_env}'") + print("Valid values: debian, arch, rhel") + sys.exit(1) + else: + selected_distros = prompt_distro_selection() + + # Poetry operations (only once) + print("=== Preparing Poetry environment ===") + if is_ci_cd: + print("CI/CD mode: skipping poetry lock") + run_command(["poetry", "install"]) + else: + print("Development mode: running poetry lock and install") + run_command(["poetry", "lock"]) + run_command(["poetry", "install"]) + + # Get version from Poetry + result = subprocess.run( + ["poetry", "version", "-s"], + capture_output=True, + text=True, + check=True + ) + version = result.stdout.strip() + print(f"Version: {version}") + + # Build for selected distributions + for distro_type in selected_distros: + build_for_distro(distro_type, version) + + print(f"\n=== Build complete for: {', '.join([get_distro_config(d)['name'] for d in selected_distros])} ===") + + # Show output directories + print("\nOutput directories:") + for distro_type in selected_distros: + config = get_distro_config(distro_type) + print(f" {config['name']}: pkg_dist_{config['pkg_suffix']}/") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/scripts/build_package_linux.sh b/scripts/build_package_linux.sh index a8bd54c..d7fe3b7 100755 --- a/scripts/build_package_linux.sh +++ b/scripts/build_package_linux.sh @@ -7,16 +7,16 @@ poetry install # Build using the Linux spec so the build is reproducible and uses the project spec poetry run pyinstaller /home/jasonross/workspace/android_file_handler_adb/scripts/spec_scripts/android-file-handler-linux.spec --distpath dist -# Package into a Debian .deb using fpm +# Package into a Linux .deb using fpm export PATH="$HOME/.local/bin:/usr/local/bin:$PATH" VERSION="$(poetry version -s)" mkdir -p dist chmod +x dist/android-file-handler -# explicit filename into dist/ (Debian .deb) +# explicit filename into dist/ (Linux .(binary type)) # change directory into dist and package the binary named 'android-file-handler' # this ensures the package installs /usr/local/bin/android-file-handler (no extra dist/ prefix) -# Debian +# Linux # Prepare packaging layout in a separate directory to avoid clobbering build artifacts PKG_DIR="pkg_dist" rm -rf "$PKG_DIR" @@ -56,7 +56,7 @@ StartupNotify=true EOF chmod 644 "$PKG_DIR/usr/share/applications/android-file-handler.desktop" -# Build the Debian package and include postinst script +# Build the Linux package and include postinst script PKG_ITEMS=( "usr/local/bin/android-file-handler" "usr/share/applications/android-file-handler.desktop" ) if [ "$ICON_INCLUDED" = true ]; then PKG_ITEMS+=( "usr/share/icons/hicolor/256x256/apps/android-file-handler.png" ) diff --git a/scripts/linux_postinst.sh b/scripts/debian_postinst.sh similarity index 100% rename from scripts/linux_postinst.sh rename to scripts/debian_postinst.sh diff --git a/scripts/rhel_postinst.sh b/scripts/rhel_postinst.sh new file mode 100644 index 0000000..19307d2 --- /dev/null +++ b/scripts/rhel_postinst.sh @@ -0,0 +1,26 @@ +#!/bin/sh +set -e + +# Post-installation script for android-file-handler +# - update desktop database if available +# - update icon cache if available +# - ensure binary is executable + +# Update desktop database if the utility exists +if command -v update-desktop-database >/dev/null 2>&1; then + update-desktop-database /usr/share/applications || true +fi + +# Update GTK icon cache for hicolor theme if utility exists +if command -v gtk-update-icon-cache >/dev/null 2>&1; then + if [ -d /usr/share/icons/hicolor ]; then + gtk-update-icon-cache -t -f /usr/share/icons/hicolor || true + fi +fi + +# Ensure installed binary is executable +if [ -f /usr/local/bin/android-file-handler ]; then + chmod 0755 /usr/bin/android-file-handler || true +fi + +exit 0 diff --git a/scripts/spec_scripts/android-file-handler-arch.spec b/scripts/spec_scripts/android-file-handler-arch.spec new file mode 100644 index 0000000..e23ade1 --- /dev/null +++ b/scripts/spec_scripts/android-file-handler-arch.spec @@ -0,0 +1,47 @@ +block_cipher = None +a = Analysis( + ['../../src/main.py'], + pathex=['src'], + binaries=[], + datas=[ + ('../../src/gui', 'gui') + ], + hiddenimports=[ + 'gui', + 'gui.file_browser', + 'gui.license_agreement', + 'gui.main_window', + 'gui.progress_handler', + 'adb_manager' + ], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='android-file-handler', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=False, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) \ No newline at end of file diff --git a/scripts/spec_scripts/android-file-handler-linux.spec b/scripts/spec_scripts/android-file-handler-debian.spec similarity index 94% rename from scripts/spec_scripts/android-file-handler-linux.spec rename to scripts/spec_scripts/android-file-handler-debian.spec index 91d6397..50eef07 100644 --- a/scripts/spec_scripts/android-file-handler-linux.spec +++ b/scripts/spec_scripts/android-file-handler-debian.spec @@ -6,7 +6,7 @@ a = Analysis( binaries=[], datas=[ ('../../src/gui', 'gui'), - ('../../scripts/linux_postinst.sh', 'scripts'), + ('../../scripts/debian_postinst.sh', 'scripts'), ], hiddenimports=[ 'gui', diff --git a/scripts/spec_scripts/android-file-handler-rhel.spec b/scripts/spec_scripts/android-file-handler-rhel.spec new file mode 100644 index 0000000..9bd562c --- /dev/null +++ b/scripts/spec_scripts/android-file-handler-rhel.spec @@ -0,0 +1,48 @@ +block_cipher = None +a = Analysis( + ['../../src/main.py'], + pathex=['src'], + binaries=[], + datas=[ + ('../../src/gui', 'gui'), + ('../../scripts/rhel_postinst.sh', 'scripts'), + ], + hiddenimports=[ + 'gui', + 'gui.file_browser', + 'gui.license_agreement', + 'gui.main_window', + 'gui.progress_handler', + 'adb_manager' + ], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='android-file-handler', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=False, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) \ No newline at end of file diff --git a/scripts/spec_scripts/android-file-handler-windows.spec b/scripts/spec_scripts/android-file-handler-windows.spec index f5bfa10..4484f91 100644 --- a/scripts/spec_scripts/android-file-handler-windows.spec +++ b/scripts/spec_scripts/android-file-handler-windows.spec @@ -1,16 +1,16 @@ # -*- mode: python ; coding: utf-8 -*- block_cipher = None a = Analysis( - ['src/main.py'], - pathex=['src'], + ['../../src/main.py'], + pathex=['../..'], binaries=[], - datas=[('src/gui', 'gui'), ('../scripts/windows/first_run_install.ps1', 'scripts/windows')], + datas=[('../../src/gui', 'gui'), ('../windows/first_run_install.ps1', 'scripts/windows')], hiddenimports=[ 'gui', 'gui.file_browser', 'gui.license_agreement', 'gui.main_window', - 'gui.progress_handler' + 'gui.progress_handler', 'adb_manager' ], hookspath=[], @@ -43,5 +43,5 @@ exe = EXE( target_arch=None, codesign_identity=None, entitlements_file=None, - icon='icon_media/robot_files_256.ico', + icon='../../icon_media/robot_files_256.ico', ) \ No newline at end of file