From 43224f40fef2d0f5040561af11b5d1e87dc67034 Mon Sep 17 00:00:00 2001 From: Anders Ingemann Date: Wed, 21 Feb 2024 12:57:56 +0100 Subject: [PATCH] Initial import --- .github/workflows/test.yaml | 35 +++++++++++++++++++++++++++++++++++ README.md | 27 +++++++++++++++++++++++++++ test.bats | 34 ++++++++++++++++++++++++++++++++++ trap.sh | 28 ++++++++++++++++++++++++++++ upkg.json | 3 +++ 5 files changed, 127 insertions(+) create mode 100644 .github/workflows/test.yaml create mode 100644 README.md create mode 100644 test.bats create mode 100644 trap.sh create mode 100644 upkg.json diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..da8d73b --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,35 @@ +name: Test + +on: + push: + branches: [ '*' ] + tags: [ 'v*' ] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@master + env: + SHELLCHECK_OPTS: -x + test: + runs-on: ubuntu-latest + steps: + - name: Setup BATS + run: | + git clone --depth 1 --branch v1.10.0 https://github.com/bats-core/bats-core.git /tmp/bats + sudo /tmp/bats/install.sh /usr/local + rm -rf /tmp/bats + sudo mkdir -p /usr/lib/bats/bats-support /usr/lib/bats/bats-assert + wget -O- 'https://github.com/ztombol/bats-support/archive/refs/tags/v0.3.0.tar.gz' | \ + sudo tar -xz --strip-components=1 -C /usr/lib/bats/bats-support + wget -O- 'https://github.com/ztombol/bats-assert/archive/refs/tags/v0.3.0.tar.gz' | \ + sudo tar -xz --strip-components=1 -C /usr/lib/bats/bats-assert + - name: Checkout + uses: actions/checkout@v3 + - uses: orbit-online/upkg@v0.14.0 + - name: Run tests + run: bats . diff --git a/README.md b/README.md new file mode 100644 index 0000000..bbab313 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# trap.sh + +Library for managing bash signal traps. + +## Contents + +- [Installation](#installation) +- [Usage](#usage) + +## Installation + +With [μpkg](https://github.com/orbit-online/upkg) + +``` +upkg install -g orbit-online/trap.sh@ +``` + +## Usage + +### `trap_append CMD SIGNAL` + +Appends `CMD` to the `SIGNAL` trap. `$TRAP_POINTER` will contain a pointer +that can be used with `trap_remove` to remove the command again. + +### `trap_remove POINTER` + +Removes the command identified by `POINTER` from the list of traps to run. diff --git a/test.bats b/test.bats new file mode 100644 index 0000000..1b4a6b4 --- /dev/null +++ b/test.bats @@ -0,0 +1,34 @@ +#!/usr/bin/env bats +# shellcheck disable=2030,2031 + +load '/usr/lib/bats/bats-support/load' +load '/usr/lib/bats/bats-assert/load' + +setup_file() { + bats_require_minimum_version 1.5.0 +} + +@test 'trap is run on signal' { + assert_equal "$(bash -ec "source $BATS_TEST_DIRNAME/trap.sh + trap_append \"echo 'USR2 signal received'\" USR2 + kill -s USR2 \$\$ + ")" 'USR2 signal received' +} + +@test 'trap removal works' { + assert_equal "$(bash -ec "source $BATS_TEST_DIRNAME/trap.sh + trap_append \"echo 'cmd to remove'\" USR2 + p=\$TRAP_POINTER + trap_append \"echo 'USR2 signal received'\" USR2 + trap_remove \$p + kill -s USR2 \$\$ + ")" 'USR2 signal received' +} + +@test 'only commands for specific signal are run' { + assert_equal "$(bash -ec "source $BATS_TEST_DIRNAME/trap.sh + trap_append \"echo 'USR1 signal received'\" USR1 + trap_append \"echo 'USR2 signal received'\" USR2 + kill -s USR2 \$\$ + ")" 'USR2 signal received' +} diff --git a/trap.sh b/trap.sh new file mode 100644 index 0000000..d0ce3db --- /dev/null +++ b/trap.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +TRAP_CMDS=() + +_trap_run() { + local signal=$1 trap_cmd + for trap_cmd in "${TRAP_CMDS[@]}"; do + [[ $trap_cmd = $signal* ]] || continue + eval "${trap_cmd#"$signal "}" || true + done +} + +trap_append() { + local cmd=$1 signal=$2 trap_cmd + TRAP_POINTER=0 + for trap_cmd in "${TRAP_CMDS[@]}"; do + [[ -n $trap_cmd ]] || break + : $((TRAP_POINTER++)) + done + TRAP_CMDS[TRAP_POINTER]="$signal $cmd" + # shellcheck disable=SC2064 + [[ $(trap -p "$signal") = "trap -- '_trap_run $signal' $signal" ]] || trap "_trap_run $signal" "$signal" +} + +trap_remove() { + local pointer=$1 + TRAP_CMDS[pointer]='' +} diff --git a/upkg.json b/upkg.json new file mode 100644 index 0000000..231a948 --- /dev/null +++ b/upkg.json @@ -0,0 +1,3 @@ +{ + "assets": ["trap.sh"] +}