<NME> kodev
<BEF> #!/usr/bin/env bash

CURDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

function assert_ret_zero {
    if [ $1 -ne 0 ]; then
        if [ ! -z "$2" ]; then
            echo $2
        fi
        exit 1
    fi
}

function setup_env {
    files=`ls -d ./koreader-emulator-*/koreader`
    assert_ret_zero $? "Emulator not found, please build it first."
    export EMU_DIR=${files[0]}
}

# Default to Android 4.0+; required for NDK 15 but with a custom NDK the strict minimum is 9.
if [[ "${ANDROID_ARCH}" == "arm64" ]] || [[ "${ANDROID_ARCH}" == "x86_64" ]]; then
    # 64bit arches require at least ABI 21
    NDKABI="${NDKABI:-21}"
else
    NDKABI="${NDKABI:-14}"
fi
export NDKABI

# Default android flavor
ANDROID_FLAVOR="${ANDROID_FLAVOR:-rocks}"
export ANDROID_FLAVOR

function assert_ret_zero() {
    if [ "${1}" -ne 0 ]; then
        if [ -n "${2}" ]; then
            echo "${2}"
        fi
        exit 1
    fi
}

function check_submodules() {
    if git submodule status | grep -qE '^\-'; then
${SUPPORTED_TARGETS}"

    while [[ $1 == '-'* ]]; do
        PARAM=`echo $1 | awk -F= '{print $1}'`
        VALUE=`echo $1 | awk -F= '{print $2}'`
        case $PARAM in
            -v | --verbose)
                export VERBOSE=1
    # inspired by https://gist.github.com/nicolasazrak/32d68ed6c845a095f75f037ecc2f0436
    trap capture_ctrl_c INT
    TEMP_DIR="$(mktemp --directory /tmp/tmp.koreaderXXX)"
    LOG="${TEMP_DIR}/memory.log"
    SCRIPT_PNG="${TEMP_DIR}/script_png.p"
    SCRIPT_SHOW="${TEMP_DIR}/script_show.p"
    IMAGE_PNG="${TEMP_DIR}/graph.png"

    echo "Memory plot output to ${TEMP_DIR}"

    cat >"${SCRIPT_PNG}" <<EOL
set term pngcairo size 1600,1200
set output "${IMAGE_PNG}"
set ylabel "RSS"
set y2label "VSZ"
set ytics nomirror
set y2tics nomirror in
set yrange [0:*]
set y2range [0:*]
plot "${LOG}" using 3 with lines axes x1y1 title "RSS", "${LOG}" using 2 with lines axes x1y2 title "VSZ"
EOL

    cat >"${SCRIPT_SHOW}" <<EOL
set term wxt noraise
set ylabel "RSS"
            assert_ret_zero $?
            ;;
        android)
            if [ ! -d ${CURDIR}/base/toolchain/android-toolchain ]; then
                make android-toolchain
                assert_ret_zero $?
            fi
reread
            assert_ret_zero $?
            ;;
        pocketbook)
            if [ ! -d ${CURDIR}/base/toolchain/pocketbook-toolchain ]; then
                make pocketbook-toolchain
                assert_ret_zero $?
            fi
    }

    # initialize at 0 so gnuplot has something to show
    echo "0 0 0" >"${LOG}"
    while true; do
        # shellcheck disable=SC2086
        ps -p "$(pgrep --delimiter ' ' $1 "$2")" -o pid=,vsz=,rss= >>"${LOG}"
        sleep 1
    done &
    LOOP_PID=$!
    gnuplot "${SCRIPT_SHOW}" &
    GNUPLOT_PID=$!
}

function setup_env() {
    SETUP_ENV_GREP_COMMAND="grep -z -v debug"
    if [ -n "${KODEBUG}" ]; then
        SETUP_ENV_GREP_COMMAND="grep -z debug"
        # for android adb install
        KODEBUG_SUFFIX=-debug
    fi
    local files=()
    while IFS= read -r -d $'\0'; do
        files+=("${REPLY}")
    done < <(find . -maxdepth 1 -name 'koreader-emulator-*' -print0 | ${SETUP_ENV_GREP_COMMAND})
    test ${#files[@]} -gt 0
    assert_ret_zero $? "Emulator not found. Please build it first."
    local idx=0
    # Warn if multiple matches were found
    if [ ${#files[@]} -gt 1 ]; then
        echo "Multiple emulator builds found:"
        local ts=()
        # Store list of ts at the same index
        for i in "${!files[@]}"; do
            local file="${files[${i}]}/koreader"
            if [ -d "${file}" ]; then
                echo "${file} (last modified on $(stat -c %y "${file}"))"
                ts[${i}]="$(stat -c %Y "${file}")"
            fi
            ;;
        android)
            make TARGET=android clean
            rm -f *.apk
            ;;
        pocketbook)
            make TARGET=pocketbook clean
                idx="${i}"
                break
            fi
        done
        # Recap
        echo "Picking the most recent one: ${files[${idx}]}/koreader"
    fi
    EMU_DIR="${files[${idx}]}/koreader"
    export EMU_DIR
    KO_LD_LIBRARY_PATH="$(realpath "${EMU_DIR}")/libs:${LD_LIBRARY_PATH}"
    # Don't export it to avoid messing with tools (e.g., debuggers).
    # We'll pass it to LuaJIT via env
}

function kodev-fetch-thirdparty() {
    make fetchthirdparty
}

SUPPORTED_TARGETS="
    kindle          Compatible with all Kindle models >= Kindle4
    kindlepw2       With compiler optimizations for Kindle models >= Paperwhite 2
    kindle-legacy   Needed only for Kindle2/3/DXG
    kobo
    cervantes
    remarkable
    sony-prstux
    android         Supports ANDROID_ARCH arm, arm64, x86 & x86_64
    pocketbook
    ubuntu-touch
    appimage
    debian          Debian package for current arch
    debian-armel    Debian package for generic armel devices
    debian-armhf    Debian package for generic armhf devices
    debian-arm64    Debian package for generic 64 bits arm devices
    macos           MacOS app bundle. You need a mac to build this package
    emu             (*default) If no TARGET is given, assume emulator
    win32
"

function kodev-build() {
    BUILD_HELP_MSG="
usage: build <OPTIONS> <TARGET>

OPTIONS:

    -v, --verbose   make the buildsystem more verbose
    -d, --debug     include debugging symbols (default for emulator)
    -n, --no-debug  no debugging symbols (default for target devices)

TARGET:
${SUPPORTED_TARGETS}"

    declare opt
    declare -r E_OPTERR=85
    declare -r short_opts="vhnd"
    declare -r long_opts="verbose,help,no-debug,debug"

    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then
        echo "${BUILD_HELP_MSG}"
        exit ${E_OPTERR}
    fi

    eval set -- "${opt}"

    while true; do
function kodev-wbuilder {
    kodev-build
    echo "[*] Running wbuilder.lua..."
    pushd ${EMU_DIR}
    EMULATE_READER_W=540 EMULATE_READER_H=720 ./luajit ./utils/wbuilder.lua
    popd
}
            -h | --help)
                echo "${BUILD_HELP_MSG}"
                exit 0
                ;;
            -n | --no-debug)
                export KODEBUG=
                KODEBUG_NO_DEFAULT=1
                ;;
            -d | --debug)
                export KODEBUG=1
                KODEBUG_NO_DEFAULT=1
                ;;
    screen_width=540
    screen_height=720
    while [[ $1 == '-'* ]]; do
        PARAM=`echo $1 | awk -F= '{print $1}'`
        VALUE=`echo $1 | awk -F= '{print $2}'`
        case $PARAM in
            --disable-touch)
                export DISABLE_TOUCH=1
        esac
        shift
    done
    shift

    check_submodules
    case "${1}" in
        cervantes)
            make TARGET=cervantes
            assert_ret_zero $?
            ;;
        kindle)
            make TARGET=kindle
            assert_ret_zero $?
            ;;
        kindlepw2)
            make TARGET=kindlepw2
            assert_ret_zero $?
            ;;
        kobo)
            make TARGET=kobo
            assert_ret_zero $?
            ;;
        remarkable)
            make TARGET=remarkable
            assert_ret_zero $?
            ;;
        setup_env
    fi

    if [ ! -d ${EMU_DIR} ]; then
        echo "Failed to find emulator directory! Please try build command first."
        exit 1
    fi

    echo "[*] Running KOReader with arguments: $@..."
    pushd ${EMU_DIR}

    if [ $# -lt 1 ]; then
        args=${CURDIR}/test
    else
        args="$@"
        [[ $args != /* ]] && args="${CURDIR}/${args}"
    fi

                { [ -e "${NDK}" ] || make -C "${CURDIR}/base/toolchain" android-ndk; }
                assert_ret_zero $?
                make android-toolchain
                assert_ret_zero $?
            }
            echo "Using NDK: ${NDK}..."
            make TARGET=android
            assert_ret_zero $?
            ;;
        pocketbook)
            make TARGET=pocketbook
            assert_ret_zero $?
            ;;
    --tags=TAGS     only run tests with given tags
    "
    while [[ $1 == '-'* ]]; do
        PARAM=`echo $1 | awk -F= '{print $1}'`
        VALUE=`echo $1 | awk -F= '{print $2}'`
        case $PARAM in
            --tags)
                opts="--tags=${VALUE}"
        debian)
            make TARGET=debian
            assert_ret_zero $?
            ;;
        debian-armel)
            make TARGET=debian-armel
            assert_ret_zero $?
            ;;
        debian-armhf)
            make TARGET=debian-armhf
            assert_ret_zero $?
            ;;
        debian-arm64)
            make TARGET=debian-arm64
            assert_ret_zero $?
            ;;
        macos)
    fi

    setup_env
    make ${EMU_DIR}/.busted
    pushd ${EMU_DIR}

    test_path=./spec/$1/unit

    if [ ! -z $2 ]; then
        test_path="${test_path}/$2"
    fi
    busted --lua=./luajit ${opts} \
        --no-auto-insulate \
        --lazy \
        -o ./spec/$1/unit/verbose_print \
        --exclude-tags=notest ${test_path}

    popd
}

function kodev-clean() {
    CLEAN_HELP_MSG="
usage: clean <TARGET>

TARGET:
${SUPPORTED_TARGETS}"

    declare opt
    declare -r E_OPTERR=85
    declare -r short_opts="nd"
    declare -r long_opts="no-debug,debug"

    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then
        echo "${CLEAN_HELP_MSG}"
        exit ${E_OPTERR}
    fi

    eval set -- "${opt}"

    while true; do
        PARAM="${1}"
        # Support using an = assignment with short options (e.g., -f=blah instead of -f blah).
        VALUE="${2/#=/}"
        case "${PARAM}" in
            -n | --no-debug)
                export KODEBUG=
                KODEBUG_NO_DEFAULT=1
                ;;
            -d | --debug)
                export KODEBUG=1
                KODEBUG_NO_DEFAULT=1
                ;;
            --)
                break
                ;;
            *)
                echo "ERROR: unknown option \"${PARAM}\""
                echo "${BUILD_HELP_MSG}"
                exit 8
                ;;
        esac
        shift
    done
    shift

    case "${1}" in
        -h | --help)
            echo "${CLEAN_HELP_MSG}"
            exit 0
            ;;
        cervantes)
            make TARGET=cervantes clean
            ;;
        kindle)
            make TARGET=kindle clean
    activate)
        echo "adding ${CURDIR} to \$PATH..."
        export PATH="${PATH}:${CURDIR}"
        eval $(luarocks path bin)
        exec ${SHELL}
        ;;
    fetch-thirdparty)
        kodev-fetch-thirdparty
        ;;
    clean)
        shift 1
        kodev-clean $@
        ;;
    build)
        shift 1
        kodev-build $@
        ;;
    release)
        shift 1
        kodev-release $@
        ;;
    wbuilder)
        kodev-wbuilder
        ;;
    run)
        shift 1
        kodev-run $@
        ;;
    test)
        shift 1
        kodev-test $@
        ;;
    log)
        shift 1
        kodev-log $@
        ;;
    --help | -h)
        echo "${HELP_MSG}"
        debian-arm64)
            make TARGET=debian-arm64 clean
            ;;
        macos)
            is_mac
            make TARGET=macos clean
            ;;
        win32)
            make TARGET=win32 clean
            ;;
        *)
            if [ -z "${KODEBUG_NO_DEFAULT}" ]; then
                # No explicit --debug / --no-debug
                # Builds a debug build by default, like kodev-run
                export KODEBUG=1
            fi

            make clean
            ;;
    esac
}

function kodev-release() {
    # SUPPORTED_RELEASE_TARGETS=$(echo ${SUPPORTED_TARGETS} | sed 's/win32//')
    SUPPORTED_RELEASE_TARGETS="${SUPPORTED_TARGETS/emu*/""}"
    RELEASE_HELP_MSG="
usage: release <OPTIONS> <TARGET>

OPTIONS:

    -d, --debug               debug-enabled release (for remote gdb)
    -i, --ignore-translation  do not fetch translation for release
    -v, --verbose             make the buildsystem more verbose

TARGET:
${SUPPORTED_RELEASE_TARGETS}"
    [ $# -lt 1 ] && {
        echo "${RELEASE_HELP_MSG}"
        exit 1
    }

    # Defaults
    ignore_translation=0

    declare opt
    declare -r E_OPTERR=85
    declare -r short_opts="divh"
    declare -r long_opts="debug,ignore-translation,verbose,help"

    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then
        echo "${RELEASE_HELP_MSG}"
        exit ${E_OPTERR}
    fi

    eval set -- "${opt}"

    while true; do
        PARAM="${1}"
        # Support using an = assignment with short options (e.g., -f=blah instead of -f blah).
        VALUE="${2/#=/}"
        case "${PARAM}" in
            -d | --debug)
                export KODEBUG=1
                ;;
            -i | --ignore-translation)
                ignore_translation=1
                ;;
            -v | --verbose)
                export VERBOSE=1
                ;;
            -h | --help)
                echo "${RELEASE_HELP_MSG}"
                exit 0
                ;;
            --)
                break
                ;;
            *)
                echo "ERROR: unknown option \"${PARAM}\""
                echo "${RELEASE_HELP_MSG}"
                exit 1
                ;;
        esac
        shift
    done
    shift

    check_submodules
    if [ "${ignore_translation}" -eq 0 ]; then
        make po || {
            echo "ERROR: failed to fetch translation."
            echo "Tip: Use --ignore-translation OPTION if you want to build a release without translation."
            exit 1
        }
    fi

    case "${1}" in
        kindle)
            kodev-build kindle
            make TARGET=kindle update
            ;;
        kindlepw2)
            kodev-build kindlepw2
            make TARGET=kindlepw2 update
            ;;
        kobo)
            kodev-build kobo
            make TARGET=kobo update
            ;;
        remarkable)
            kodev-build remarkable
            make TARGET=remarkable update
            ;;
        sony-prstux)
            kodev-build sony-prstux
            make TARGET=sony-prstux update
            ;;
        cervantes)
            kodev-build cervantes
            make TARGET=cervantes update
            ;;
        kindle-legacy)
            kodev-build kindle-legacy
            make TARGET=kindle-legacy update
            ;;
        android)
            kodev-build android
            export PATH=${PATH}:${CURDIR}/base/toolchain/android-sdk-linux/tools
            command -v android &>/dev/null || {
                make -C "${CURDIR}/base/toolchain" android-sdk
            }
            ANDROID_HOME=$(dirname "$(dirname "$(command -v android)")")
            export ANDROID_HOME
            export PATH="${PATH}:${NDK}"
            make TARGET=android update
            ;;
        pocketbook)
            kodev-build pocketbook
            make TARGET=pocketbook update
            ;;
        ubuntu-touch)
            kodev-build ubuntu-touch
            make TARGET=ubuntu-touch update
            ;;
        appimage)
            kodev-build appimage
            make TARGET=appimage update
            ;;
        debian)
            kodev-build debian
            make TARGET=debian update
            ;;
        debian-armel)
            kodev-build debian-armel
            make TARGET=debian-armel update
            ;;
        debian-armhf)
            kodev-build debian-armhf
            make TARGET=debian-armhf update
            ;;
        debian-arm64)
            kodev-build debian-arm64
            make TARGET=debian-arm64 update
            ;;
        macos)
            is_mac
            kodev-build macos
            make TARGET=macos update
            ;;
        *)
            echo "Unsupported target for release: $1."
            echo "${RELEASE_HELP_MSG}"
            exit 1
            ;;
    esac
}

function kodev-wbuilder() {
    kodev-build
    echo "[*] Running wbuilder.lua..."
    pushd "${EMU_DIR}" && {
        EMULATE_READER_W=540 EMULATE_READER_H=720 ./luajit ./tools/wbuilder.lua
    } && popd || exit
}

function kodev-run() {
    RUN_HELP_MSG="
usage: run <OPTIONS> <TARGET>

OPTIONS:

    -h X, --screen-height=X  set height of the emulator screen (default: 720)
    -w X, --screen-width=X   set width of the emulator screen (default: 540)
    -d X, --screen-dpi=X     set DPI of the emulator screen (default: 160)
    -b, --no-build           run reader without rebuilding
    -n, --no-debug           no debugging symbols (requires rebuilding)
    -t, --disable-touch      use this if you want to simulate keyboard only devices
    -s FOO --simulate=FOO    simulate dimension and other specs for a given device model
                             supported model: hidpi, kobo-forma, kobo-aura-one, kobo-clara, kindle-paperwhite, kobo-h2o, legacy-paperwhite, kindle
    -g X, --gdb=X            run with debugger (default: nemiver)
    -p, --graph              graph memory use (requires gnuplot)
    -v X, --valgrind=X       run with valgrind (default: \"valgrind --tool=memcheck --trace-children=yes --leak-check=full --track-origins=yes --show-reachable=yes\")
    -c, --callgrind          run with valgrind's callgrind (valgrind --tool=callgrind --trace-children=yes)
    -S, --no-catchsegv       prevents wrapping by catchsegv

TARGET:

    android         install and run KOReader on an Android device connected through ADB
    "

    # NOTE: Speaking of Valgrind, if your libdrm/mesa isn't built w/ valgrind markings, there's a Valgrind suppression file for AMD cards in the tools folder.
    #       Just append --suppressions=${PWD/tools/valgrind_amd.supp to your valgrind command.

    # Defaults
    screen_width=540
    screen_height=720
    export KODEBUG=1

    declare opt
    declare -r E_OPTERR=85
    declare -r short_opts="tbng::pv::cw:h:d:s:SH"
    declare -r long_opts="disable-touch,no-build,gdb::,graph,valgrind::,callgrind,screen-width:,screen-height:,screen-dpi:,simulate:,no-catchsegv,help"

    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then
        echo "${RUN_HELP_MSG}"
        exit ${E_OPTERR}
    fi

    eval set -- "${opt}"

    while true; do
        PARAM="${1}"
        # Support using an = assignment with short options (e.g., -f=blah instead of -f blah).
        VALUE="${2/#=/}"
        case "${PARAM}" in
            -t | --disable-touch)
                export DISABLE_TOUCH=1
                ;;
            -b | --no-build)
                no_build=1
                ;;
            -n | --no-debug)
                export KODEBUG=
                ;;
            -g | --gdb)
                if [ -n "${VALUE}" ]; then
                    gdb="${VALUE}"
                else
                    # Try to use friendly defaults for gdb
                    if command -v nemiver >/dev/null; then
                        # Nemiver is a nice GUI
                        gdb="nemiver"
                    elif command -v ddd >/dev/null; then
                        # DDD is a slightly less nice GUI
                        gdb="ddd"
                    elif command -v cgdb >/dev/null; then
                        # cgdb is a nice curses-based gdb front
                        gdb="cgdb"
                    elif command -v gdb >/dev/null; then
                        # gdb -tui is a slightly less nice terminal user interface
                        gdb="gdb -tui"
                    else
                        echo "Couldn't find gdb."
                        exit 1
                    fi
                fi
                shift
                ;;
            -p | --graph)
                graph_memory=1
                ;;
            -v | --valgrind)
                if [ -n "${VALUE}" ]; then
                    valgrind="${VALUE}"
                else
                    # Try to use sensible defaults for valgrind
                    if command -v valgrind >/dev/null; then
                        valgrind="valgrind --tool=memcheck --trace-children=yes --leak-check=full --track-origins=yes --show-reachable=yes"
                    else
                        echo "Couldn't find valgrind."
                        exit 1
                    fi
                fi
                shift
                ;;
            -c | --callgrind)
                # Try to use sensible defaults for valgrind
                if command -v valgrind >/dev/null; then
                    valgrind="valgrind --tool=callgrind --trace-children=yes"
                else
                    echo "Couldn't find valgrind."
                    exit 1
                fi
                ;;
            -w | --screen-width)
                screen_width=${VALUE}
                shift
                ;;
            -h | --screen-height)
                # simple numeric check due to overlap between -h for help and height
                if [ -n "${VALUE##*[!0-9]*}" ]; then
                    screen_height=${VALUE}
                else
                    echo "ERROR: Invalid value: \"${VALUE}\""
                    echo "${RUN_HELP_MSG}"
                    exit 1
                fi
                shift
                ;;
            -d | --screen-dpi)
                screen_dpi=${VALUE}
                shift
                ;;
            -s | --simulate)
                device_model="${VALUE}"
                case "${device_model}" in
                    kindle)
                        screen_width=600
                        screen_height=800
                        screen_dpi=167
                        ;;
                    legacy-paperwhite)
                        screen_width=758
                        screen_height=1024
                        screen_dpi=212
                        ;;
                    kobo-forma)
                        screen_width=1440
                        screen_height=1920
                        screen_dpi=300
                        ;;
                    kobo-aura-one)
                        screen_width=1404
                        screen_height=1872
                        screen_dpi=300
                        ;;
                    kobo-clara | kindle-paperwhite)
                        screen_width=1072
                        screen_height=1448
                        screen_dpi=300
                        ;;
                    kobo-h2o)
                        screen_width=1080
                        screen_height=1429
                        screen_dpi=265
                        ;;
                    hidpi)
                        screen_width=1500
                        screen_height=2000
                        screen_dpi=600
                        ;;
                    *)
                        echo "ERROR: spec unknown for ${device_model}."
                        ;;
                esac
                shift
                ;;
            -S | --no-catchsegv)
                no_catchsegv=1
                ;;
            -H | --help)
                echo "${RUN_HELP_MSG}"
                exit 0
                ;;
            --)
                break
                ;;
            *)
                echo "ERROR: unknown option \"${PARAM}\""
                echo "${RUN_HELP_MSG}"
                exit 8
                ;;
        esac
        shift
    done
    shift

    case "${1}" in
        android)
            command -v adb >/dev/null && {
                if [ -z "${no_build}" ]; then
                    echo "[*] Building KOReader for Android ${ANDROID_ARCH}…"
                    kodev-release --ignore-translation android
                    assert_ret_zero $?
                fi
                setup_env
                # clear logcat to get rid of useless cruft
                adb logcat -c
                # uninstall existing package to make sure *everything* is gone from memory
                # no assert_ret_zero; uninstall is allowed to fail if there's nothing to uninstall
                adb uninstall "org.koreader.launcher"
                adb install "koreader-android-${ANDROID_ARCH}${KODEBUG_SUFFIX}-${VERSION}.apk"
                assert_ret_zero $?
                # there's no adb run so we do this…
                adb shell monkey -p org.koreader.launcher -c android.intent.category.LAUNCHER 1
                assert_ret_zero $?
                adb logcat KOReader:V luajit-launcher:V "*:E"
            } || echo "Failed to find adb in PATH to interact with Android device."
            ;;
        *)
            if [ -z "${no_build}" ]; then
                echo "[*] Building KOReader…"
                if [ -z "${KODEBUG}" ]; then
                    kodev-build --no-debug
                else
                    kodev-build
                fi
            else
                setup_env
            fi

            if [ ! -d "${EMU_DIR}" ]; then
                echo "Failed to find emulator directory! Please try build command first."
                exit 1
            fi

            if [ -n "${graph_memory}" ]; then
                gnuplot_wrapper "--parent $$" "reader.lua"
            fi

            KOREADER_ARGS="-d"
            KOREADER_COMMAND="env LD_LIBRARY_PATH=${KO_LD_LIBRARY_PATH} ./reader.lua ${KOREADER_ARGS}"

            # run with catchsegv by default when it is available (unless no-catchsegv is enabled, c.f., #7036)
            # see https://github.com/koreader/koreader/issues/2878#issuecomment-326796777
            if [ -z "${no_catchsegv}" ]; then
                if command -v catchsegv >/dev/null; then
                    KOREADER_COMMAND="$(command -v catchsegv) ${KOREADER_COMMAND}"
                fi
            fi

            if [ -n "${valgrind}" ]; then
                KOREADER_COMMAND="${valgrind} env LD_LIBRARY_PATH=${KO_LD_LIBRARY_PATH} ./luajit reader.lua ${KOREADER_ARGS}"
            fi

            echo "[*] Running KOReader with arguments: $* ..."
            pushd "${EMU_DIR}" && {
                if [ $# -ge 1 ]; then
                    args="$*"
                    [[ "${args}" != /* ]] && args="${CURDIR}/${args}"
                fi

                if [ -n "${gdb}" ]; then
                    # We don't want to stack valgrind/catchsegv on top of GDB ;).
                    if [[ "${gdb}" == gdb* ]]; then
                        # The standard CLI needs a little hand holding to properly pass arguments to the process it'll monitor
                        KOREADER_COMMAND="${gdb} --args env LD_LIBRARY_PATH=${KO_LD_LIBRARY_PATH} ./luajit reader.lua ${KOREADER_ARGS} ${args}"
                    else
                        KOREADER_COMMAND="${gdb} env LD_LIBRARY_PATH=${KO_LD_LIBRARY_PATH} ./luajit reader.lua ${KOREADER_ARGS} ${args}"
                    fi
                else
                    KOREADER_COMMAND="${KOREADER_COMMAND} ${args}"
                fi

                RETURN_VALUE=85
                while [ "${RETURN_VALUE}" -eq 85 ]; do
                    # shellcheck disable=SC2086
                    env EMULATE_READER_W="${screen_width}" EMULATE_READER_H="${screen_height}" EMULATE_READER_DPI="${screen_dpi}" \
                        ${KOREADER_COMMAND}
                    RETURN_VALUE=$?
                done
            } && popd || exit

            if [ -n "${graph_memory}" ]; then
                capture_ctrl_c
            fi

            exit ${RETURN_VALUE}
            ;;
    esac
}

function kodev-test() {
    TEST_HELP_MSG="
usage: test <OPTIONS> [front|base] <TEST_NAME>

    TEST_NAME is optional. If no TEST_NAME is given, all tests will be run.

OPTIONS:

    -p, --graph         graph memory use (requires gnuplot)
    -n, --no-debug      no debugging symbols (default for target devices)
    -t, --tags=TAGS     only run tests with given tags
    "

    declare opt
    declare -r E_OPTERR=85
    declare -r short_opts="pt:nh"
    declare -r long_opts="graph,tags:,no-debug,help"

    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then
        echo "${TEST_HELP_MSG}"
        exit ${E_OPTERR}
    fi

    eval set -- "${opt}"

    while true; do
        PARAM="${1}"
        # Support using an = assignment with short options (e.g., -f=blah instead of -f blah).
        VALUE="${2/#=/}"
        case "${PARAM}" in
            -p | --graph)
                graph_memory=1
                ;;
            -n | --no-debug)
                export KODEBUG=
                KODEBUG_NO_DEFAULT=1
                ;;
            -t | --tags)
                opts="--tags=${VALUE}"
                shift
                ;;
            -h | --help)
                echo "${TEST_HELP_MSG}"
                exit 0
                ;;
            --)
                break
                ;;
            *)
                echo "ERROR: unknown option \"${PARAM}\""
                echo "${TEST_HELP_MSG}"
                exit 8
                ;;
        esac
        shift
    done
    shift

    [ $# -lt 1 ] && {
        echo "${TEST_HELP_MSG}"
        exit 1
    }
    [[ "${1}" != "front" && "${1}" != "base" ]] && {
        echo "Invalid test suite: $1!"
        echo "${TEST_HELP_MSG}"
        exit 1
    }

    set -e
    check_submodules && kodev-build
    setup_env

    make "${EMU_DIR}/.busted"
    pushd "${EMU_DIR}" && {
        test_path_basedir="./spec/$1/unit"
        rm -rf "${test_path_basedir}"/data/*.sdr

        test_path="${test_path_basedir}"
        if [ -n "${2}" ]; then
            test_path="${test_path_basedir}/$2"
        fi

        echo "Running tests in" "${test_path}"
        env LD_LIBRARY_PATH="${KO_LD_LIBRARY_PATH}" \
            busted --lua="./luajit" "${opts}" \
            --output=gtest \
            --lpath="${test_path_basedir}/?.lua" \
            --exclude-tags=notest "${test_path}"
    } && popd || exit
}

function kodev-cov() {
    COV_HELP_MSG="
usage: cov <OPTIONS>

OPTIONS:

    -f, --full              show full coverage report (down to each line)
    -s, --show-previous     show coverage stats from previous run
    -n, --no-debug          no debugging symbols (default for target devices)
    "

    # Defaults
    show_full=0
    show_previous=0

    declare opt
    declare -r E_OPTERR=85
    declare -r short_opts="fsn"
    declare -r long_opts="full,show-previous,no-debug"

    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then
        echo "${COV_HELP_MSG}"
        exit ${E_OPTERR}
    fi

    eval set -- "${opt}"

    while true; do
        PARAM="${1}"
        # Support using an = assignment with short options (e.g., -f=blah instead of -f blah).
        VALUE="${2/#=/}"
        case "${PARAM}" in
            -f | --full)
                show_full=1
                ;;
            -s | --show-previous)
                show_previous=1
                ;;
            -n | --no-debug)
                export KODEBUG=
                KODEBUG_NO_DEFAULT=1
                ;;
            -h | --help)
                echo "${COV_HELP_MSG}"
                exit 0
                ;;
            --)
                break
                ;;
            *)
                echo "ERROR: unknown option \"${PARAM}\""
                echo "${COV_HELP_MSG}"
                exit 8
                ;;
        esac
        shift
    done
    shift

    set -e
    check_submodules && kodev-build
    setup_env
    make "${EMU_DIR}/.busted"
    pushd "${EMU_DIR}" && {
        target=front
        test_path="./spec/${target}/unit"
        if [ "${show_previous}" -eq 0 ]; then
            echo "Running tests in" ${test_path}
            env LD_LIBRARY_PATH="${KO_LD_LIBRARY_PATH}" \
                busted --lua="./luajit" \
                --sort-files \
                -o "./spec/${target}/unit/verbose_print" \
                --coverage \
                --exclude-tags=nocov "${test_path}" || {
                echo "Failed to run tests!" && exit 1
            }
        fi
        if [ "${show_full}" -eq 1 ]; then
            cat luacov.report.out
        else
            LUACOV_REPORT_SUMMARY=$(grep -nm1 -e '^Summary$' luacov.report.out | cut -d: -f1)
            tail -n \
                +$((LUACOV_REPORT_SUMMARY - 1)) \
                luacov.report.out
        fi
    } && popd || exit
}

function kodev-log() {
    LOG_HELP_MSG="
usage: log <OPTIONS> <TARGET>

OPTIONS:

    -d, --debug               more verbose logs (e.g., debug builds)

TARGET:

    android
"
    [ $# -lt 1 ] && {
        echo "${LOG_HELP_MSG}"
        exit 1
    }

    # Defaults
    ignore_translation=0

    declare opt
    declare -r E_OPTERR=85
    declare -r short_opts="dh"
    declare -r long_opts="debug, help"

    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then
        echo "${LOG_HELP_MSG}"
        exit ${E_OPTERR}
    fi

    eval set -- "${opt}"

    while true; do
        PARAM="${1}"
        # Support using an = assignment with short options (e.g., -f=blah instead of -f blah).
        VALUE="${2/#=/}"
        case "${PARAM}" in
            -d | --debug)
                export KODEBUG=1
                ;;
            -h | --help)
                echo "${LOG_HELP_MSG}"
                exit 0
                ;;
            --)
                break
                ;;
            *)
                echo "ERROR: unknown option \"${PARAM}\""
                echo "${RELEASE_HELP_MSG}"
                exit 1
                ;;
        esac
        shift
    done
    shift

    case "${1}" in
        android)
            if command -v pidcat >/dev/null; then
                if [ -n "${KODEBUG}" ]; then
                    pidcat "org.koreader.launcher"
                else
                    pidcat org.koreader.launcher --min-level=I
                fi
            else
                if [ -n "${KODEBUG}" ]; then
                    adb logcat 'KOReader:V ApkUpdater:V Assets:V Device:V dlopen:V EPD:V EventReceiver:V Lights:V LuaJIT:V MainActivity:V NativeGlue:V NativeThread:V Timeout:V ActivityManager:V AndroidRuntime:V DEBUG:* *:F'
                else
                    adb logcat 'KOReader:I MainActivity:V NativeGlue:V NativeThread:V ActivityManager:W AndroidRuntime:E DEBUG:* *:F'
                fi
            fi
            ;;
        *)
            echo "Unsupported target: $1."
            echo "${LOG_HELP_MSG}"
            exit 1
            ;;
    esac
}

HELP_MSG="
usage: $0 COMMAND <ARGS>

Supported commands:

    activate            Bootstrap shell environment for kodev
    build               Build KOReader
    clean               Clean KOReader build
    fetch-thirdparty    Fetch thirdparty dependencies for build
    log                 Tail log stream for a running KOReader app
    release             Build KOReader release package
    run                 Run KOReader
    test                Run busted tests
    check               Run luacheck static-analysis
    cov                 Run busted tests for coverage
    wbuilder            Run wbuilder.lua script (useful for building new UI widget)
    prompt              Run a LuaJIT shell within KOReader's environment
"
[ $# -lt 1 ] && {
    echo "Missing command."
    echo "${HELP_MSG}"
    exit 1
}

case "${1}" in
    activate)
        echo "adding ${CURDIR} to \$PATH..."
        export PATH="${PATH}:${CURDIR}"
        eval "$(luarocks path --bin)"
        exec "${SHELL}"
        ;;
    fetch-thirdparty)
        kodev-fetch-thirdparty
        ;;
    clean)
        shift 1
        kodev-clean "$@"
        ;;
    build)
        shift 1
        kodev-build "$@"
        ;;
    release)
        shift 1
        kodev-release "$@"
        ;;
    wbuilder)
        kodev-wbuilder
        ;;
    run)
        shift 1
        kodev-run "$@"
        ;;
    test)
        shift 1
        kodev-test "$@"
        ;;
    check)
        luacheck -q {reader,setupkoenv,datastorage}.lua frontend plugins spec
        ;;
    cov)
        shift 1
        kodev-cov "$@"
        ;;
    prompt)
        kodev-build
        pushd "${EMU_DIR}" && {
            env LD_LIBRARY_PATH="${KO_LD_LIBRARY_PATH}" \
                ./luajit -i setupkoenv.lua
        } && popd || exit
        ;;
    log)
        shift 1
        kodev-log "$@"
        ;;
    -h | --help)
        echo "${HELP_MSG}"
        exit 0
        ;;
    *)
        echo "Unknown command: $1."
        echo "${HELP_MSG}"
        exit 8
        ;;
esac

<MSG> kodev code quality

<DFF> @@ -3,16 +3,16 @@
 CURDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 
 function assert_ret_zero {
-    if [ $1 -ne 0 ]; then
+    if [ "$1" -ne 0 ]; then
         if [ ! -z "$2" ]; then
-            echo $2
+            echo "$2"
         fi
         exit 1
     fi
 }
 
 function setup_env {
-    files=`ls -d ./koreader-emulator-*/koreader`
+    files=$(ls -d ./koreader-emulator-*/koreader)
     assert_ret_zero $? "Emulator not found, please build it first."
     export EMU_DIR=${files[0]}
 }
@@ -44,8 +44,8 @@ TARGET:
 ${SUPPORTED_TARGETS}"
 
     while [[ $1 == '-'* ]]; do
-        PARAM=`echo $1 | awk -F= '{print $1}'`
-        VALUE=`echo $1 | awk -F= '{print $2}'`
+        PARAM=$(echo "$1" | awk -F= '{print $1}')
+        VALUE=$(echo "$1" | awk -F= '{print $2}')
         case $PARAM in
             -v | --verbose)
                 export VERBOSE=1
@@ -77,7 +77,7 @@ ${SUPPORTED_TARGETS}"
             assert_ret_zero $?
             ;;
         android)
-            if [ ! -d ${CURDIR}/base/toolchain/android-toolchain ]; then
+            if [ ! -d "${CURDIR}/base/toolchain/android-toolchain" ]; then
                 make android-toolchain
                 assert_ret_zero $?
             fi
@@ -85,7 +85,7 @@ ${SUPPORTED_TARGETS}"
             assert_ret_zero $?
             ;;
         pocketbook)
-            if [ ! -d ${CURDIR}/base/toolchain/pocketbook-toolchain ]; then
+            if [ ! -d "${CURDIR}/base/toolchain/pocketbook-toolchain" ]; then
                 make pocketbook-toolchain
                 assert_ret_zero $?
             fi
@@ -131,7 +131,7 @@ ${SUPPORTED_TARGETS}"
             ;;
         android)
             make TARGET=android clean
-            rm -f *.apk
+            rm -f ./*.apk
             ;;
         pocketbook)
             make TARGET=pocketbook clean
@@ -203,7 +203,7 @@ ${SUPPORTED_RELEASE_TARGETS}"
 function kodev-wbuilder {
     kodev-build
     echo "[*] Running wbuilder.lua..."
-    pushd ${EMU_DIR}
+    pushd "${EMU_DIR}"
     EMULATE_READER_W=540 EMULATE_READER_H=720 ./luajit ./utils/wbuilder.lua
     popd
 }
@@ -222,8 +222,8 @@ OPTIONS:
     screen_width=540
     screen_height=720
     while [[ $1 == '-'* ]]; do
-        PARAM=`echo $1 | awk -F= '{print $1}'`
-        VALUE=`echo $1 | awk -F= '{print $2}'`
+        PARAM=$(echo "$1" | awk -F= '{print $1}')
+        VALUE=$(echo "$1" | awk -F= '{print $2}')
         case $PARAM in
             --disable-touch)
                 export DISABLE_TOUCH=1
@@ -257,18 +257,18 @@ OPTIONS:
         setup_env
     fi
 
-    if [ ! -d ${EMU_DIR} ]; then
+    if [ ! -d "${EMU_DIR}" ]; then
         echo "Failed to find emulator directory! Please try build command first."
         exit 1
     fi
 
-    echo "[*] Running KOReader with arguments: $@..."
-    pushd ${EMU_DIR}
+    echo "[*] Running KOReader with arguments: $*..."
+    pushd "${EMU_DIR}"
 
     if [ $# -lt 1 ]; then
         args=${CURDIR}/test
     else
-        args="$@"
+        args="$*"
         [[ $args != /* ]] && args="${CURDIR}/${args}"
     fi
 
@@ -288,8 +288,8 @@ OPTIONS:
     --tags=TAGS     only run tests with given tags
     "
     while [[ $1 == '-'* ]]; do
-        PARAM=`echo $1 | awk -F= '{print $1}'`
-        VALUE=`echo $1 | awk -F= '{print $2}'`
+        PARAM=$(echo "$1" | awk -F= '{print $1}')
+        VALUE=$(echo "$1" | awk -F= '{print $2}')
         case $PARAM in
             --tags)
                 opts="--tags=${VALUE}"
@@ -313,19 +313,19 @@ OPTIONS:
     fi
 
     setup_env
-    make ${EMU_DIR}/.busted
-    pushd ${EMU_DIR}
+    make "${EMU_DIR}/.busted"
+    pushd "${EMU_DIR}"
 
-    test_path=./spec/$1/unit
+    test_path="./spec/$1/unit"
 
-    if [ ! -z $2 ]; then
+    if [ ! -z "$2" ]; then
         test_path="${test_path}/$2"
     fi
-    busted --lua=./luajit ${opts} \
+    busted --lua="./luajit ${opts}" \
         --no-auto-insulate \
         --lazy \
-        -o ./spec/$1/unit/verbose_print \
-        --exclude-tags=notest ${test_path}
+        -o "./spec/$1/unit/verbose_print" \
+        --exclude-tags=notest "${test_path}"
 
     popd
 }
@@ -388,38 +388,38 @@ case $1 in
     activate)
         echo "adding ${CURDIR} to \$PATH..."
         export PATH="${PATH}:${CURDIR}"
-        eval $(luarocks path bin)
-        exec ${SHELL}
+        eval "$(luarocks path bin)"
+        exec "${SHELL}"
         ;;
     fetch-thirdparty)
         kodev-fetch-thirdparty
         ;;
     clean)
         shift 1
-        kodev-clean $@
+        kodev-clean "$@"
         ;;
     build)
         shift 1
-        kodev-build $@
+        kodev-build "$@"
         ;;
     release)
         shift 1
-        kodev-release $@
+        kodev-release "$@"
         ;;
     wbuilder)
         kodev-wbuilder
         ;;
     run)
         shift 1
-        kodev-run $@
+        kodev-run "$@"
         ;;
     test)
         shift 1
-        kodev-test $@
+        kodev-test "$@"
         ;;
     log)
         shift 1
-        kodev-log $@
+        kodev-log "$@"
         ;;
     --help | -h)
         echo "${HELP_MSG}"

{'commit': 'diff --git a/kodev b/kodev\nindex fc472e2d..09e689d4 100755\n--- a/kodev\n+++ b/kodev\n@@ -3,16 +3,16 @@\n CURDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"\n \n function assert_ret_zero {\n-    if [ $1 -ne 0 ]; then\n+    if [ "$1" -ne 0 ]; then\n         if [ ! -z "$2" ]; then\n-            echo $2\n+            echo "$2"\n         fi\n         exit 1\n     fi\n }\n \n function setup_env {\n-    files=`ls -d ./koreader-emulator-*/koreader`\n+    files=$(ls -d ./koreader-emulator-*/koreader)\n     assert_ret_zero $? "Emulator not found, please build it first."\n     export EMU_DIR=${files[0]}\n }\n@@ -44,8 +44,8 @@ TARGET:\n ${SUPPORTED_TARGETS}"\n \n     while [[ $1 == \'-\'* ]]; do\n-        PARAM=`echo $1 | awk -F= \'{print $1}\'`\n-        VALUE=`echo $1 | awk -F= \'{print $2}\'`\n+        PARAM=$(echo "$1" | awk -F= \'{print $1}\')\n+        VALUE=$(echo "$1" | awk -F= \'{print $2}\')\n         case $PARAM in\n             -v | --verbose)\n                 export VERBOSE=1\n@@ -77,7 +77,7 @@ ${SUPPORTED_TARGETS}"\n             assert_ret_zero $?\n             ;;\n         android)\n-            if [ ! -d ${CURDIR}/base/toolchain/android-toolchain ]; then\n+            if [ ! -d "${CURDIR}/base/toolchain/android-toolchain" ]; then\n                 make android-toolchain\n                 assert_ret_zero $?\n             fi\n@@ -85,7 +85,7 @@ ${SUPPORTED_TARGETS}"\n             assert_ret_zero $?\n             ;;\n         pocketbook)\n-            if [ ! -d ${CURDIR}/base/toolchain/pocketbook-toolchain ]; then\n+            if [ ! -d "${CURDIR}/base/toolchain/pocketbook-toolchain" ]; then\n                 make pocketbook-toolchain\n                 assert_ret_zero $?\n             fi\n@@ -131,7 +131,7 @@ ${SUPPORTED_TARGETS}"\n             ;;\n         android)\n             make TARGET=android clean\n-            rm -f *.apk\n+            rm -f ./*.apk\n             ;;\n         pocketbook)\n             make TARGET=pocketbook clean\n@@ -203,7 +203,7 @@ ${SUPPORTED_RELEASE_TARGETS}"\n function kodev-wbuilder {\n     kodev-build\n     echo "[*] Running wbuilder.lua..."\n-    pushd ${EMU_DIR}\n+    pushd "${EMU_DIR}"\n     EMULATE_READER_W=540 EMULATE_READER_H=720 ./luajit ./utils/wbuilder.lua\n     popd\n }\n@@ -222,8 +222,8 @@ OPTIONS:\n     screen_width=540\n     screen_height=720\n     while [[ $1 == \'-\'* ]]; do\n-        PARAM=`echo $1 | awk -F= \'{print $1}\'`\n-        VALUE=`echo $1 | awk -F= \'{print $2}\'`\n+        PARAM=$(echo "$1" | awk -F= \'{print $1}\')\n+        VALUE=$(echo "$1" | awk -F= \'{print $2}\')\n         case $PARAM in\n             --disable-touch)\n                 export DISABLE_TOUCH=1\n@@ -257,18 +257,18 @@ OPTIONS:\n         setup_env\n     fi\n \n-    if [ ! -d ${EMU_DIR} ]; then\n+    if [ ! -d "${EMU_DIR}" ]; then\n         echo "Failed to find emulator directory! Please try build command first."\n         exit 1\n     fi\n \n-    echo "[*] Running KOReader with arguments: $@..."\n-    pushd ${EMU_DIR}\n+    echo "[*] Running KOReader with arguments: $*..."\n+    pushd "${EMU_DIR}"\n \n     if [ $# -lt 1 ]; then\n         args=${CURDIR}/test\n     else\n-        args="$@"\n+        args="$*"\n         [[ $args != /* ]] && args="${CURDIR}/${args}"\n     fi\n \n@@ -288,8 +288,8 @@ OPTIONS:\n     --tags=TAGS     only run tests with given tags\n     "\n     while [[ $1 == \'-\'* ]]; do\n-        PARAM=`echo $1 | awk -F= \'{print $1}\'`\n-        VALUE=`echo $1 | awk -F= \'{print $2}\'`\n+        PARAM=$(echo "$1" | awk -F= \'{print $1}\')\n+        VALUE=$(echo "$1" | awk -F= \'{print $2}\')\n         case $PARAM in\n             --tags)\n                 opts="--tags=${VALUE}"\n@@ -313,19 +313,19 @@ OPTIONS:\n     fi\n \n     setup_env\n-    make ${EMU_DIR}/.busted\n-    pushd ${EMU_DIR}\n+    make "${EMU_DIR}/.busted"\n+    pushd "${EMU_DIR}"\n \n-    test_path=./spec/$1/unit\n+    test_path="./spec/$1/unit"\n \n-    if [ ! -z $2 ]; then\n+    if [ ! -z "$2" ]; then\n         test_path="${test_path}/$2"\n     fi\n-    busted --lua=./luajit ${opts} \\\n+    busted --lua="./luajit ${opts}" \\\n         --no-auto-insulate \\\n         --lazy \\\n-        -o ./spec/$1/unit/verbose_print \\\n-        --exclude-tags=notest ${test_path}\n+        -o "./spec/$1/unit/verbose_print" \\\n+        --exclude-tags=notest "${test_path}"\n \n     popd\n }\n@@ -388,38 +388,38 @@ case $1 in\n     activate)\n         echo "adding ${CURDIR} to \\$PATH..."\n         export PATH="${PATH}:${CURDIR}"\n-        eval $(luarocks path bin)\n-        exec ${SHELL}\n+        eval "$(luarocks path bin)"\n+        exec "${SHELL}"\n         ;;\n     fetch-thirdparty)\n         kodev-fetch-thirdparty\n         ;;\n     clean)\n         shift 1\n-        kodev-clean $@\n+        kodev-clean "$@"\n         ;;\n     build)\n         shift 1\n-        kodev-build $@\n+        kodev-build "$@"\n         ;;\n     release)\n         shift 1\n-        kodev-release $@\n+        kodev-release "$@"\n         ;;\n     wbuilder)\n         kodev-wbuilder\n         ;;\n     run)\n         shift 1\n-        kodev-run $@\n+        kodev-run "$@"\n         ;;\n     test)\n         shift 1\n-        kodev-test $@\n+        kodev-test "$@"\n         ;;\n     log)\n         shift 1\n-        kodev-log $@\n+        kodev-log "$@"\n         ;;\n     --help | -h)\n         echo "${HELP_MSG}"\n', 'commit_subject': 'kodev code quality', 'repo_name': 'koreader/koreader', 'committer': {'name': 'Frans de Jonge', 'email': '807d67be87a9aeacd1bff8b3eb885eb0f5b378c8@gmail.com', 'time_sec': '1462536408', 'tz_offset': '120', 'date': {'seconds': '1462536408'}}, 'commit_tree': '7d8c27437d1f8e1843e64adbb4ba4f8031ef63e1', 'commit_message': 'kodev code quality\n', 'language_name': 'Python', 'license': 'agpl-3.0', 'hunks': '@@ -3,16 +3,16 @@\n CURDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"\n \n function assert_ret_zero {\n-    if [ $1 -ne 0 ]; then\n+    if [ "$1" -ne 0 ]; then\n         if [ ! -z "$2" ]; then\n-            echo $2\n+            echo "$2"\n         fi\n         exit 1\n     fi\n }\n \n function setup_env {\n-    files=`ls -d ./koreader-emulator-*/koreader`\n+    files=$(ls -d ./koreader-emulator-*/koreader)\n     assert_ret_zero $? "Emulator not found, please build it first."\n     export EMU_DIR=${files[0]}\n }\n@@ -44,8 +44,8 @@ TARGET:\n ${SUPPORTED_TARGETS}"\n \n     while [[ $1 == \'-\'* ]]; do\n-        PARAM=`echo $1 | awk -F= \'{print $1}\'`\n-        VALUE=`echo $1 | awk -F= \'{print $2}\'`\n+        PARAM=$(echo "$1" | awk -F= \'{print $1}\')\n+        VALUE=$(echo "$1" | awk -F= \'{print $2}\')\n         case $PARAM in\n             -v | --verbose)\n                 export VERBOSE=1\n@@ -77,7 +77,7 @@ ${SUPPORTED_TARGETS}"\n             assert_ret_zero $?\n             ;;\n         android)\n-            if [ ! -d ${CURDIR}/base/toolchain/android-toolchain ]; then\n+            if [ ! -d "${CURDIR}/base/toolchain/android-toolchain" ]; then\n                 make android-toolchain\n                 assert_ret_zero $?\n             fi\n@@ -85,7 +85,7 @@ ${SUPPORTED_TARGETS}"\n             assert_ret_zero $?\n             ;;\n         pocketbook)\n-            if [ ! -d ${CURDIR}/base/toolchain/pocketbook-toolchain ]; then\n+            if [ ! -d "${CURDIR}/base/toolchain/pocketbook-toolchain" ]; then\n                 make pocketbook-toolchain\n                 assert_ret_zero $?\n             fi\n@@ -131,7 +131,7 @@ ${SUPPORTED_TARGETS}"\n             ;;\n         android)\n             make TARGET=android clean\n-            rm -f *.apk\n+            rm -f ./*.apk\n             ;;\n         pocketbook)\n             make TARGET=pocketbook clean\n@@ -203,7 +203,7 @@ ${SUPPORTED_RELEASE_TARGETS}"\n function kodev-wbuilder {\n     kodev-build\n     echo "[*] Running wbuilder.lua..."\n-    pushd ${EMU_DIR}\n+    pushd "${EMU_DIR}"\n     EMULATE_READER_W=540 EMULATE_READER_H=720 ./luajit ./utils/wbuilder.lua\n     popd\n }\n@@ -222,8 +222,8 @@ OPTIONS:\n     screen_width=540\n     screen_height=720\n     while [[ $1 == \'-\'* ]]; do\n-        PARAM=`echo $1 | awk -F= \'{print $1}\'`\n-        VALUE=`echo $1 | awk -F= \'{print $2}\'`\n+        PARAM=$(echo "$1" | awk -F= \'{print $1}\')\n+        VALUE=$(echo "$1" | awk -F= \'{print $2}\')\n         case $PARAM in\n             --disable-touch)\n                 export DISABLE_TOUCH=1\n@@ -257,18 +257,18 @@ OPTIONS:\n         setup_env\n     fi\n \n-    if [ ! -d ${EMU_DIR} ]; then\n+    if [ ! -d "${EMU_DIR}" ]; then\n         echo "Failed to find emulator directory! Please try build command first."\n         exit 1\n     fi\n \n-    echo "[*] Running KOReader with arguments: $@..."\n-    pushd ${EMU_DIR}\n+    echo "[*] Running KOReader with arguments: $*..."\n+    pushd "${EMU_DIR}"\n \n     if [ $# -lt 1 ]; then\n         args=${CURDIR}/test\n     else\n-        args="$@"\n+        args="$*"\n         [[ $args != /* ]] && args="${CURDIR}/${args}"\n     fi\n \n@@ -288,8 +288,8 @@ OPTIONS:\n     --tags=TAGS     only run tests with given tags\n     "\n     while [[ $1 == \'-\'* ]]; do\n-        PARAM=`echo $1 | awk -F= \'{print $1}\'`\n-        VALUE=`echo $1 | awk -F= \'{print $2}\'`\n+        PARAM=$(echo "$1" | awk -F= \'{print $1}\')\n+        VALUE=$(echo "$1" | awk -F= \'{print $2}\')\n         case $PARAM in\n             --tags)\n                 opts="--tags=${VALUE}"\n@@ -313,19 +313,19 @@ OPTIONS:\n     fi\n \n     setup_env\n-    make ${EMU_DIR}/.busted\n-    pushd ${EMU_DIR}\n+    make "${EMU_DIR}/.busted"\n+    pushd "${EMU_DIR}"\n \n-    test_path=./spec/$1/unit\n+    test_path="./spec/$1/unit"\n \n-    if [ ! -z $2 ]; then\n+    if [ ! -z "$2" ]; then\n         test_path="${test_path}/$2"\n     fi\n-    busted --lua=./luajit ${opts} \\\n+    busted --lua="./luajit ${opts}" \\\n         --no-auto-insulate \\\n         --lazy \\\n-        -o ./spec/$1/unit/verbose_print \\\n-        --exclude-tags=notest ${test_path}\n+        -o "./spec/$1/unit/verbose_print" \\\n+        --exclude-tags=notest "${test_path}"\n \n     popd\n }\n@@ -388,38 +388,38 @@ case $1 in\n     activate)\n         echo "adding ${CURDIR} to \\$PATH..."\n         export PATH="${PATH}:${CURDIR}"\n-        eval $(luarocks path bin)\n-        exec ${SHELL}\n+        eval "$(luarocks path bin)"\n+        exec "${SHELL}"\n         ;;\n     fetch-thirdparty)\n         kodev-fetch-thirdparty\n         ;;\n     clean)\n         shift 1\n-        kodev-clean $@\n+        kodev-clean "$@"\n         ;;\n     build)\n         shift 1\n-        kodev-build $@\n+        kodev-build "$@"\n         ;;\n     release)\n         shift 1\n-        kodev-release $@\n+        kodev-release "$@"\n         ;;\n     wbuilder)\n         kodev-wbuilder\n         ;;\n     run)\n         shift 1\n-        kodev-run $@\n+        kodev-run "$@"\n         ;;\n     test)\n         shift 1\n-        kodev-test $@\n+        kodev-test "$@"\n         ;;\n     log)\n         shift 1\n-        kodev-log $@\n+        kodev-log "$@"\n         ;;\n     --help | -h)\n         echo "${HELP_MSG}"\n', 'addition_count': 32, 'deletion_count': 32, 'src_file': 'a/kodev', 'tgt_file': 'b/kodev', 'file_extension': '', 'before_file': '#!/usr/bin/env bash\n\nCURDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"\n\nfunction assert_ret_zero {\n    if [ $1 -ne 0 ]; then\n        if [ ! -z "$2" ]; then\n            echo $2\n        fi\n        exit 1\n    fi\n}\n\nfunction setup_env {\n    files=`ls -d ./koreader-emulator-*/koreader`\n    assert_ret_zero $? "Emulator not found, please build it first."\n    export EMU_DIR=${files[0]}\n}\n\n# Default to Android 4.0+; required for NDK 15 but with a custom NDK the strict minimum is 9.\nif [[ "${ANDROID_ARCH}" == "arm64" ]] || [[ "${ANDROID_ARCH}" == "x86_64" ]]; then\n    # 64bit arches require at least ABI 21\n    NDKABI="${NDKABI:-21}"\nelse\n    NDKABI="${NDKABI:-14}"\nfi\nexport NDKABI\n\n# Default android flavor\nANDROID_FLAVOR="${ANDROID_FLAVOR:-rocks}"\nexport ANDROID_FLAVOR\n\nfunction assert_ret_zero() {\n    if [ "${1}" -ne 0 ]; then\n        if [ -n "${2}" ]; then\n            echo "${2}"\n        fi\n        exit 1\n    fi\n}\n\nfunction check_submodules() {\n    if git submodule status | grep -qE \'^\\-\'; then\n${SUPPORTED_TARGETS}"\n\n    while [[ $1 == \'-\'* ]]; do\n        PARAM=`echo $1 | awk -F= \'{print $1}\'`\n        VALUE=`echo $1 | awk -F= \'{print $2}\'`\n        case $PARAM in\n            -v | --verbose)\n                export VERBOSE=1\n    # inspired by https://gist.github.com/nicolasazrak/32d68ed6c845a095f75f037ecc2f0436\n    trap capture_ctrl_c INT\n    TEMP_DIR="$(mktemp --directory /tmp/tmp.koreaderXXX)"\n    LOG="${TEMP_DIR}/memory.log"\n    SCRIPT_PNG="${TEMP_DIR}/script_png.p"\n    SCRIPT_SHOW="${TEMP_DIR}/script_show.p"\n    IMAGE_PNG="${TEMP_DIR}/graph.png"\n\n    echo "Memory plot output to ${TEMP_DIR}"\n\n    cat >"${SCRIPT_PNG}" <<EOL\nset term pngcairo size 1600,1200\nset output "${IMAGE_PNG}"\nset ylabel "RSS"\nset y2label "VSZ"\nset ytics nomirror\nset y2tics nomirror in\nset yrange [0:*]\nset y2range [0:*]\nplot "${LOG}" using 3 with lines axes x1y1 title "RSS", "${LOG}" using 2 with lines axes x1y2 title "VSZ"\nEOL\n\n    cat >"${SCRIPT_SHOW}" <<EOL\nset term wxt noraise\nset ylabel "RSS"\n            assert_ret_zero $?\n            ;;\n        android)\n            if [ ! -d ${CURDIR}/base/toolchain/android-toolchain ]; then\n                make android-toolchain\n                assert_ret_zero $?\n            fi\nreread\n            assert_ret_zero $?\n            ;;\n        pocketbook)\n            if [ ! -d ${CURDIR}/base/toolchain/pocketbook-toolchain ]; then\n                make pocketbook-toolchain\n                assert_ret_zero $?\n            fi\n    }\n\n    # initialize at 0 so gnuplot has something to show\n    echo "0 0 0" >"${LOG}"\n    while true; do\n        # shellcheck disable=SC2086\n        ps -p "$(pgrep --delimiter \' \' $1 "$2")" -o pid=,vsz=,rss= >>"${LOG}"\n        sleep 1\n    done &\n    LOOP_PID=$!\n    gnuplot "${SCRIPT_SHOW}" &\n    GNUPLOT_PID=$!\n}\n\nfunction setup_env() {\n    SETUP_ENV_GREP_COMMAND="grep -z -v debug"\n    if [ -n "${KODEBUG}" ]; then\n        SETUP_ENV_GREP_COMMAND="grep -z debug"\n        # for android adb install\n        KODEBUG_SUFFIX=-debug\n    fi\n    local files=()\n    while IFS= read -r -d $\'\\0\'; do\n        files+=("${REPLY}")\n    done < <(find . -maxdepth 1 -name \'koreader-emulator-*\' -print0 | ${SETUP_ENV_GREP_COMMAND})\n    test ${#files[@]} -gt 0\n    assert_ret_zero $? "Emulator not found. Please build it first."\n    local idx=0\n    # Warn if multiple matches were found\n    if [ ${#files[@]} -gt 1 ]; then\n        echo "Multiple emulator builds found:"\n        local ts=()\n        # Store list of ts at the same index\n        for i in "${!files[@]}"; do\n            local file="${files[${i}]}/koreader"\n            if [ -d "${file}" ]; then\n                echo "${file} (last modified on $(stat -c %y "${file}"))"\n                ts[${i}]="$(stat -c %Y "${file}")"\n            fi\n            ;;\n        android)\n            make TARGET=android clean\n            rm -f *.apk\n            ;;\n        pocketbook)\n            make TARGET=pocketbook clean\n                idx="${i}"\n                break\n            fi\n        done\n        # Recap\n        echo "Picking the most recent one: ${files[${idx}]}/koreader"\n    fi\n    EMU_DIR="${files[${idx}]}/koreader"\n    export EMU_DIR\n    KO_LD_LIBRARY_PATH="$(realpath "${EMU_DIR}")/libs:${LD_LIBRARY_PATH}"\n    # Don\'t export it to avoid messing with tools (e.g., debuggers).\n    # We\'ll pass it to LuaJIT via env\n}\n\nfunction kodev-fetch-thirdparty() {\n    make fetchthirdparty\n}\n\nSUPPORTED_TARGETS="\n    kindle          Compatible with all Kindle models >= Kindle4\n    kindlepw2       With compiler optimizations for Kindle models >= Paperwhite 2\n    kindle-legacy   Needed only for Kindle2/3/DXG\n    kobo\n    cervantes\n    remarkable\n    sony-prstux\n    android         Supports ANDROID_ARCH arm, arm64, x86 & x86_64\n    pocketbook\n    ubuntu-touch\n    appimage\n    debian          Debian package for current arch\n    debian-armel    Debian package for generic armel devices\n    debian-armhf    Debian package for generic armhf devices\n    debian-arm64    Debian package for generic 64 bits arm devices\n    macos           MacOS app bundle. You need a mac to build this package\n    emu             (*default) If no TARGET is given, assume emulator\n    win32\n"\n\nfunction kodev-build() {\n    BUILD_HELP_MSG="\nusage: build <OPTIONS> <TARGET>\n\nOPTIONS:\n\n    -v, --verbose   make the buildsystem more verbose\n    -d, --debug     include debugging symbols (default for emulator)\n    -n, --no-debug  no debugging symbols (default for target devices)\n\nTARGET:\n${SUPPORTED_TARGETS}"\n\n    declare opt\n    declare -r E_OPTERR=85\n    declare -r short_opts="vhnd"\n    declare -r long_opts="verbose,help,no-debug,debug"\n\n    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then\n        echo "${BUILD_HELP_MSG}"\n        exit ${E_OPTERR}\n    fi\n\n    eval set -- "${opt}"\n\n    while true; do\nfunction kodev-wbuilder {\n    kodev-build\n    echo "[*] Running wbuilder.lua..."\n    pushd ${EMU_DIR}\n    EMULATE_READER_W=540 EMULATE_READER_H=720 ./luajit ./utils/wbuilder.lua\n    popd\n}\n            -h | --help)\n                echo "${BUILD_HELP_MSG}"\n                exit 0\n                ;;\n            -n | --no-debug)\n                export KODEBUG=\n                KODEBUG_NO_DEFAULT=1\n                ;;\n            -d | --debug)\n                export KODEBUG=1\n                KODEBUG_NO_DEFAULT=1\n                ;;\n    screen_width=540\n    screen_height=720\n    while [[ $1 == \'-\'* ]]; do\n        PARAM=`echo $1 | awk -F= \'{print $1}\'`\n        VALUE=`echo $1 | awk -F= \'{print $2}\'`\n        case $PARAM in\n            --disable-touch)\n                export DISABLE_TOUCH=1\n        esac\n        shift\n    done\n    shift\n\n    check_submodules\n    case "${1}" in\n        cervantes)\n            make TARGET=cervantes\n            assert_ret_zero $?\n            ;;\n        kindle)\n            make TARGET=kindle\n            assert_ret_zero $?\n            ;;\n        kindlepw2)\n            make TARGET=kindlepw2\n            assert_ret_zero $?\n            ;;\n        kobo)\n            make TARGET=kobo\n            assert_ret_zero $?\n            ;;\n        remarkable)\n            make TARGET=remarkable\n            assert_ret_zero $?\n            ;;\n        setup_env\n    fi\n\n    if [ ! -d ${EMU_DIR} ]; then\n        echo "Failed to find emulator directory! Please try build command first."\n        exit 1\n    fi\n\n    echo "[*] Running KOReader with arguments: $@..."\n    pushd ${EMU_DIR}\n\n    if [ $# -lt 1 ]; then\n        args=${CURDIR}/test\n    else\n        args="$@"\n        [[ $args != /* ]] && args="${CURDIR}/${args}"\n    fi\n\n                { [ -e "${NDK}" ] || make -C "${CURDIR}/base/toolchain" android-ndk; }\n                assert_ret_zero $?\n                make android-toolchain\n                assert_ret_zero $?\n            }\n            echo "Using NDK: ${NDK}..."\n            make TARGET=android\n            assert_ret_zero $?\n            ;;\n        pocketbook)\n            make TARGET=pocketbook\n            assert_ret_zero $?\n            ;;\n    --tags=TAGS     only run tests with given tags\n    "\n    while [[ $1 == \'-\'* ]]; do\n        PARAM=`echo $1 | awk -F= \'{print $1}\'`\n        VALUE=`echo $1 | awk -F= \'{print $2}\'`\n        case $PARAM in\n            --tags)\n                opts="--tags=${VALUE}"\n        debian)\n            make TARGET=debian\n            assert_ret_zero $?\n            ;;\n        debian-armel)\n            make TARGET=debian-armel\n            assert_ret_zero $?\n            ;;\n        debian-armhf)\n            make TARGET=debian-armhf\n            assert_ret_zero $?\n            ;;\n        debian-arm64)\n            make TARGET=debian-arm64\n            assert_ret_zero $?\n            ;;\n        macos)\n    fi\n\n    setup_env\n    make ${EMU_DIR}/.busted\n    pushd ${EMU_DIR}\n\n    test_path=./spec/$1/unit\n\n    if [ ! -z $2 ]; then\n        test_path="${test_path}/$2"\n    fi\n    busted --lua=./luajit ${opts} \\\n        --no-auto-insulate \\\n        --lazy \\\n        -o ./spec/$1/unit/verbose_print \\\n        --exclude-tags=notest ${test_path}\n\n    popd\n}\n\nfunction kodev-clean() {\n    CLEAN_HELP_MSG="\nusage: clean <TARGET>\n\nTARGET:\n${SUPPORTED_TARGETS}"\n\n    declare opt\n    declare -r E_OPTERR=85\n    declare -r short_opts="nd"\n    declare -r long_opts="no-debug,debug"\n\n    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then\n        echo "${CLEAN_HELP_MSG}"\n        exit ${E_OPTERR}\n    fi\n\n    eval set -- "${opt}"\n\n    while true; do\n        PARAM="${1}"\n        # Support using an = assignment with short options (e.g., -f=blah instead of -f blah).\n        VALUE="${2/#=/}"\n        case "${PARAM}" in\n            -n | --no-debug)\n                export KODEBUG=\n                KODEBUG_NO_DEFAULT=1\n                ;;\n            -d | --debug)\n                export KODEBUG=1\n                KODEBUG_NO_DEFAULT=1\n                ;;\n            --)\n                break\n                ;;\n            *)\n                echo "ERROR: unknown option \\"${PARAM}\\""\n                echo "${BUILD_HELP_MSG}"\n                exit 8\n                ;;\n        esac\n        shift\n    done\n    shift\n\n    case "${1}" in\n        -h | --help)\n            echo "${CLEAN_HELP_MSG}"\n            exit 0\n            ;;\n        cervantes)\n            make TARGET=cervantes clean\n            ;;\n        kindle)\n            make TARGET=kindle clean\n    activate)\n        echo "adding ${CURDIR} to \\$PATH..."\n        export PATH="${PATH}:${CURDIR}"\n        eval $(luarocks path bin)\n        exec ${SHELL}\n        ;;\n    fetch-thirdparty)\n        kodev-fetch-thirdparty\n        ;;\n    clean)\n        shift 1\n        kodev-clean $@\n        ;;\n    build)\n        shift 1\n        kodev-build $@\n        ;;\n    release)\n        shift 1\n        kodev-release $@\n        ;;\n    wbuilder)\n        kodev-wbuilder\n        ;;\n    run)\n        shift 1\n        kodev-run $@\n        ;;\n    test)\n        shift 1\n        kodev-test $@\n        ;;\n    log)\n        shift 1\n        kodev-log $@\n        ;;\n    --help | -h)\n        echo "${HELP_MSG}"\n        debian-arm64)\n            make TARGET=debian-arm64 clean\n            ;;\n        macos)\n            is_mac\n            make TARGET=macos clean\n            ;;\n        win32)\n            make TARGET=win32 clean\n            ;;\n        *)\n            if [ -z "${KODEBUG_NO_DEFAULT}" ]; then\n                # No explicit --debug / --no-debug\n                # Builds a debug build by default, like kodev-run\n                export KODEBUG=1\n            fi\n\n            make clean\n            ;;\n    esac\n}\n\nfunction kodev-release() {\n    # SUPPORTED_RELEASE_TARGETS=$(echo ${SUPPORTED_TARGETS} | sed \'s/win32//\')\n    SUPPORTED_RELEASE_TARGETS="${SUPPORTED_TARGETS/emu*/""}"\n    RELEASE_HELP_MSG="\nusage: release <OPTIONS> <TARGET>\n\nOPTIONS:\n\n    -d, --debug               debug-enabled release (for remote gdb)\n    -i, --ignore-translation  do not fetch translation for release\n    -v, --verbose             make the buildsystem more verbose\n\nTARGET:\n${SUPPORTED_RELEASE_TARGETS}"\n    [ $# -lt 1 ] && {\n        echo "${RELEASE_HELP_MSG}"\n        exit 1\n    }\n\n    # Defaults\n    ignore_translation=0\n\n    declare opt\n    declare -r E_OPTERR=85\n    declare -r short_opts="divh"\n    declare -r long_opts="debug,ignore-translation,verbose,help"\n\n    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then\n        echo "${RELEASE_HELP_MSG}"\n        exit ${E_OPTERR}\n    fi\n\n    eval set -- "${opt}"\n\n    while true; do\n        PARAM="${1}"\n        # Support using an = assignment with short options (e.g., -f=blah instead of -f blah).\n        VALUE="${2/#=/}"\n        case "${PARAM}" in\n            -d | --debug)\n                export KODEBUG=1\n                ;;\n            -i | --ignore-translation)\n                ignore_translation=1\n                ;;\n            -v | --verbose)\n                export VERBOSE=1\n                ;;\n            -h | --help)\n                echo "${RELEASE_HELP_MSG}"\n                exit 0\n                ;;\n            --)\n                break\n                ;;\n            *)\n                echo "ERROR: unknown option \\"${PARAM}\\""\n                echo "${RELEASE_HELP_MSG}"\n                exit 1\n                ;;\n        esac\n        shift\n    done\n    shift\n\n    check_submodules\n    if [ "${ignore_translation}" -eq 0 ]; then\n        make po || {\n            echo "ERROR: failed to fetch translation."\n            echo "Tip: Use --ignore-translation OPTION if you want to build a release without translation."\n            exit 1\n        }\n    fi\n\n    case "${1}" in\n        kindle)\n            kodev-build kindle\n            make TARGET=kindle update\n            ;;\n        kindlepw2)\n            kodev-build kindlepw2\n            make TARGET=kindlepw2 update\n            ;;\n        kobo)\n            kodev-build kobo\n            make TARGET=kobo update\n            ;;\n        remarkable)\n            kodev-build remarkable\n            make TARGET=remarkable update\n            ;;\n        sony-prstux)\n            kodev-build sony-prstux\n            make TARGET=sony-prstux update\n            ;;\n        cervantes)\n            kodev-build cervantes\n            make TARGET=cervantes update\n            ;;\n        kindle-legacy)\n            kodev-build kindle-legacy\n            make TARGET=kindle-legacy update\n            ;;\n        android)\n            kodev-build android\n            export PATH=${PATH}:${CURDIR}/base/toolchain/android-sdk-linux/tools\n            command -v android &>/dev/null || {\n                make -C "${CURDIR}/base/toolchain" android-sdk\n            }\n            ANDROID_HOME=$(dirname "$(dirname "$(command -v android)")")\n            export ANDROID_HOME\n            export PATH="${PATH}:${NDK}"\n            make TARGET=android update\n            ;;\n        pocketbook)\n            kodev-build pocketbook\n            make TARGET=pocketbook update\n            ;;\n        ubuntu-touch)\n            kodev-build ubuntu-touch\n            make TARGET=ubuntu-touch update\n            ;;\n        appimage)\n            kodev-build appimage\n            make TARGET=appimage update\n            ;;\n        debian)\n            kodev-build debian\n            make TARGET=debian update\n            ;;\n        debian-armel)\n            kodev-build debian-armel\n            make TARGET=debian-armel update\n            ;;\n        debian-armhf)\n            kodev-build debian-armhf\n            make TARGET=debian-armhf update\n            ;;\n        debian-arm64)\n            kodev-build debian-arm64\n            make TARGET=debian-arm64 update\n            ;;\n        macos)\n            is_mac\n            kodev-build macos\n            make TARGET=macos update\n            ;;\n        *)\n            echo "Unsupported target for release: $1."\n            echo "${RELEASE_HELP_MSG}"\n            exit 1\n            ;;\n    esac\n}\n\nfunction kodev-wbuilder() {\n    kodev-build\n    echo "[*] Running wbuilder.lua..."\n    pushd "${EMU_DIR}" && {\n        EMULATE_READER_W=540 EMULATE_READER_H=720 ./luajit ./tools/wbuilder.lua\n    } && popd || exit\n}\n\nfunction kodev-run() {\n    RUN_HELP_MSG="\nusage: run <OPTIONS> <TARGET>\n\nOPTIONS:\n\n    -h X, --screen-height=X  set height of the emulator screen (default: 720)\n    -w X, --screen-width=X   set width of the emulator screen (default: 540)\n    -d X, --screen-dpi=X     set DPI of the emulator screen (default: 160)\n    -b, --no-build           run reader without rebuilding\n    -n, --no-debug           no debugging symbols (requires rebuilding)\n    -t, --disable-touch      use this if you want to simulate keyboard only devices\n    -s FOO --simulate=FOO    simulate dimension and other specs for a given device model\n                             supported model: hidpi, kobo-forma, kobo-aura-one, kobo-clara, kindle-paperwhite, kobo-h2o, legacy-paperwhite, kindle\n    -g X, --gdb=X            run with debugger (default: nemiver)\n    -p, --graph              graph memory use (requires gnuplot)\n    -v X, --valgrind=X       run with valgrind (default: \\"valgrind --tool=memcheck --trace-children=yes --leak-check=full --track-origins=yes --show-reachable=yes\\")\n    -c, --callgrind          run with valgrind\'s callgrind (valgrind --tool=callgrind --trace-children=yes)\n    -S, --no-catchsegv       prevents wrapping by catchsegv\n\nTARGET:\n\n    android         install and run KOReader on an Android device connected through ADB\n    "\n\n    # NOTE: Speaking of Valgrind, if your libdrm/mesa isn\'t built w/ valgrind markings, there\'s a Valgrind suppression file for AMD cards in the tools folder.\n    #       Just append --suppressions=${PWD/tools/valgrind_amd.supp to your valgrind command.\n\n    # Defaults\n    screen_width=540\n    screen_height=720\n    export KODEBUG=1\n\n    declare opt\n    declare -r E_OPTERR=85\n    declare -r short_opts="tbng::pv::cw:h:d:s:SH"\n    declare -r long_opts="disable-touch,no-build,gdb::,graph,valgrind::,callgrind,screen-width:,screen-height:,screen-dpi:,simulate:,no-catchsegv,help"\n\n    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then\n        echo "${RUN_HELP_MSG}"\n        exit ${E_OPTERR}\n    fi\n\n    eval set -- "${opt}"\n\n    while true; do\n        PARAM="${1}"\n        # Support using an = assignment with short options (e.g., -f=blah instead of -f blah).\n        VALUE="${2/#=/}"\n        case "${PARAM}" in\n            -t | --disable-touch)\n                export DISABLE_TOUCH=1\n                ;;\n            -b | --no-build)\n                no_build=1\n                ;;\n            -n | --no-debug)\n                export KODEBUG=\n                ;;\n            -g | --gdb)\n                if [ -n "${VALUE}" ]; then\n                    gdb="${VALUE}"\n                else\n                    # Try to use friendly defaults for gdb\n                    if command -v nemiver >/dev/null; then\n                        # Nemiver is a nice GUI\n                        gdb="nemiver"\n                    elif command -v ddd >/dev/null; then\n                        # DDD is a slightly less nice GUI\n                        gdb="ddd"\n                    elif command -v cgdb >/dev/null; then\n                        # cgdb is a nice curses-based gdb front\n                        gdb="cgdb"\n                    elif command -v gdb >/dev/null; then\n                        # gdb -tui is a slightly less nice terminal user interface\n                        gdb="gdb -tui"\n                    else\n                        echo "Couldn\'t find gdb."\n                        exit 1\n                    fi\n                fi\n                shift\n                ;;\n            -p | --graph)\n                graph_memory=1\n                ;;\n            -v | --valgrind)\n                if [ -n "${VALUE}" ]; then\n                    valgrind="${VALUE}"\n                else\n                    # Try to use sensible defaults for valgrind\n                    if command -v valgrind >/dev/null; then\n                        valgrind="valgrind --tool=memcheck --trace-children=yes --leak-check=full --track-origins=yes --show-reachable=yes"\n                    else\n                        echo "Couldn\'t find valgrind."\n                        exit 1\n                    fi\n                fi\n                shift\n                ;;\n            -c | --callgrind)\n                # Try to use sensible defaults for valgrind\n                if command -v valgrind >/dev/null; then\n                    valgrind="valgrind --tool=callgrind --trace-children=yes"\n                else\n                    echo "Couldn\'t find valgrind."\n                    exit 1\n                fi\n                ;;\n            -w | --screen-width)\n                screen_width=${VALUE}\n                shift\n                ;;\n            -h | --screen-height)\n                # simple numeric check due to overlap between -h for help and height\n                if [ -n "${VALUE##*[!0-9]*}" ]; then\n                    screen_height=${VALUE}\n                else\n                    echo "ERROR: Invalid value: \\"${VALUE}\\""\n                    echo "${RUN_HELP_MSG}"\n                    exit 1\n                fi\n                shift\n                ;;\n            -d | --screen-dpi)\n                screen_dpi=${VALUE}\n                shift\n                ;;\n            -s | --simulate)\n                device_model="${VALUE}"\n                case "${device_model}" in\n                    kindle)\n                        screen_width=600\n                        screen_height=800\n                        screen_dpi=167\n                        ;;\n                    legacy-paperwhite)\n                        screen_width=758\n                        screen_height=1024\n                        screen_dpi=212\n                        ;;\n                    kobo-forma)\n                        screen_width=1440\n                        screen_height=1920\n                        screen_dpi=300\n                        ;;\n                    kobo-aura-one)\n                        screen_width=1404\n                        screen_height=1872\n                        screen_dpi=300\n                        ;;\n                    kobo-clara | kindle-paperwhite)\n                        screen_width=1072\n                        screen_height=1448\n                        screen_dpi=300\n                        ;;\n                    kobo-h2o)\n                        screen_width=1080\n                        screen_height=1429\n                        screen_dpi=265\n                        ;;\n                    hidpi)\n                        screen_width=1500\n                        screen_height=2000\n                        screen_dpi=600\n                        ;;\n                    *)\n                        echo "ERROR: spec unknown for ${device_model}."\n                        ;;\n                esac\n                shift\n                ;;\n            -S | --no-catchsegv)\n                no_catchsegv=1\n                ;;\n            -H | --help)\n                echo "${RUN_HELP_MSG}"\n                exit 0\n                ;;\n            --)\n                break\n                ;;\n            *)\n                echo "ERROR: unknown option \\"${PARAM}\\""\n                echo "${RUN_HELP_MSG}"\n                exit 8\n                ;;\n        esac\n        shift\n    done\n    shift\n\n    case "${1}" in\n        android)\n            command -v adb >/dev/null && {\n                if [ -z "${no_build}" ]; then\n                    echo "[*] Building KOReader for Android ${ANDROID_ARCH}…"\n                    kodev-release --ignore-translation android\n                    assert_ret_zero $?\n                fi\n                setup_env\n                # clear logcat to get rid of useless cruft\n                adb logcat -c\n                # uninstall existing package to make sure *everything* is gone from memory\n                # no assert_ret_zero; uninstall is allowed to fail if there\'s nothing to uninstall\n                adb uninstall "org.koreader.launcher"\n                adb install "koreader-android-${ANDROID_ARCH}${KODEBUG_SUFFIX}-${VERSION}.apk"\n                assert_ret_zero $?\n                # there\'s no adb run so we do this…\n                adb shell monkey -p org.koreader.launcher -c android.intent.category.LAUNCHER 1\n                assert_ret_zero $?\n                adb logcat KOReader:V luajit-launcher:V "*:E"\n            } || echo "Failed to find adb in PATH to interact with Android device."\n            ;;\n        *)\n            if [ -z "${no_build}" ]; then\n                echo "[*] Building KOReader…"\n                if [ -z "${KODEBUG}" ]; then\n                    kodev-build --no-debug\n                else\n                    kodev-build\n                fi\n            else\n                setup_env\n            fi\n\n            if [ ! -d "${EMU_DIR}" ]; then\n                echo "Failed to find emulator directory! Please try build command first."\n                exit 1\n            fi\n\n            if [ -n "${graph_memory}" ]; then\n                gnuplot_wrapper "--parent $$" "reader.lua"\n            fi\n\n            KOREADER_ARGS="-d"\n            KOREADER_COMMAND="env LD_LIBRARY_PATH=${KO_LD_LIBRARY_PATH} ./reader.lua ${KOREADER_ARGS}"\n\n            # run with catchsegv by default when it is available (unless no-catchsegv is enabled, c.f., #7036)\n            # see https://github.com/koreader/koreader/issues/2878#issuecomment-326796777\n            if [ -z "${no_catchsegv}" ]; then\n                if command -v catchsegv >/dev/null; then\n                    KOREADER_COMMAND="$(command -v catchsegv) ${KOREADER_COMMAND}"\n                fi\n            fi\n\n            if [ -n "${valgrind}" ]; then\n                KOREADER_COMMAND="${valgrind} env LD_LIBRARY_PATH=${KO_LD_LIBRARY_PATH} ./luajit reader.lua ${KOREADER_ARGS}"\n            fi\n\n            echo "[*] Running KOReader with arguments: $* ..."\n            pushd "${EMU_DIR}" && {\n                if [ $# -ge 1 ]; then\n                    args="$*"\n                    [[ "${args}" != /* ]] && args="${CURDIR}/${args}"\n                fi\n\n                if [ -n "${gdb}" ]; then\n                    # We don\'t want to stack valgrind/catchsegv on top of GDB ;).\n                    if [[ "${gdb}" == gdb* ]]; then\n                        # The standard CLI needs a little hand holding to properly pass arguments to the process it\'ll monitor\n                        KOREADER_COMMAND="${gdb} --args env LD_LIBRARY_PATH=${KO_LD_LIBRARY_PATH} ./luajit reader.lua ${KOREADER_ARGS} ${args}"\n                    else\n                        KOREADER_COMMAND="${gdb} env LD_LIBRARY_PATH=${KO_LD_LIBRARY_PATH} ./luajit reader.lua ${KOREADER_ARGS} ${args}"\n                    fi\n                else\n                    KOREADER_COMMAND="${KOREADER_COMMAND} ${args}"\n                fi\n\n                RETURN_VALUE=85\n                while [ "${RETURN_VALUE}" -eq 85 ]; do\n                    # shellcheck disable=SC2086\n                    env EMULATE_READER_W="${screen_width}" EMULATE_READER_H="${screen_height}" EMULATE_READER_DPI="${screen_dpi}" \\\n                        ${KOREADER_COMMAND}\n                    RETURN_VALUE=$?\n                done\n            } && popd || exit\n\n            if [ -n "${graph_memory}" ]; then\n                capture_ctrl_c\n            fi\n\n            exit ${RETURN_VALUE}\n            ;;\n    esac\n}\n\nfunction kodev-test() {\n    TEST_HELP_MSG="\nusage: test <OPTIONS> [front|base] <TEST_NAME>\n\n    TEST_NAME is optional. If no TEST_NAME is given, all tests will be run.\n\nOPTIONS:\n\n    -p, --graph         graph memory use (requires gnuplot)\n    -n, --no-debug      no debugging symbols (default for target devices)\n    -t, --tags=TAGS     only run tests with given tags\n    "\n\n    declare opt\n    declare -r E_OPTERR=85\n    declare -r short_opts="pt:nh"\n    declare -r long_opts="graph,tags:,no-debug,help"\n\n    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then\n        echo "${TEST_HELP_MSG}"\n        exit ${E_OPTERR}\n    fi\n\n    eval set -- "${opt}"\n\n    while true; do\n        PARAM="${1}"\n        # Support using an = assignment with short options (e.g., -f=blah instead of -f blah).\n        VALUE="${2/#=/}"\n        case "${PARAM}" in\n            -p | --graph)\n                graph_memory=1\n                ;;\n            -n | --no-debug)\n                export KODEBUG=\n                KODEBUG_NO_DEFAULT=1\n                ;;\n            -t | --tags)\n                opts="--tags=${VALUE}"\n                shift\n                ;;\n            -h | --help)\n                echo "${TEST_HELP_MSG}"\n                exit 0\n                ;;\n            --)\n                break\n                ;;\n            *)\n                echo "ERROR: unknown option \\"${PARAM}\\""\n                echo "${TEST_HELP_MSG}"\n                exit 8\n                ;;\n        esac\n        shift\n    done\n    shift\n\n    [ $# -lt 1 ] && {\n        echo "${TEST_HELP_MSG}"\n        exit 1\n    }\n    [[ "${1}" != "front" && "${1}" != "base" ]] && {\n        echo "Invalid test suite: $1!"\n        echo "${TEST_HELP_MSG}"\n        exit 1\n    }\n\n    set -e\n    check_submodules && kodev-build\n    setup_env\n\n    make "${EMU_DIR}/.busted"\n    pushd "${EMU_DIR}" && {\n        test_path_basedir="./spec/$1/unit"\n        rm -rf "${test_path_basedir}"/data/*.sdr\n\n        test_path="${test_path_basedir}"\n        if [ -n "${2}" ]; then\n            test_path="${test_path_basedir}/$2"\n        fi\n\n        echo "Running tests in" "${test_path}"\n        env LD_LIBRARY_PATH="${KO_LD_LIBRARY_PATH}" \\\n            busted --lua="./luajit" "${opts}" \\\n            --output=gtest \\\n            --lpath="${test_path_basedir}/?.lua" \\\n            --exclude-tags=notest "${test_path}"\n    } && popd || exit\n}\n\nfunction kodev-cov() {\n    COV_HELP_MSG="\nusage: cov <OPTIONS>\n\nOPTIONS:\n\n    -f, --full              show full coverage report (down to each line)\n    -s, --show-previous     show coverage stats from previous run\n    -n, --no-debug          no debugging symbols (default for target devices)\n    "\n\n    # Defaults\n    show_full=0\n    show_previous=0\n\n    declare opt\n    declare -r E_OPTERR=85\n    declare -r short_opts="fsn"\n    declare -r long_opts="full,show-previous,no-debug"\n\n    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then\n        echo "${COV_HELP_MSG}"\n        exit ${E_OPTERR}\n    fi\n\n    eval set -- "${opt}"\n\n    while true; do\n        PARAM="${1}"\n        # Support using an = assignment with short options (e.g., -f=blah instead of -f blah).\n        VALUE="${2/#=/}"\n        case "${PARAM}" in\n            -f | --full)\n                show_full=1\n                ;;\n            -s | --show-previous)\n                show_previous=1\n                ;;\n            -n | --no-debug)\n                export KODEBUG=\n                KODEBUG_NO_DEFAULT=1\n                ;;\n            -h | --help)\n                echo "${COV_HELP_MSG}"\n                exit 0\n                ;;\n            --)\n                break\n                ;;\n            *)\n                echo "ERROR: unknown option \\"${PARAM}\\""\n                echo "${COV_HELP_MSG}"\n                exit 8\n                ;;\n        esac\n        shift\n    done\n    shift\n\n    set -e\n    check_submodules && kodev-build\n    setup_env\n    make "${EMU_DIR}/.busted"\n    pushd "${EMU_DIR}" && {\n        target=front\n        test_path="./spec/${target}/unit"\n        if [ "${show_previous}" -eq 0 ]; then\n            echo "Running tests in" ${test_path}\n            env LD_LIBRARY_PATH="${KO_LD_LIBRARY_PATH}" \\\n                busted --lua="./luajit" \\\n                --sort-files \\\n                -o "./spec/${target}/unit/verbose_print" \\\n                --coverage \\\n                --exclude-tags=nocov "${test_path}" || {\n                echo "Failed to run tests!" && exit 1\n            }\n        fi\n        if [ "${show_full}" -eq 1 ]; then\n            cat luacov.report.out\n        else\n            LUACOV_REPORT_SUMMARY=$(grep -nm1 -e \'^Summary$\' luacov.report.out | cut -d: -f1)\n            tail -n \\\n                +$((LUACOV_REPORT_SUMMARY - 1)) \\\n                luacov.report.out\n        fi\n    } && popd || exit\n}\n\nfunction kodev-log() {\n    LOG_HELP_MSG="\nusage: log <OPTIONS> <TARGET>\n\nOPTIONS:\n\n    -d, --debug               more verbose logs (e.g., debug builds)\n\nTARGET:\n\n    android\n"\n    [ $# -lt 1 ] && {\n        echo "${LOG_HELP_MSG}"\n        exit 1\n    }\n\n    # Defaults\n    ignore_translation=0\n\n    declare opt\n    declare -r E_OPTERR=85\n    declare -r short_opts="dh"\n    declare -r long_opts="debug, help"\n\n    if ! opt=$(getopt -o "${short_opts}" --long "${long_opts}" --name "kodev" -- "${@}"); then\n        echo "${LOG_HELP_MSG}"\n        exit ${E_OPTERR}\n    fi\n\n    eval set -- "${opt}"\n\n    while true; do\n        PARAM="${1}"\n        # Support using an = assignment with short options (e.g., -f=blah instead of -f blah).\n        VALUE="${2/#=/}"\n        case "${PARAM}" in\n            -d | --debug)\n                export KODEBUG=1\n                ;;\n            -h | --help)\n                echo "${LOG_HELP_MSG}"\n                exit 0\n                ;;\n            --)\n                break\n                ;;\n            *)\n                echo "ERROR: unknown option \\"${PARAM}\\""\n                echo "${RELEASE_HELP_MSG}"\n                exit 1\n                ;;\n        esac\n        shift\n    done\n    shift\n\n    case "${1}" in\n        android)\n            if command -v pidcat >/dev/null; then\n                if [ -n "${KODEBUG}" ]; then\n                    pidcat "org.koreader.launcher"\n                else\n                    pidcat org.koreader.launcher --min-level=I\n                fi\n            else\n                if [ -n "${KODEBUG}" ]; then\n                    adb logcat \'KOReader:V ApkUpdater:V Assets:V Device:V dlopen:V EPD:V EventReceiver:V Lights:V LuaJIT:V MainActivity:V NativeGlue:V NativeThread:V Timeout:V ActivityManager:V AndroidRuntime:V DEBUG:* *:F\'\n                else\n                    adb logcat \'KOReader:I MainActivity:V NativeGlue:V NativeThread:V ActivityManager:W AndroidRuntime:E DEBUG:* *:F\'\n                fi\n            fi\n            ;;\n        *)\n            echo "Unsupported target: $1."\n            echo "${LOG_HELP_MSG}"\n            exit 1\n            ;;\n    esac\n}\n\nHELP_MSG="\nusage: $0 COMMAND <ARGS>\n\nSupported commands:\n\n    activate            Bootstrap shell environment for kodev\n    build               Build KOReader\n    clean               Clean KOReader build\n    fetch-thirdparty    Fetch thirdparty dependencies for build\n    log                 Tail log stream for a running KOReader app\n    release             Build KOReader release package\n    run                 Run KOReader\n    test                Run busted tests\n    check               Run luacheck static-analysis\n    cov                 Run busted tests for coverage\n    wbuilder            Run wbuilder.lua script (useful for building new UI widget)\n    prompt              Run a LuaJIT shell within KOReader\'s environment\n"\n[ $# -lt 1 ] && {\n    echo "Missing command."\n    echo "${HELP_MSG}"\n    exit 1\n}\n\ncase "${1}" in\n    activate)\n        echo "adding ${CURDIR} to \\$PATH..."\n        export PATH="${PATH}:${CURDIR}"\n        eval "$(luarocks path --bin)"\n        exec "${SHELL}"\n        ;;\n    fetch-thirdparty)\n        kodev-fetch-thirdparty\n        ;;\n    clean)\n        shift 1\n        kodev-clean "$@"\n        ;;\n    build)\n        shift 1\n        kodev-build "$@"\n        ;;\n    release)\n        shift 1\n        kodev-release "$@"\n        ;;\n    wbuilder)\n        kodev-wbuilder\n        ;;\n    run)\n        shift 1\n        kodev-run "$@"\n        ;;\n    test)\n        shift 1\n        kodev-test "$@"\n        ;;\n    check)\n        luacheck -q {reader,setupkoenv,datastorage}.lua frontend plugins spec\n        ;;\n    cov)\n        shift 1\n        kodev-cov "$@"\n        ;;\n    prompt)\n        kodev-build\n        pushd "${EMU_DIR}" && {\n            env LD_LIBRARY_PATH="${KO_LD_LIBRARY_PATH}" \\\n                ./luajit -i setupkoenv.lua\n        } && popd || exit\n        ;;\n    log)\n        shift 1\n        kodev-log "$@"\n        ;;\n    -h | --help)\n        echo "${HELP_MSG}"\n        exit 0\n        ;;\n    *)\n        echo "Unknown command: $1."\n        echo "${HELP_MSG}"\n        exit 8\n        ;;\nesac\n', 'message': 'kodev code quality\n', 'author_name': 'Frans de Jonge', 'lang': 'kodev'}