Skip to content

Commit

Permalink
chore(actions): add workflow 📦 Package
Browse files Browse the repository at this point in the history
- 新增 GitHub Actions Workflow「📦 Package」
- 支持 win_x64, win_x86, mac(>=10.15) 平台二进制可执行文件的自动打包
  • Loading branch information
txperl committed Aug 12, 2021
1 parent c070396 commit 80b21c5
Show file tree
Hide file tree
Showing 7 changed files with 456 additions and 2 deletions.
119 changes: 119 additions & 0 deletions .github/workflows/pkg.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
name: 📦 Package

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:
inputs:
releaseTag:
description: 'Release Tag'
required: true
default: 'v'
releaseName:
description: 'Release Name'
required: true
default: 'test'
releaseBody:
description: 'Release Body'
required: true
default: 'Enjoy.'

jobs:
build-win-mac:
name: Package on ${{ matrix.version }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
# os: [windows-2019, windows-2019, macos-10.15]
include:
- os: windows-2019
version: win_x64
pythonArch: 'x64'
- os: windows-2019
version: win_x86
pythonArch: 'x86'
- os: macos-10.15
version: mac
pythonArch: 'x64'

steps:
- uses: actions/checkout@v2

- name: Classify files, prepare to be packaged
run: |
mkdir ./.pkg/code
mkdir ./.pkg/public
cp -r ./altfe/ ./.pkg/code/altfe/
cp -r ./app/ ./.pkg/code/app/
cp ./main.py ./.pkg/code/
cp -r ./usr/ ./.pkg/public/usr/
cp ./config.yml ./.pkg/public/
cp ./LICENSE ./.pkg/public/
cp ./README.md ./.pkg/public/
- name: Setup Python 3.7
uses: actions/[email protected]
with:
python-version: 3.7
architecture: ${{ matrix.pythonArch }}

- name: Install Requirements
run: |
pip install -r ./requirements.txt
pip install pyinstaller
- name: Run py-pkger.py
run: |
cd ./.pkg/
python ./py-pkger.py auto
- name: Compress to ZIP (win)
if: ${{ matrix.os == 'windows-2019' }}
run: |
cd ./.pkg/dist/
mv ./main.exe ./PixivBiu.exe
Compress-Archive * ../../${{ matrix.version }}.zip
- name: Compress to ZIP (mac)
if: ${{ matrix.os == 'macos-10.15' }}
run: |
cd ./.pkg/dist/
mv ./main ./PixivBiu
zip -r ../../${{ matrix.version }}.zip *
- name: Upload to Artifact
uses: actions/upload-artifact@v2
with:
name: pixivbiuArt
path: ./${{ matrix.version }}.zip

Release:
needs: [build-win-mac]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2

- name: Download from Artifact
uses: actions/download-artifact@v2
with:
name: pixivbiuArt

- name: Rename
run: |
mv ./win_x86.zip ./PixivBiu_${{ github.event.inputs.releaseTag }}_win_x86.zip
mv ./win_x64.zip ./PixivBiu_${{ github.event.inputs.releaseTag }}_win_x64.zip
mv ./mac.zip ./PixivBiu_${{ github.event.inputs.releaseTag }}_mac_intel.zip
- name: Release and Done
uses: ncipollo/release-action@v1
with:
artifacts: "PixivBiu_${{ github.event.inputs.releaseTag }}_win_x86.zip,PixivBiu_${{ github.event.inputs.releaseTag }}_win_x64.zip,PixivBiu_${{ github.event.inputs.releaseTag }}_mac_intel.zip"
tag: ${{ github.event.inputs.releaseTag }}
name: ${{ github.event.inputs.releaseName }}
body: ${{ github.event.inputs.releaseBody }}
token: ${{ secrets.GITHUB_TOKEN }}
160 changes: 160 additions & 0 deletions .pkg/py-pkger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import os
import shutil
import sys
import warnings
from pathlib import Path

import cloudscraper
import pixivpy3

with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
import imp
from modulefinder import ModuleFinder

ROOT_PATH = os.path.split(os.path.realpath(sys.argv[0]))[0]
CODE_PATH = os.path.join(ROOT_PATH, "code")
PUBLIC_PATH = os.path.join(ROOT_PATH, "public")
TMP_PATH = os.path.join(ROOT_PATH, "tmp")
DIST_PATH = os.path.join(ROOT_PATH, "dist")


# 复制文件夹
def copyDIR(src, dst, cover=True, ignore=[]):
if not os.path.exists(dst):
os.makedirs(dst)
for item in os.listdir(src):
s = os.path.join(src, item)
d = os.path.join(dst, item)
if item in ignore:
print("[Ignored] " + s)
continue
if os.path.isdir(s):
copyDIR(s, d, cover, ignore)
else:
if cover is True or (
not os.path.exists(d) or os.stat(s).st_mtime - os.stat(d).st_mtime > 1
):
shutil.copy2(s, d)
print("[Copied] %s -> %s" % (s, d))


# 清空文件夹
def deleteDIR(folder):
if not os.path.exists(folder):
return
for filename in os.listdir(folder):
file_path = os.path.join(folder, filename)
try:
if os.path.isfile(file_path) or os.path.islink(file_path):
os.unlink(file_path)
elif os.path.isdir(file_path):
shutil.rmtree(file_path)
except Exception as e:
print("Failed to delete %s. Reason: %s" % (file_path, e))


# 替换文件
def replaceFile(ori, dst):
if not os.path.exists(ori) or not os.path.exists(dst):
return False
print("[Replaced] %s -> %s" % (ori, dst))
with open(ori, "r", encoding="utf-8") as f:
data = f.read()
with open(dst, "w", encoding="utf-8") as f:
f.write(data)


# 列出路径下所有文件
def files(path, frmt="*", OTH=["", "pyc", "DS_Store"]):
tmp = []
r = []
for x in list(Path(path).glob("*")):
if os.path.isdir(x):
tmp += files(x, frmt)
else:
if frmt == "*" or len(str(x).split(frmt)) > 1:
tmp.append([str(x), x.stem, x.suffix[1:]])
for x in tmp:
if x[2] in OTH:
continue
r.append(x)
return r


# 修复 ModuleFinder 可能 BUG
class ModuleFinderR(ModuleFinder):
def run_script(self, pathname):
self.msg(2, "run_script", pathname)
with open(pathname, encoding="utf-8") as fp:
stuff = ("", "r", imp.PY_SOURCE)
self.load_module('__main__', fp, pathname, stuff)


if __name__ == "__main__":
silent = False
if len(sys.argv) == 2:
if sys.argv[1] == "auto":
silent = True
args = {
"-F": "",
"--distpath": DIST_PATH,
"--workpath": os.path.join(TMP_PATH, "build"),
"--specpath": CODE_PATH,
}
oargs = []
hiddenImport = []
finder = ModuleFinderR()
BET = ";" if os.name == "nt" else ":"
SPT = "\\" if os.name == "nt" else "/"

# 支持 CloudScraper
if silent or input("是否替换 CloudScraper/user_agent/__init__.py 文件?") == "y":
cdsr = os.path.dirname(cloudscraper.__file__)
replaceFile(f"{ROOT_PATH}{SPT}r_cloudscraper.py", f"{cdsr}{SPT}user_agent{SPT}__init__.py")

# pixivpy
if silent or input("是否替换 pixivpy3/bapi.py 文件?") == "y":
pxpy = os.path.dirname(pixivpy3.__file__)
replaceFile(f"{ROOT_PATH}{SPT}r_pixivpy.py", f"{pxpy}{SPT}bapi.py")

# 导入动态加载的文件、模块
for x in files(os.path.join(CODE_PATH, "app")):
print(x)
ori = x[0].replace(CODE_PATH, "")
dest = "/".join(ori.split(SPT)[:-1])
oargs.append(f"--add-data {ori[1:]}{BET}{dest[1:]}")
# 分析动态加载文件中所使用的包
if x[2] == "py":
finder.run_script(x[0])
for name, mod in finder.modules.items():
module = name.split(".")[0] if os.name == "nt" else name
if module not in hiddenImport:
hiddenImport.append(module)
for x in hiddenImport:
oargs.append(f"--hidden-import {x}")

# 图标加载
if os.name == "nt":
args["--icon"] = os.path.join(ROOT_PATH, "r_pixiv.ico")

# 参数拼接
forarg = ""
for x in args:
forarg += " " + x + (" " if args[x] != "" else "") + args[x]
for x in oargs:
forarg += " " + x

# 清空 DIST 文件夹
if silent or input("是否清空 DIST 生成文件夹?") == "y":
deleteDIR(DIST_PATH)

# 复制 PUBLIC 文件
copyDIR(PUBLIC_PATH, DIST_PATH, True, ["cache", ".token.json", ".DS_Store"])

# PyInstaller 打包
os.system("pyinstaller%s %s" % (forarg, os.path.join(CODE_PATH, "main.py")))

# 清空 TMP 文件夹
if silent or input("是否清空 TMP 缓存文件夹?") == "y":
deleteDIR(TMP_PATH)
Loading

0 comments on commit 80b21c5

Please sign in to comment.