diff --git a/.github/workflows/interactive-command.yml b/.github/workflows/interactive-command.yml index 3e20b1a..cd07246 100644 --- a/.github/workflows/interactive-command.yml +++ b/.github/workflows/interactive-command.yml @@ -6,11 +6,11 @@ on: command: description: "Command to execute" required: true - default: "sed --version" + default: "demo/all-demos.sh" os: description: "Operating system to run the command on" required: true - default: "ubuntu-latest" + default: "macos-latest" type: choice options: - ubuntu-latest @@ -21,6 +21,9 @@ on: default: false type: boolean +run-name: | + ICE: ${{ inputs.command }} (${{ inputs.os }}, GNU? ${{ inputs.install_gnu_tools }}) + permissions: contents: read @@ -29,30 +32,16 @@ jobs: runs-on: ${{ inputs.os }} steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + submodules: recursive + - name: Install GNU tools on macOS - if: runner.os == 'macos-latest' && inputs.install_gnu_tools == 'true' + if: ${{ inputs.install_gnu_tools }} run: | - brew install gnu-sed gawk grep findutils coreutils gnu-tar gnu-time gnu-indent gnu-getopt gnu-which - brew install gdate gxargs gcut ghead gtail gtr guniq gwc gdiff - echo 'export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/gawk/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/grep/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/findutils/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/gnu-time/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/gnu-indent/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/gnu-getopt/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/gnu-which/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/gdate/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/gxargs/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/gcut/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/ghead/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/gtail/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/gtr/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/guniq/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/gwc/libexec/gnubin:$PATH"' >> $GITHUB_ENV - echo 'export PATH="/usr/local/opt/gdiff/libexec/gnubin:$PATH"' >> $GITHUB_ENV + bin/gnu-install.sh - name: Execute command run: ${{ inputs.command }} diff --git a/bin/gnu-install.sh b/bin/gnu-install.sh new file mode 100755 index 0000000..b0b139e --- /dev/null +++ b/bin/gnu-install.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +### +### Script to install GNU tools (typically on macOS). +### +### Requires `brew` to be installed. +### + +set -o errexit # abort on nonzero exit status +set -o nounset # abort on unbound variable +set -o pipefail # don't hide errors within pipes + +### GNU Tools to install +### +### References: +### - https://gist.github.com/skyzyx/3438280b18e4f7c490db8a2a2ca0b9da +### - https://www.topbug.net/blog/2013/04/14/install-and-use-gnu-command-line-tools-in-mac-os-x/ +### https://github.com/asantra1/macOS-gnu-tools/blob/master/gnu-cmd.sh + +declare -a GNU_TOOLS=( + "binutils" + "coreutils" + "diffutils" + "ed" + "findutils" + "gawk" + "gnu-indent" + "gnu-sed" + "gnu-tar" + "gnu-which" + "gnutls" + "grep" + "gzip" + "screen" + "watch" + "wdiff" + "wget" +) + +### Validate `brew` is installed +if ! command -v brew &>/dev/null; then + echo "Error: 'brew' is required. Please install it first." + exit 1 +fi + +### Install GNU Tools +for tool in "${GNU_TOOLS[@]}"; do + if brew list --formula | grep -q "^${tool}\$"; then + if brew outdated --formula | grep -q "^${tool}\$"; then + echo "Updating ${tool}..." + brew upgrade "${tool}" + else + echo "${tool} is already installed and up-to-date." + fi + else + echo "Installing ${tool}..." + brew install "${tool}" + fi +done diff --git a/demo/all-demos.sh b/demo/all-demos.sh new file mode 100755 index 0000000..bea70b6 --- /dev/null +++ b/demo/all-demos.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +### +### Run all demo scripts. +### + +SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" +declare -r SCRIPT_DIR + +# Find all -demo.sh files in the demo directory and run them. +for demo_script in "${SCRIPT_DIR}"/*-demo.sh; do + if [[ -f "${demo_script}" ]]; then + echo "Running demo: ${demo_script}" + "${demo_script}" + echo + fi +done diff --git a/demo/gnucompat-demo.sh b/demo/gnucompat-demo.sh new file mode 100755 index 0000000..90f13f6 --- /dev/null +++ b/demo/gnucompat-demo.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +### +### Demo for GNU Tools Compatibility Layer +### + +SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" +declare -r SCRIPT_DIR +# shellcheck source=/dev/null +source "${SCRIPT_DIR}/../lib_gnucompat.sh" + +# Function to output the path and GNU status of a command +function output_command_info() { + local cmd_var_name="${1}" + local cmd="${!cmd_var_name}" + local cmd_path + cmd_path=$(command -v "${cmd}") + local gnu_status + if is_gnu "${cmd}"; then + gnu_status="Yes" + else + gnu_status="No" + fi + echo "${cmd_var_name}: ${cmd_path} (GNU? ${gnu_status})" +} + +# Output information for each command +output_command_info "SED" +output_command_info "AWK" +output_command_info "GREP" +output_command_info "FIND" +output_command_info "SORT" +output_command_info "TAR" +output_command_info "DATE" +output_command_info "XARGS" +output_command_info "CUT" +output_command_info "HEAD" +output_command_info "TAIL" +output_command_info "TR" +output_command_info "UNIQ" +output_command_info "WC" +output_command_info "DIFF" diff --git a/lib_gnucompat.sh b/lib_gnucompat.sh index e000435..5c36813 100644 --- a/lib_gnucompat.sh +++ b/lib_gnucompat.sh @@ -156,11 +156,16 @@ export DIFF function is_gnu() { local cmd="${1:?Error: No command provided to is_gnu function}" - # Check if the command is a GNU tool by expecting the version output - # to contain "GNU". + # Check if the command is available + if ! command -v "${cmd}" &>/dev/null; then + return 0 + fi + + ("${cmd}" --version &>/dev/null) || return 1 + local version_output version_output="$("${cmd}" --version 2>&1)" - if "${GREP}" -q "GNU" <<<"${version_output}"; then + if [[ "${version_output}" == *"GNU"* ]]; then return 0 else return 1