From c4b7411261223b2fcdb8b7f909f57644cdba6054 Mon Sep 17 00:00:00 2001 From: Timmy Welch Date: Sat, 22 Apr 2023 17:54:58 -0700 Subject: [PATCH] Use tox for building --- .flake8 | 6 - .github/workflows/build.yaml | 67 ++--- .github/workflows/package.yaml | 57 +--- .pre-commit-config.yaml | 28 +- .travis.yml | 59 ---- CONTRIBUTING.md | 75 ++--- MANIFEST.in | 7 - Makefile | 76 ----- README.md | 14 +- .../linux => build-tools}/ComicTagger.desktop | 2 +- .../comictagger.spec | 4 +- build-tools/get_appimage.py | 26 ++ {mac => build-tools/mac}/Makefile | 0 {mac => build-tools/mac}/app.icns | Bin {mac => build-tools/mac}/make_thin.sh | 0 {mac => build-tools/mac}/volume.icns | Bin {windows => build-tools/windows}/app.ico | Bin build-tools/zip_artifacts.py | 47 +++ comictaggerlib/filerenamer.py | 5 +- desktop-integration/mac/ComicTagger | 4 - desktop-integration/mac/Info.plist | 32 -- desktop-integration/mac/main.sh | 17 -- .../windows/ComicTagger-pip.lnk | 4 - requirements-7Z.txt | 1 - requirements-CBR.txt | 1 - requirements-GUI.txt | 1 - requirements.txt | 14 - requirements_dev.txt | 12 - setup.cfg | 281 ++++++++++++++++++ setup.py | 91 +----- 30 files changed, 437 insertions(+), 494 deletions(-) delete mode 100644 .flake8 delete mode 100644 .travis.yml delete mode 100644 MANIFEST.in delete mode 100644 Makefile rename {desktop-integration/linux => build-tools}/ComicTagger.desktop (92%) rename comictagger.spec => build-tools/comictagger.spec (98%) create mode 100644 build-tools/get_appimage.py rename {mac => build-tools/mac}/Makefile (100%) rename {mac => build-tools/mac}/app.icns (100%) rename {mac => build-tools/mac}/make_thin.sh (100%) rename {mac => build-tools/mac}/volume.icns (100%) rename {windows => build-tools/windows}/app.ico (100%) create mode 100644 build-tools/zip_artifacts.py delete mode 100644 desktop-integration/mac/ComicTagger delete mode 100644 desktop-integration/mac/Info.plist delete mode 100755 desktop-integration/mac/main.sh delete mode 100644 desktop-integration/windows/ComicTagger-pip.lnk delete mode 100644 requirements-7Z.txt delete mode 100644 requirements-CBR.txt delete mode 100644 requirements-GUI.txt delete mode 100644 requirements.txt delete mode 100644 requirements_dev.txt create mode 100644 setup.cfg diff --git a/.flake8 b/.flake8 deleted file mode 100644 index f2b9c0f..0000000 --- a/.flake8 +++ /dev/null @@ -1,6 +0,0 @@ -[flake8] -max-line-length = 120 -extend-ignore = E203, E501, A003 -extend-exclude = venv, scripts, build, dist, comictaggerlib/ctversion.py -per-file-ignores = - comictaggerlib/cli.py: T20 diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index eb5d993..165951a 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,8 +1,8 @@ name: CI env: - PIP: pip - PYTHON: python + PKG_CONFIG_PATH: /usr/local/opt/icu4c/lib/pkgconfig + LC_COLLATE: en_US.UTF-8 on: pull_request: push: @@ -23,24 +23,18 @@ jobs: os: [ubuntu-latest] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} - - uses: syphar/restore-virtualenv@v1.2 - id: cache-virtualenv - - - uses: syphar/restore-pip-download-cache@v1 - if: steps.cache-virtualenv.outputs.cache-hit != 'true' - - name: Install build dependencies run: | - python -m pip install --upgrade --upgrade-strategy eager -r requirements_dev.txt + python -m pip install flake8 - uses: reviewdog/action-setup@v1 with: @@ -57,72 +51,45 @@ jobs: os: [ubuntu-latest, macos-10.15, windows-latest] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} - - uses: syphar/restore-virtualenv@v1.2 - id: cache-virtualenv - - - uses: syphar/restore-pip-download-cache@v1 - if: steps.cache-virtualenv.outputs.cache-hit != 'true' - - - name: Install build dependencies + - name: Install tox run: | - python -m pip install --upgrade --upgrade-strategy eager -r requirements_dev.txt + python -m pip install --upgrade --upgrade-strategy eager tox - - name: Install Windows build dependencies - run: | - choco install -y zip - if: runner.os == 'Windows' - name: Install macos dependencies run: | brew install icu4c pkg-config - export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"; - export PATH="/usr/local/opt/icu4c/bin:/usr/local/opt/icu4c/sbin:$PATH" - python -m pip install --no-binary=pyicu pyicu + # export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"; + # export PATH="/usr/local/opt/icu4c/bin:/usr/local/opt/icu4c/sbin:$PATH" if: runner.os == 'macOS' + - name: Install linux dependencies run: | sudo apt-get install pkg-config libicu-dev libqt5gui5 libfuse2 - export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"; - export PATH="/usr/local/opt/icu4c/bin:/usr/local/opt/icu4c/sbin:$PATH" - python -m pip install --no-binary=pyicu pyicu + # export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"; + # export PATH="/usr/local/opt/icu4c/bin:/usr/local/opt/icu4c/sbin:$PATH" if: runner.os == 'Linux' - name: Build and install PyPi packages run: | - make clean pydist - python -m pip install "dist/$(python setup.py --fullname)-py3-none-any.whl[all]" - - - name: build - run: | - make dist - - - name: build appimage - run: | - make appimage - if: runner.os == 'Linux' + python -m tox r -m build - name: Archive production artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: "${{ format('ComicTagger-{0}', runner.os) }}" path: | dist/*.zip - - - name: Archive production artifacts - appimage - uses: actions/upload-artifact@v2 - with: - name: "${{ format('ComicTagger-{0}', runner.os) }}" - path: | dist/*.AppImage - name: PyTest run: | - python -m pytest + python -m tox r diff --git a/.github/workflows/package.yaml b/.github/workflows/package.yaml index 6eebcc4..96e094e 100644 --- a/.github/workflows/package.yaml +++ b/.github/workflows/package.yaml @@ -1,8 +1,8 @@ name: Package env: - PIP: pip - PYTHON: python + PKG_CONFIG_PATH: /usr/local/opt/icu4c/lib/pkgconfig + LC_COLLATE: en_US.UTF-8 on: push: tags: @@ -18,66 +18,41 @@ jobs: os: [ubuntu-latest, macos-10.15, windows-latest] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} - - uses: syphar/restore-virtualenv@v1.2 - id: cache-virtualenv - - - uses: syphar/restore-pip-download-cache@v1 - if: steps.cache-virtualenv.outputs.cache-hit != 'true' - - - name: Install build dependencies + - name: Install tox run: | - python -m pip install --upgrade --upgrade-strategy eager -r requirements_dev.txt + python -m pip install --upgrade --upgrade-strategy eager tox - - name: Install Windows build dependencies - run: | - choco install -y zip if: runner.os == 'Windows' - name: Install macos dependencies run: | brew install icu4c pkg-config - export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"; - export PATH="/usr/local/opt/icu4c/bin:/usr/local/opt/icu4c/sbin:$PATH" - python -m pip install --no-binary=pyicu pyicu + # export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"; + # export PATH="/usr/local/opt/icu4c/bin:/usr/local/opt/icu4c/sbin:$PATH" if: runner.os == 'macOS' + - name: Install linux dependencies run: | sudo apt-get install pkg-config libicu-dev libqt5gui5 - export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"; - export PATH="/usr/local/opt/icu4c/bin:/usr/local/opt/icu4c/sbin:$PATH" - python -m pip install --no-binary=pyicu pyicu + # export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"; + # export PATH="/usr/local/opt/icu4c/bin:/usr/local/opt/icu4c/sbin:$PATH" if: runner.os == 'Linux' - name: Build, Install and Test PyPi packages run: | - make clean pydist - python -m pip install "dist/$(python setup.py --fullname)-py3-none-any.whl[all]" - python -m flake8 - python -m pytest - - - name: "Publish distribution 📦 to PyPI" - if: startsWith(github.ref, 'refs/tags/') && runner.os == 'Linux' - uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_API_TOKEN }} - packages_dir: dist - - - name: Build PyInstaller package - run: | - make dist - - - name: Build AppImage package - run: | - make appimage - if: runner.os == 'Linux' + python -m tox r + python -m tox r -m release + env: + TWINE_USERNAME=__token__ + TWINE_PASSWORD=${{ secrets.PYPI_API_TOKEN }} - name: Get release name if: startsWith(github.ref, 'refs/tags/') diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 29226fc..870f477 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,25 +13,25 @@ repos: rev: v2.2.0 hooks: - id: setup-cfg-fmt -- repo: https://github.com/PyCQA/isort - rev: 5.12.0 - hooks: - - id: isort - args: [--af,--add-import, 'from __future__ import annotations'] -- repo: https://github.com/asottile/pyupgrade - rev: v3.3.1 - hooks: - - id: pyupgrade - args: [--py39-plus] -- repo: https://github.com/psf/black - rev: 23.1.0 - hooks: - - id: black - repo: https://github.com/PyCQA/autoflake rev: v2.0.1 hooks: - id: autoflake args: [-i, --remove-all-unused-imports, --ignore-init-module-imports] +- repo: https://github.com/asottile/pyupgrade + rev: v3.3.1 + hooks: + - id: pyupgrade + args: [--py39-plus] +- repo: https://github.com/PyCQA/isort + rev: 5.12.0 + hooks: + - id: isort + args: [--af,--add-import, 'from __future__ import annotations'] +- repo: https://github.com/psf/black + rev: 23.1.0 + hooks: + - id: black - repo: https://github.com/PyCQA/flake8 rev: 6.0.0 hooks: diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 99a9ce0..0000000 --- a/.travis.yml +++ /dev/null @@ -1,59 +0,0 @@ -language: python -# Only build tags -if: type = pull_request OR tag IS present -branches: - only: - - develop - - /^\d+\.\d+\.\d+.*$/ -env: - global: - - PYTHON=python3 - - PIP=pip3 - - SETUPTOOLS_SCM_PRETEND_VERSION=$TRAVIS_TAG - - MAKE=make -matrix: - include: - - os: linux - python: 3.8 - - name: "Python: 3.7" - os: osx - language: shell - python: 3.7 - env: PYTHON=python3 PIP="python3 -m pip" - cache: - - directories: - - $HOME/Library/Caches/pip - - os: windows - language: bash - env: PATH=/C/Python37:/C/Python37/Scripts:$PATH MAKE=mingw32-make PIP=pip PYTHON=python -before_install: - - if [ "$TRAVIS_OS_NAME" = "windows" ]; then choco install -y python --version 3.7.9; choco install -y mingw zip; fi -install: - - $PIP install -r requirements_dev.txt - - $PIP install -r requirements-GUI.txt - - $PIP install -r requirements-CBR.txt -script: - - if [ "$TRAVIS_OS_NAME" != "linux" ]; then $MAKE dist ; fi - -deploy: - - name: "$TRAVIS_TAG" - body: Released ComicTagger $TRAVIS_TAG - provider: releases - skip_cleanup: true - api_key: - secure: RgohcOJOfLhXXT12bMWaLwOqhe+ClSCYXjYuUJuWK4/E1fdd1xu1ebdQU+MI/R8cZ0Efz3sr2n3NkO/Aa8gN68xEfuF7RVRMm64P9oPrfZgGdsD6H43rU/6kN8bgaDRmCYpLTfXaJ+/gq0x1QDkhWJuceF2BYEGGvL0BvS/TUsLyjVxs8ujTplLyguXHNEv4/7Yz7SBNZZmUHjBuq/y+l8ds3ra9rSgAVAN1tMXoFKJPv+SNNkpTo5WUNMPzBnN041F1rzqHwYDLog2V7Krp9JkXzheRFdAr51/tJBYzEd8AtYVdYvaIvoO6A4PiTZ7MpsmcZZPAWqLQU00UTm/PhT/LVR+7+f8lOBG07RgNNHB+edjDRz3TAuqyuZl9wURWTZKTPuO49TkZMz7Wm0DRNZHvBm1IXLeSG7Tll2YL1+WpZNZg+Dhro2J1QD3vxDXafhMdTCB4z0q5aKpG93IT0p6oXOO0oEGOPZYbA2c5R3SXWSyqd1E1gdhbVjIZr59h++TEf1zz07tvWHqPuAF/Ly/j+dIcY2wj0EzRWaSASWgUpTnMljAkHtWhqDw4GXGDRkRUWRJl1d0/JyVqCeIdRzDQNl8/q7BcO3F1zqr1PgnYdz0lfwWxL1/ekw2vHOJE/GOdkyvX0aJrnaOV338mjJbfGHYv4ESc9ow1kdtIbiU= - file_glob: true - file: dist/*.zip - draft: true - on: - tags: true - condition: $TRAVIS_OS_NAME != "linux" - - provider: pypi - user: __token__ - password: - secure: h+y5WkE8igf864dnsbGPFvOBkyPkuBYtnDRt+EgxHd71EZnV2YP7ns2Cx12su/SVVDdZCBlmHVtkhl6Jmqy+0rTkSYx+3mlBOqyl8Cj5+BlP/dP7Bdmhs2uLZk2YYL1avbC0A6eoNJFtCkjurnB/jCGE433rvMECWJ5x2HsQTKchCmDAEdAZbRBJrzLFsrIC+6NXW1IJZjd+OojbhLSyVar2Jr32foh6huTcBu/x278V1+zIC/Rwy3W67+3c4aZxYrI47FoYFza0jjFfr3EoSkKYUSByMTIvhWaqB2gIsF0T160jgDd8Lcgej+86ACEuG0v01VE7xoougqlOaJ94eAmapeM7oQXzekSwSAxcK3JQSfgWk/AvPhp07T4pQ8vCZmky6yqvVp1EzfKarTeub1rOnv+qo1znKLrBtOoq6t8pOAeczDdIDs51XT/hxaijpMRCM8vHxN4Kqnc4DY+3KcF7UFyH1ifQJHQe71tLBsM/GnAcJM5/3ykFVGvRJ716p4aa6IoGsdNk6bqlysNh7nURDl+bfm+CDXRkO2jkFwUFNqPHW7JwY6ZFx+b5SM3TzC3obJhfMS7OC37fo2geISOTR0xVie6NvpN6TjNAxFTfDxWJI7yH3Al2w43B3uYDd97WeiN+B+HVWtdaER87IVSRbRqFrRub+V+xrozT0y0= - skip_existing: true - skip_cleanup: true - on: - tags: true - condition: $TRAVIS_OS_NAME = "linux" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3f01cd8..1e9e4ee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -41,7 +41,7 @@ Please open a [GitHub Pull Request](https://github.com/comictagger/comictagger/p Currently only python 3.9 is supported however 3.10 will probably work if you try it -Those on linux should install `Pillow` from the system package manager if possible and if the GUI and/or the CBR/RAR comicbooks are going to be used `pyqt5` and `unrar-cffi` should be installed from the system package manager +Those on linux should install `Pillow` from the system package manager if possible and if the GUI `pyqt5` should be installed from the system package manager Those on macOS will need to ensure that you are using python3 in x86 mode either by installing an x86 only version of python or using the universal installer and using `python3-intel64` instead of `python3` @@ -50,10 +50,10 @@ Those on macOS will need to ensure that you are using python3 in x86 mode either git clone https://github.com/comictagger/comictagger.git ``` -2. It is preferred to use a virtual env for running from source, adding the `--system-site-packages` allows packages already installed via the system package manager to be used: +2. It is preferred to use a virtual env for running from source: ``` -python3 -m venv --system-site-packages venv +python3 -m venv venv ``` 3. Activate the virtual env: @@ -65,73 +65,34 @@ or if on windows PowerShell . venv/bin/activate.ps1 ``` -4. install dependencies: +4. Install tox: ```bash -pip install -r requirements_dev.txt -r requirements.txt -# if installing optional dependencies -pip install -r requirements-GUI.txt -r requirements-CBR.txt +pip install tox ``` -5. install ComicTagger +5. If you are on an M1 Mac you will need to export two environment variables for tests to pass. ``` -pip install . +export tox_python=python3.9-intel64 +export tox_env=m1env ``` -6. (optionally) run pytest to ensure that their are no failures (xfailed means expected failure) +6. install ComicTagger ``` -$ pytest -============================= test session starts ============================== -platform darwin -- Python 3.9.12, pytest-7.1.1, pluggy-1.0.0 -rootdir: /Users/timmy/build/source/comictagger -collected 61 items - -tests/test_FilenameParser.py ..x......x.xxx.xx....xxxxxx.xx.x..xxxxxxx [ 67%] -tests/test_comicarchive.py x... [ 73%] -tests/test_rename.py ..xxx.xx..XXX.XX [100%] - -================== 27 passed, 29 xfailed, 5 xpassed in 2.68s =================== +tox run -e venv ``` 7. Make your changes -8. run code tools and correct any issues +8. Build to ensure that your changes work: this will produce a binary build in the dist folder ```bash -black . -isort . -flake8 . -pytest +tox run -m build ``` -black: formats all of the code consistently so there are no surprises
+The build runs these formatters and linters automatically + +setup-cfg-fmt: Formats the setup.cfg file +autoflake: Removes unused imports isort: sorts imports so that you can always find where an import is located
+black: formats all of the code consistently so there are no surprises
flake8: checks for code quality and style (warns for unused imports and similar issues)
+mypy: checks the types of variables and functions to catch errors pytest: runs tests for ComicTagger functionality - - -if on mac or linux most of this can be accomplished by running -``` -make install -# or make PYTHON=python3-intel64 install -. venv/bin/activate -make CI -``` -There is also `make check` which will run all of the code tools in a read-only capacity -``` -$ make check -venv/bin/black --check . -All done! ✨ 🍰 ✨ -52 files would be left unchanged. -venv/bin/isort --check . -Skipped 6 files -venv/bin/flake8 . -venv/bin/pytest -============================= test session starts ============================== -platform darwin -- Python 3.9.12, pytest-7.1.1, pluggy-1.0.0 -rootdir: /Users/timmy/build/source/comictagger -collected 61 items - -tests/test_FilenameParser.py ..x......x.xxx.xx....xxxxxx.xx.x..xxxxxxx [ 67%] -tests/test_comicarchive.py x... [ 73%] -tests/test_rename.py ..xxx.xx..XXX.XX [100%] - -================== 27 passed, 29 xfailed, 5 xpassed in 2.68s =================== -``` diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index e341d47..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,7 +0,0 @@ -include README.md -include release_notes.txt -include requirements.txt -recursive-include scripts *.py *.txt -recursive-include desktop-integration * -include windows/app.ico -include mac/app.icns diff --git a/Makefile b/Makefile deleted file mode 100644 index 20860fd..0000000 --- a/Makefile +++ /dev/null @@ -1,76 +0,0 @@ -PIP ?= pip3 -PYTHON ?= python3 -VERSION_STR := $(shell $(PYTHON) setup.py --version) - -SITE_PACKAGES := $(shell $(PYTHON) -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])') -PACKAGE_PATH = $(SITE_PACKAGES)/comictagger.egg-link - -VENV := $(shell echo $${VIRTUAL_ENV-venv}) -PY3 := $(shell command -v $(PYTHON) 2> /dev/null) -PYTHON_VENV := $(VENV)/bin/python -INSTALL_STAMP := $(VENV)/.install.stamp - - -ifeq ($(OS),Windows_NT) - PYTHON_VENV := $(VENV)/Scripts/python.exe - OS_VERSION=win-$(PROCESSOR_ARCHITECTURE) - APP_NAME=comictagger.exe - FINAL_NAME=ComicTagger-$(VERSION_STR)-$(OS_VERSION).exe -else ifeq ($(shell uname -s),Darwin) - OS_VERSION=osx-$(shell defaults read loginwindow SystemVersionStampAsString)-$(shell uname -m) - APP_NAME=ComicTagger.app - FINAL_NAME=ComicTagger-$(VERSION_STR)-$(OS_VERSION).app -else - APP_NAME=comictagger - FINAL_NAME=ComicTagger-$(VERSION_STR)-$(shell uname -s) -endif - -.PHONY: all clean pydist dist CI check appimage - -all: clean dist - -$(PYTHON_VENV): - @if [ -z $(PY3) ]; then echo "Python 3 could not be found."; exit 2; fi - $(PY3) -m venv $(VENV) - -clean: - find . -maxdepth 4 -type d -name "__pycache__" -print -depth -exec rm -rf {} \; - rm -rf $(PACKAGE_PATH) $(INSTALL_STAMP) build dist MANIFEST comictaggerlib/ctversion.py - $(MAKE) -C mac clean - -CI: install - $(PYTHON_VENV) -m black . - $(PYTHON_VENV) -m isort . - $(PYTHON_VENV) -m flake8 . - $(PYTHON_VENV) -m pytest - -check: install - $(PYTHON_VENV) -m black --check . - $(PYTHON_VENV) -m isort --check . - $(PYTHON_VENV) -m flake8 . - $(PYTHON_VENV) -m pytest - -pydist: - $(PYTHON_VENV) -m build - -install: $(INSTALL_STAMP) -$(INSTALL_STAMP): $(PYTHON_VENV) requirements.txt requirements_dev.txt - $(PYTHON_VENV) -m pip install -r requirements_dev.txt - $(PYTHON_VENV) -m pip install -e . - touch $(INSTALL_STAMP) - -dist: dist/$(FINAL_NAME).zip - -dist/$(FINAL_NAME).zip: - pyinstaller -y comictagger.spec - cd dist && zip -r $(FINAL_NAME).zip $(APP_NAME) - -dist/appimagetool: - curl -L https://github.com/AppImage/AppImageKit/releases/latest/download/appimagetool-x86_64.AppImage > dist/appimagetool - chmod +x dist/appimagetool - -appimage: dist dist/appimagetool - rm -rf dist/appimage && cp -a dist/comictagger dist/appimage - cd dist/appimage/ && ln -s comictaggerlib/graphics/app.png app.png && ln -s comictagger AppRun - sed -e 's|/usr/local/share/comictagger/app.png|app|g' -e 's|%%CTSCRIPT%% %F|./comictagger|g' desktop-integration/linux/ComicTagger.desktop > dist/appimage/AppRun.desktop - cd dist && ./appimagetool appimage diff --git a/README.md b/README.md index c276be0..477dc6b 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ For details, screen-shots, and more, visit [the Wiki](https://github.com/comicta ### Binaries -Windows and macOS binaries are provided in the [Releases Page](https://github.com/comictagger/comictagger/releases). +Windows, Linux and MacOS binaries are provided in the [Releases Page](https://github.com/comictagger/comictagger/releases). Just unzip the archive in any folder and run, no additional installation steps are required. @@ -47,7 +47,14 @@ A pip package is provided, you can install it with: $ pip3 install comictagger[GUI] ``` -There are two optional dependencies GUI and CBR. You can install the optional dependencies by specifying one or more of `GUI`,`CBR` or `all` in braces e.g. `comictagger[CBR,GUI]` +There are optional dependencies. You can install the optional dependencies by specifying one or more of them in braces e.g. `comictagger[CBR,GUI]` + +Optional dependencies: +1. `ICU`: Ensures that comic pages are supported correctly. This should always be installed. *Currently only exists in the latest alpha release * +1. `CBR`: Provides support for CBR/RAR files. +1. `GUI`: Installs the GUI. +1. `7Z`: Provides support for CB7/7Z files. +1. `all`: Installs all of the above optional dependencies. ### Chocolatey installation (Windows only) @@ -59,8 +66,7 @@ choco install comictagger 1. Ensure you have python 3.9 installed 2. Clone this repository `git clone https://github.com/comictagger/comictagger.git` - 3. `pip3 install -r requirements_dev.txt` - 7. `pip3 install .` or `pip3 install .[GUI]` + 7. `pip3 install .[ICU]` or `pip3 install .[GUI,ICU]` ## Contributors diff --git a/desktop-integration/linux/ComicTagger.desktop b/build-tools/ComicTagger.desktop similarity index 92% rename from desktop-integration/linux/ComicTagger.desktop rename to build-tools/ComicTagger.desktop index 1300d91..b34ba7a 100644 --- a/desktop-integration/linux/ComicTagger.desktop +++ b/build-tools/ComicTagger.desktop @@ -3,7 +3,7 @@ Encoding=UTF-8 Name=ComicTagger GenericName=Comic Metadata Editor Comment=A cross-platform GUI/CLI app for writing metadata to comic archives -Exec=%%CTSCRIPT%% %F +Exec=comictagger %F Icon=/usr/local/share/comictagger/app.png Terminal=false Type=Application diff --git a/comictagger.spec b/build-tools/comictagger.spec similarity index 98% rename from comictagger.spec rename to build-tools/comictagger.spec index fa199b9..8f1f040 100644 --- a/comictagger.spec +++ b/build-tools/comictagger.spec @@ -9,7 +9,7 @@ block_cipher = None a = Analysis( - ["comictaggerlib/__main__.py"], + ["../comictaggerlib/__main__.py"], pathex=[], binaries=[], datas=[], @@ -237,5 +237,5 @@ if platform.system() not in ["Windows"]: }, ], }, - bundle_identifier=None, + bundle_identifier="com.comictagger", ) diff --git a/build-tools/get_appimage.py b/build-tools/get_appimage.py new file mode 100644 index 0000000..5a5ed1c --- /dev/null +++ b/build-tools/get_appimage.py @@ -0,0 +1,26 @@ +from __future__ import annotations + +import os +import pathlib +import stat + +import requests + + +def urlretrieve(url: str, dest: str) -> None: + resp = requests.get(url) + if resp.status_code == 200: + pathlib.Path(dest).write_bytes(resp.content) + + +APPIMAGETOOL = "build/appimagetool-x86_64.AppImage" +if os.path.exists(APPIMAGETOOL): + raise SystemExit(0) + +urlretrieve( + "https://github.com/AppImage/AppImageKit/releases/latest/download/appimagetool-x86_64.AppImage", APPIMAGETOOL +) +os.chmod(APPIMAGETOOL, stat.S_IRWXU) + +if not os.path.exists(APPIMAGETOOL): + raise SystemExit(1) diff --git a/mac/Makefile b/build-tools/mac/Makefile similarity index 100% rename from mac/Makefile rename to build-tools/mac/Makefile diff --git a/mac/app.icns b/build-tools/mac/app.icns similarity index 100% rename from mac/app.icns rename to build-tools/mac/app.icns diff --git a/mac/make_thin.sh b/build-tools/mac/make_thin.sh similarity index 100% rename from mac/make_thin.sh rename to build-tools/mac/make_thin.sh diff --git a/mac/volume.icns b/build-tools/mac/volume.icns similarity index 100% rename from mac/volume.icns rename to build-tools/mac/volume.icns diff --git a/windows/app.ico b/build-tools/windows/app.ico similarity index 100% rename from windows/app.ico rename to build-tools/windows/app.ico diff --git a/build-tools/zip_artifacts.py b/build-tools/zip_artifacts.py new file mode 100644 index 0000000..300b069 --- /dev/null +++ b/build-tools/zip_artifacts.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +import os +import pathlib +import platform +import zipfile + +from comictaggerlib.ctversion import __version__ + +app = "ComicTagger" +exe = app.casefold() +if platform.system() == "Windows": + os_version = f"win-{platform.machine()}" + app_name = f"{exe}.exe" + final_name = f"{app}-{__version__}-{os_version}.exe" +elif platform.system() == "Darwin": + ver = platform.mac_ver() + os_version = f"osx-{ver[0]}-{ver[2]}" + app_name = f"{app}.app" + final_name = f"{app}-{__version__}-{os_version}.app" +else: + app_name = exe + final_name = f"ComicTagger-{__version__}-{platform.system()}" + +path = f"dist/{app_name}" +zip_file = pathlib.Path(f"dist/{final_name}.zip") + + +def addToZip(zf, path, zippath): + if os.path.isfile(path): + zf.write(path, zippath) + elif os.path.isdir(path): + if zippath: + zf.write(path, zippath) + for nm in sorted(os.listdir(path)): + addToZip(zf, os.path.join(path, nm), os.path.join(zippath, nm)) + # else: ignore + + +zip_file.unlink(missing_ok=True) +with zipfile.ZipFile(zip_file, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=8) as zf: + zippath = os.path.basename(path) + if not zippath: + zippath = os.path.basename(os.path.dirname(path)) + if zippath in ("", os.curdir, os.pardir): + zippath = "" + addToZip(zf, path, zippath) diff --git a/comictaggerlib/filerenamer.py b/comictaggerlib/filerenamer.py index 3abad0e..8aca69e 100644 --- a/comictaggerlib/filerenamer.py +++ b/comictaggerlib/filerenamer.py @@ -20,6 +20,7 @@ import logging import os import pathlib import string +from collections.abc import Mapping, Sequence from typing import Any, cast from pathvalidate import Platform, normalize_platform, sanitize_filename @@ -94,8 +95,8 @@ class MetadataFormatter(string.Formatter): def _vformat( self, format_string: str, - args: list[Any], - kwargs: dict[str, Any], + args: Sequence[Any], + kwargs: Mapping[str, Any], used_args: set[Any], recursion_depth: int, auto_arg_index: int = 0, diff --git a/desktop-integration/mac/ComicTagger b/desktop-integration/mac/ComicTagger deleted file mode 100644 index 7c79e43..0000000 --- a/desktop-integration/mac/ComicTagger +++ /dev/null @@ -1,4 +0,0 @@ -This file is a placeholder that will automatically be replaced with a symlink to -the local machine's Python framework python binary. - -When pip does an uninstall, it will remove the link. diff --git a/desktop-integration/mac/Info.plist b/desktop-integration/mac/Info.plist deleted file mode 100644 index cdbf493..0000000 --- a/desktop-integration/mac/Info.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - main.sh - CFBundleIconFile - app.icns - CFBundleIdentifier - org.comictagger.comictagger - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ComicTagger - CFBundlePackageType - APPL - CFBundleShortVersionString - %%CTVERSION%% - CFBundleSignature - ???? - CFBundleVersion - %%CTVERSION%% - NSAppleScriptEnabled - YES - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/desktop-integration/mac/main.sh b/desktop-integration/mac/main.sh deleted file mode 100755 index 1d2fe4f..0000000 --- a/desktop-integration/mac/main.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -# This is a lot of hoop-jumping to get the absolute path -# of this script, so that we can use the Symlinked python -# binary to call the CT script. This is all so that the -# Mac menu doesn't say "Python". - -realpath() -{ - [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" -} - -CTSCRIPT=%%CTSCRIPT%% - -THIS=$(realpath $0) -THIS_FOLDER=$(dirname $THIS) -"$THIS_FOLDER/ComicTagger" "$CTSCRIPT" diff --git a/desktop-integration/windows/ComicTagger-pip.lnk b/desktop-integration/windows/ComicTagger-pip.lnk deleted file mode 100644 index c0cadfa..0000000 --- a/desktop-integration/windows/ComicTagger-pip.lnk +++ /dev/null @@ -1,4 +0,0 @@ -This file is a placeholder that will automatically be replaced with a Windows -shortcut on the user's desktop. - -When pip does an uninstall, it will remove the shortcut file. diff --git a/requirements-7Z.txt b/requirements-7Z.txt deleted file mode 100644 index 014d24e..0000000 --- a/requirements-7Z.txt +++ /dev/null @@ -1 +0,0 @@ -py7zr diff --git a/requirements-CBR.txt b/requirements-CBR.txt deleted file mode 100644 index f5c5f0a..0000000 --- a/requirements-CBR.txt +++ /dev/null @@ -1 +0,0 @@ -rarfile>=4.0 diff --git a/requirements-GUI.txt b/requirements-GUI.txt deleted file mode 100644 index 2d07ca0..0000000 --- a/requirements-GUI.txt +++ /dev/null @@ -1 +0,0 @@ -PyQt5 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 7a936ec..0000000 --- a/requirements.txt +++ /dev/null @@ -1,14 +0,0 @@ -appdirs==1.4.4 -beautifulsoup4>=4.1 -importlib_metadata>=3.3.0 -natsort>=8.1.0 -pathvalidate -pillow>=9.1.0, <10 -pycountry -#pyicu; sys_platform == 'linux' or sys_platform == 'darwin' -rapidfuzz>=2.12.0 -requests==2.* -settngs==0.6.2 -text2digits -typing_extensions -wordninja diff --git a/requirements_dev.txt b/requirements_dev.txt deleted file mode 100644 index ace72dd..0000000 --- a/requirements_dev.txt +++ /dev/null @@ -1,12 +0,0 @@ -black>=22 -build -flake8==4.* -flake8-black -flake8-encodings -flake8-isort -isort>=5.10 -pyinstaller>=5.6.2 -pytest==7.* -setuptools>=42 -setuptools_scm[toml]>=3.4 -wheel diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..953e11d --- /dev/null +++ b/setup.cfg @@ -0,0 +1,281 @@ +[metadata] +name = comictagger +description = A cross-platform GUI/CLI app for writing metadata to comic archives +long_description = file: README.md +long_description_content_type = text/markdown +url = https://github.com/comictagger/comictagger +author = ComicTagger team +author_email = comictagger@gmail.com +license = Apache License 2.0 +classifiers = + Development Status :: 4 - Beta + Environment :: Console + Environment :: MacOS X + Environment :: Win32 (MS Windows) + Environment :: X11 Applications :: Qt + Intended Audience :: End Users/Desktop + License :: OSI Approved :: Apache Software License + Natural Language :: English + Operating System :: OS Independent + Programming Language :: Python :: 3 + Programming Language :: Python :: 3 :: Only + Topic :: Multimedia :: Graphics + Topic :: Other/Nonlisted Topic + Topic :: Utilities +keywords = + comictagger + comics + comic + metadata + tagging + tagger + +[options] +packages = find: +install_requires = + appdirs==1.4.4 + beautifulsoup4>=4.1 + importlib-metadata>=3.3.0 + natsort>=8.1.0 + pathvalidate + pillow>=9.1.0,<10 + pycountry + rapidfuzz>=2.12.0 + requests==2.* + settngs==0.6.2 + text2digits + typing-extensions + wordninja +python_requires = >=3.9 + +[options.packages.find] +exclude = tests; testing + +[options.entry_points] +console_scripts = comictagger=comictaggerlib.main:main +comicapi.archiver = + zip = comicapi.archivers.zip:ZipArchiver + sevenzip = comicapi.archivers.sevenzip:SevenZipArchiver + rar = comicapi.archivers.rar:RarArchiver + folder = comicapi.archivers.folder:FolderArchiver +comictagger.talker = + comicvine = comictalker.talkers.comicvine:ComicVineTalker +pyinstaller40 = + hook-dirs = comictaggerlib.__pyinstaller:get_hook_dirs + +[options.extras_require] +7Z = + py7zr +CBR = + rarfile>=4.0 +GUI = + PyQt5 +ICU = + pyicu;sys_platform == 'linux' or sys_platform == 'darwin' +all = + PyQt5 + py7zr + rarfile>=4.0 + pyicu;sys_platform == 'linux' or sys_platform == 'darwin' + +[options.package_data] +comicapi = + data/* +comictaggerlib = + ui/* + graphics/* + +[tox:tox] +env_list = + format + py3.9-{none,gui,7z,cbr,icu,all} +minversion = 4.4.12 +basepython = {env:tox_python:python3.9} + +[testenv] +description = run the tests with pytest +package = wheel +wheel_build_env = .pkg +deps = + pytest>=7 +extras = + 7z: 7Z + cbr: CBR + gui: GUI + icu: ICU + all: all +commands = + python -m pytest {tty:--color=yes} {posargs} + icu,all: python -c 'import importlib,platform; importlib.import_module("icu") if platform.system() != "Windows" else ...' # Sanity check for icu + +[m1env] +description = run the tests with pytest +package = wheel +wheel_build_env = .pkg +deps = + pytest>=7 + icu,all: pyicu-binary +extras = + 7z: 7Z + cbr: CBR + gui: GUI + all: 7Z,CBR,GUI + +[testenv:py3.9-{icu,all}] +base = {env:tox_env:testenv} + +[testenv:format] +labels = + release + build +skip_install = true +deps = + black>=22 + isort>=5.10 + setup-cfg-fmt + autoflake + pyupgrade +commands = + -setup-cfg-fmt setup.cfg + -python -m autoflake -i --remove-all-unused-imports --ignore-init-module-imports . + -python -m isort --af --add-import 'from __future__ import annotations' . + -python -m black . + +[testenv:lint] +labels = + release +skip_install = true +depends = format +deps = + flake8==4.* + flake8-black + flake8-encodings + flake8-isort + mypy + types-setuptools + types-requests +commands = + python -m flake8 . + python -m mypy --ignore-missing-imports comicapi comictaggerlib comictalker + +[testenv:clean] +description = Clean development outputs +labels = + release + build +depends = + format + lint +skip_install = true +commands = + -python -c 'import shutil,pathlib; \ + shutil.rmtree("./build/", ignore_errors=True); \ + shutil.rmtree("./dist/", ignore_errors=True); \ + pathlib.Path("./comictaggerlib/ctversion.py").unlink(missing_ok=True); \ + pathlib.Path("comictagger.spec").unlink(missing_ok=True)' + +[testenv:wheel] +description = Generate wheel and tar.gz +labels = + release + build +depends = clean +skip_install = true +deps = + build +commands = + python -m build + +[testenv:pypi-upload] +description = Upload wheel to PyPi +platform = Linux +labels = + release +skip_install = true +depends = wheel +deps = + twine +passenv = + TWINE_* +setenv = + TWINE_NON_INTERACTIVE=true +commands = + python -m twine upload dist/*.whl dist/*.tar.gz + +[testenv:pyinstaller] +description = Generate pyinstaller executable +labels = + release + build +base = {env:tox_env:testenv} +depends = + clean + pypi-upload +deps = + pyinstaller>=5.6.2 +extras = + all +commands = + python -c 'import importlib,platform; importlib.import_module("icu") if platform.system() != "Windows" else ...' # Sanity check for icu + pyinstaller -y build-tools/comictagger.spec + +[testenv:appimage] +description = Generate appimage executable +skip_install = true +platform = Linux +base = {env:tox_env:testenv} +labels = + release + build +depends = + clean + pypi-upload + pyinstaller +deps = + requests +extras = + all +commands = + python -c 'import importlib,platform; importlib.import_module("icu") if platform.system() != "Windows" else ...' # Sanity check for icu + -python -c 'import shutil; shutil.rmtree("./build/", ignore_errors=True)' + python -c 'import shutil,pathlib; shutil.copytree("./dist/comictagger/", "./build/appimage", dirs_exist_ok=True); \ + shutil.copy("./comictaggerlib/graphics/app.png", "./build/appimage/app.png"); \ + pathlib.Path("./build/appimage/AppRun").symlink_to("comictagger"); \ + pathlib.Path("./build/appimage/AppRun.desktop").write_text( \ + pathlib.Path("build-tools/ComicTagger.desktop").read_text() \ + .replace("/usr/local/share/comictagger/app.png", "app") \ + .replace("Exec=comictagger", "Exec=./comictagger"))' + python ./build-tools/get_appimage.py + ./build/appimagetool ./build/appimage + +[testenv:zip_artifacts] +description = Zip release artifacts +labels = + release + build +depends = + wheel + pyinstaller + appimage +commands = + python ./build-tools/zip_artifacts.py + +[testenv:venv] +envdir = venv +deps = + flake8==4.* + flake8-black + flake8-encodings + flake8-isort + mypy + types-setuptools + types-requests + build + pyinstaller>=5.6.2 + +[flake8] +max-line-length = 120 +extend-ignore = E203, E501, A003 +extend-exclude = venv, scripts, build, dist, comictaggerlib/ctversion.py +per-file-ignores = + comictaggerlib/cli.py: T20 diff --git a/setup.py b/setup.py index 5ff775b..a03590f 100644 --- a/setup.py +++ b/setup.py @@ -1,92 +1,5 @@ -# Setup file for comictagger python source (no wheels yet) -# -# An entry point script called "comictagger" will be created -# -# Currently commented out, an experiment at desktop integration. -# It seems that post installation tweaks are broken by wheel files. -# Kept here for further research - from __future__ import annotations -import glob -import os +from setuptools import setup -from setuptools import find_packages, setup - - -def read(fname: str) -> str: - """ - Read the contents of a file. - Parameters - ---------- - fname : str - Path to file. - Returns - ------- - str - File contents. - """ - with open(os.path.join(os.path.dirname(__file__), fname), encoding="utf-8") as f: - return f.read() - - -install_requires = read("requirements.txt").splitlines() - -# Dynamically determine extra dependencies -extras_require = {} -extra_req_files = glob.glob("requirements-*.txt") -for extra_req_file in extra_req_files: - name = os.path.splitext(extra_req_file)[0].removeprefix("requirements-") - extras_require[name] = read(extra_req_file).splitlines() - -# If there are any extras, add a catch-all case that includes everything. -# This assumes that entries in extras_require are lists (not single strings), -# and that there are no duplicated packages across the extras. -if extras_require: - extras_require["all"] = sorted({x for v in extras_require.values() for x in v}) - - -setup( - name="comictagger", - install_requires=install_requires, - extras_require=extras_require, - python_requires=">=3.9", - description="A cross-platform GUI/CLI app for writing metadata to comic archives", - author="ComicTagger team", - author_email="comictagger@gmail.com", - url="https://github.com/comictagger/comictagger", - packages=find_packages(exclude=["tests", "testing"]), - package_data={"comictaggerlib": ["ui/*", "graphics/*"], "comicapi": ["data/*"]}, - entry_points={ - "console_scripts": ["comictagger=comictaggerlib.main:main"], - "pyinstaller40": ["hook-dirs = comictaggerlib.__pyinstaller:get_hook_dirs"], - "comicapi.archiver": [ - "zip = comicapi.archivers.zip:ZipArchiver", - "sevenzip = comicapi.archivers.sevenzip:SevenZipArchiver", - "rar = comicapi.archivers.rar:RarArchiver", - "folder = comicapi.archivers.folder:FolderArchiver", - ], - "comictagger.talker": [ - "comicvine = comictalker.talkers.comicvine:ComicVineTalker", - ], - }, - classifiers=[ - "Development Status :: 4 - Beta", - "Environment :: Console", - "Environment :: Win32 (MS Windows)", - "Environment :: MacOS X", - "Environment :: X11 Applications :: Qt", - "Intended Audience :: End Users/Desktop", - "License :: OSI Approved :: Apache Software License", - "Natural Language :: English", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3.9", - "Topic :: Utilities", - "Topic :: Other/Nonlisted Topic", - "Topic :: Multimedia :: Graphics", - ], - keywords=["comictagger", "comics", "comic", "metadata", "tagging", "tagger"], - license="Apache License 2.0", - long_description=read("README.md"), - long_description_content_type="text/markdown", -) +setup()