From f7e071444605ec72a6f4577dc7fc63b880d4dd61 Mon Sep 17 00:00:00 2001 From: cbdev Date: Sat, 28 Dec 2019 15:11:26 +0100 Subject: Fix OSX CI --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to '.travis.yml') diff --git a/.travis.yml b/.travis.yml index bdaf63a..7db9167 100644 --- a/.travis.yml +++ b/.travis.yml @@ -180,7 +180,8 @@ install: before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ccache ola lua openssl jack; fi +# 'brew install' sometimes returns non-zero for some arcane reason. Executing 'true' resets the exit code and allows Travis to continue building... + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ccache ola lua openssl jack; true; fi # OpenSSL is not a proper install due to some Apple bull, so provide additional locations via the environment... # Additionally, newer versions of this "recipe" seem to use the name 'openssl@1.1' instead of plain 'openssl' and there seems to be # no way to programmatically get the link and include paths. Genius! Hardcoding the new version for the time being... -- cgit v1.2.3 From e4374c59881032ef644fbb2fd54a554dc4d914b1 Mon Sep 17 00:00:00 2001 From: Spacelord Date: Tue, 31 Dec 2019 00:35:02 +0100 Subject: Automated travis deployment --- .travis-ci.sh | 33 ++++++++++++++++++++++++++++++++- .travis.yml | 10 ++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) (limited to '.travis.yml') diff --git a/.travis-ci.sh b/.travis-ci.sh index da36c17..593b254 100644 --- a/.travis-ci.sh +++ b/.travis-ci.sh @@ -76,9 +76,40 @@ elif [[ $TASK = 'windows' ]]; then travis_fold start "make_windows" make windows; travis_fold end "make_windows" + + if [ "$(git describe)" == "$(git describe --abbrev=0)" ]; then + mkdir ./deployment + mkdir ./deployment/backends + mkdir ./deployment/docs + cp ./midimonster.exe ./deployment/ + cp ./backends/*.dll ./deployment/backends/ + cp ./monster.cfg ./deployment/monster.cfg + cp ./backends/*.md ./deployment/docs/ + cp -r ./configs ./deployment/ + cd ./deployment + zip -r "./midimonster-$(git describe)-windows.zip" "./" + rm -v !("*.zip") + fi + + else # Otherwise compile as normal travis_fold start "make" make full; + +if [ "$(git describe)" == "$(git describe --abbrev=0)" ]; then + mkdir ./deployment + mkdir ./deployment/backends + mkdir ./deployment/docs + cp ./midimonster ./deployment/ + cp ./backends/*.so ./deployment/backends/ + cp ./monster.cfg ./deployment/monster.cfg + cp ./backends/*.md ./deployment/docs/ + cp -r ./configs ./deployment/ + cd ./deployment + tar czf "midimonster-$(git describe)-linux64.tgz" * + rm -v !("*.tgz") + fi + travis_fold end "make" -fi +fi \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 7db9167..3299c66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -200,3 +200,13 @@ before_install: after_script: - if [ "$TASK" = "coverity" ]; then tail -n 10000 ${TRAVIS_BUILD_DIR}/cov-int/build-log.txt; cat ${TRAVIS_BUILD_DIR}/cov-int/scm_log.txt; fi + +deploy: + provider: releases + api_key: $GITHUB_TOKEN +file: + - "./deployment/*" + skip_cleanup: true + draft: true + on: + tags: true \ No newline at end of file -- cgit v1.2.3 From bbcefdf737452e2fcb4b7703a6348825a2112994 Mon Sep 17 00:00:00 2001 From: Spacelord Date: Tue, 31 Dec 2019 00:42:12 +0100 Subject: fix travis deployment --- .travis.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to '.travis.yml') diff --git a/.travis.yml b/.travis.yml index 3299c66..ea6ffc5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -204,9 +204,8 @@ after_script: deploy: provider: releases api_key: $GITHUB_TOKEN -file: - - "./deployment/*" - skip_cleanup: true - draft: true - on: - tags: true \ No newline at end of file + file: ./deployment/* + skip_cleanup: true + draft: true + on: + tags: true \ No newline at end of file -- cgit v1.2.3 From 599430276d4cc7ca3cec27513a5a318fd5e5de25 Mon Sep 17 00:00:00 2001 From: cbdev Date: Tue, 31 Dec 2019 01:53:23 +0100 Subject: Pull tags in CI before build --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to '.travis.yml') diff --git a/.travis.yml b/.travis.yml index ea6ffc5..6c81d1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,6 @@ addons: - *core_build - mingw-w64 - matrix: fast_finish: true include: @@ -179,6 +178,8 @@ install: - if [ "$TASK" = "codespell" ]; then pip install --user git+https://github.com/codespell-project/codespell.git; fi before_install: +# Travis clones with --branch, which omits tags. Since we use them for the version string at build time, fetch them + - git pull --tags - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi # 'brew install' sometimes returns non-zero for some arcane reason. Executing 'true' resets the exit code and allows Travis to continue building... - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ccache ola lua openssl jack; true; fi @@ -208,4 +209,4 @@ deploy: skip_cleanup: true draft: true on: - tags: true \ No newline at end of file + tags: true -- cgit v1.2.3 From 87fe68ef7d929b2f79e695df649b374fe0e2c572 Mon Sep 17 00:00:00 2001 From: cbdev Date: Tue, 31 Dec 2019 10:33:29 +0100 Subject: Enable globs for Travis deployments --- .travis.yml | 1 + 1 file changed, 1 insertion(+) (limited to '.travis.yml') diff --git a/.travis.yml b/.travis.yml index 6c81d1b..21c2a40 100644 --- a/.travis.yml +++ b/.travis.yml @@ -204,6 +204,7 @@ after_script: deploy: provider: releases + file_glob: true api_key: $GITHUB_TOKEN file: ./deployment/* skip_cleanup: true -- cgit v1.2.3 From f8ed6c26683c041ec61dac46d740b4b87df811ad Mon Sep 17 00:00:00 2001 From: cbdev Date: Sat, 4 Jan 2020 18:58:19 +0100 Subject: Build the Lua backend on Windows using CI --- .travis-ci.sh | 1 + .travis.yml | 2 ++ 2 files changed, 3 insertions(+) (limited to '.travis.yml') diff --git a/.travis-ci.sh b/.travis-ci.sh index 1475dea..c278b33 100644 --- a/.travis-ci.sh +++ b/.travis-ci.sh @@ -75,6 +75,7 @@ elif [[ $TASK = 'windows' ]]; then # Run sanitized compile travis_fold start "make_windows" make windows; + make -C backends lua.dll travis_fold end "make_windows" travis_fold start "deploy_windows" if [ "$(git describe)" == "$(git describe --abbrev=0)" ]; then diff --git a/.travis.yml b/.travis.yml index 21c2a40..5c0a3ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -198,6 +198,8 @@ before_install: #OS X uses something other than $CXX variable - if [ "$TRAVIS_OS_NAME" == "linux" -a \( "$TASK" = "compile" -o "$TASK" = "sanitize" \) ]; then $CXX --version; fi - if [ "$TASK" == "spellintian" -o "$TASK" == "spellintian-duplicates" ]; then wget "http://archive.ubuntu.com/ubuntu/pool/main/l/lintian/lintian_2.5.104_all.deb"; sudo dpkg -i lintian_*.deb; sudo apt-get install -f -y; fi # Install a later lintian +# Download libraries to link with on Windows + - if [ "$TASK" == "windows" ]; then mkdir libs; wget "https://downloads.sourceforge.net/project/luabinaries/5.3.5/Windows%20Libraries/Dynamic/lua-5.3.5_Win64_dllw6_lib.zip" -O lua53.zip; unzip lua53.zip lua53.dll; mv lua53.dll libs; fi after_script: - if [ "$TASK" = "coverity" ]; then tail -n 10000 ${TRAVIS_BUILD_DIR}/cov-int/build-log.txt; cat ${TRAVIS_BUILD_DIR}/cov-int/scm_log.txt; fi -- cgit v1.2.3 From 1b3878956f02e274c480815774f9c6f39d65117f Mon Sep 17 00:00:00 2001 From: cbdev Date: Wed, 26 Feb 2020 00:04:55 +0100 Subject: Use (spell-)lintian from package repositories in CI --- .travis.yml | 2 +- Makefile | 9 +++++++-- backends/loopback.c | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) (limited to '.travis.yml') diff --git a/.travis.yml b/.travis.yml index 5c0a3ec..e311a5a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ addons: - libjack-jackd2-dev - liblua5.3-dev - libssl-dev + - lintian packages: &core_build_gpp_latest - *core_build - gcc-8 @@ -197,7 +198,6 @@ before_install: - $CC --version #OS X uses something other than $CXX variable - if [ "$TRAVIS_OS_NAME" == "linux" -a \( "$TASK" = "compile" -o "$TASK" = "sanitize" \) ]; then $CXX --version; fi - - if [ "$TASK" == "spellintian" -o "$TASK" == "spellintian-duplicates" ]; then wget "http://archive.ubuntu.com/ubuntu/pool/main/l/lintian/lintian_2.5.104_all.deb"; sudo dpkg -i lintian_*.deb; sudo apt-get install -f -y; fi # Install a later lintian # Download libraries to link with on Windows - if [ "$TASK" == "windows" ]; then mkdir libs; wget "https://downloads.sourceforge.net/project/luabinaries/5.3.5/Windows%20Libraries/Dynamic/lua-5.3.5_Win64_dllw6_lib.zip" -O lua53.zip; unzip lua53.zip lua53.dll; mv lua53.dll libs; fi diff --git a/Makefile b/Makefile index 6a835ac..bda7bb1 100644 --- a/Makefile +++ b/Makefile @@ -55,10 +55,14 @@ backends-full: midimonster: midimonster.c portability.h $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $< $(OBJS) $(LDLIBS) -o $@ -resource.o: midimonster.rc - x86_64-w64-mingw32-windres $(RCCFLAGS) $< -o $@ --output-format=coff +resource.o: midimonster.rc midimonster.ico + $(RCC) $(RCCFLAGS) $< -o $@ --output-format=coff + +midimonster.ico: MIDIMonster.svg + convert -density 384 $< -define icon:auto-resize $@ midimonster.exe: export CC = x86_64-w64-mingw32-gcc +midimonster.exe: RCC ?= x86_64-w64-mingw32-windres midimonster.exe: CFLAGS += -Wno-format midimonster.exe: LDLIBS = -lws2_32 midimonster.exe: LDFLAGS += -Wl,--out-implib,libmmapi.a @@ -84,6 +88,7 @@ install: install -d "$(DESTDIR)$(EXAMPLES)" install -m 0644 configs/* "$(DESTDIR)$(EXAMPLES)" ifdef DEFAULT_CFG +# Only install the default configuration if it is not already present to avoid overwriting it ifeq (,$(wildcard $(DEFAULT_CFG))) install -Dm 0644 monster.cfg "$(DESTDIR)$(DEFAULT_CFG)" endif diff --git a/backends/loopback.c b/backends/loopback.c index eaecdb4..4274832 100644 --- a/backends/loopback.c +++ b/backends/loopback.c @@ -102,6 +102,7 @@ static int loopback_shutdown(size_t n, instance** inst){ } free(data->name); free(inst[u]->impl); + inst[u]->impl = NULL; } LOG("Backend shut down"); -- cgit v1.2.3 From f67459da93dcda4b78de3fe1cf97500d579abdf3 Mon Sep 17 00:00:00 2001 From: cbdev Date: Fri, 28 Feb 2020 00:29:18 +0100 Subject: Document commandline parameters in manpage (Fixes #48), update CI to Ubuntu bionic --- .travis.yml | 39 +++++++++++++-------------------------- midimonster.1 | 24 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 26 deletions(-) (limited to '.travis.yml') diff --git a/.travis.yml b/.travis.yml index e311a5a..41eaad8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ language: c -# Use the latest Travis images since they are more up to date than the stable release. group: edge before_script: @@ -35,7 +34,7 @@ addons: - *core_build - mingw-w64 -matrix: +jobs: fast_finish: true include: - os: osx @@ -54,28 +53,23 @@ matrix: env: - TASK='sanitize' - os: linux - dist: xenial + dist: bionic compiler: clang env: TASK='compile' addons: apt: packages: - *core_build_clang_latest - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-6.0 - os: linux - dist: xenial + dist: bionic compiler: gcc env: TASK='compile' addons: apt: packages: - *core_build_gpp_latest - sources: - - ubuntu-toolchain-r-test - os: linux - dist: xenial + dist: bionic compiler: mingw32-gcc env: - TASK='windows' @@ -84,21 +78,16 @@ matrix: apt: packages: - *core_build_windows - sources: - - ubuntu-toolchain-r-test - os: linux - dist: xenial + dist: bionic compiler: clang env: TASK='sanitize' addons: apt: packages: - *core_build_clang_latest - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-6.0 - os: linux - dist: xenial + dist: bionic compiler: gcc env: TASK='coverity' addons: @@ -107,10 +96,8 @@ matrix: # Coverity doesn't work with g++-5 or g++-6 yet - *core_build - gcc-4.9 - sources: - - ubuntu-toolchain-r-test - os: linux - dist: xenial + dist: bionic env: TASK='spellintian' addons: apt: @@ -118,7 +105,7 @@ matrix: - *core_build - moreutils - os: linux - dist: xenial + dist: bionic env: TASK='spellintian-duplicates' addons: apt: @@ -126,7 +113,7 @@ matrix: - *core_build - moreutils - os: linux - dist: xenial + dist: bionic env: TASK='codespell' addons: apt: @@ -135,14 +122,14 @@ matrix: - moreutils allow_failures: - os: linux - dist: xenial + dist: bionic compiler: gcc env: TASK='coverity' - os: linux - dist: xenial + dist: bionic env: TASK='spellintian-duplicates' - os: linux - dist: xenial + dist: bionic env: TASK='codespell' env: @@ -207,7 +194,7 @@ after_script: deploy: provider: releases file_glob: true - api_key: $GITHUB_TOKEN + token: $GITHUB_TOKEN file: ./deployment/* skip_cleanup: true draft: true diff --git a/midimonster.1 b/midimonster.1 index 131ed44..44c414e 100644 --- a/midimonster.1 +++ b/midimonster.1 @@ -4,6 +4,12 @@ midimonster \- Multi-protocol translation tool .SH SYNOPSIS .B midimonster .I config-file +.RB [ "-i" +.IR instance.option=value ] +.RB [ "-b" +.IR backend.option=value ] + +.B midimonster -v .SH DESCRIPTION .B MIDIMonster allows the user to translate any channel on one supported protocol into channel(s) @@ -12,7 +18,25 @@ on any other (or the same) supported protocol. .TP .I config-file The configuration file to read. If not specified, a default configuration file is read. + +.TP +.BI "-i " instance.option=value +Supply an additional instance configuration option +.IR option " for " instance "." +Command-line overrides are applied when the instance is first mentioned in the configuration file. + +.TP +.BI "-b " backend.option=value +Supply an additional backend configuration option +.IR option " to " backend "." +Command-line overrides are applied when the backend is first mentioned in the configuration file. + +.B -v +Display version information .SH "SEE ALSO" Online documentation and repository at https://github.com/cbdevnet/midimonster + +For more and in-depth information see the homepage at https://midimonster.net/ +as well as the knowledge base at https://kb.midimonster.net/ .SH AUTHOR Fabian "cbdev" Stumpf -- cgit v1.2.3 From d35415760f9efcb482ebe3480463ee6f7b5a9735 Mon Sep 17 00:00:00 2001 From: cbdev Date: Fri, 28 Feb 2020 00:48:54 +0100 Subject: Reorder CI builds, fix CI config warnings --- .travis.yml | 65 ++++++++++++++++--------------------------------------------- 1 file changed, 17 insertions(+), 48 deletions(-) (limited to '.travis.yml') diff --git a/.travis.yml b/.travis.yml index 41eaad8..2900b96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: c group: edge +os: linux +dist: bionic before_script: - export -f travis_fold @@ -37,21 +39,6 @@ addons: jobs: fast_finish: true include: - - os: osx - osx_image: xcode10.2 - compiler: clang - env: - - TASK='compile' - - os: osx - osx_image: xcode10.2 - compiler: gcc - env: - - TASK='compile' - - os: osx - osx_image: xcode10.2 - compiler: clang - env: - - TASK='sanitize' - os: linux dist: bionic compiler: clang @@ -86,16 +73,6 @@ jobs: apt: packages: - *core_build_clang_latest - - os: linux - dist: bionic - compiler: gcc - env: TASK='coverity' - addons: - apt: - packages: - # Coverity doesn't work with g++-5 or g++-6 yet - - *core_build - - gcc-4.9 - os: linux dist: bionic env: TASK='spellintian' @@ -120,11 +97,22 @@ jobs: packages: - *core_build - moreutils - allow_failures: - - os: linux - dist: bionic + - os: osx + osx_image: xcode10.2 + compiler: clang + env: + - TASK='compile' + - os: osx + osx_image: xcode10.2 compiler: gcc - env: TASK='coverity' + env: + - TASK='compile' + - os: osx + osx_image: xcode10.2 + compiler: clang + env: + - TASK='sanitize' + allow_failures: - os: linux dist: bionic env: TASK='spellintian-duplicates' @@ -138,21 +126,6 @@ env: - TERM=dumb # Parallel make build - MAKEFLAGS="-j 2" - # -- BEGIN Coverity Scan ENV - - COVERITY_SCAN_BUILD_COMMAND_PREPEND="cov-configure --comptype gcc --compiler gcc-4.9 --template" - # The build command with all of the arguments that you would apply to a manual `cov-build` - # Usually this is the same as STANDARD_BUILD_COMMAND, excluding the automated test arguments - - COVERITY_SCAN_BUILD_COMMAND="make" - # Name of the project - - COVERITY_SCAN_PROJECT_NAME="$TRAVIS_REPO_SLUG" - # Email address for notifications related to this build - # - COVERITY_SCAN_NOTIFICATION_EMAIL="" - # Regular expression selects on which branches to run analysis - # Be aware of quotas. Do not run on every branch/commit - - COVERITY_SCAN_BRANCH_PATTERN=".*" - # COVERITY_SCAN_TOKEN via "travis encrypt" using the repo's public key - # - secure: "" - # -- END Coverity Scan ENV cache: apt: true @@ -177,7 +150,6 @@ before_install: - export CFLAGS="$CFLAGS -I/usr/local/opt/openssl@1.1/include" - export LDFLAGS="$LDFLAGS -L/usr/local/opt/openssl@1.1/lib" - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then PATH=/usr/local/opt/ccache/libexec:$PATH; fi # Use ccache on Mac too -#Coverity doesn't work with g++ 5 or 6, so only upgrade to g++ 4.9 for that - if [ "$TRAVIS_OS_NAME" == "linux" -a \( "$TASK" = "compile" -o "$TASK" = "sanitize" \) -a "$CC" = "gcc" ]; then export CC="ccache gcc-8"; export CXX="ccache g++-8"; fi #Use the latest clang if we're compiling with clang - if [ "$TRAVIS_OS_NAME" == "linux" -a "$CC" = "clang" ]; then export CC="clang-6.0"; export CXX="clang-6.0"; fi @@ -188,9 +160,6 @@ before_install: # Download libraries to link with on Windows - if [ "$TASK" == "windows" ]; then mkdir libs; wget "https://downloads.sourceforge.net/project/luabinaries/5.3.5/Windows%20Libraries/Dynamic/lua-5.3.5_Win64_dllw6_lib.zip" -O lua53.zip; unzip lua53.zip lua53.dll; mv lua53.dll libs; fi -after_script: - - if [ "$TASK" = "coverity" ]; then tail -n 10000 ${TRAVIS_BUILD_DIR}/cov-int/build-log.txt; cat ${TRAVIS_BUILD_DIR}/cov-int/scm_log.txt; fi - deploy: provider: releases file_glob: true -- cgit v1.2.3 From fe84e353f2580315804319438b1951752249a9ee Mon Sep 17 00:00:00 2001 From: cbdev Date: Tue, 3 Mar 2020 23:11:14 +0100 Subject: Implement python backend --- .travis.yml | 3 +- README.md | 5 +- backends/Makefile | 2 +- backends/python.c | 419 +++++++++++++++++++++++++++++++++++++++++++++++++++++ backends/python.h | 25 ++++ backends/python.md | 63 ++++++++ 6 files changed, 514 insertions(+), 3 deletions(-) create mode 100644 backends/python.c create mode 100644 backends/python.h create mode 100644 backends/python.md (limited to '.travis.yml') diff --git a/.travis.yml b/.travis.yml index 2900b96..d9c03d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ addons: - libola-dev - libjack-jackd2-dev - liblua5.3-dev + - python3-dev - libssl-dev - lintian packages: &core_build_gpp_latest @@ -143,7 +144,7 @@ before_install: - git pull --tags - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi # 'brew install' sometimes returns non-zero for some arcane reason. Executing 'true' resets the exit code and allows Travis to continue building... - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ccache ola lua openssl jack; true; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ccache ola lua openssl jack python3; true; fi # OpenSSL is not a proper install due to some Apple bull, so provide additional locations via the environment... # Additionally, newer versions of this "recipe" seem to use the name 'openssl@1.1' instead of plain 'openssl' and there seems to be # no way to programmatically get the link and include paths. Genius! Hardcoding the new version for the time being... diff --git a/README.md b/README.md index 27629f2..19fb62c 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Currently, the MIDIMonster supports the following protocols: | MA Lighting Web Remote | Linux, Windows, OSX | GrandMA2 and dot2 (incl. OnPC) | [`maweb`](backends/maweb.md) | | JACK/LV2 Control Voltage (CV) | Linux, OSX | | [`jack`](backends/jack.md) | | Lua Scripting | Linux, Windows, OSX | | [`lua`](backends/lua.md) | +| Python Scripting | Linux, OSX | | [`python`](backends/python.md) | | Loopback | Linux, Windows, OSX | | [`loopback`](backends/loopback.md) | With these features, the MIDIMonster allows users to control any channel on any of these protocols, and translate any channel on @@ -146,6 +147,7 @@ special information. These documentation files are located in the `backends/` di * [`osc` backend documentation](backends/osc.md) * [`openpixelcontrol` backend documentation](backends/openpixelcontrol.md) * [`lua` backend documentation](backends/lua.md) +* [`python` backend documentation](backends/python.md) * [`maweb` backend documentation](backends/maweb.md) ## Installation @@ -192,8 +194,9 @@ support for the protocols to translate. * `liblua5.3-dev` (for the lua backend) * `libola-dev` (for the optional OLA backend) * `libjack-jackd2-dev` (for the JACK backend) -* `pkg-config` (as some projects and systems like to spread their files around) * `libssl-dev` (for the MA Web Remote backend) +* `python3-dev` (for the Python backend) +* `pkg-config` (as some projects and systems like to spread their files around) * A C compiler * GNUmake diff --git a/backends/Makefile b/backends/Makefile index 191a495..366d4b4 100644 --- a/backends/Makefile +++ b/backends/Makefile @@ -1,7 +1,7 @@ .PHONY: all clean full LINUX_BACKENDS = midi.so evdev.so WINDOWS_BACKENDS = artnet.dll osc.dll loopback.dll sacn.dll maweb.dll winmidi.dll openpixelcontrol.dll -BACKENDS = artnet.so osc.so loopback.so sacn.so lua.so maweb.so jack.so openpixelcontrol.so +BACKENDS = artnet.so osc.so loopback.so sacn.so lua.so maweb.so jack.so openpixelcontrol.so python.so OPTIONAL_BACKENDS = ola.so BACKEND_LIB = libmmbackend.o diff --git a/backends/python.c b/backends/python.c new file mode 100644 index 0000000..9fad0ae --- /dev/null +++ b/backends/python.c @@ -0,0 +1,419 @@ +#define BACKEND_NAME "python" + +#define PY_SSIZE_T_CLEAN +#include +#include +#include "python.h" + +#define MMPY_INSTANCE_KEY "midimonster_instance" + +/* + * TODO might want to export the full MM_API set to python at some point + */ + +static PyThreadState* python_main = NULL; +static wchar_t* program_name = NULL; + +MM_PLUGIN_API int init(){ + backend python = { + .name = BACKEND_NAME, + .conf = python_configure, + .create = python_instance, + .conf_instance = python_configure_instance, + .channel = python_channel, + .handle = python_set, + .process = python_handle, + .start = python_start, + .shutdown = python_shutdown + }; + + //register backend + if(mm_backend_register(python)){ + LOG("Failed to register backend"); + return 1; + } + return 0; +} + +static int python_configure(char* option, char* value){ + LOG("No backend configuration possible"); + return 1; +} + +static int python_prepend_str(PyObject* list, char* str){ + if(!list || !str){ + return 1; + } + + PyObject* item = PyUnicode_FromString(str); + if(!item){ + return 1; + } + + if(PyList_Insert(list, 0, item) < 0){ + Py_DECREF(item); + return 1; + } + Py_DECREF(item); + return 0; +} + +static PyObject* mmpy_output(PyObject* self, PyObject* args){ + instance* inst = *((instance**) PyModule_GetState(self)); + python_instance_data* data = (python_instance_data*) inst->impl; + const char* channel_name = NULL; + channel* chan = NULL; + channel_value val = { + 0 + }; + size_t u; + + if(!PyArg_ParseTuple(args, "sd", &channel_name, &val.normalised)){ + return NULL; + } + + val.normalised = clamp(val.normalised, 1.0, 0.0); + + for(u = 0; u < data->channels; u++){ + if(!strcmp(data->channel[u].name, channel_name)){ + DBGPF("Setting channel %s.%s to %f", inst->name, channel_name, val.normalised); + chan = mm_channel(inst, u, 0); + //this should never happen + if(!chan){ + LOGPF("Failed to fetch parsed channel %s.%s", inst->name, channel_name); + break; + } + data->channel[u].out = val.normalised; + mm_channel_event(chan, val); + break; + } + } + + if(u == data->channels){ + DBGPF("Output on unknown channel %s.%s, no event pushed", inst->name, channel_name); + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* mmpy_channel_value(PyObject* self, PyObject* args, uint8_t in){ + instance* inst = *((instance**) PyModule_GetState(self)); + python_instance_data* data = (python_instance_data*) inst->impl; + const char* channel_name = NULL; + size_t u; + + if(!PyArg_ParseTuple(args, "s", &channel_name)){ + return NULL; + } + + for(u = 0; u < data->channels; u++){ + if(!strcmp(data->channel[u].name, channel_name)){ + return PyFloat_FromDouble(in ? data->channel[u].in : data->channel[u].out); + } + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* mmpy_current_handler(PyObject* self, PyObject* args){ + instance* inst = *((instance**) PyModule_GetState(self)); + python_instance_data* data = (python_instance_data*) inst->impl; + + if(data->current_channel){ + return PyUnicode_FromString(data->current_channel->name); + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* mmpy_output_value(PyObject* self, PyObject* args){ + return mmpy_channel_value(self, args, 0); +} + +static PyObject* mmpy_input_value(PyObject* self, PyObject* args){ + return mmpy_channel_value(self, args, 1); +} + +static int mmpy_exec(PyObject* module) { + instance** inst = (instance**) PyModule_GetState(module); + //FIXME actually use interpreter dict (from python 3.8) here at some point + PyObject* capsule = PyDict_GetItemString(PyThreadState_GetDict(), MMPY_INSTANCE_KEY); + if(capsule && inst){ + *inst = PyCapsule_GetPointer(capsule, NULL); + return 0; + } + + //TODO raise exception + return -1; +} + +static int python_configure_instance(instance* inst, char* option, char* value){ + python_instance_data* data = (python_instance_data*) inst->impl; + PyObject* module = NULL; + + //load python script + if(!strcmp(option, "module")){ + //swap to interpreter + PyEval_RestoreThread(data->interpreter); + //import the module + module = PyImport_ImportModule(value); + if(!module){ + LOGPF("Failed to import module %s to instance %s", value, inst->name); + PyErr_Print(); + } + Py_XDECREF(module); + PyEval_ReleaseThread(data->interpreter); + return 0; + } + + LOGPF("Unknown instance parameter %s for instance %s", option, inst->name); + return 1; +} + +static PyObject* mmpy_init(){ + static PyModuleDef_Slot mmpy_slots[] = { + {Py_mod_exec, (void*) mmpy_exec}, + {0} + }; + + static PyMethodDef mmpy_methods[] = { + {"output", mmpy_output, METH_VARARGS, "Output a channel event"}, + {"inputvalue", mmpy_input_value, METH_VARARGS, "Get last input value for a channel"}, + {"outputvalue", mmpy_output_value, METH_VARARGS, "Get the last output value for a channel"}, + {"current", mmpy_current_handler, METH_VARARGS, "Get the name of the currently executing channel handler"}, + {0} + }; + + static struct PyModuleDef mmpy = { + PyModuleDef_HEAD_INIT, + "midimonster", + NULL, /*doc size*/ + sizeof(instance*), + mmpy_methods, + mmpy_slots + }; + + //single-phase init + //return PyModule_Create(&mmpy); + + //multi-phase init + return PyModuleDef_Init(&mmpy); +} + +static int python_instance(instance* inst){ + python_instance_data* data = calloc(1, sizeof(python_instance_data)); + PyObject* interpreter_dict = NULL; + char current_directory[8192]; + if(!data){ + LOG("Failed to allocate memory"); + return 1; + } + + //lazy-init because we need the interpreter running before _start, + //but don't want it running if no instances are defined + if(!python_main){ + LOG("Initializing main python interpreter"); + if(PyImport_AppendInittab("midimonster", &mmpy_init)){ + LOG("Failed to extend python inittab for main interpreter"); + } + program_name = Py_DecodeLocale("midimonster", NULL); + Py_SetProgramName(program_name); + //initialize python + Py_InitializeEx(0); + //create, acquire and release the GIL + PyEval_InitThreads(); + python_main = PyEval_SaveThread(); + } + + //acquire the GIL before creating a new interpreter + PyEval_RestoreThread(python_main); + //create subinterpreter for new instance + data->interpreter = Py_NewInterpreter(); + + //push cwd as import path + if(getcwd(current_directory, sizeof(current_directory))){ + if(python_prepend_str(PySys_GetObject("path"), current_directory)){ + LOG("Failed to push current working directory to python"); + goto bail; + } + } + + //push the instance pointer for later module initialization + //FIXME python 3.8 introduces interpreter_dict = PyInterpreterState_GetDict(data->interpreter->interp); + //for now use thread state... + interpreter_dict = PyThreadState_GetDict(); + if(!interpreter_dict){ + LOG("Failed to access per-interpreter data storage"); + goto bail; + } + //FIXME this might leak a reference to the capsule + if(PyDict_SetItemString(interpreter_dict, MMPY_INSTANCE_KEY, PyCapsule_New(inst, NULL, NULL))){ + LOG("Failed to set per-interpreter instance pointer"); + goto bail; + } + + //NewInterpreter leaves us with the GIL, drop it + PyEval_ReleaseThread(data->interpreter); + inst->impl = data; + return 0; + +bail: + if(data->interpreter){ + PyEval_ReleaseThread(data->interpreter); + } + free(data); + return 1; +} + +static channel* python_channel(instance* inst, char* spec, uint8_t flags){ + python_instance_data* data = (python_instance_data*) inst->impl; + size_t u; + + for(u = 0; u < data->channels; u++){ + if(!strcmp(data->channel[u].name, spec)){ + break; + } + } + + if(u == data->channels){ + data->channel = realloc(data->channel, (data->channels + 1) * sizeof(mmpython_channel)); + if(!data->channel){ + data->channels = 0; + LOG("Failed to allocate memory"); + return NULL; + } + memset(data->channel + u, 0, sizeof(mmpython_channel)); + + data->channel[u].name = strdup(spec); + if(!data->channel[u].name){ + LOG("Failed to allocate memory"); + return NULL; + } + data->channels++; + } + + return mm_channel(inst, u, 1); +} + +static int python_set(instance* inst, size_t num, channel** c, channel_value* v){ + python_instance_data* data = (python_instance_data*) inst->impl; + mmpython_channel* chan = NULL; + PyObject* result = NULL; + size_t u; + + //swap to interpreter + PyEval_RestoreThread(data->interpreter); + + for(u = 0; u < num; u++){ + chan = data->channel + c[u]->ident; + + //update input value buffer + chan->in = v[u].normalised; + + //call handler if present + if(chan->handler){ + DBGPF("Calling handler for %s.%s", inst->name, chan->name); + data->current_channel = chan; + result = PyObject_CallFunction(chan->handler, "d", chan->in); + Py_XDECREF(result); + data->current_channel = NULL; + DBGPF("Done with handler for %s.%s", inst->name, chan->name); + } + } + + PyEval_ReleaseThread(data->interpreter); + return 0; +} + +static int python_handle(size_t num, managed_fd* fds){ + //TODO implement some kind of intervaling functionality before people get it in their heads to start `import threading` + return 0; +} + +static int python_start(size_t n, instance** inst){ + python_instance_data* data = NULL; + PyObject* module = NULL; + size_t u, p; + char* module_name = NULL, *channel_name = NULL; + + //resolve channel references to handler functions + for(u = 0; u < n; u++){ + data = (python_instance_data*) inst[u]->impl; + + //switch to interpreter + PyEval_RestoreThread(data->interpreter); + for(p = 0; p < data->channels; p++){ + module = PyImport_AddModule("__main__"); + channel_name = data->channel[p].name; + module_name = strchr(channel_name, '.'); + if(module_name){ + *module_name = 0; + //returns borrowed reference + module = PyImport_AddModule(channel_name); + + if(!module){ + LOGPF("Module %s for qualified channel %s.%s is not loaded on instance %s", channel_name, channel_name, module_name + 1, inst[u]->name); + return 1; + } + + *module_name = '.'; + channel_name = module_name + 1; + } + + //returns new reference + data->channel[p].handler = PyObject_GetAttrString(module, channel_name); + } + + //release interpreter + PyEval_ReleaseThread(data->interpreter); + } + return 0; +} + +static int python_shutdown(size_t n, instance** inst){ + size_t u, p; + python_instance_data* data = NULL; + + //clean up channels + //this needs to be done before stopping the interpreters, + //because the handler references are refcounted + for(u = 0; u < n; u++){ + data = (python_instance_data*) inst[u]->impl; + for(p = 0; p < data->channels; p++){ + free(data->channel[p].name); + Py_XDECREF(data->channel[p].handler); + } + free(data->channel); + //do not free data here, needed for shutting down interpreters + } + + if(python_main){ + //just used to lock the GIL + PyEval_RestoreThread(python_main); + + for(u = 0; u < n; u++){ + data = (python_instance_data*) inst[u]->impl; + DBGPF("Shutting down interpreter for instance %s", inst[u]->name); + //swap to interpreter and end it, GIL is held after this but state is NULL + PyThreadState_Swap(data->interpreter); + PyErr_Clear(); + //PyThreadState_Clear(data->interpreter); + Py_EndInterpreter(data->interpreter); + + free(data); + } + + //shut down main interpreter + PyThreadState_Swap(python_main); + if(Py_FinalizeEx()){ + LOG("Failed to destroy python interpreters"); + } + PyMem_RawFree(program_name); + } + + LOG("Backend shut down"); + return 0; +} diff --git a/backends/python.h b/backends/python.h new file mode 100644 index 0000000..10411ca --- /dev/null +++ b/backends/python.h @@ -0,0 +1,25 @@ +#include "midimonster.h" + +MM_PLUGIN_API int init(); +static int python_configure(char* option, char* value); +static int python_configure_instance(instance* inst, char* option, char* value); +static int python_instance(instance* inst); +static channel* python_channel(instance* inst, char* spec, uint8_t flags); +static int python_set(instance* inst, size_t num, channel** c, channel_value* v); +static int python_handle(size_t num, managed_fd* fds); +static int python_start(size_t n, instance** inst); +static int python_shutdown(size_t n, instance** inst); + +typedef struct /*_python_channel_data*/ { + char* name; + PyObject* handler; + double in; + double out; +} mmpython_channel; + +typedef struct /*_python_instance_data*/ { + PyThreadState* interpreter; + size_t channels; + mmpython_channel* channel; + mmpython_channel* current_channel; +} python_instance_data; diff --git a/backends/python.md b/backends/python.md new file mode 100644 index 0000000..5f81e70 --- /dev/null +++ b/backends/python.md @@ -0,0 +1,63 @@ +### The `python` backend + +The `python` backend provides a flexible programming environment, allowing users +to route, generate and manipulate channel events using the Python 3 scripting languge. + +Every instance has its own interpreter, which can be loaded with multiple Python modules. +These modules may contain member functions accepting a single `float` parameter, which can +then be used as target channels. For each incoming event, the handler function is called. + +To interact with the MIDIMonster core, import the `midimonster` module from within your module. + +The `midimonster` module provides the following functions: + +| Function | Usage example | Description | +|-------------------------------|---------------------------------------|-----------------------------------------------| +| `output(string, float)` | `midimonster.output("foo", 0.75)` | Output a value event to a channel | +| `inputvalue(string)` | `midimonster.inputvalue("foo")` | Get the last input value on a channel | +| `outputvalue(string)` | `midimonster.outputvalue("bar")` | Get the last output value on a channel | +| `current()` | `print(midimonster.current())` | Returns the name of the input channel whose handler function is currently running or `None` if the interpreter was called from another context | + +Example Python module: +``` +import midimonster + +def in1(value): + midimonster.output("out1", 1 - value) +``` + +Input values range between 0.0 and 1.0, output values are clamped to the same range. + +#### Global configuration + +The `python` backend does not take any global configuration. + +#### Instance configuration + +| Option | Example value | Default value | Description | +|---------------|-----------------------|-----------------------|-----------------------------------------------| +| `module` | `my_handlers.py` | none | (Path to) Python module source file, relative to configuration file location | + +A single instance may have multiple `module` options specified. This will make all handlers available within their +module namespaces (see the section on channel specification). + +#### Channel specification + +Channel names may be any valid Python function name. To call handler functions in a module, +specify the channel as the functions qualified path (by prefixing it with the module name and a dot). + +Example mappings: +``` +py1.my_handlers.in1 < py1.foo +py1.out1 > py2.module.handler +``` + +#### Known bugs / problems + +Output values will not trigger corresponding input event handlers unless the channel is mapped +back in the MIDIMonster configuration. This is intentional. + +Importing a Python module named `midimonster` may cause problems and is unsupported. + +There is currently no functionality for cyclic execution. This may be implemented in a future +release. -- cgit v1.2.3 From 2a112633bfd56ddc9ece64973ef20654bf175429 Mon Sep 17 00:00:00 2001 From: cbdev Date: Wed, 4 Mar 2020 01:54:51 +0100 Subject: Try to override Python 2.7 installation in CI, fix typo --- .travis.yml | 3 ++- README.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to '.travis.yml') diff --git a/.travis.yml b/.travis.yml index d9c03d3..b9b6969 100644 --- a/.travis.yml +++ b/.travis.yml @@ -144,7 +144,8 @@ before_install: - git pull --tags - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi # 'brew install' sometimes returns non-zero for some arcane reason. Executing 'true' resets the exit code and allows Travis to continue building... - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ccache ola lua openssl jack python3; true; fi +# Travis seems to have Python 2.7 installed by default, which for some reason prevents pkg-config from reading python3.pc + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ccache ola lua openssl jack python3; brew link --overwrite python; true; fi # OpenSSL is not a proper install due to some Apple bull, so provide additional locations via the environment... # Additionally, newer versions of this "recipe" seem to use the name 'openssl@1.1' instead of plain 'openssl' and there seems to be # no way to programmatically get the link and include paths. Genius! Hardcoding the new version for the time being... diff --git a/README.md b/README.md index 19fb62c..124d6b0 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ one protocol into channel(s) on any other (or the same) supported protocol, for * Control lighting fixtures or DAWs using gamepad controllers, trackballs, etc ([Example configuration](configs/evdev.cfg)) * Play games, type, or control your mouse using MIDI controllers ([Example configuration](configs/midi-mouse.cfg)) -If you encounter a bug or suspect a problem with a a protocol implementation, please +If you encounter a bug or suspect a problem with a protocol implementation, please [open an Issue](https://github.com/cbdevnet/midimonster/issues) or get in touch with us via IRC on [Hackint in `#midimonster`](https://webirc.hackint.org/#irc://irc.hackint.org/#midimonster). We are happy to hear from you! -- cgit v1.2.3 From 20803bd7d7578706ad55b56cf1a4d8865b5c1285 Mon Sep 17 00:00:00 2001 From: cbdev Date: Wed, 11 Mar 2020 20:44:24 +0100 Subject: Restructure CI spellchecking --- .travis-ci.sh | 80 +++++++++++++++++++++-------------------------------------- .travis.yml | 46 +++++++++++----------------------- 2 files changed, 43 insertions(+), 83 deletions(-) (limited to '.travis.yml') diff --git a/.travis-ci.sh b/.travis-ci.sh index 8008026..e9e3df3 100644 --- a/.travis-ci.sh +++ b/.travis-ci.sh @@ -1,66 +1,42 @@ #!/bin/bash -# This script is triggered from the script section of .travis.yml -# It runs the appropriate commands depending on the task requested. +if [ "$TASK" = "spellcheck" ]; then + result=0 + # Create list of files to be spellchecked + spellcheck_files=$(find -type f | grep -v ".git/") -set -e + # Run spellintian to find spelling errors + sl_results=$(spellintian $spellcheck_files 2>&1) -SPELLINGBLACKLIST=$(cat <<-BLACKLIST --wholename "./.git/*" -BLACKLIST -) + sl_errors=$(wc -l <<< "$sl_results") + sl_errors_dups=$((grep "\(duplicate word\)" | wc -l) <<< "$sl_results") + sl_errors_nodups=$((grep -v "\(duplicate word\)" | wc -l) <<< "$sl_results") -if [[ $TASK = 'spellintian' ]]; then - # run spellintian only if it is the requested task, ignoring duplicate words - spellingfiles=$(eval "find ./ -type f -and ! \( \ - $SPELLINGBLACKLIST \ - \) | xargs") - # count the number of spellintian errors, ignoring duplicate words - spellingerrors=$(zrun spellintian $spellingfiles 2>&1 | grep -v "\(duplicate word\)" | wc -l) - if [[ $spellingerrors -ne 0 ]]; then - # print the output for info - zrun spellintian $spellingfiles | grep -v "\(duplicate word\)" - echo "Found $spellingerrors spelling errors via spellintian, ignoring duplicates" - exit 1; + if [ "$sl_errors" -ne 0 ]; then + printf "Spellintian found %s errors (%s spelling, %s duplicate words):\n\n" "$sl_errors" "$sl_errors_nodups" "$sl_errors_dups" + printf "%s\n\n" "$sl_results" + result=1 else - echo "Found $spellingerrors spelling errors via spellintian, ignoring duplicates" - fi; -elif [[ $TASK = 'spellintian-duplicates' ]]; then - # run spellintian only if it is the requested task - spellingfiles=$(eval "find ./ -type f -and ! \( \ - $SPELLINGBLACKLIST \ - \) | xargs") - # count the number of spellintian errors - spellingerrors=$(zrun spellintian $spellingfiles 2>&1 | wc -l) - if [[ $spellingerrors -ne 0 ]]; then - # print the output for info - zrun spellintian $spellingfiles - echo "Found $spellingerrors spelling errors via spellintian" - exit 1; - else - echo "Found $spellingerrors spelling errors via spellintian" - fi; -elif [[ $TASK = 'codespell' ]]; then - # run codespell only if it is the requested task - spellingfiles=$(eval "find ./ -type f -and ! \( \ - $SPELLINGBLACKLIST \ - \) | xargs") - # count the number of codespell errors - spellingerrors=$(zrun codespell --check-filenames --check-hidden --quiet 2 --regex "[a-zA-Z0-9][\\-'a-zA-Z0-9]+[a-zA-Z0-9]" $spellingfiles 2>&1 | wc -l) - if [[ $spellingerrors -ne 0 ]]; then - # print the output for info - zrun codespell --check-filenames --check-hidden --quiet 2 --regex "[a-zA-Z0-9][\\-'a-zA-Z0-9]+[a-zA-Z0-9]" $spellingfiles - echo "Found $spellingerrors spelling errors via codespell" - exit 1; + printf "Spellintian reports no errors\n" + fi + + # Run codespell to find some more + cs_results=$(codespell --check-filenames --check-hidden --quiet 2 --regex "[a-zA-Z0-9][\\-'a-zA-Z0-9]+[a-zA-Z0-9]" $spellcheck_files 2>&1) + cs_errors=$(wc -l <<< "$cs_results") + if [ "$cs_errors" -ne 0 ]; then + printf "Codespell found %s errors:\n\n" "$cs_errors" + printf "%s\n\n" "$cs_results" + result=1 else - echo "Found $spellingerrors spelling errors via codespell" - fi; -elif [[ $TASK = 'sanitize' ]]; then + printf "Codespell reports no errors\n" + fi + exit "$result" +elif [ "$TASK" = 'sanitize' ]; then # Run sanitized compile travis_fold start "make_sanitize" make sanitize; travis_fold end "make_sanitize" -elif [[ $TASK = 'windows' ]]; then +elif [ "$TASK" = 'windows' ]; then travis_fold start "make_windows" make windows; make -C backends lua.dll diff --git a/.travis.yml b/.travis.yml index b9b6969..48b4b71 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,6 @@ script: addons: apt: packages: &base_build - # This is the absolute minimum for configure to pass - # Non C++ based tasks use it so they can run make builtfiles - ccache packages: &core_build # This is all the bits we need to enable all options @@ -36,6 +34,11 @@ addons: packages: &core_build_windows - *core_build - mingw-w64 + packages: &linters + - lintian + - codespell + - shellcheck + - cloc jobs: fast_finish: true @@ -74,30 +77,6 @@ jobs: apt: packages: - *core_build_clang_latest - - os: linux - dist: bionic - env: TASK='spellintian' - addons: - apt: - packages: - - *core_build - - moreutils - - os: linux - dist: bionic - env: TASK='spellintian-duplicates' - addons: - apt: - packages: - - *core_build - - moreutils - - os: linux - dist: bionic - env: TASK='codespell' - addons: - apt: - packages: - - *core_build - - moreutils - os: osx osx_image: xcode10.2 compiler: clang @@ -116,10 +95,18 @@ jobs: allow_failures: - os: linux dist: bionic - env: TASK='spellintian-duplicates' + env: TASK='codesmell' + addons: + apt: + packages: + - *linters - os: linux dist: bionic - env: TASK='codespell' + env: TASK='spellcheck' + addons: + apt: + packages: + - *linters env: global: @@ -136,9 +123,6 @@ cache: before_cache: - ccache -s # see how many hits ccache got -install: - - if [ "$TASK" = "codespell" ]; then pip install --user git+https://github.com/codespell-project/codespell.git; fi - before_install: # Travis clones with --branch, which omits tags. Since we use them for the version string at build time, fetch them - git pull --tags -- cgit v1.2.3 From abb1ffd367f4046d77ac62b0b017b407997bc43b Mon Sep 17 00:00:00 2001 From: cbdev Date: Wed, 11 Mar 2020 21:53:14 +0100 Subject: Add codesmell statistics to CI --- .travis-ci.sh | 34 +++++++++++++++++++++++++++++++--- .travis.yml | 12 ++++++++++-- midimonster.h | 6 ++++-- 3 files changed, 45 insertions(+), 7 deletions(-) (limited to '.travis.yml') diff --git a/.travis-ci.sh b/.travis-ci.sh index e9e3df3..763e558 100644 --- a/.travis-ci.sh +++ b/.travis-ci.sh @@ -21,7 +21,7 @@ if [ "$TASK" = "spellcheck" ]; then fi # Run codespell to find some more - cs_results=$(codespell --check-filenames --check-hidden --quiet 2 --regex "[a-zA-Z0-9][\\-'a-zA-Z0-9]+[a-zA-Z0-9]" $spellcheck_files 2>&1) + cs_results=$(codespell --check-hidden --quiet 2 --regex "[a-zA-Z0-9][\\-'a-zA-Z0-9]+[a-zA-Z0-9]" $spellcheck_files 2>&1) cs_errors=$(wc -l <<< "$cs_results") if [ "$cs_errors" -ne 0 ]; then printf "Codespell found %s errors:\n\n" "$cs_errors" @@ -31,12 +31,40 @@ if [ "$TASK" = "spellcheck" ]; then printf "Codespell reports no errors\n" fi exit "$result" -elif [ "$TASK" = 'sanitize' ]; then +elif [ "$TASK" = "codesmell" ]; then + result=0 + + if [ -z "$(which lizard)" ]; then + printf "Installing lizard...\n" + pip3 install lizard + fi + + # Run shellcheck for all shell scripts + printf "Running shellcheck...\n" + shell_files="$(find . -type f -iname \*.sh)" + xargs shellcheck -Cnever -s bash <<< "$shell_files" + if [ "$?" -ne "0" ]; then + result=1 + fi + + # Run cloc for some stats + printf "Code statistics:\n\n" + cloc ./ + + # Run lizard for the project + printf "Running lizard for code complexity analysis\n" + lizard ./ + if [ "$?" -ne "0" ]; then + result=1 + fi + + exit "$result" +elif [ "$TASK" = "sanitize" ]; then # Run sanitized compile travis_fold start "make_sanitize" make sanitize; travis_fold end "make_sanitize" -elif [ "$TASK" = 'windows' ]; then +elif [ "$TASK" = "windows" ]; then travis_fold start "make_windows" make windows; make -C backends lua.dll diff --git a/.travis.yml b/.travis.yml index 48b4b71..a5de2f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ before_script: - export -f travis_fold script: - - "bash -ex .travis-ci.sh" + - "bash .travis-ci.sh" addons: apt: @@ -35,6 +35,8 @@ addons: - *core_build - mingw-w64 packages: &linters + - python3 + - python3-pip - lintian - codespell - shellcheck @@ -92,7 +94,6 @@ jobs: compiler: clang env: - TASK='sanitize' - allow_failures: - os: linux dist: bionic env: TASK='codesmell' @@ -107,6 +108,13 @@ jobs: apt: packages: - *linters + allow_failures: + - os: linux + dist: bionic + env: TASK='codesmell' + - os: linux + dist: bionic + env: TASK='spellcheck' env: global: diff --git a/midimonster.h b/midimonster.h index bad83c7..dc0e255 100644 --- a/midimonster.h +++ b/midimonster.h @@ -234,10 +234,12 @@ MM_API instance* mm_instance_find(char* backend, uint64_t ident); * matching `ident`, a pointer to it is returned. * This API is just a convenience function. The array of channels is * only used for mapping internally, creating and managing your own - * channel store is possible. + * channel store is possible. When returning pointers from a + * backend-local channel store, the returned pointers must stay + * valid over the lifetime of the instance. * For each channel with a non-NULL `impl` field registered using * this function, the backend will receive a call to its channel_free - * function. + * function (if it exists). */ MM_API channel* mm_channel(instance* i, uint64_t ident, uint8_t create); -- cgit v1.2.3 From 5087d4ebde3f9a1ec775928ec25f50099be3d8ad Mon Sep 17 00:00:00 2001 From: Spacelord Date: Thu, 12 Mar 2020 14:31:21 +0100 Subject: Add travis irc notification --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to '.travis.yml') diff --git a/.travis.yml b/.travis.yml index a5de2f4..c3bcc12 100644 --- a/.travis.yml +++ b/.travis.yml @@ -154,6 +154,15 @@ before_install: # Download libraries to link with on Windows - if [ "$TASK" == "windows" ]; then mkdir libs; wget "https://downloads.sourceforge.net/project/luabinaries/5.3.5/Windows%20Libraries/Dynamic/lua-5.3.5_Win64_dllw6_lib.zip" -O lua53.zip; unzip lua53.zip lua53.dll; mv lua53.dll libs; fi +notifications: + irc: + channels: + - "rc.hackint.org#midimonster" + on_success: change # default: always + on_failure: always # default: always + nick: MIDIMonster CI + use_notice: true + deploy: provider: releases file_glob: true -- cgit v1.2.3 From 378296f1b49c64f20c61966d2dcc8c8143181a07 Mon Sep 17 00:00:00 2001 From: Spacelord Date: Thu, 12 Mar 2020 14:40:42 +0100 Subject: Fix typo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to '.travis.yml') diff --git a/.travis.yml b/.travis.yml index c3bcc12..b9c2b9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -157,7 +157,7 @@ before_install: notifications: irc: channels: - - "rc.hackint.org#midimonster" + - "irc.hackint.org#midimonster" on_success: change # default: always on_failure: always # default: always nick: MIDIMonster CI -- cgit v1.2.3 From 4b120a64f68fd7f36e8080981d68d0830d113205 Mon Sep 17 00:00:00 2001 From: cbdev Date: Thu, 12 Mar 2020 21:51:43 +0100 Subject: Fix rate-limited frame synthesis --- .travis.yml | 2 +- backends/artnet.c | 4 ++-- backends/sacn.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to '.travis.yml') diff --git a/.travis.yml b/.travis.yml index b9c2b9d..d7c25b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -160,7 +160,7 @@ notifications: - "irc.hackint.org#midimonster" on_success: change # default: always on_failure: always # default: always - nick: MIDIMonster CI + nick: mm_ci use_notice: true deploy: diff --git a/backends/artnet.c b/backends/artnet.c index 7d5d9ee..34fc82d 100644 --- a/backends/artnet.c +++ b/backends/artnet.c @@ -280,8 +280,8 @@ static int artnet_set(instance* inst, size_t num, channel** c, channel_value* v) //check output rate limit, request next frame if(frame_delta < ARTNET_FRAME_TIMEOUT){ artnet_fd[data->fd_index].output_instance[u].mark = 1; - if(!next_frame || next_frame > (ARTNET_KEEPALIVE_INTERVAL - frame_delta)){ - next_frame = (ARTNET_KEEPALIVE_INTERVAL - frame_delta); + if(!next_frame || next_frame > (ARTNET_FRAME_TIMEOUT - frame_delta)){ + next_frame = (ARTNET_FRAME_TIMEOUT - frame_delta); } return 0; } diff --git a/backends/sacn.c b/backends/sacn.c index c9be8ff..495bdf3 100644 --- a/backends/sacn.c +++ b/backends/sacn.c @@ -374,8 +374,8 @@ static int sacn_set(instance* inst, size_t num, channel** c, channel_value* v){ //check if ratelimiting engaged if(frame_delta < SACN_FRAME_TIMEOUT){ global_cfg.fd[data->fd_index].universe[u].mark = 1; - if(!global_cfg.next_frame || global_cfg.next_frame > (SACN_KEEPALIVE_INTERVAL - frame_delta)){ - global_cfg.next_frame = (SACN_KEEPALIVE_INTERVAL - frame_delta); + if(!global_cfg.next_frame || global_cfg.next_frame > (SACN_FRAME_TIMEOUT - frame_delta)){ + global_cfg.next_frame = (SACN_FRAME_TIMEOUT - frame_delta); } return 0; } -- cgit v1.2.3