diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..ad403a9 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,39 @@ +name: Build and Test + +on: [push, pull_request] + +env: + DEBIAN_FRONTEND: noninteractive + DIST_DIR: dist + +jobs: + build: + runs-on: ubuntu-latest + container: + image: ubuntu:22.04 + steps: + - uses: actions/checkout@v4 + + - name: Install build dependencies + run: | + apt-get update -qq + apt-get install -yqq --no-install-recommends \ + ca-certificates curl git \ + debhelper devscripts dpkg-dev meson pkg-config \ + python3-all-dev python3-pip python3-setuptools python3-venv python3-wheel \ + libpcre3-dev + curl -sLO https://launchpad.net/~kxstudio-debian/+archive/ubuntu/toolchain/+files/meson_1.9.1-1kxstudio2_all.deb + dpkg -i meson_1.9.1-1kxstudio2_all.deb + + - name: Build + run: ./scripts/build.sh + + - name: Test + run: ./scripts/test.sh + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: lilvlib-packages + path: dist/ + retention-days: 30 diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml deleted file mode 100644 index 0382254..0000000 --- a/.github/workflows/pylint.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: pylint - -on: [push, pull_request] - -env: - DEBIAN_FRONTEND: noninteractive - -jobs: - pylint: - runs-on: ubuntu-latest - container: - image: ubuntu:22.04 - steps: - - uses: actions/checkout@v4 - - name: Install dependencies - run: | - apt-get update -qq - apt-get install -yqq --no-install-recommends \ - bash ca-certificates curl git openssl \ - debhelper devscripts dpkg-dev git meson pkg-config python3-all-dev python3-virtualenv libpcre3-dev - curl -sLO https://launchpad.net/~kxstudio-debian/+archive/ubuntu/toolchain/+files/meson_1.9.1-1kxstudio2_all.deb - dpkg -i meson_1.9.1-1kxstudio2_all.deb - - name: Build and install python3-lilv - run: | - ./build-python3-lilv.sh - dpkg -i python3-lilv_*.deb - - name: Setup pylint - shell: bash - run: | - virtualenv --system-site-packages lilvlib-env - source lilvlib-env/bin/activate - pip3 install pylint - - name: Run pylint - shell: bash - run: | - virtualenv --system-site-packages lilvlib-env - source lilvlib-env/bin/activate - pylint -E lilvlib/lilvlib.py diff --git a/Dockerfile b/Dockerfile index 58cf8ec..9b8b278 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,73 @@ -# This Dockerfile can be used to build lilvlib using: -# - Ubuntu 18 -# - Python 3.6 +# Multi-stage Dockerfile for building and testing lilvlib +# Usage: +# docker build -t lilvlib-build . +# docker run --rm -v $(pwd)/dist:/dist lilvlib-build +# +# To run only the build stage (skip tests): +# docker build --target builder -t lilvlib-builder . -FROM moddevices/devtools:ub18-py36 +# ============================================================================= +# Stage 1: Builder - compile python3-lilv and build wheel +# ============================================================================= +FROM ubuntu:22.04 AS builder -LABEL Alexandre Cunha +ENV DEBIAN_FRONTEND=noninteractive -RUN mkdir /root/.ssh -RUN touch /root/.ssh/known_hosts -RUN ssh-keyscan github.com >> /root/.ssh/known_hosts +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + debhelper \ + devscripts \ + dpkg-dev \ + git \ + libpcre3-dev \ + meson \ + pkg-config \ + python3-all-dev \ + python3-pip \ + python3-setuptools \ + python3-wheel \ + && rm -rf /var/lib/apt/lists/* -RUN apt-get install --no-install-recommends -qy libpcre3-dev \ - devscripts pkg-config swig debhelper python3-numpy \ - && apt-get clean +# Ubuntu 22.04's meson (0.61.2) is incompatible with the build +RUN curl -sLO https://launchpad.net/~kxstudio-debian/+archive/ubuntu/toolchain/+files/meson_1.9.1-1kxstudio2_all.deb \ + && dpkg -i meson_1.9.1-1kxstudio2_all.deb \ + && rm meson_1.9.1-1kxstudio2_all.deb -COPY . /lilvlib -WORKDIR /lilvlib +WORKDIR /src +COPY . . -RUN ./build-python3-lilv.sh -RUN pip3 wheel -w wheelhouse . +ENV DIST_DIR=/artifacts +RUN ./scripts/build.sh + +# ============================================================================= +# Stage 2: Tester - validate artifacts in a clean environment +# ============================================================================= +FROM ubuntu:22.04 AS tester + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + python3 \ + python3-pip \ + python3-venv \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /src +COPY --from=builder /artifacts /artifacts +COPY --from=builder /src/test.py /src/ +COPY --from=builder /src/lilvlib /src/lilvlib +COPY --from=builder /src/scripts /src/scripts + +ENV DIST_DIR=/artifacts +RUN apt-get update && ./scripts/test.sh && rm -rf /var/lib/apt/lists/* + +# ============================================================================= +# Final Stage: Artifacts - extract build outputs (runs after tests pass) +# ============================================================================= +FROM ubuntu:22.04 + +WORKDIR /artifacts +COPY --from=tester /artifacts /artifacts + +CMD ["sh", "-c", "cp -v /artifacts/* /dist/ 2>/dev/null || echo 'Mount a volume to /dist to extract artifacts: docker run --rm -v $(pwd)/dist:/dist '"] diff --git a/lilvlib/lilvlib.py b/lilvlib/lilvlib.py index 3e2fa73..0956e1b 100755 --- a/lilvlib/lilvlib.py +++ b/lilvlib/lilvlib.py @@ -692,7 +692,7 @@ def get_plugin_info(world, plugin, useAbsolutePath = True): elif len(brand) > 16: brand = brand[:16] - errors.append("plugin brand has more than 11 characters") + errors.append("plugin brand has more than 16 characters") # -------------------------------------------------------------------------------------------------------- # label @@ -716,7 +716,7 @@ def get_plugin_info(world, plugin, useAbsolutePath = True): elif len(label) > 24: label = label[:24] - errors.append("plugin label has more than 16 characters") + errors.append("plugin label has more than 24 characters") # -------------------------------------------------------------------------------------------------------- # bundles @@ -1379,12 +1379,10 @@ def get_plugins_info(bundles): # ------------------------------------------------------------------------------------------------------------ -if __name__ == '__main__': - from sys import argv, exit +def main(): + from sys import argv from pprint import pprint - #get_plugins_info(argv[1:]) - #for i in get_plugins_info(argv[1:]): pprint(i) - #exit(0) + for i in get_plugins_info(argv[1:]): warnings = i['warnings'].copy() @@ -1408,3 +1406,8 @@ def get_plugins_info(bundles): }, width=200) # ------------------------------------------------------------------------------------------------------------ + +if __name__ == '__main__': + main() + +# ------------------------------------------------------------------------------------------------------------ diff --git a/lv2_validate_mod b/lv2_validate_mod index 8cedf3b..7b1f16a 100755 --- a/lv2_validate_mod +++ b/lv2_validate_mod @@ -6,22 +6,22 @@ LV2DIR=${PREFIX}/lib/lv2 # don't check all lv2 bundles, if atom.lv2 is installed the others should be too if [ ! -d ${LV2DIR}/atom.lv2 ]; then echo "${LV2DIR}/atom.lv2 directory is missing" - exit + exit 1 fi if [ ! -d ${LV2DIR}/dg-properties.lv2 ]; then echo "${LV2DIR}/dg-properties.lv2 directory is missing" - exit + exit 1 fi if [ ! -d ${LV2DIR}/kx-properties.lv2 ]; then echo "${LV2DIR}/kx-properties.lv2 directory is missing" - exit + exit 1 fi if [ ! -d ${LV2DIR}/mod-license.lv2 ]; then echo "${LV2DIR}/mod-license.lv2 directory is missing" - exit + exit 1 fi if [ -z "${1}" ]; then diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1621d6f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,34 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "mod-lilvlib" +version = "1.1.0" +description = "A set of helper methods to extract plugin and pedalboard data from TTLs using lilv" +readme = "README.md" +license = {text = "MIT"} +authors = [ + { name = "Falktx", email = "falktx@mod.audio" } +] +classifiers = [ + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] + +[project.urls] +Homepage = "https://github.com/mod-audio/lilvlib" +Repository = "https://github.com/mod-audio/lilvlib" + +[project.scripts] +lilvlib = "lilvlib.lilvlib:main" + +[tool.setuptools.packages.find] +include = ["lilvlib*"] diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..06e1415 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +DIST_DIR="${DIST_DIR:-$ROOT_DIR/dist}" + +cd "$ROOT_DIR" + +echo "==> Building python3-lilv debian package..." +./build-python3-lilv.sh + +echo "==> Building wheel..." +mkdir -p "$DIST_DIR" +pip3 install --upgrade pip +pip3 wheel --no-deps -w "$DIST_DIR" . + +echo "==> Copying debian package to $DIST_DIR..." +cp python3-lilv_*.deb "$DIST_DIR/" + +echo "==> Build complete. Artifacts in $DIST_DIR:" +ls -la "$DIST_DIR" diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100755 index 0000000..1ab2e10 --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +DIST_DIR="${DIST_DIR:-$ROOT_DIR/dist}" +VENV_DIR="${VENV_DIR:-/tmp/test-venv}" + +echo "==> Creating virtual environment..." +python3 -m venv --system-site-packages "$VENV_DIR" +source "$VENV_DIR/bin/activate" +pip install --upgrade pip + +echo "==> Installing debian package..." +dpkg -i "$DIST_DIR"/python3-lilv_*.deb + +echo "==> Installing wheel..." +pip install "$DIST_DIR"/mod_lilvlib-*.whl + +echo "==> Testing imports..." +python -c "import lilv; print('lilv import OK')" +python -c "import lilvlib; print('lilvlib import OK, version:', lilvlib.__version__)" + +echo "==> Testing CLI..." +which lilvlib + +echo "==> Running test script..." +cd "$ROOT_DIR" +python test.py + +echo "==> Running pylint..." +pip install pylint +pylint -E lilvlib/lilvlib.py + +echo "==> All tests passed" diff --git a/setup.py b/setup.py deleted file mode 100644 index b56fcc0..0000000 --- a/setup.py +++ /dev/null @@ -1,40 +0,0 @@ -import os -import re -import sys - -from setuptools import setup - -with open('lilvlib/__init__.py', 'r') as fh: - version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', fh.read(), re.MULTILINE).group(1) - -buildid = os.environ.get('SETUP_BUILD_ID', None) -version = '{0}.dev{1}'.format(version, buildid) if buildid else version - - -def main(): - setup( - name='mod-lilvlib', - version=version, - description='A set of helper methods to extract plugin and pedalboard data from TTLs using lilv', - author='Falktx', - author_email='falktx@mod.audio', - license='MIT', - packages=['lilvlib'], - install_requires=[], # lilv must be installed locally but cannot be resolved by PIP - entry_points={'console_scripts': ['lilvlib = lilvlib.lilvlib:main']}, - classifiers=[ - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Natural Language :: English', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - ], - url='https://github.com/mod-audio/lilvlib', - ) - - -if __name__ == '__main__': - if len(sys.argv) > 1 and sys.argv[1] == 'package_version': - print(version) - exit(0) - main()