Merge pull request #1 from jyapayne/create-macos-action
Add github actions for macos
This commit is contained in:
commit
cd6c0e507f
18 changed files with 850 additions and 29 deletions
362
.github/workflows/default.yml
vendored
Normal file
362
.github/workflows/default.yml
vendored
Normal file
|
|
@ -0,0 +1,362 @@
|
||||||
|
# This is a basic workflow to help you get started with Actions
|
||||||
|
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
# Controls when the workflow will run
|
||||||
|
on:
|
||||||
|
# Triggers the workflow on push or pull request events but only for the "master" branch
|
||||||
|
push:
|
||||||
|
branches: [ "master" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "master" ]
|
||||||
|
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||||
|
jobs:
|
||||||
|
ubuntu:
|
||||||
|
name: Build Ubuntu Debian package
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-20.04, ubuntu-22.04]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.10.8'
|
||||||
|
|
||||||
|
- name: Install prereqs
|
||||||
|
run: |
|
||||||
|
sudo apt install -y libegl-dev libxcb-keysyms1 libxcb-randr0 libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-shape0 libxcb-xkb1 libxcb-render-util0
|
||||||
|
|
||||||
|
- name: Setup Env Vars
|
||||||
|
run: |
|
||||||
|
echo "BUILD_DIR=build" >> $GITHUB_ENV
|
||||||
|
echo "DIST_DIR=dist" >> $GITHUB_ENV
|
||||||
|
FILE_LOC=$(find . -name info.py)
|
||||||
|
export VER="$(cat $FILE_LOC | grep -w version | awk -F'"' '$0=$2')"
|
||||||
|
export PROJ_NAME="$(cat $FILE_LOC | grep -w name | awk -F'"' '$0=$2')"
|
||||||
|
export PROJ_MOD="$(cat $FILE_LOC | grep -w module_name | awk -F'"' '$0=$2')"
|
||||||
|
export MAIN_FILE="$(cat $FILE_LOC | grep -w main_file | awk -F'"' '$0=$2')"
|
||||||
|
export MAIN_MOD="$(cat $FILE_LOC | grep -w main_module | awk -F'"' '$0=$2')"
|
||||||
|
export BUNDLE_ID="$(cat $FILE_LOC | grep -w bundle_identifier | awk -F'"' '$0=$2')"
|
||||||
|
export EMAIL="$(cat $FILE_LOC | grep -w email | awk -F'"' '$0=$2')"
|
||||||
|
export DESCRIPTION="$(cat $FILE_LOC | grep -w description | awk -F'"' '$0=$2')"
|
||||||
|
echo "VER=$VER" >> $GITHUB_ENV
|
||||||
|
echo "DESCRIPTION=$DESCRIPTION" >> $GITHUB_ENV
|
||||||
|
echo "PROJECT_NAME=$PROJ_NAME" >> $GITHUB_ENV
|
||||||
|
echo "PROJ_DIR=$PROJ_MOD" >> $GITHUB_ENV
|
||||||
|
echo "PROJ_PATH=$PROJ_MOD" >> $GITHUB_ENV
|
||||||
|
echo "PROJ_MOD=$PROJ_MOD" >> $GITHUB_ENV
|
||||||
|
echo "MAIN_MOD=$MAIN_MOD" >> $GITHUB_ENV
|
||||||
|
echo "MAIN_FILE=$MAIN_FILE" >> $GITHUB_ENV
|
||||||
|
echo "BUNDLE_ID=$BUNDLE_ID" >> $GITHUB_ENV
|
||||||
|
echo "EMAIL=$EMAIL" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Check Python install
|
||||||
|
run: |
|
||||||
|
pip3 install --upgrade pip
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
|
||||||
|
which python3
|
||||||
|
python3 --version
|
||||||
|
which pip3
|
||||||
|
pip3 --version
|
||||||
|
file python3
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
source venv/bin/activate
|
||||||
|
pip3 install -U pip setuptools wheel certifi
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
pip3 install py2app
|
||||||
|
PYINSTALLER_COMPILE_BOOTLOADER=1 MACOSX_DEPLOYMENT_TARGET=10.9 pip3 install https://github.com/pyinstaller/pyinstaller/tarball/develop --no-binary :all:
|
||||||
|
|
||||||
|
- name: Check Python dependencies
|
||||||
|
run: |
|
||||||
|
source venv/bin/activate
|
||||||
|
python3 -c "from PySide6 import __version__; print(__version__)"
|
||||||
|
python3 -c "from PySide6.QtCore import __version__; print(__version__)"
|
||||||
|
python3 -c "from PySide6.QtCore import QLibraryInfo; print(QLibraryInfo.location(QLibraryInfo.LibrariesPath))"
|
||||||
|
python3 -c "import ssl; print(ssl)"
|
||||||
|
python3 -c "from py2app.recipes import pyside6"
|
||||||
|
python3 -c 'from distutils.sysconfig import get_config_var; print(get_config_var("LDLIBRARY"))'
|
||||||
|
|
||||||
|
- name: Setup Deb
|
||||||
|
run: |
|
||||||
|
source venv/bin/activate
|
||||||
|
python3 create_pyinstaller_file.py
|
||||||
|
pyinstaller -w --noconfirm --hidden-import PySide6 \
|
||||||
|
--add-data "${{ env.PROJ_DIR }}/resources:." \
|
||||||
|
--icon "${{ env.PROJ_DIR }}/resources/icon.png" \
|
||||||
|
--hidden-import configobj \
|
||||||
|
--workpath "${{ env.BUILD_DIR }}" \
|
||||||
|
--distpath "${{ env.DIST_DIR }}" \
|
||||||
|
-n "${{ env.PROJ_MOD }}" pyinstaller.py
|
||||||
|
mv "${{ env.DIST_DIR }}/${{ env.PROJ_MOD }}" "./${{ env.PROJ_MOD }}-tar"
|
||||||
|
tar -czvf ${{ env.PROJ_MOD }}.tar.gz ${{ env.PROJ_MOD }}-tar/*
|
||||||
|
ci/deb-script.sh
|
||||||
|
|
||||||
|
- uses: jiro4989/build-deb-action@v2
|
||||||
|
with:
|
||||||
|
package: ${{ env.PROJ_PATH }}-${{ env.VER }}-${{ matrix.os }}-deb
|
||||||
|
package_root: .debpkg
|
||||||
|
maintainer: ${{ env.EMAIL }}
|
||||||
|
version: ${{ env.VER }} # refs/tags/v*.*.*
|
||||||
|
arch: 'all'
|
||||||
|
depends: 'libc6 (>= 2.2.1)'
|
||||||
|
desc: "${{ env.DESCRIPTION }}"
|
||||||
|
|
||||||
|
- name: Deploy tar
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ env.PROJ_PATH }}_${{ env.VER }}_${{ matrix.os }}-tar
|
||||||
|
path: |
|
||||||
|
${{ env.PROJ_MOD }}.tar.gz
|
||||||
|
|
||||||
|
- name: Deploy deb
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ env.PROJ_PATH }}_${{ env.VER }}_${{ matrix.os }}-deb
|
||||||
|
path: |
|
||||||
|
./*.deb
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
with:
|
||||||
|
generate_release_notes: true
|
||||||
|
files: |
|
||||||
|
${{ env.PROJ_MOD }}.tar.gz
|
||||||
|
./*.deb
|
||||||
|
|
||||||
|
windows:
|
||||||
|
name: Build for Windows
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [windows-2019]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.10.8'
|
||||||
|
|
||||||
|
- name: Check Python install
|
||||||
|
run: |
|
||||||
|
python -m venv venv
|
||||||
|
venv\Scripts\Activate.ps1
|
||||||
|
which python
|
||||||
|
python --version
|
||||||
|
python -c "import struct; print(struct.calcsize('P') * 8)"
|
||||||
|
which pip
|
||||||
|
pip --version
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
venv\Scripts\Activate.ps1
|
||||||
|
pip install -U setuptools wheel pip pillow
|
||||||
|
pip install -r requirements.txt
|
||||||
|
pip install https://github.com/pyinstaller/pyinstaller/tarball/develop
|
||||||
|
|
||||||
|
- name: Check Python dependencies
|
||||||
|
run: |
|
||||||
|
venv\Scripts\Activate.ps1
|
||||||
|
python -c "from PySide6 import __version__; print(__version__)"
|
||||||
|
python -c "from PySide6.QtCore import __version__; print(__version__)"
|
||||||
|
python -c "from PySide6.QtCore import QLibraryInfo; print(QLibraryInfo.location(QLibraryInfo.LibrariesPath))"
|
||||||
|
|
||||||
|
- name: Setup Env Vars
|
||||||
|
run: |
|
||||||
|
$FILE_LOC = (Get-ChildItem -Path .\ -Filter info.py -Recurse -ErrorAction SilentlyContinue -Force | foreach {$_.FullName})
|
||||||
|
$VER = (findstr /b version $FILE_LOC).split('"')[1]
|
||||||
|
echo "VER=$VER" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||||
|
echo "BUILD_DIR=build" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||||
|
echo "DIST_DIR=dist" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||||
|
$PROJ_NAME = (findstr /b name $FILE_LOC).split('"')[1]
|
||||||
|
$PROJ_MOD = (findstr /b module_name $FILE_LOC).split('"')[1]
|
||||||
|
$MAIN_FILE = (findstr /b main_file $FILE_LOC).split('"')[1]
|
||||||
|
$MAIN_MOD = (findstr /b main_mod $FILE_LOC).split('"')[1]
|
||||||
|
echo "PROJECT_NAME=$PROJ_NAME" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||||
|
echo "PROJ_MOD=$PROJ_MOD" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||||
|
echo "PROJ_DIR=$PROJ_MOD" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||||
|
echo "MAIN_FILE=$MAIN_FILE" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||||
|
echo "MAIN_MOD=$MAIN_MOD" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
venv\Scripts\Activate.ps1
|
||||||
|
python create_pyinstaller_file.py
|
||||||
|
pyinstaller -w --noconfirm --hidden-import PySide6 `
|
||||||
|
--add-data "${{ env.PROJ_DIR }}\resources;." `
|
||||||
|
-i ${{ env.PROJ_DIR }}\resources\icon.ico `
|
||||||
|
--hidden-import pkg_resources `
|
||||||
|
--workpath "${{ env.BUILD_DIR }}" `
|
||||||
|
--distpath "${{ env.DIST_DIR }}" `
|
||||||
|
--onedir -n "${{ env.PROJECT_NAME }}" pyinstaller.py
|
||||||
|
Compress-Archive -Path .\${{env.DIST_DIR}}\${{env.PROJECT_NAME}} -DestinationPath ${{env.PROJECT_NAME}}-${{ env.VER }}-windows-x64.zip
|
||||||
|
|
||||||
|
|
||||||
|
- name: Deploy Zip
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ env.PROJECT_NAME }}_${{ env.VER }}-${{ matrix.os }}-zip
|
||||||
|
path: |
|
||||||
|
${{ env.PROJECT_NAME }}-${{ env.VER }}-windows-x64.zip
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
with:
|
||||||
|
generate_release_notes: true
|
||||||
|
files: |
|
||||||
|
${{ env.PROJECT_NAME }}-${{ env.VER }}-windows-x64.zip
|
||||||
|
|
||||||
|
|
||||||
|
macos:
|
||||||
|
name: Build for macOS
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [macos-11, macos-12]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup Homebrew
|
||||||
|
run: |
|
||||||
|
NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||||
|
brew install create-dmg
|
||||||
|
- name: Setup Python
|
||||||
|
run: |
|
||||||
|
wget https://www.python.org/ftp/python/3.10.8/python-3.10.8-macos11.pkg
|
||||||
|
sudo installer -verbose -pkg ./python-3*.pkg -target /
|
||||||
|
echo "/Library/Frameworks/Python.framework/Versions/3.10/bin" >> $GITHUB_PATH
|
||||||
|
- name: Setup Env Vars
|
||||||
|
run: |
|
||||||
|
echo "BUILD_DIR=build" >> $GITHUB_ENV
|
||||||
|
echo "DIST_DIR=dist" >> $GITHUB_ENV
|
||||||
|
FILE_LOC=$(find . -name info.py)
|
||||||
|
export VER="$(cat $FILE_LOC | grep -w version | awk -F'"' '$0=$2')"
|
||||||
|
export PROJ_NAME="$(cat $FILE_LOC | grep -w name | awk -F'"' '$0=$2')"
|
||||||
|
export PROJ_MOD="$(cat $FILE_LOC | grep -w module_name | awk -F'"' '$0=$2')"
|
||||||
|
export MAIN_FILE="$(cat $FILE_LOC | grep -w main_file | awk -F'"' '$0=$2')"
|
||||||
|
export MAIN_MOD="$(cat $FILE_LOC | grep -w main_module | awk -F'"' '$0=$2')"
|
||||||
|
export BUNDLE_ID="$(cat $FILE_LOC | grep -w bundle_identifier | awk -F'"' '$0=$2')"
|
||||||
|
echo "VER=$VER" >> $GITHUB_ENV
|
||||||
|
echo "PROJECT_NAME=$PROJ_NAME" >> $GITHUB_ENV
|
||||||
|
echo "PROJ_DIR=$PROJ_MOD" >> $GITHUB_ENV
|
||||||
|
echo "PROJ_MOD=$PROJ_MOD" >> $GITHUB_ENV
|
||||||
|
echo "MAIN_FILE=$MAIN_FILE" >> $GITHUB_ENV
|
||||||
|
echo "MAIN_MOD=$MAIN_MOD" >> $GITHUB_ENV
|
||||||
|
echo "BUNDLE_ID=$BUNDLE_ID" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Check Python install
|
||||||
|
run: |
|
||||||
|
pip3 install --upgrade pip
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
which python3
|
||||||
|
python3 --version
|
||||||
|
which pip3
|
||||||
|
pip3 --version
|
||||||
|
file python3
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
source venv/bin/activate
|
||||||
|
pip3 install -U pip setuptools wheel pyclean
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
pip3 install py2app
|
||||||
|
PYINSTALLER_COMPILE_BOOTLOADER=1 MACOSX_DEPLOYMENT_TARGET=10.9 pip3 install https://github.com/pyinstaller/pyinstaller/tarball/develop --no-binary :all:
|
||||||
|
|
||||||
|
- name: Install universal2 dependencies
|
||||||
|
env:
|
||||||
|
CFLAGS: -arch x86_64 -arch arm64
|
||||||
|
ARCHFLAGS: -arch x86_64 -arch arm64
|
||||||
|
run: |
|
||||||
|
source venv/bin/activate
|
||||||
|
pip3 uninstall cffi -y
|
||||||
|
pip3 install --no-binary :all: cffi
|
||||||
|
pip3 uninstall cryptography -y
|
||||||
|
pip3 download --platform macosx_10_10_universal2 --only-binary :all: --no-deps --dest . cryptography
|
||||||
|
pip3 install --no-cache-dir --no-index --find-links . cryptography
|
||||||
|
|
||||||
|
- name: Check Python dependencies
|
||||||
|
run: |
|
||||||
|
source venv/bin/activate
|
||||||
|
python3 -c "from PySide6 import __version__; print(__version__)"
|
||||||
|
python3 -c "from PySide6.QtCore import __version__; print(__version__)"
|
||||||
|
python3 -c "from PySide6.QtCore import QLibraryInfo; print(QLibraryInfo.location(QLibraryInfo.LibrariesPath))"
|
||||||
|
python3 -c "import ssl; print(ssl)"
|
||||||
|
python3 -c "from py2app.recipes import pyside6"
|
||||||
|
python3 -c 'from distutils.sysconfig import get_config_var; print(get_config_var("LDLIBRARY"))'
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
source venv/bin/activate
|
||||||
|
python3 create_pyinstaller_file.py
|
||||||
|
# py2app works better
|
||||||
|
python3 buildPy2app.py py2app
|
||||||
|
# pyinstaller -w --noconfirm --hidden-import PySide6 \
|
||||||
|
# --add-data "${{ env.PROJ_DIR }}/resources:." \
|
||||||
|
# --icon "${{ env.PROJ_DIR }}/resources/icon.icns" \
|
||||||
|
# --target-architecture universal2 \
|
||||||
|
# --osx-bundle-identifier "${{ env.BUNDLE_ID }}" \
|
||||||
|
# --hidden-import pkg_resources \
|
||||||
|
# --distpath "${{ env.BUILD_DIR }}/ProjectMac" \
|
||||||
|
# --onefile -n "${{ env.PROJECT_NAME }}" pyinstaller.py
|
||||||
|
mv "${{ env.DIST_DIR }}/${{ env.PROJECT_NAME }}.app" "${{ env.PROJECT_NAME }}.app"
|
||||||
|
# Clean the directory so it's not full of python bytecode
|
||||||
|
pyclean "${{ env.PROJECT_NAME }}.app"
|
||||||
|
python3 ci/cleandist.py "${{ env.PROJECT_NAME }}.app"
|
||||||
|
python3 ci/codesign.py "${{ env.PROJECT_NAME }}.app"
|
||||||
|
zip -ry "${{ env.PROJECT_NAME }}_${{ env.VER }}-macos-universal.zip" "${{ env.PROJECT_NAME }}.app"
|
||||||
|
|
||||||
|
- name: Prepare for deployment
|
||||||
|
run: |
|
||||||
|
source venv/bin/activate
|
||||||
|
mkdir -p "${{ env.DIST_DIR }}/dmg"
|
||||||
|
test -f "${{ env.PROJECT_NAME }}_${{ env.VER }}.dmg" && rm "${{ env.PROJECT_NAME }}_${{ env.VER }}.dmg"
|
||||||
|
mv "${{ env.PROJECT_NAME }}.app" "${{ env.DIST_DIR}}/dmg/"
|
||||||
|
create-dmg \
|
||||||
|
--volname "${{ env.PROJECT_NAME }}-${{ env.VER }} Installer" \
|
||||||
|
--volicon "${{ env.PROJ_DIR }}/resources/icon.icns" \
|
||||||
|
--window-pos 200 120 \
|
||||||
|
--window-size 800 400 \
|
||||||
|
--icon-size 100 \
|
||||||
|
--icon "${{ env.PROJECT_NAME }}.app" 200 190 \
|
||||||
|
--hide-extension "${{ env.PROJECT_NAME }}.app" \
|
||||||
|
--app-drop-link 600 185 \
|
||||||
|
"${{ env.PROJECT_NAME }}_${{ env.VER }}-universal.dmg" \
|
||||||
|
"${{ env.DIST_DIR }}/dmg/"
|
||||||
|
ls -al ${{ env.DIST_DIR }}
|
||||||
|
|
||||||
|
- name: Deploy Zip
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ env.PROJECT_NAME }}_${{ env.VER }}-${{ matrix.os }}-zip
|
||||||
|
path: |
|
||||||
|
${{ env.PROJECT_NAME }}_${{ env.VER }}-macos-universal.zip
|
||||||
|
|
||||||
|
- name: Deploy DMG
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ env.PROJECT_NAME }}_${{ env.VER }}-${{ matrix.os}}-dmg
|
||||||
|
path: |
|
||||||
|
${{ env.PROJECT_NAME }}_${{ env.VER }}-universal.dmg
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
with:
|
||||||
|
generate_release_notes: true
|
||||||
|
files: |
|
||||||
|
${{ env.PROJECT_NAME }}_${{ env.VER }}-universal.dmg
|
||||||
|
${{ env.PROJECT_NAME }}_${{ env.VER }}-macos-universal.zip
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -127,3 +127,4 @@ dmypy.json
|
||||||
|
|
||||||
# Pyre type checker
|
# Pyre type checker
|
||||||
.pyre/
|
.pyre/
|
||||||
|
.DS_Store
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,36 @@
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from package_alias import package
|
||||||
|
|
||||||
module_name = "project"
|
info = package.info
|
||||||
name = "Project"
|
|
||||||
version = ""
|
|
||||||
main_file = "main.py"
|
|
||||||
|
|
||||||
# Overrides the above
|
name = info.name
|
||||||
exec(open("info.py").read())
|
version = info.version
|
||||||
|
bundle_identifier = info.bundle_identifier
|
||||||
|
module_name = info.module_name
|
||||||
|
|
||||||
|
APP = [f'pyinstaller.py']
|
||||||
APP = [f'{module_name}/{main_file}']
|
|
||||||
DATA_FILES = [
|
DATA_FILES = [
|
||||||
('resources', glob(module_name + '/resources/*.png') + glob(module_name + '/resources/*.rtf') + glob(module_name + '/resources/*.txt')),
|
('resources', glob(module_name + '/resources/*')),
|
||||||
]
|
]
|
||||||
OPTIONS = {
|
OPTIONS = {
|
||||||
|
'arch': 'universal2',
|
||||||
|
'optimize': 2,
|
||||||
'iconfile': module_name + '/resources/icon.icns',
|
'iconfile': module_name + '/resources/icon.icns',
|
||||||
'extra_scripts': 'info.py',
|
'includes': {'PySide6.QtCore', 'PySide6.QtUiTools', 'PySide6.QtGui', 'PySide6.QtWidgets', 'certifi', },
|
||||||
'includes': {'PySide6.QtCore', 'PySide6.QtUiTools', 'PySide6.QtGui', 'PySide6.QtWidgets', 'certifi', 'cffi', 'pem'},
|
'excludes': {'tkinter', "unittest"},
|
||||||
'excludes': {'tkinter'},
|
|
||||||
'qt_plugins': [
|
'qt_plugins': [
|
||||||
'platforms/libqcocoa.dylib',
|
'platforms/libqcocoa.dylib',
|
||||||
'platforms/libqminimal.dylib',
|
'platforms/libqminimal.dylib',
|
||||||
'platforms/libqoffscreen.dylib',
|
'platforms/libqoffscreen.dylib',
|
||||||
'styles/libqmacstyle.dylib'
|
'styles/libqmacstyle.dylib'
|
||||||
],
|
],
|
||||||
|
'argv_emulation': True,
|
||||||
'plist': {
|
'plist': {
|
||||||
'CFBundleName': name,
|
'CFBundleName': name,
|
||||||
'CFBundleShortVersionString': version,
|
'CFBundleShortVersionString': version,
|
||||||
'CFBundleIdentifier': f'pl.{module_name}.{name}',
|
'CFBundleIdentifier': bundle_identifier,
|
||||||
'LSMinimumSystemVersion': '10.12.0',
|
'LSMinimumSystemVersion': '10.12.0',
|
||||||
'NSHumanReadableCopyright': f'Copyright © {datetime.now().year} {name} All Rights Reserved',
|
'NSHumanReadableCopyright': f'Copyright © {datetime.now().year} {name} All Rights Reserved',
|
||||||
}
|
}
|
||||||
|
|
|
||||||
21
ci/appdatatemplate.xml
Normal file
21
ci/appdatatemplate.xml
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component type="desktop-application">
|
||||||
|
<id>$BUNDLE_ID</id>
|
||||||
|
<metadata_license>$METADATA_LICENSE</metadata_license>
|
||||||
|
<project_license>$PROJECT_LICENSE</project_license>
|
||||||
|
<name>$PROJ_NAME</name>
|
||||||
|
<summary>$SUMMARY</summary>
|
||||||
|
<description>
|
||||||
|
<p>$DESCRIPTION</p>
|
||||||
|
</description>
|
||||||
|
<launchable type="desktop-id">$BUNDLE_ID.desktop</launchable>
|
||||||
|
<url type="homepage">$HOMEPAGE</url>
|
||||||
|
<screenshots>
|
||||||
|
<screenshot type="default">
|
||||||
|
<image>$SCREENSHOT</image>
|
||||||
|
</screenshot>
|
||||||
|
</screenshots>
|
||||||
|
<provides>
|
||||||
|
<id>$BUNDLE_ID.desktop</id>
|
||||||
|
</provides>
|
||||||
|
</component>
|
||||||
3
ci/bintemplate
Normal file
3
ci/bintemplate
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
/usr/bin/$PROJ_MOD-bin/$PROJ_MOD "$@"
|
||||||
122
ci/cleandist.py
Normal file
122
ci/cleandist.py
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from glob import glob
|
||||||
|
|
||||||
|
pyver = platform.python_version_tuple()[0] + '.' + platform.python_version_tuple()[1]
|
||||||
|
|
||||||
|
# Clean resources
|
||||||
|
def clean(glob_path: str = "", to_be_kept=None, to_be_deleted=None):
|
||||||
|
to_be_kept = to_be_kept or []
|
||||||
|
to_be_deleted = to_be_deleted or []
|
||||||
|
|
||||||
|
if to_be_kept and glob_path:
|
||||||
|
for f in glob(glob_path):
|
||||||
|
if not any({k in f for k in to_be_kept}):
|
||||||
|
to_be_deleted.append(f)
|
||||||
|
|
||||||
|
for p in to_be_deleted:
|
||||||
|
if os.path.exists(p):
|
||||||
|
if os.path.isdir(p):
|
||||||
|
shutil.rmtree(p, ignore_errors=True)
|
||||||
|
else:
|
||||||
|
os.remove(p)
|
||||||
|
|
||||||
|
|
||||||
|
def clean_resources(app_path: str):
|
||||||
|
PATH = '{app_path}/Contents/Resources/'
|
||||||
|
|
||||||
|
to_be_kept = []
|
||||||
|
to_be_deleted = []
|
||||||
|
|
||||||
|
clean(f'{PATH}/qt*', to_be_deleted=to_be_deleted, to_be_kept=to_be_kept)
|
||||||
|
|
||||||
|
|
||||||
|
def clean_pyside6(app_path: str):
|
||||||
|
# Clean PySide6 folder
|
||||||
|
|
||||||
|
PATH = f'{app_path}/Contents/Resources/lib/python{pyver}/PySide6'
|
||||||
|
|
||||||
|
shutil.rmtree(f'{PATH}/examples', ignore_errors=True)
|
||||||
|
shutil.rmtree(f'{PATH}/include', ignore_errors=True)
|
||||||
|
shutil.rmtree(f'{PATH}/Qt/libexec', ignore_errors=True)
|
||||||
|
|
||||||
|
to_be_kept = ['QtCore', 'QtGui', 'QtWidgets']
|
||||||
|
to_be_deleted = []
|
||||||
|
|
||||||
|
for f in glob(f'{PATH}/Qt*'):
|
||||||
|
if not any({k in f for k in to_be_kept}):
|
||||||
|
to_be_deleted.append(f)
|
||||||
|
|
||||||
|
for a in glob(f'{PATH}/*.app'):
|
||||||
|
to_be_deleted.append(a)
|
||||||
|
|
||||||
|
to_be_deleted.remove(f'{PATH}/Qt')
|
||||||
|
to_be_deleted.extend([
|
||||||
|
f'{PATH}/lupdate',
|
||||||
|
f'{PATH}/qmllint',
|
||||||
|
f'{PATH}/lrelease',
|
||||||
|
f'{PATH}/qmlformat',
|
||||||
|
f'{PATH}/qmlls',
|
||||||
|
])
|
||||||
|
clean(to_be_deleted=to_be_deleted)
|
||||||
|
|
||||||
|
|
||||||
|
def clean_qt(app_path: str):
|
||||||
|
# Clean PySide6/Qt folder
|
||||||
|
|
||||||
|
PATH = f'{app_path}/Contents/Resources/lib/python{pyver}/PySide6/Qt'
|
||||||
|
|
||||||
|
to_be_deleted = [f'{PATH}/qml', f'{PATH}/translations']
|
||||||
|
|
||||||
|
clean(to_be_deleted=to_be_deleted)
|
||||||
|
|
||||||
|
|
||||||
|
def clean_lib(app_path: str):
|
||||||
|
# Clean PySide6/Qt/lib folder
|
||||||
|
|
||||||
|
PATH = f'{app_path}/Contents/Resources/lib/python{pyver}/PySide6/Qt/lib'
|
||||||
|
|
||||||
|
to_be_kept = ['QtCore', 'QtDBus', 'QtGui', 'QtWidgets']
|
||||||
|
to_be_deleted = [f'{PATH}/metatypes']
|
||||||
|
|
||||||
|
clean(f'{PATH}/Qt*', to_be_kept=to_be_kept, to_be_deleted=to_be_deleted)
|
||||||
|
|
||||||
|
|
||||||
|
def clean_plugins(app_path: str):
|
||||||
|
# Clean PySide6/Qt/plugins folder
|
||||||
|
PATH = f'{app_path}/Contents/Resources/lib/python{pyver}/PySide6/Qt/plugins'
|
||||||
|
|
||||||
|
to_be_kept = ['platforms', 'styles']
|
||||||
|
to_be_deleted = []
|
||||||
|
|
||||||
|
clean(f'{PATH}/*', to_be_kept=to_be_kept, to_be_deleted=to_be_deleted)
|
||||||
|
|
||||||
|
|
||||||
|
def symlink_shiboken(app_path: str):
|
||||||
|
# symlink .so from shiboken6 to PySide6 folder
|
||||||
|
cwd = os.getcwd()
|
||||||
|
|
||||||
|
FROM = f'{app_path}/Contents/Resources/lib/python{pyver}/shiboken6'
|
||||||
|
TO = f'{app_path}/Contents/Resources/lib/python{pyver}/PySide6'
|
||||||
|
|
||||||
|
fn = os.path.basename(glob(f'{FROM}/libshiboken6*.dylib')[0])
|
||||||
|
|
||||||
|
os.chdir(TO)
|
||||||
|
os.symlink(f'../shiboken6/{fn}', f'./{fn}')
|
||||||
|
os.chdir(cwd)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
app_path = sys.argv[1]
|
||||||
|
|
||||||
|
clean_resources(app_path)
|
||||||
|
clean_pyside6(app_path)
|
||||||
|
clean_qt(app_path)
|
||||||
|
clean_lib(app_path)
|
||||||
|
clean_plugins(app_path)
|
||||||
|
symlink_shiboken(app_path)
|
||||||
|
|
||||||
|
main()
|
||||||
224
ci/codesign.py
Normal file
224
ci/codesign.py
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Generator, List, Optional
|
||||||
|
|
||||||
|
from macholib.MachO import MachO
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
import fcntl
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
from macholib.util import is_platform_file
|
||||||
|
|
||||||
|
def _dosign(*path):
|
||||||
|
with reset_blocking_status():
|
||||||
|
subprocess.check_call(
|
||||||
|
(
|
||||||
|
"codesign",
|
||||||
|
"--deep",
|
||||||
|
"--force",
|
||||||
|
"-s",
|
||||||
|
"-",
|
||||||
|
"--preserve-metadata=identifier,entitlements,flags,runtime",
|
||||||
|
"-f",
|
||||||
|
"-vvvv",
|
||||||
|
)
|
||||||
|
+ path,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _macho_find(path):
|
||||||
|
for basename, _dirs, files in os.walk(path):
|
||||||
|
for fn in files:
|
||||||
|
path = os.path.join(basename, fn)
|
||||||
|
if is_platform_file(path):
|
||||||
|
yield path
|
||||||
|
|
||||||
|
def codesign_adhoc(bundle):
|
||||||
|
"""
|
||||||
|
(Re)sign a bundle
|
||||||
|
|
||||||
|
Signing should be done "depth-first", sign
|
||||||
|
libraries before signing the libraries/executables
|
||||||
|
linking to them.
|
||||||
|
|
||||||
|
The current implementation is a crude hack,
|
||||||
|
but is better than nothing. Signing properly requires
|
||||||
|
performing a topological sort using dependencies.
|
||||||
|
|
||||||
|
"codesign" will resign the entire bundle, but only
|
||||||
|
if partial signatures are valid.
|
||||||
|
"""
|
||||||
|
# try:
|
||||||
|
# _dosign(bundle)
|
||||||
|
# return
|
||||||
|
# except subprocess.CalledProcessError:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
platfiles = list(_macho_find(bundle))
|
||||||
|
print("sign", platfiles)
|
||||||
|
while platfiles:
|
||||||
|
failed = []
|
||||||
|
for file in platfiles:
|
||||||
|
failed = []
|
||||||
|
try:
|
||||||
|
_dosign(file)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
failed.append(file)
|
||||||
|
if failed == platfiles:
|
||||||
|
raise RuntimeError("Cannot sign bundle %r" % (bundle,))
|
||||||
|
platfiles = failed
|
||||||
|
|
||||||
|
for _ in range(5):
|
||||||
|
try:
|
||||||
|
_dosign(bundle)
|
||||||
|
break
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
time.sleep(1)
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def reset_blocking_status():
|
||||||
|
"""
|
||||||
|
Contextmanager that resets the non-blocking status of
|
||||||
|
the std* streams as necessary. Used with all calls of
|
||||||
|
xcode tools, mostly because ibtool tends to set the
|
||||||
|
std* streams to non-blocking.
|
||||||
|
"""
|
||||||
|
orig_nonblocking = [
|
||||||
|
fcntl.fcntl(fd, fcntl.F_GETFL) & os.O_NONBLOCK for fd in (0, 1, 2)
|
||||||
|
]
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
|
||||||
|
finally:
|
||||||
|
for fd, is_nonblocking in zip((0, 1, 2), orig_nonblocking):
|
||||||
|
cur = fcntl.fcntl(fd, fcntl.F_GETFL)
|
||||||
|
if is_nonblocking:
|
||||||
|
reset = cur | os.O_NONBLOCK
|
||||||
|
else:
|
||||||
|
reset = cur & ~os.O_NONBLOCK
|
||||||
|
|
||||||
|
if cur != reset:
|
||||||
|
print("Resetting blocking status of %s" % (fd,))
|
||||||
|
fcntl.fcntl(fd, fcntl.F_SETFL, reset)
|
||||||
|
|
||||||
|
def create_symlink(folder: Path) -> None:
|
||||||
|
"""Create the appropriate symlink in the MacOS folder
|
||||||
|
pointing to the Resources folder.
|
||||||
|
"""
|
||||||
|
sibbling = Path(str(folder).replace("MacOS", ""))
|
||||||
|
|
||||||
|
# PyQt5/Qt/qml/QtQml/Models.2
|
||||||
|
root = str(sibbling).partition("Contents")[2].lstrip("/")
|
||||||
|
# ../../../../
|
||||||
|
backward = "../" * (root.count("/") + 1)
|
||||||
|
# ../../../../Resources/PyQt5/Qt/qml/QtQml/Models.2
|
||||||
|
good_path = f"{backward}Resources/{root}"
|
||||||
|
|
||||||
|
folder.symlink_to(good_path)
|
||||||
|
|
||||||
|
|
||||||
|
def fix_dll(dll: Path) -> None:
|
||||||
|
"""Fix the DLL lookup paths to use relative ones for Qt dependencies.
|
||||||
|
Inspiration: PyInstaller/depend/dylib.py:mac_set_relative_dylib_deps()
|
||||||
|
Currently one header is pointing to (we are in the Resources folder):
|
||||||
|
@loader_path/../../../../QtCore (it is referencing to the old MacOS folder)
|
||||||
|
It will be converted to:
|
||||||
|
@loader_path/../../../../../../MacOS/QtCore
|
||||||
|
"""
|
||||||
|
|
||||||
|
def match_func(pth: str) -> Optional[str]:
|
||||||
|
"""Callback function for MachO.rewriteLoadCommands() that is
|
||||||
|
called on every lookup path setted in the DLL headers.
|
||||||
|
By returning None for system libraries, it changes nothing.
|
||||||
|
Else we return a relative path pointing to the good file
|
||||||
|
in the MacOS folder.
|
||||||
|
"""
|
||||||
|
basename = os.path.basename(pth)
|
||||||
|
if not basename.startswith("Qt"):
|
||||||
|
return None
|
||||||
|
return f"@loader_path{good_path}/{basename}"
|
||||||
|
|
||||||
|
# Resources/PyQt5/Qt/qml/QtQuick/Controls.2/Fusion
|
||||||
|
root = str(dll.parent).partition("Contents")[2][1:]
|
||||||
|
# /../../../../../../..
|
||||||
|
backward = "/.." * (root.count("/") + 1)
|
||||||
|
# /../../../../../../../MacOS
|
||||||
|
good_path = f"{backward}/MacOS"
|
||||||
|
|
||||||
|
# Rewrite Mach headers with corrected @loader_path
|
||||||
|
mach_dll = MachO(dll)
|
||||||
|
mach_dll.rewriteLoadCommands(match_func)
|
||||||
|
with open(mach_dll.filename, "rb+") as f:
|
||||||
|
for header in mach_dll.headers:
|
||||||
|
f.seek(0)
|
||||||
|
mach_dll.write(f)
|
||||||
|
f.seek(0, 2)
|
||||||
|
f.flush()
|
||||||
|
|
||||||
|
|
||||||
|
def find_problematic_folders(folder: Path) -> Generator[Path, None, None]:
|
||||||
|
"""Recursively yields problematic folders (containing a dot in their name)."""
|
||||||
|
for path in folder.iterdir():
|
||||||
|
print(path)
|
||||||
|
if not path.is_dir() or path.is_symlink():
|
||||||
|
# Skip simlinks as they are allowed (even with a dot)
|
||||||
|
continue
|
||||||
|
if "." in path.name:
|
||||||
|
yield path
|
||||||
|
else:
|
||||||
|
yield from find_problematic_folders(path)
|
||||||
|
|
||||||
|
|
||||||
|
def move_contents_to_resources(folder: Path) -> Generator[Path, None, None]:
|
||||||
|
"""Recursively move any non symlink file from a problematic folder
|
||||||
|
to the sibbling one in Resources.
|
||||||
|
"""
|
||||||
|
for path in folder.iterdir():
|
||||||
|
if path.is_symlink():
|
||||||
|
continue
|
||||||
|
if path.name == "qml":
|
||||||
|
yield from move_contents_to_resources(path)
|
||||||
|
else:
|
||||||
|
sibbling = Path(str(path).replace("MacOS", "Resources"))
|
||||||
|
sibbling.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.move(path, sibbling)
|
||||||
|
yield sibbling
|
||||||
|
|
||||||
|
|
||||||
|
def main(args: List[str]):
|
||||||
|
"""
|
||||||
|
Fix the application to allow codesign (NXDRIVE-1301).
|
||||||
|
Take one or more .app as arguments: "Nuxeo Drive.app".
|
||||||
|
To overall process will:
|
||||||
|
- move problematic folders from MacOS to Resources
|
||||||
|
- fix the DLLs lookup paths
|
||||||
|
- create the appropriate symbolic link
|
||||||
|
"""
|
||||||
|
for app in args:
|
||||||
|
name = os.path.basename(app)
|
||||||
|
print(f">>> [{name}] Fixing Qt folder names")
|
||||||
|
path = Path(app) / "Contents" / "MacOS"
|
||||||
|
for folder in find_problematic_folders(path):
|
||||||
|
for file in move_contents_to_resources(folder):
|
||||||
|
try:
|
||||||
|
fix_dll(file)
|
||||||
|
except (ValueError, IsADirectoryError):
|
||||||
|
continue
|
||||||
|
shutil.rmtree(folder)
|
||||||
|
create_symlink(folder)
|
||||||
|
print(f" !! Fixed {folder}")
|
||||||
|
codesign_adhoc(app)
|
||||||
|
print(f">>> [{name}] Application fixed.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
||||||
52
ci/deb-script.sh
Executable file
52
ci/deb-script.sh
Executable file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
set -x
|
||||||
|
set -e
|
||||||
|
|
||||||
|
BUILD_DIR=".debpkg"
|
||||||
|
mkdir -p "$BUILD_DIR"
|
||||||
|
|
||||||
|
# store repo root as variable
|
||||||
|
REPO_ROOT=$(readlink -f $(dirname $(dirname "$0")))
|
||||||
|
OLD_CWD=$(readlink -f .)
|
||||||
|
FILE_LOC=$(find $REPO_ROOT -name info.py)
|
||||||
|
|
||||||
|
export VER="$(cat $FILE_LOC | grep -w version | awk -F'"' '$0=$2')"
|
||||||
|
export PROJ_NAME="$(cat $FILE_LOC | grep -w name | awk -F'"' '$0=$2')"
|
||||||
|
export PROJ_MOD="$(cat $FILE_LOC | grep -w module_name | awk -F'"' '$0=$2')"
|
||||||
|
export MAIN_FILE="$(cat $FILE_LOC | grep -w main_file | awk -F'"' '$0=$2')"
|
||||||
|
export BUNDLE_ID="$(cat $FILE_LOC | grep -w bundle_identifier | awk -F'"' '$0=$2')"
|
||||||
|
export PROJECT_LICENSE="$(cat $FILE_LOC | grep -w project_license | awk -F'"' '$0=$2')"
|
||||||
|
export SCREENSHOT="$(cat $FILE_LOC | grep -w screenshot | awk -F'"' '$0=$2')"
|
||||||
|
export METADATA_LICENSE="$(cat $FILE_LOC | grep -w metadata_license | awk -F'"' '$0=$2')"
|
||||||
|
export DESCRIPTION="$(cat $FILE_LOC | grep -w description | awk -F'"' '$0=$2')"
|
||||||
|
export HOMEPAGE="$(cat $FILE_LOC | grep -w homepage | awk -F'"' '$0=$2')"
|
||||||
|
export SUMMARY="$(cat $FILE_LOC | grep -w summary | awk -F'"' '$0=$2')"
|
||||||
|
export CATEGORIES="$(cat $FILE_LOC | grep -w categories | awk -F'"' '$0=$2')"
|
||||||
|
export MIMETYPE="$(cat $FILE_LOC | grep -w mimetype | awk -F'"' '$0=$2')"
|
||||||
|
export KEYWORDS="$(cat $FILE_LOC | grep -w keywords | awk -F'"' '$0=$2')"
|
||||||
|
export APP_TYPE="$(cat $FILE_LOC | grep -w application_type | awk -F'"' '$0=$2')"
|
||||||
|
export MAIN_MOD="$(cat $FILE_LOC | grep -w main_module | awk -F'"' '$0=$2')"
|
||||||
|
export EMAIL="$(cat $FILE_LOC | grep -w email | awk -F'"' '$0=$2')"
|
||||||
|
|
||||||
|
pushd "$BUILD_DIR"
|
||||||
|
|
||||||
|
# move and rename .desktop file
|
||||||
|
cat > $PROJ_MOD.desktop <(envsubst < $REPO_ROOT/ci/projectemplate.desktop)
|
||||||
|
|
||||||
|
|
||||||
|
mkdir -p $PROJ_MOD/usr/bin/$PROJ_MOD-bin
|
||||||
|
|
||||||
|
chmod +x $REPO_ROOT/$PROJ_MOD-tar/$PROJ_MOD
|
||||||
|
cp -r $REPO_ROOT/$PROJ_MOD-tar/* $PROJ_MOD/usr/bin/$PROJ_MOD-bin/
|
||||||
|
|
||||||
|
cat > $PROJ_MOD/usr/bin/$PROJ_MOD <(envsubst < $REPO_ROOT/ci/bintemplate)
|
||||||
|
chmod +x $PROJ_MOD/usr/bin/$PROJ_MOD
|
||||||
|
|
||||||
|
mkdir -p $PROJ_MOD/usr/share/applications
|
||||||
|
mkdir -p $PROJ_MOD/usr/lib/$PROJ_MOD
|
||||||
|
|
||||||
|
cp $PROJ_MOD.desktop $PROJ_MOD/usr/share/applications
|
||||||
|
chmod +x $PROJ_MOD/usr/share/applications/$PROJ_MOD.desktop
|
||||||
|
|
||||||
|
mkdir -p $PROJ_MOD/DEBIAN
|
||||||
9
ci/projectemplate.desktop
Normal file
9
ci/projectemplate.desktop
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=$PROJ_NAME
|
||||||
|
Comment=$DESCRIPTION
|
||||||
|
Exec=$PROJ_MOD %u
|
||||||
|
Type=$APP_TYPE
|
||||||
|
Icon=icon
|
||||||
|
Categories=$CATEGORIES;
|
||||||
|
MimeType=$MIME_TYPES
|
||||||
|
Keywords=$PROJ_MOD;$KEYWORDS
|
||||||
7
create_pyinstaller_file.py
Normal file
7
create_pyinstaller_file.py
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
from package_alias import package_name, package
|
||||||
|
|
||||||
|
with open("pyinstaller.py", "w+") as f:
|
||||||
|
f.writelines([
|
||||||
|
f"from {package_name} import {package.info.main_module}\n",
|
||||||
|
f"{package.info.main_module}.main()"
|
||||||
|
])
|
||||||
3
info.cfg
3
info.cfg
|
|
@ -1,3 +0,0 @@
|
||||||
version="0.1.0"
|
|
||||||
name="Project"
|
|
||||||
module_name="project"
|
|
||||||
6
info.py
6
info.py
|
|
@ -1,6 +0,0 @@
|
||||||
version="0.1.0"
|
|
||||||
name="Project"
|
|
||||||
module_name="project"
|
|
||||||
company_name="Project Company"
|
|
||||||
bundle_identifier="com.projectcompany.project.Project"
|
|
||||||
main_file="main.py"
|
|
||||||
11
package_alias.py
Normal file
11
package_alias.py
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from glob import glob
|
||||||
|
|
||||||
|
info_name = 'info'
|
||||||
|
info_file = glob(os.path.join('*', f'{info_name}.py'))[0]
|
||||||
|
package_name = info_file.split(os.path.sep)[0]
|
||||||
|
|
||||||
|
package = __import__(f"{package_name}", fromlist=["main", "info"])
|
||||||
|
if package_name not in sys.modules:
|
||||||
|
sys.modules[package_name] = package
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
from .. import info
|
|
||||||
|
|
||||||
version = info.version
|
|
||||||
name = info.name
|
|
||||||
module_name = info.module_name
|
|
||||||
18
project/info.py
Normal file
18
project/info.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
version="0.1.0"
|
||||||
|
name="Project"
|
||||||
|
module_name="project"
|
||||||
|
company_name="Project Company"
|
||||||
|
bundle_identifier="com.projectcompany.project.Project"
|
||||||
|
main_file="main.py"
|
||||||
|
main_module="main"
|
||||||
|
metadata_license="MIT"
|
||||||
|
project_license="PRIVATE"
|
||||||
|
email="user@example.com"
|
||||||
|
homepage="https://example.com"
|
||||||
|
screenshot=""
|
||||||
|
summary="A project of your creation."
|
||||||
|
description="A project of your creation."
|
||||||
|
keywords="interesting;good"
|
||||||
|
categories="CategoryA;CategoryB"
|
||||||
|
mimetype="image/x-foo;image/y-foo"
|
||||||
|
application_type="Application"
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from PySide6.QtWidgets import QMainWindow, QApplication, QLabel, QVBoxLayout, QPushButton, QWidget
|
from PySide6.QtWidgets import QMainWindow, QApplication, QLabel, QVBoxLayout, QPushButton, QWidget
|
||||||
from PySide6.QtGui import QIcon
|
from PySide6.QtGui import QIcon
|
||||||
from . import name as project_name
|
from . import info
|
||||||
|
project_name = info.name
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
@ -22,7 +23,10 @@ class MainWindow(QMainWindow):
|
||||||
|
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def main():
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
w = MainWindow()
|
w = MainWindow()
|
||||||
app.exec_()
|
app.exec_()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
|
||||||
BIN
project/resources/icon.ico
Normal file
BIN
project/resources/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 142 KiB |
BIN
project/resources/icon.png
Normal file
BIN
project/resources/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 671 KiB |
Loading…
Add table
Add a link
Reference in a new issue