From 764ef51a2c1bea4fd972341efa5b2436d8834a97 Mon Sep 17 00:00:00 2001 From: Dan Bornstein Date: Tue, 5 Dec 2023 14:45:04 -0800 Subject: [PATCH] New option `--runner-script`. --- CHANGELOG.md | 8 + .../bashy-node/node-project/build-main-module | 16 ++ .../bashy-node/node-project/runner-script.txt | 150 ++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 scripts/lib/bashy-node/node-project/runner-script.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ae95b0..e89c5b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ versioning principles. Unstable releases do not. ### [Unreleased] +Breaking changes: +* None. + +Other notable changes: +* `bashy-node`: + * New option `--runner-script` for `node-project build-main-module`, using + code extracted from sibling project `lactoserv`. + ### v2.8 -- 2023-11-30 This is a stable-ish release. No further breaking changes are currently diff --git a/scripts/lib/bashy-node/node-project/build-main-module b/scripts/lib/bashy-node/node-project/build-main-module index 52e988b..84f951c 100755 --- a/scripts/lib/bashy-node/node-project/build-main-module +++ b/scripts/lib/bashy-node/node-project/build-main-module @@ -34,6 +34,9 @@ define-usage --with-help $' --out= Directory where built output goes. Defaults to `out` directly under the main product directory. + --runner-script= + Create a script to run the system in the `out` directory, with the given + name. --unsafely-run-npm-install-scripts If specified, runs any install-time scripts defined by modules. This is reasonably considered an unsafe practice (it is a vector for @@ -51,6 +54,9 @@ opt-multi --required --var=modulesDirs --filter='/./' modules-dirs # Built output directory. opt-value --var=outDir out +# Name of runner script to add to the output, if any. +opt-value --var=runnerScript runner-script + # Run npm install-time scripts? opt-toggle --var=runNpmInstallScripts unsafely-run-npm-install-scripts @@ -380,5 +386,15 @@ if (( !platformSpecific )); then || exit "$?" fi +if [[ ${runnerScript} != '' ]]; then + progress-msg 'Copying runner script...' + binDir="${outProjectDir}/bin" + true \ + && mkdir -p "${binDir}" \ + && cp "$(this-cmd-dir)/runner-script.txt" "${binDir}/${runnerScript}" \ + && chmod 755 "${binDir}/${runnerScript}" \ + || exit "$?" +fi + progress-msg progress-msg "Built Node project ${projectName}." diff --git a/scripts/lib/bashy-node/node-project/runner-script.txt b/scripts/lib/bashy-node/node-project/runner-script.txt new file mode 100644 index 0000000..7746097 --- /dev/null +++ b/scripts/lib/bashy-node/node-project/runner-script.txt @@ -0,0 +1,150 @@ +#!/bin/bash +# +# Copyright 2022-2023 the Bashy-lib Authors (Dan Bornstein et alia). +# SPDX-License-Identifier: Apache-2.0 + +# Figure out the symlink-resolved program name and directory. +cmdName="$(readlink -f "$0")" || exit "$?" +cmdDir="${cmdName%/*}" +cmdName="${cmdName##*/}" +baseDir="${cmdDir%/*}" + + +# +# Argument processing +# + +# This _just_ extracts `--print-node-command` and `--node-opts ... --`, leaving +# everything else intact, because the bulk of the options are processed by the +# main program. + +# Options to pass to `node`. +nodeOpts=() + +# Arguments to pass to the main program. +mainArgs=() + +# Print the `node ...` command to stderr before actually running it? +printNodeCommand=0 + +# Collect node options? +wantNodeOpts=0 + +while (( $# != 0 )); do + if (( wantNodeOpts )); then + if [[ $1 == '--' ]]; then + wantNodeOpts=0 + else + nodeOpts+=("$1") + fi + shift + continue + fi + + case "$1" in + --node-opts) + wantNodeOpts=1 + ;; + --print-node-command) + printNodeCommand=1 + ;; + --*|-?*) + # Option to pass through. + mainArgs+=("$1") + ;; + *) + # Non-option argument (including `--` to explicitly end options). + break + ;; + esac + + shift +done + +# Append the rest of the arguments to `mainArgs`. +mainArgs+=("$@") + + +# +# Helper functions +# + +# Prints an error message to `stderr`. +function error-msg { + echo 1>&2 "$@" +} + +# Checks one dependency. +function check-dependency { + local name="$1" + local versionCmd="$2" + local match="$3" + local versionMsg="$4" + + # Extract just the binary (executable / command / tool) name. + local cmdName='' + if [[ ${versionCmd} =~ ^([^ ]+) ]]; then + cmdName="${BASH_REMATCH[1]}" + else + # Note: This indicates a bug in this script, not a problem with the + # environment. + error-msg "Could not determine binary name for ${name}." + return 1 + fi + + # Verify that the command exists at all. + if ! which "${cmdName}" >/dev/null 2>&1; then + error-msg "Missing required binary for ${name}: ${cmdName}" + return 1 + fi + + local version + version=$(eval "${versionCmd}") \ + || { + # Note: This indicates a bug in this script, not a problem with the + # environment. + error-msg "Trouble running version command for ${name}." + return 1 + } + + if [[ !(${version} =~ ${match}) ]]; then + error-msg "Unsupported version of ${name}: ${version}" + error-msg " required: ${versionMsg}" + return 1 + fi +} + + +# +# Main script +# + +check-dependency \ + 'Node' \ + 'node --version | sed -e "s/^v//g"' \ + '^(18|19|20)\.' \ + '18..20' \ +|| exit "$?" + +# Notes: +# * `--no-warnings` suppresses Node's built-in warning printer, which we do +# because the program is expected to include its own warning handler. +# * `--experimental-vm-modules` enables the `node:vm/Module` class and related +# functionality. +fullCommand=( + node "${nodeOpts[@]}" --no-warnings --experimental-vm-modules + "${baseDir}/lib/code/index.js" + --outer-command-name="${cmdName}" + "${mainArgs[@]}" +) + +if (( printNodeCommand )); then + echo 1>&2 'Running system via command:' + printf 1>&2 ' %q\n' "${fullCommand[@]}" +fi + +# Note: `exec` minimizes the number of processes left lying around. That is, no +# need for this script to take up space once the system is running. In addition +# to just being tidy, it helps when this program is run via / within a service +# manager such as `systemd`. +exec "${fullCommand[@]}"