diff --git a/scripts/lib/bashy-basics/_setup.sh b/scripts/lib/bashy-basics/_setup.sh index edb4b41c9..1dceb43f2 100644 --- a/scripts/lib/bashy-basics/_setup.sh +++ b/scripts/lib/bashy-basics/_setup.sh @@ -62,42 +62,55 @@ function check-json-output-args { # Converts a JSON array to a Bash array of elements. Stores into the named # variable. With option `--lenient`, treats a non-array as a single-element -# array. +# array. By default, the set elements are JSON values; with option `--raw`, +# produces raw (unquoted strings, etc.) elements. function jbash-array { # Note: Because we use `eval`, local variables are given name prefixes to # avoid conflicts with the caller. - local _bashy_lenient=0 - if [[ $1 == --lenient ]]; then - _bashy_lenient=1 + local _bashy_lenient=false + local _bashy_raw=false + while true; do + case "$1" in + --lenient) + _bashy_lenient=true + ;; + --raw) + _bashy_raw=true + ;; + *) + break + ;; + esac shift - fi + done local _bashy_name="$1" local _bashy_value="$2" - # `--output=compact` guarantees an element per line. - if (( _bashy_lenient )); then - _bashy_value="$( - jget --output=compact "${_bashy_value}" \ - 'if type == "array" then .[] else . end' - )" \ - || return "$?" - else - _bashy_value="$( - jget --output=compact "${_bashy_value}" ' - if type == "array" then - .[] - else - "Not an array: \(.)" | halt_error(1) - end - ' - )" \ - || return "$?" - fi - - # This uses `eval`. - set-array-from-lines "${_bashy_name}" "${_bashy_value}" + eval "$( + jget --output=raw "${_bashy_value}" \ + lenient:json="${_bashy_lenient}" \ + name="${_bashy_name}" \ + raw:json="${_bashy_raw}" \ + ' + def processOne: + if $raw and (type == "string") then . else tojson end + | " \(@sh)" + ; + + if $lenient then + if type == "array" then . else [.] end + elif type == "array" then + . + else + "Not an array: \(.)" | halt_error(1) + end + | map(processOne) + | ["\($name)=(", .[], ")"] + | join("\n") + ' + )" } # Interprets standardized (for this project) JSON "post-processing" arguments. diff --git a/scripts/lib/bashy-node/node-project/find-module-dependencies b/scripts/lib/bashy-node/node-project/find-module-dependencies index 7270faae6..e4f3a9e88 100755 --- a/scripts/lib/bashy-node/node-project/find-module-dependencies +++ b/scripts/lib/bashy-node/node-project/find-module-dependencies @@ -14,8 +14,8 @@ define-usage $' ${name} [ ...] [--] Transitively finds all module dependencies from the one given, which must - be the name of a module defined in this codebase. Prints out a JSON object - with bindings as follows: + be the name of a module defined under the indicated modules directory. + Prints out a JSON object with bindings as follows: * `main: string` -- The originally requested module. * `localDeps: [name, ...]` -- Local module dependencies. @@ -27,10 +27,17 @@ define-usage $' If a dependency cycle is detected, this prints a diagnostic message and exits with an error. + This tool is opinionated: The modules directories are taken to define + submodules (in the Node sense) under the top-level name `@this`. + + **Note:** Exactly one of the two `--modules-*` options must be specified. + --modules-dir= - Directory containing all source modules. Required. **Note:** Each of the - modules is expected to be defined to have the name `@this/` where - names the directory the module is in. + Path to a directory containing all module sources to be used. + --modules-dirs= + JSON array of one or more paths to directories containing module sources. + If the same-named module exists in more than one modules directory, the + first one listed "wins." ${help} ' @@ -38,8 +45,10 @@ define-usage $' # Want help? opt-action --call='{ usage; exit }' help/h -# Directory containing all the modules -opt-value --required --var=modulesDir --filter='/./' modules-dir +# Directory or directories containing all the modules. +opt-value --var=modulesDir --filter='/./' modules-dir +opt-value --var=modulesDirsJson --filter='/^\[.*\]$/' modules-dirs +require-exactly-one-arg-of modules-dir modules-dirs # The module to start at. positional-arg --required --var=moduleName module-name @@ -51,9 +60,16 @@ process-args "$@" || usage --short # Main script # -if [[ ! (-d ${modulesDir} && -r ${modulesDir}) ]]; then - error-msg "Not a readable directory: ${modulesDir}" - exit 1 +modulesDirs=() +if [[ ${modulesDir} != '' ]]; then + if [[ ! (-d ${modulesDir} && -r ${modulesDir}) ]]; then + error-msg "Not a readable directory: ${modulesDir}" + exit 1 + fi + modulesDirs=("${modulesDir}") +else + jbash-array --raw modulesDirs "${modulesDirsJson}" \ + || exit "$?" fi # Collect all of the modules referenced by this package, transitively including @@ -79,11 +95,21 @@ while true; do # Reminder: `${var##*/}` removes everything up to the last slash. In this # case, it's trimming `@this/` off of `oneDep`. - moduleDir="${modulesDir}/${oneDep##*/}" - pkgFile="${moduleDir}/package.json" + oneDepName="${oneDep##*/}" + + for moduleDir in "${modulesDirs[@]}"; do + moduleDir="${moduleDir}/${oneDepName}" + pkgFile="${moduleDir}/package.json" + + if [[ -r ${pkgFile} ]]; then + break + fi + + moduleDir='' + done - if [[ ! -r "${pkgFile}" ]]; then - echo "Not readable: ${pkgFile}" 1>&2 + if [[ ${moduleDir} == '' ]]; then + error-msg "Could not find module: ${oneDep}" exit 1 fi