summaryrefslogtreecommitdiffstats
path: root/ci
diff options
context:
space:
mode:
Diffstat (limited to 'ci')
-rwxr-xr-xci/build-freebsd.sh35
-rwxr-xr-xci/build-linux-old.sh18
-rwxr-xr-xci/build-macos.sh25
-rwxr-xr-xci/build-mingw64.sh313
-rwxr-xr-xci/build-msys2.sh26
-rwxr-xr-xci/build-openbsd.sh22
-rwxr-xr-xci/build-tumbleweed.sh25
-rwxr-xr-xci/lint-commit-msg.py118
8 files changed, 475 insertions, 107 deletions
diff --git a/ci/build-freebsd.sh b/ci/build-freebsd.sh
index 32ba0df010..e272ef6774 100755
--- a/ci/build-freebsd.sh
+++ b/ci/build-freebsd.sh
@@ -5,22 +5,25 @@ export CFLAGS="$CFLAGS -isystem/usr/local/include"
export CXXFLAGS="$CXXFLAGS -isystem/usr/local/include"
export LDFLAGS="$LDFLAGS -L/usr/local/lib"
-if [ ! -e "./waf" ] ; then
- python3 ./bootstrap.py
-fi
+# TODO: readd -Ddvbin=enabled
-python3 ./waf configure \
- --enable-libmpv-shared \
- --enable-lua \
- --enable-egl-drm \
- --enable-openal \
- --enable-sdl2 \
- --enable-vaapi-wayland \
- --enable-vdpau \
- --enable-vulkan \
- $(pkg info -q v4l_compat && echo --enable-dvbin) \
- $(pkg info -q libdvdnav && echo --enable-dvdnav) \
- $(pkg info -q libcdio-paranoia && echo --enable-cdda) \
+meson setup build \
+ --werror \
+ -Dc_args="-Wno-error=deprecated -Wno-error=deprecated-declarations -march=native" \
+ -Diconv=disabled \
+ -Dlibmpv=true \
+ -Dlua=enabled \
+ -Degl-drm=enabled \
+ -Dopenal=enabled \
+ -Dsndio=enabled \
+ -Dtests=true \
+ -Dvdpau=enabled \
+ -Dvulkan=enabled \
+ -Doss-audio=enabled \
+ $(pkg info -q libdvdnav && echo -Ddvdnav=enabled) \
+ $(pkg info -q libcdio-paranoia && echo -Dcdda=enabled) \
+ $(pkg info -q pipewire && echo -Dpipewire=enabled) \
$NULL
-python3 ./waf build
+meson compile -C build
+./build/mpv -v --no-config
diff --git a/ci/build-linux-old.sh b/ci/build-linux-old.sh
new file mode 100755
index 0000000000..d9cd9eef04
--- /dev/null
+++ b/ci/build-linux-old.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+set -e
+
+# clone exactly the oldest libplacebo we want to support
+rm -rf subprojects
+mkdir -p subprojects
+git clone https://code.videolan.org/videolan/libplacebo.git \
+ --recurse-submodules --shallow-submodules \
+ --depth=1 --branch v6.338 subprojects/libplacebo \
+
+meson setup build \
+ -Dlibplacebo:vulkan=disabled \
+ -Dlibmpv=true \
+ -Dlua=enabled \
+ -Dtests=true
+
+meson compile -C build
+./build/mpv -v --no-config
diff --git a/ci/build-macos.sh b/ci/build-macos.sh
index 347a75160f..d11befa13a 100755
--- a/ci/build-macos.sh
+++ b/ci/build-macos.sh
@@ -10,17 +10,16 @@ if [[ -d "./build/${MPV_VARIANT}" ]] ; then
rm -rf "./build/${MPV_VARIANT}"
fi
-if [[ ! -e "./waf" ]] ; then
- python3 ./bootstrap.py
-fi
-
-PKG_CONFIG_PATH="${FFMPEG_SYSROOT}/lib/pkgconfig/" CC="${CC}" CXX="${CXX}" python3 \
- ./waf configure \
- --variant="${MPV_VARIANT}" \
- --prefix="${MPV_INSTALL_PREFIX}" \
- --enable-{gl,iconv,lcms2,libmpv-shared,lua,jpeg,plain-gl,zlib} \
- --enable-{cocoa,coreaudio,gl-cocoa,macos-cocoa-cb,macos-touchbar,videotoolbox-gl}
-
-python3 ./waf build --variant="${MPV_VARIANT}" -j4
+PKG_CONFIG_PATH="${FFMPEG_SYSROOT}/lib/pkgconfig/" CC="${CC}" CXX="${CXX}" \
+meson setup build \
+ --werror \
+ -Dprefix="${MPV_INSTALL_PREFIX}" \
+ -D{c_args,objc_args}="-Wno-error=deprecated -Wno-error=deprecated-declarations" \
+ -D{libmpv,tests}=true \
+ -D{gl,iconv,lcms2,lua,jpeg,plain-gl,zlib}=enabled \
+ -D{cocoa,coreaudio,gl-cocoa,videotoolbox-gl,videotoolbox-pl}=enabled \
+ -D{swift-build,macos-cocoa-cb,macos-media-player,macos-touchbar,vulkan}=enabled
-python3 ./waf install --variant="${MPV_VARIANT}"
+meson compile -C build -j4
+meson install -C build
+./build/mpv -v --no-config
diff --git a/ci/build-mingw64.sh b/ci/build-mingw64.sh
index 77a7c99cbb..5ca8cf166f 100755
--- a/ci/build-mingw64.sh
+++ b/ci/build-mingw64.sh
@@ -6,14 +6,11 @@ ln -snf . "$prefix_dir/usr"
ln -snf . "$prefix_dir/local"
wget="wget -nc --progress=bar:force"
-gitclone="git clone --depth=10"
-commonflags="--disable-static --enable-shared"
-
-export PKG_CONFIG_SYSROOT_DIR="$prefix_dir"
-export PKG_CONFIG_LIBDIR="$PKG_CONFIG_SYSROOT_DIR/lib/pkgconfig"
+gitclone="git clone --depth=1 --recursive --shallow-submodules"
# -posix is Ubuntu's variant with pthreads support
export CC=$TARGET-gcc-posix
+export AS=$TARGET-gcc-posix
export CXX=$TARGET-g++-posix
export AR=$TARGET-ar
export NM=$TARGET-nm
@@ -22,130 +19,310 @@ export RANLIB=$TARGET-ranlib
export CFLAGS="-O2 -pipe -Wall -D_FORTIFY_SOURCE=2"
export LDFLAGS="-fstack-protector-strong"
-function builddir () {
+# anything that uses pkg-config
+export PKG_CONFIG_SYSROOT_DIR="$prefix_dir"
+export PKG_CONFIG_LIBDIR="$PKG_CONFIG_SYSROOT_DIR/lib/pkgconfig"
+
+# autotools(-like)
+commonflags="--disable-static --enable-shared"
+
+# meson
+fam=x86_64
+[[ "$TARGET" == "i686-"* ]] && fam=x86
+cat >"$prefix_dir/crossfile" <<EOF
+[built-in options]
+buildtype = 'release'
+wrap_mode = 'nodownload'
+[binaries]
+c = ['ccache', '${CC}']
+cpp = ['ccache', '${CXX}']
+ar = '${AR}'
+strip = '${TARGET}-strip'
+pkgconfig = 'pkg-config'
+windres = '${TARGET}-windres'
+dlltool = '${TARGET}-dlltool'
+[host_machine]
+system = 'windows'
+cpu_family = '${fam}'
+cpu = '${TARGET%%-*}'
+endian = 'little'
+EOF
+
+# CMake
+cmake_args=(
+ -Wno-dev
+ -DCMAKE_SYSTEM_PROCESSOR="${fam}"
+ -DCMAKE_SYSTEM_NAME=Windows
+ -DCMAKE_FIND_ROOT_PATH="$PKG_CONFIG_SYSROOT_DIR"
+ -DCMAKE_RC_COMPILER="${TARGET}-windres"
+ -DCMAKE_ASM_COMPILER="$AS"
+ -DCMAKE_BUILD_TYPE=Release
+)
+
+export CC="ccache $CC"
+export CXX="ccache $CXX"
+
+function builddir {
[ -d "$1/builddir" ] && rm -rf "$1/builddir"
mkdir -p "$1/builddir"
pushd "$1/builddir"
}
-function makeplusinstall () {
- make -j$(nproc)
- make DESTDIR="$prefix_dir" install
+function makeplusinstall {
+ if [ -f build.ninja ]; then
+ ninja
+ DESTDIR="$prefix_dir" ninja install
+ else
+ make -j$(nproc)
+ make DESTDIR="$prefix_dir" install
+ fi
}
-function gettar () {
- name="${1##*/}"
+function gettar {
+ local name="${1##*/}"
[ -d "${name%%.*}" ] && return 0
$wget "$1"
tar -xaf "$name"
}
-## iconv
-if [ ! -e "$prefix_dir/lib/libiconv.dll.a" ]; then
- ver=1.16
+function build_if_missing {
+ local name=${1//-/_}
+ local mark_var=_${name}_mark
+ local mark_file=$prefix_dir/${!mark_var}
+ [ -e "$mark_file" ] && return 0
+ echo "::group::Building $1"
+ _$name
+ echo "::endgroup::"
+ if [ ! -e "$mark_file" ]; then
+ echo "Error: Build of $1 completed but $mark_file was not created."
+ return 2
+ fi
+}
+
+
+## mpv's dependencies
+
+_iconv () {
+ local ver=1.17
gettar "https://ftp.gnu.org/pub/gnu/libiconv/libiconv-${ver}.tar.gz"
builddir libiconv-${ver}
../configure --host=$TARGET $commonflags
makeplusinstall
popd
-fi
+}
+_iconv_mark=lib/libiconv.dll.a
-## zlib
-if [ ! -e "$prefix_dir/lib/libz.dll.a" ]; then
- ver=1.2.11
- gettar "https://zlib.net/zlib-${ver}.tar.gz"
+_zlib () {
+ local ver=1.3.1
+ gettar "https://zlib.net/fossils/zlib-${ver}.tar.gz"
pushd zlib-${ver}
- make -fwin32/Makefile.gcc PREFIX=$TARGET- SHARED_MODE=1 \
+ make -fwin32/Makefile.gcc clean
+ make -fwin32/Makefile.gcc PREFIX=$TARGET- CC="$CC" SHARED_MODE=1 \
DESTDIR="$prefix_dir" install \
BINARY_PATH=/bin INCLUDE_PATH=/include LIBRARY_PATH=/lib
popd
-fi
+}
+_zlib_mark=lib/libz.dll.a
-## ffmpeg
-if [ ! -e "$prefix_dir/lib/libavcodec.dll.a" ]; then
+_dav1d () {
+ [ -d dav1d ] || $gitclone https://code.videolan.org/videolan/dav1d.git
+ builddir dav1d
+ meson setup .. --cross-file "$prefix_dir/crossfile" \
+ -Denable_{tools,tests}=false
+ makeplusinstall
+ popd
+}
+_dav1d_mark=lib/libdav1d.dll.a
+
+_ffmpeg () {
[ -d ffmpeg ] || $gitclone https://github.com/FFmpeg/FFmpeg.git ffmpeg
builddir ffmpeg
- ../configure --pkg-config=pkg-config --target-os=mingw32 \
- --enable-cross-compile --cross-prefix=$TARGET- --arch=${TARGET%%-*} \
- $commonflags \
- --disable-{stripping,doc,programs,muxers,encoders,devices}
+ local args=(
+ --pkg-config=pkg-config --target-os=mingw32
+ --enable-cross-compile --cross-prefix=$TARGET- --arch=${TARGET%%-*}
+ --cc="$CC" --cxx="$CXX" $commonflags
+ --disable-{doc,programs,muxers,encoders}
+ --enable-muxer=spdif --enable-encoder=mjpeg,png --enable-libdav1d
+ )
+ pkg-config vulkan && args+=(--enable-vulkan --enable-libshaderc)
+ ../configure "${args[@]}"
makeplusinstall
popd
-fi
+}
+_ffmpeg_mark=lib/libavcodec.dll.a
-## shaderc
-if [ ! -e "$prefix_dir/lib/libshaderc_shared.dll.a" ]; then
+_shaderc () {
if [ ! -d shaderc ]; then
$gitclone https://github.com/google/shaderc.git
(cd shaderc && ./utils/git-sync-deps)
fi
builddir shaderc
- cmake .. -DCMAKE_SYSTEM_NAME=Windows \
- -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF \
- -DSHADERC_SKIP_TESTS=ON -DCMAKE_INSTALL_PREFIX=/
+ cmake .. "${cmake_args[@]}" \
+ -DBUILD_SHARED_LIBS=OFF -DSHADERC_SKIP_TESTS=ON
makeplusinstall
popd
-fi
+}
+_shaderc_mark=lib/libshaderc_shared.dll.a
-## spirv-cross
-if [ ! -e "$prefix_dir/lib/libspirv-cross-c-shared.dll.a" ]; then
+_spirv_cross () {
[ -d SPIRV-Cross ] || $gitclone https://github.com/KhronosGroup/SPIRV-Cross
builddir SPIRV-Cross
- cmake .. -DCMAKE_SYSTEM_NAME=Windows \
+ cmake .. "${cmake_args[@]}" \
-DSPIRV_CROSS_SHARED=ON -DSPIRV_CROSS_{CLI,STATIC}=OFF
makeplusinstall
popd
-fi
+}
+_spirv_cross_mark=lib/libspirv-cross-c-shared.dll.a
+
+_nv_headers () {
+ [ -d nv-codec-headers ] || $gitclone https://github.com/FFmpeg/nv-codec-headers
+ pushd nv-codec-headers
+ makeplusinstall
+ popd
+}
+_nv_headers_mark=include/ffnvcodec/dynlink_loader.h
+
+_vulkan_headers () {
+ [ -d Vulkan-Headers ] || $gitclone https://github.com/KhronosGroup/Vulkan-Headers
+ builddir Vulkan-Headers
+ cmake .. "${cmake_args[@]}"
+ makeplusinstall
+ popd
+}
+_vulkan_headers_mark=include/vulkan/vulkan.h
+
+_vulkan_loader () {
+ [ -d Vulkan-Loader ] || $gitclone https://github.com/KhronosGroup/Vulkan-Loader
+ builddir Vulkan-Loader
+ cmake .. "${cmake_args[@]}" \
+ -DENABLE_WERROR=OFF -DUSE_GAS=ON
+ makeplusinstall
+ popd
+}
+_vulkan_loader_mark=lib/libvulkan-1.dll.a
-## freetype2
-if [ ! -e "$prefix_dir/lib/libfreetype.dll.a" ]; then
- ver=2.10.2
- gettar "https://download.savannah.gnu.org/releases/freetype/freetype-${ver}.tar.gz"
+_libplacebo () {
+ [ -d libplacebo ] || $gitclone https://code.videolan.org/videolan/libplacebo.git
+ builddir libplacebo
+ meson setup .. --cross-file "$prefix_dir/crossfile" \
+ -Ddemos=false -D{opengl,d3d11}=enabled
+ makeplusinstall
+ popd
+}
+_libplacebo_mark=lib/libplacebo.dll.a
+
+_freetype () {
+ local ver=2.13.2
+ gettar "https://mirror.netcologne.de/savannah/freetype/freetype-${ver}.tar.xz"
builddir freetype-${ver}
- ZLIB_LIBS="-L'$prefix_dir/lib' -lz" \
- ../configure --host=$TARGET $commonflags --with-png=no
+ meson setup .. --cross-file "$prefix_dir/crossfile"
makeplusinstall
popd
-fi
-[ -f "$prefix_dir/lib/libfreetype.dll.a" ] || { echo "libtool fuckup"; exit 1; }
+}
+_freetype_mark=lib/libfreetype.dll.a
-## fribidi
-if [ ! -e "$prefix_dir/lib/libfribidi.dll.a" ]; then
- ver=1.0.9
+_fribidi () {
+ local ver=1.0.14
gettar "https://github.com/fribidi/fribidi/releases/download/v${ver}/fribidi-${ver}.tar.xz"
builddir fribidi-${ver}
- ../configure --host=$TARGET $commonflags
+ meson setup .. --cross-file "$prefix_dir/crossfile" \
+ -D{tests,docs}=false
makeplusinstall
popd
-fi
+}
+_fribidi_mark=lib/libfribidi.dll.a
-## libass
-if [ ! -e "$prefix_dir/lib/libass.dll.a" ]; then
+_harfbuzz () {
+ local ver=8.4.0
+ gettar "https://github.com/harfbuzz/harfbuzz/releases/download/${ver}/harfbuzz-${ver}.tar.xz"
+ builddir harfbuzz-${ver}
+ meson setup .. --cross-file "$prefix_dir/crossfile" \
+ -Dtests=disabled
+ makeplusinstall
+ popd
+}
+_harfbuzz_mark=lib/libharfbuzz.dll.a
+
+_libass () {
[ -d libass ] || $gitclone https://github.com/libass/libass.git
builddir libass
[ -f ../configure ] || (cd .. && ./autogen.sh)
../configure --host=$TARGET $commonflags
makeplusinstall
popd
-fi
+}
+_libass_mark=lib/libass.dll.a
-## luajit
-if [ ! -e "$prefix_dir/lib/libluajit-5.1.a" ]; then
- ver=2.0.5
- gettar "http://luajit.org/download/LuaJIT-${ver}.tar.gz"
- pushd LuaJIT-${ver}
- hostcc=gcc
- [[ "$TARGET" == "i686-"* ]] && hostcc="$hostcc -m32"
- make HOST_CC="$hostcc" CROSS=$TARGET- TARGET_SYS=Windows \
- BUILDMODE=static amalg
+_luajit () {
+ [ -d LuaJIT ] || $gitclone https://github.com/LuaJIT/LuaJIT.git
+ pushd LuaJIT
+ local hostcc="ccache cc"
+ local flags=
+ [[ "$TARGET" == "i686-"* ]] && { hostcc="$hostcc -m32"; flags=XCFLAGS=-DLUAJIT_NO_UNWIND; }
+ make TARGET_SYS=Windows clean
+ make TARGET_SYS=Windows HOST_CC="$hostcc" CROSS="ccache $TARGET-" \
+ BUILDMODE=static $flags amalg
make DESTDIR="$prefix_dir" INSTALL_DEP= FILE_T=luajit.exe install
popd
+}
+_luajit_mark=lib/libluajit-5.1.a
+
+for x in iconv zlib shaderc spirv-cross nv-headers dav1d; do
+ build_if_missing $x
+done
+if [[ "$TARGET" != "i686-"* ]]; then
+ build_if_missing vulkan-headers
+ build_if_missing vulkan-loader
fi
+for x in ffmpeg libplacebo freetype fribidi harfbuzz libass luajit; do
+ build_if_missing $x
+done
## mpv
-PKG_CONFIG=pkg-config CFLAGS="-I'$prefix_dir/include'" LDFLAGS="-L'$prefix_dir/lib'" \
-python3 ./waf configure \
- --enable-libmpv-shared --lua=luajit \
- --enable-{shaderc,spirv-cross,d3d11}
-python3 ./waf build --verbose
+[ -z "$1" ] && exit 0
+
+CFLAGS+=" -I'$prefix_dir/include'"
+LDFLAGS+=" -L'$prefix_dir/lib'"
+export CFLAGS LDFLAGS
+build=mingw_build
+rm -rf $build
+
+meson setup $build --cross-file "$prefix_dir/crossfile" \
+ --werror \
+ -Dc_args="-Wno-error=deprecated -Wno-error=deprecated-declarations" \
+ --buildtype debugoptimized \
+ -Dlibmpv=true -Dlua=luajit \
+ -D{shaderc,spirv-cross,d3d11}=enabled
+
+meson compile -C $build
+
+if [ "$2" = pack ]; then
+ mkdir -p artifact/tmp
+ echo "Copying:"
+ cp -pv $build/mpv.com $build/mpv.exe artifact/
+ # copy everything we can get our hands on
+ cp -p "$prefix_dir/bin/"*.dll artifact/tmp/
+ shopt -s nullglob
+ for file in /usr/lib/gcc/$TARGET/*-posix/*.dll /usr/$TARGET/lib/*.dll; do
+ cp -p "$file" artifact/tmp/
+ done
+ # pick DLLs we need
+ pushd artifact/tmp
+ dlls=(
+ libgcc_*.dll lib{ssp,stdc++,winpthread}-[0-9]*.dll # compiler runtime
+ av*.dll sw*.dll lib{ass,freetype,fribidi,harfbuzz,iconv,placebo}-[0-9]*.dll
+ lib{shaderc_shared,spirv-cross-c-shared,dav1d}.dll zlib1.dll
+ )
+ if [[ -f vulkan-1.dll ]]; then
+ dlls+=(vulkan-1.dll)
+ fi
+ mv -v "${dlls[@]}" ..
+ popd
+
+ echo "Archiving:"
+ pushd artifact
+ rm -rf tmp
+ zip -9r "../mpv-git-$(date +%F)-$(git rev-parse --short HEAD)-${TARGET%%-*}.zip" -- *
+ popd
+fi
diff --git a/ci/build-msys2.sh b/ci/build-msys2.sh
new file mode 100755
index 0000000000..1a0e0226aa
--- /dev/null
+++ b/ci/build-msys2.sh
@@ -0,0 +1,26 @@
+#!/bin/sh -e
+
+meson setup build \
+ --werror \
+ -Dc_args="-Wno-error=deprecated -Wno-error=deprecated-declarations" \
+ -D cdda=enabled \
+ -D d3d-hwaccel=enabled \
+ -D d3d11=enabled \
+ -D dvdnav=enabled \
+ -D egl-angle-lib=enabled \
+ -D egl-angle-win32=enabled \
+ -D jpeg=enabled \
+ -D lcms2=enabled \
+ -D libarchive=enabled \
+ -D libbluray=enabled \
+ -D libmpv=true \
+ -D lua=enabled \
+ -D pdf-build=enabled \
+ -D rubberband=enabled \
+ -D shaderc=enabled \
+ -D spirv-cross=enabled \
+ -D tests=true \
+ -D uchardet=enabled \
+ -D vapoursynth=enabled
+meson compile -C build
+./build/mpv.com -v --no-config
diff --git a/ci/build-openbsd.sh b/ci/build-openbsd.sh
new file mode 100755
index 0000000000..8e9125cf38
--- /dev/null
+++ b/ci/build-openbsd.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+set -e
+
+# libplacebo on openBSD is too old; use a subproject
+rm -rf subprojects
+mkdir -p subprojects
+git clone https://code.videolan.org/videolan/libplacebo.git \
+ --recurse-submodules --shallow-submodules \
+ --depth=1 --recurse-submodules subprojects/libplacebo
+
+meson setup build \
+ -Dlibmpv=true \
+ -Dlua=enabled \
+ -Dopenal=enabled \
+ -Dpulse=enabled \
+ -Dtests=true \
+ -Dvulkan=enabled \
+ -Ddvdnav=enabled \
+ -Dcdda=enabled
+
+meson compile -C build
+./build/mpv -v --no-config
diff --git a/ci/build-tumbleweed.sh b/ci/build-tumbleweed.sh
index 9c0c2851a6..069372a21c 100755
--- a/ci/build-tumbleweed.sh
+++ b/ci/build-tumbleweed.sh
@@ -1,13 +1,18 @@
#!/bin/sh
set -e
-python3 ./waf configure \
- --enable-cdda \
- --enable-dvbin \
- --enable-dvdnav \
- --enable-libarchive \
- --enable-libmpv-shared \
- --enable-manpage-build \
- --enable-shaderc \
- --enable-vulkan
-python3 ./waf build --verbose
+meson setup build \
+ --werror \
+ -Dc_args="-Wno-error=deprecated -Wno-error=deprecated-declarations" \
+ -Db_sanitize=address,undefined \
+ -Dcdda=enabled \
+ -Ddvbin=enabled \
+ -Ddvdnav=enabled \
+ -Dlibarchive=enabled \
+ -Dlibmpv=true \
+ -Dmanpage-build=enabled \
+ -Dpipewire=enabled \
+ -Dtests=true \
+ -Dvulkan=enabled
+meson compile -C build
+./build/mpv -v --no-config
diff --git a/ci/lint-commit-msg.py b/ci/lint-commit-msg.py
new file mode 100755
index 0000000000..9c7881ba07
--- /dev/null
+++ b/ci/lint-commit-msg.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python3
+import os, sys, json, subprocess, re
+from typing import Dict, Tuple, Callable, Optional
+
+def call(cmd) -> str:
+ sys.stdout.flush()
+ ret = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, text=True)
+ return ret.stdout
+
+lint_rules: Dict[str, Tuple[Callable, str]] = {}
+
+def lint_rule(description: str):
+ def f(func):
+ assert func.__name__ not in lint_rules.keys()
+ lint_rules[func.__name__] = (func, description)
+ return f
+
+def get_commit_range() -> Optional[str]:
+ if len(sys.argv) > 1:
+ return sys.argv[1]
+ # https://github.com/actions/runner/issues/342#issuecomment-590670059
+ event_name = os.environ["GITHUB_EVENT_NAME"]
+ with open(os.environ["GITHUB_EVENT_PATH"], "rb") as f:
+ event = json.load(f)
+ if event_name == "push":
+ if event["created"] or event["forced"]:
+ print("Skipping logic on branch creation or force-push")
+ return None
+ return event["before"] + "..." + event["after"]
+ elif event_name == "pull_request":
+ return event["pull_request"]["base"]["sha"] + ".." + event["pull_request"]["head"]["sha"]
+ return None
+
+def do_lint(commit_range: str) -> bool:
+ commits = call(["git", "log", "--pretty=format:%H %s", commit_range]).splitlines()
+ print(f"Linting {len(commits)} commit(s):")
+ any_failed = False
+ for commit in commits:
+ sha, _, _ = commit.partition(' ')
+ #print(commit)
+ body = call(["git", "show", "-s", "--format=%B", sha]).splitlines()
+ failed = []
+ if len(body) == 0:
+ failed.append("* Commit message must not be empty")
+ else:
+ for k, v in lint_rules.items():
+ if not v[0](body):
+ failed.append(f"* {v[1]} [{k}]")
+ if failed:
+ any_failed = True
+ print("-" * 40)
+ sys.stdout.flush()
+ subprocess.run(["git", "-P", "show", "-s", sha])
+ print("\nhas the following issues:")
+ print("\n".join(failed))
+ print("-" * 40)
+ return any_failed
+
+################################################################################
+
+NO_PREFIX_WHITELIST = r"^Revert \"(.*)\"|^Reapply \"(.*)\"|^Release [0-9]|^Update VERSION$"
+
+@lint_rule("Subject line must contain a prefix identifying the sub system")
+def subsystem_prefix(body):
+ if re.search(NO_PREFIX_WHITELIST, body[0]):
+ return True
+ m = re.search(r"^([^:]+):\s", body[0])
+ if not m:
+ return False
+ # a comma-separated list is okay
+ s = re.sub(r",\s+", "", m.group(1))
+ # but no spaces otherwise
+ return not " " in s
+
+@lint_rule("First word after : must be lower case")
+def description_lowercase(body):
+ if re.search(NO_PREFIX_WHITELIST, body[0]):
+ return True
+ # Allow all caps for acronyms and such
+ if re.search(r":\s[A-Z]{2,}\s", body[0]):
+ return True
+ return re.search(r":\s+[a-z0-9]", body[0])
+
+@lint_rule("Subject line must not end with a full stop")
+def no_dot(body):
+ return not body[0].rstrip().endswith('.')
+
+@lint_rule("There must be an empty line between subject and extended description")
+def empty_line(body):
+ return len(body) == 1 or body[1].strip() == ""
+
+# been seeing this one all over github lately, must be the webshits
+@lint_rule("Do not use 'conventional commits' style")
+def no_cc(body):
+ return not re.search(r"(?i)^(feat|fix|chore|refactor)[!:(]", body[0])
+
+@lint_rule("History must be linear, no merge commits")
+def no_merge(body):
+ return not body[0].startswith("Merge ")
+
+@lint_rule("Subject line should be shorter than 72 characters")
+def line_too_long(body):
+ revert = re.search(r"^Revert \"(.*)\"|^Reapply \"(.*)\"", body[0])
+ return True if revert else len(body[0]) <= 72
+
+@lint_rule("Prefix should not include C file extensions (use `vo_gpu: ...` not `vo_gpu.c: ...`)")
+def no_file_exts(body):
+ return not re.search(r"[a-z0-9]\.[ch]:\s", body[0])
+
+################################################################################
+
+if __name__ == "__main__":
+ commit_range = get_commit_range()
+ if commit_range is None:
+ exit(0)
+ print("Commit range:", commit_range)
+ any_failed = do_lint(commit_range)
+ exit(1 if any_failed else 0)