From 7f9454cf14929f457b4b2965a0fcec1a20e250b4 Mon Sep 17 00:00:00 2001 From: Go Kudo Date: Fri, 23 Aug 2024 00:44:39 +0000 Subject: [PATCH] refactor --- README.md | 25 +++++ README_ja.md | 25 +++++ patches/ltmain.sh.patch | 2 +- pskel.sh | 214 ++++++++++++++++++++++++---------------- 4 files changed, 180 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index 440bb24..4aee00d 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,31 @@ A sample MySQL configuration is included in `compose.yaml` (commented out). Testing on Windows is possible through GitHub Actions. A sample configuration for Windows CI is included in `.github/workflows/ci.yaml` (commented out). +## Code Coverage + +### Checking Coverage in Development Environment + +You can check the code coverage using lcov with the `pskel` command: + +```bash +$ pskel coverage +~~~ +Reading tracefile /workspaces/pskel/ext/lcov.info + |Lines |Functions |Branches +Filename |Rate Num|Rate Num|Rate Num +================================================== +[/workspaces/pskel/ext/] +bongo.c |75.0% 20|80.0% 5| - 0 +================================================== + Total:|75.0% 20|80.0% 5| - 0 +``` + +### Checking Coverage in GitHub Actions + +You can use [octocov](https://github.com/k1LoW/octocov) to check coverage information in GitHub Actions. + +When you create a Pull Request, octocov automatically comments with the coverage information. + ## Frequently Asked Questions ### Q: Can I use debuggers like gdb or lldb? diff --git a/README_ja.md b/README_ja.md index 8171633..0e1d1f2 100644 --- a/README_ja.md +++ b/README_ja.md @@ -89,6 +89,31 @@ MySQL のサンプル設定が `compose.yaml` にコメントアウトされた Windows上でのテストも、 GitHub Actions を通じて実行可能です。 `.github/workflows/ci.yaml`に Windows CI 用のサンプル設定がコメントアウトされています。 +## コードカバレッジ + +### 開発環境下での確認 + +`pskel` コマンドで lcov を利用したカバレッジの確認を行うことができます。 + +```bash +$ pskel coverage +~~~ +Reading tracefile /workspaces/pskel/ext/lcov.info + |Lines |Functions |Branches +Filename |Rate Num|Rate Num|Rate Num +================================================== +[/workspaces/pskel/ext/] +bongo.c |75.0% 20|80.0% 5| - 0 +================================================== + Total:|75.0% 20|80.0% 5| - 0 +``` + +### GitHub Actions での確認 + +[octocov](https://github.com/k1LoW/octocov) を用いて GitHub Actions でカバレッジ情報を確認することができます。 + +Pull Request を作成すると自動的に octocov によるカバレッジがコメントされます。 + ## よくある質問 ### Q: gdb や lldb などのデバッガは使用できますか? diff --git a/patches/ltmain.sh.patch b/patches/ltmain.sh.patch index cede4b0..70d0822 100644 --- a/patches/ltmain.sh.patch +++ b/patches/ltmain.sh.patch @@ -1,5 +1,5 @@ --- ext/build/ltmain.sh 2024-08-20 13:47:39.489351765 +0000 -+++ ext/build/ltmainp.sh 2024-08-20 13:51:02.825496572 +0000 ++++ ext/build/ltmain.sh 2024-08-20 13:51:02.825496572 +0000 @@ -3467,7 +3467,7 @@ EOF tempremovelist=`$echo "$output_objdir/*"` for p in $tempremovelist; do diff --git a/pskel.sh b/pskel.sh index 3fb93b9..5621c27 100755 --- a/pskel.sh +++ b/pskel.sh @@ -1,19 +1,19 @@ -#!/bin/sh -e +#!/bin/sh + +set -e get_ext_dir() { PSKEL_EXT_DIR="/ext" - if test -d "${CODESPACE_VSCODE_FOLDER}"; then - echo "[Pskel] GitHub Codespace workspace detected, use \"${CODESPACE_VSCODE_FOLDER}/ext\"." >&2 + if [ -d "${CODESPACE_VSCODE_FOLDER}" ]; then + echo "[Pskel] GitHub Codespace workspace detected, using \"${CODESPACE_VSCODE_FOLDER}/ext\"." >&2 PSKEL_EXT_DIR="${CODESPACE_VSCODE_FOLDER}/ext" - elif test -d "/workspaces/pskel/ext"; then - echo "[Pskel] Development Containers workspace detected, use \"/workspaces/pskel/ext\"." >&2 + elif [ -d "/workspaces/pskel/ext" ]; then + echo "[Pskel] Development Containers workspace detected, using \"/workspaces/pskel/ext\"." >&2 PSKEL_EXT_DIR="/workspaces/pskel/ext" - else - if test -f "/ext/.gitkeep" && test $(cat "/ext/.gitkeep") = "pskel_uninitialized" && ! test "x${1}" = "x--no-init"; then - echo "[Pskel] Uninitialized project detected, initialize default skeleton." >&2 - cmd_init "skeleton" >&2 - fi + elif [ -f "/ext/.gitkeep" ] && [ "$(cat "/ext/.gitkeep")" = "pskel_uninitialized" ] && [ "${1}" != "--no-init" ]; then + echo "[Pskel] Uninitialized project detected, initializing default skeleton." >&2 + cmd_init "skeleton" >&2 fi echo "${PSKEL_EXT_DIR}" @@ -24,79 +24,99 @@ cmd_usage() { Usage: ${0} [task] ... Available commands: - init create new extension - test test extension - build build PHP runtime + init create new extension + test test extension + build build PHP runtime + coverage generate code coverage EOF } cmd_init() { - if test "${1}" = "-h" || test "${1}" = "--help" || test "${#}" -lt 1; then - cat << EOF -Usage: $0 init [extension_name] [ext_skel.php options...] + case "${1}" in + -h|--help) + cat << EOF +Usage: ${0} init [extension_name] [ext_skel.php options...] EOF - return 0 - fi + return 0 + ;; + "") + echo "Error: Extension name is required." >&2 + return 1 + ;; + esac PSKEL_EXT_DIR="$(get_ext_dir --no-init)" - /usr/local/bin/php "/usr/src/php/ext/ext_skel.php" --ext "${1}" --dir "/tmp" ${@} + /usr/local/bin/php "/usr/src/php/ext/ext_skel.php" --ext "${1}" --dir "/tmp" "${@}" rm "${PSKEL_EXT_DIR}/.gitkeep" rsync -av "/tmp/${1}/" "${PSKEL_EXT_DIR}/" rm -rf "/tmp/${1}" } cmd_test() { - if test "${1}" = "-h" || test "${1}" = "--help"; then - cat << EOF + case "${1}" in + -h|--help) + cat << EOF Usage: ${0} test [test_type|php_binary_name] -env: - CFLAGS, CPPFLAGS: Compile flags - TEST_PHP_ARGS: Test flags +Environment variables: + CFLAGS, CPPFLAGS: Compilation flags + TEST_PHP_ARGS: Test flags EOF - return 0 - fi - - if test "x${1}" = "x"; then - CC="$(which "gcc")"; CXX="$(which "g++")"; CMD="php" - else - case "${1}" in - debug) - if ! type "debug-php" > /dev/null 2>&1; then - CC="$(which "gcc")" CXX="$(which "g++")" CFLAGS="-DZEND_TRACK_ARENA_ALLOC" CPPFLAGS="${CFLAGS}" CONFIGURE_OPTS="--enable-debug $(php -r "echo PHP_ZTS === 1 ? '--enable-zts' : '';") --enable-option-checking=fatal --disable-phpdbg --disable-cgi --disable-fpm --enable-cli --without-pcre-jit --disable-opcache-jit --disable-zend-max-execution-timers" cmd_build "debug" - fi && \ - CC="$(which "gcc")"; CXX="$(which "g++")"; CMD="debug-php";; - gcov) - if ! type "gcc-gcov-php" > /dev/null 2>&1; then - CC="$(which "gcc")" CXX="$(which "g++")" CFLAGS="--coverage -DZEND_TRACK_ARENA_ALLOC" CPPFLAGS="${CFLAGS}" CONFIGURE_OPTS="--enable-gcov --enable-debug $(php -r "echo PHP_ZTS === 1 ? '--enable-zts' : '';") --enable-option-checking=fatal --disable-phpdbg --disable-cgi --disable-fpm --enable-cli --without-pcre-jit --disable-opcache-jit --disable-zend-max-execution-timers" cmd_build "gcc-gcov" - fi && \ - CFLAGS="${CFLAGS} --coverage" CPPFLAGS="${CPPFLAGS} --coverage" CC="$(which "gcc")"; CXX="$(which "g++")"; CMD="gcc-gcov-php";; - valgrind) - if ! type "gcc-valgrind-php" > /dev/null 2>&1; then - CC="$(which "gcc")" CXX="$(which "g++")" CFLAGS="-DZEND_TRACK_ARENA_ALLOC" CPPFLAGS="${CFLAGS}" CONFIGURE_OPTS="--enable-debug $(php -r "echo PHP_ZTS === 1 ? '--enable-zts' : '';") --enable-option-checking=fatal --disable-phpdbg --disable-cgi --disable-fpm --enable-cli --without-pcre-jit --disable-opcache-jit --disable-zend-max-execution-timers --with-valgrind" cmd_build "gcc-valgrind" - fi && \ - TEST_PHP_ARGS="${TEST_PHP_ARGS} -m" CC="$(which "gcc")"; CXX="$(which "g++")"; CMD="gcc-valgrind-php";; - msan) - if ! type "clang-msan-php" > /dev/null 2>&1; then - CC="$(which "clang")" CXX="$(which "clang++")" CFLAGS="-DZEND_TRACK_ARENA_ALLOC" CPPFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS} -fsanitize=memory" CONFIGURE_OPTS="--enable-debug $(php -r "echo PHP_ZTS === 1 ? '--enable-zts' : '';") --enable-option-checking=fatal --disable-phpdbg --disable-cgi --disable-fpm --enable-cli --without-pcre-jit --disable-opcache-jit --disable-zend-max-execution-timers --enable-memory-sanitizer" cmd_build "clang-msan" - fi && \ - CFLAGS="${CFLAGS} -fsanitize=memory"; CPPFLAGS="${CPPFLAGS}"; LDFLAGS="-fsanitize=memory"; CC="$(which "clang")"; CXX="$(which "clang++")"; CMD="clang-msan-php";; - asan) - if ! type "clang-asan-php" > /dev/null 2>&1; then - CC="$(which "clang")" CXX="$(which "clang++")" CFLAGS="-DZEND_TRACK_ARENA_ALLOC" CPPFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS} -fsanitize=address" CONFIGURE_OPTS="--enable-debug $(php -r "echo PHP_ZTS === 1 ? '--enable-zts' : '';") --enable-option-checking=fatal --disable-phpdbg --disable-cgi --disable-fpm --enable-cli --without-pcre-jit --disable-opcache-jit --disable-zend-max-execution-timers --enable-address-sanitizer" cmd_build "clang-asan" - fi && \ - CFLAGS="${CFLAGS} -fsanitize=address"; CPPFLAGS="${CPPFLAGS}"; LDFLAGS="-fsanitize=address"; CC="$(which "clang")"; CXX="$(which "clang++")"; CMD="clang-asan-php";; - ubsan) - if ! type "clang-ubsan-php" > /dev/null 2>&1; then - CC="$(which "clang")" CXX="$(which "clang++")" CFLAGS="-DZEND_TRACK_ARENA_ALLOC" CPPFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS} -fsanitize=undefined" CONFIGURE_OPTS="--enable-debug $(php -r "echo PHP_ZTS === 1 ? '--enable-zts' : '';") --enable-option-checking=fatal --disable-phpdbg --disable-cgi --disable-fpm --enable-cli --without-pcre-jit --disable-opcache-jit --disable-zend-max-execution-timers --enable-undefined-sanitizer" cmd_build "clang-ubsan" - fi && \ - CFLAGS="${CFLAGS} -fsanitize=undefined"; CPPFLAGS="${CPPFLAGS}"; LDFLAGS="-fsanitize=undefined"; CC="$(which "clang")"; CXX="$(which "clang++")"; CMD="clang-ubsan-php";; - *) CMD="${1}" - esac - fi + return 0 + ;; + debug|gcov|valgrind) + CC="$(command -v "gcc")" + CXX="$(command -v "g++")" + case "${1}" in + debug) build_php_if_not_exists "debug";; + gcov) + CONFIGURE_OPTS="--enable-gcov" + build_php_if_not_exists "gcov" + CFLAGS="${CFLAGS} --coverage" + ;; + valgrind) + CONFIGURE_OPTS="--with-valgrind" + build_php_if_not_exists "valgrind" + TEST_PHP_ARGS="${TEST_PHP_ARGS} -m" + ;; + esac + CMD="$(basename "${CC}")-${1}-php" + ;; + msan|asan|ubsan) + CC="$(command -v "clang")" + CXX="$(command -v "clang++")" + case "${1}" in + msan) + CONFIGURE_OPTS="--enable-memory-sanitizer" + build_php_if_not_exists "msan" + CFLAGS="${CFLAGS} -fsanitize=memory" + LDFLAGS="${LDFLAGS} -fsanitize=memory" + ;; + asan) + CONFIGURE_OPTS="--enable-address-sanitizer" + build_php_if_not_exists "asan" + CFLAGS="${CFLAGS} -fsanitize=address" + LDFLAGS="${LDFLAGS} -fsanitize=address" + ;; + ubsan) + CONFIGURE_OPTS="--enable-undefined-sanitizer" + build_php_if_not_exists "ubsan" + CFLAGS="${CFLAGS} -fsanitize=undefined" + LDFLAGS="${LDFLAGS} -fsanitize=undefined" + ;; + esac + CMD="$(basename "${CC}")-${1}-php" + ;; + "") + CMD="php" + ;; + *) + CMD="${1}" + ;; + esac for BIN in "${CMD}" "${CMD}ize" "${CMD}-config"; do - if ! type "${BIN}" > /dev/null 2>&1; then - echo "Invalid argument: '${CMD}', executable file not found" >&2 + if ! command -v "${BIN}" >/dev/null 2>&1; then + echo "Error: Invalid argument '${CMD}', executable file not found" >&2 exit 1 fi done @@ -105,31 +125,44 @@ EOF cd "${PSKEL_EXT_DIR}" "${CMD}ize" - if test "$("${CMD}" -r "echo PHP_VERSION_ID;")" -lt "80400"; then + if [ "$("${CMD}" -r "echo PHP_VERSION_ID;")" -lt "80400" ]; then patch "./build/ltmain.sh" "./../patches/ltmain.sh.patch" echo "[Pskel] ltmain.sh patched" >&2 fi - CC=${CC} CXX=${CXX} CFLAGS="${CFLAGS}" CPPFLAGS="${CPPFLAGS}" LDFLAGS="${LDFLAGS}" ./configure --with-php-config="$(which "${CMD}-config")" + CC="${CC}" CXX="${CXX}" CFLAGS="${CFLAGS}" CPPFLAGS="${CPPFLAGS}" LDFLAGS="${LDFLAGS}" ./configure --with-php-config="$(command -v "${CMD}-config")" make clean make -j"$(nproc)" TEST_PHP_ARGS="${TEST_PHP_ARGS} --show-diff -q" make test cd - } +build_php_if_not_exists() { + if ! command -v "$(basename "${CC}")-${1}-php" >/dev/null 2>&1; then + CC="${CC}" \ + CXX="${CXX}" \ + CFLAGS="-DZEND_TRACK_ARENA_ALLOC" \ + CPPFLAGS="${CFLAGS}" \ + LDFLAGS="${LDFLAGS}" \ + CONFIGURE_OPTS="${CONFIGURE_OPTS} --enable-debug $(php -r "echo PHP_ZTS === 1 ? '--enable-zts' : '';") --enable-option-checking=fatal --disable-phpdbg --disable-cgi --disable-fpm --enable-cli --without-pcre-jit --disable-opcache-jit --disable-zend-max-execution-timers" \ + cmd_build "$(basename "${CC}")-${1}" + fi +} + cmd_build() { - if test "${1}" = "-h" || test "${1}" = "--help"; then - cat << EOF + case "${1}" in + -h|--help) + cat << EOF Usage: ${0} build [php_binary_prefix] -env: - CFLAGS, CPPFLAGS: Compile flags - CONFIGURE_OPTS: ./configure options +Environment variables: + CFLAGS, CPPFLAGS: Compilation flags + CONFIGURE_OPTS: ./configure options EOF - return 0 - fi - - if ! test "x${1}" = "x"; then - CONFIGURE_OPTS="--program-prefix="${1}-" --includedir="/usr/local/include/${1}-php" ${CONFIGURE_OPTS}" - fi + return 0 + ;; + ?*) + CONFIGURE_OPTS="--program-prefix=${1}- --includedir=/usr/local/include/${1}-php ${CONFIGURE_OPTS}" + ;; + esac cd "/usr/src/php" ./buildconf --force @@ -142,11 +175,22 @@ EOF } cmd_coverage() { + case "${1}" in + -h|--help) + cat << EOF +Usage: ${0} coverage +Environment variables: + LCOV_OPTS: lcov capture options +EOF + return 0 + ;; + esac + cmd_test "gcov" PSKEL_EXT_DIR="$(get_ext_dir)" - lcov --capture --directory "${PSKEL_EXT_DIR}" ${LCOV_OPTIONS} --exclude "/usr/local/include/*" --output-file "${PSKEL_EXT_DIR}/lcov.info" + lcov --capture --directory "${PSKEL_EXT_DIR}" ${LCOV_OPTS} --exclude "/usr/local/include/*" --output-file "${PSKEL_EXT_DIR}/lcov.info" lcov --list "${PSKEL_EXT_DIR}/lcov.info" } @@ -156,11 +200,11 @@ if [ $# -eq 0 ]; then fi case "${1}" in - help) shift && cmd_usage;; - init) shift && cmd_init "${@}";; - test) shift && cmd_test "${@}";; - build) shift && cmd_build "${@}";; - coverage) shift && cmd_coverage "${@}";; + help) shift; cmd_usage;; + init) shift; cmd_init "${@}";; + test) shift; cmd_test "${@}";; + build) shift; cmd_build "${@}";; + coverage) shift; cmd_coverage "${@}";; *) echo "${0} error: invalid command: '${1}'" >&2 cmd_usage