Skip to content

Commit dd2b67b

Browse files
committed
README,commands,plugins,use: Update search docs
Closes #137. These updates explain the updates to command script, library module, and plugin search precedence. It could probably be improved, but at least the basic information is now present and discoverable.
1 parent 71d729f commit dd2b67b

File tree

5 files changed

+102
-37
lines changed

5 files changed

+102
-37
lines changed

README.md

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -274,17 +274,18 @@ interpreted as relative to the project root.
274274
Your project structure may look something like this:
275275

276276
```
277-
project/
277+
project-root/
278278
go - main ./go script
279-
scripts/ - project ./go command scripts
279+
lib/ - publicly-exported modules (if the project is a go-bash-script plugin)
280+
scripts/ (or bin/) - project (or plugin) ./go command scripts
280281
lib/ - project-specific Bash library modules (see "Modules" section)
281282
plugins/ - (optional) third-party command scripts (see `./go help plugins`)
282283
.../
283284
bin/ - plugin ./go command scripts
284-
lib/ - optional Bash library modules (see "Modules" section)
285+
lib/ - publicly-exported Bash library modules (see "Modules" section)
285286
go-script-bash/
286287
go-core.bash - top-level functions
287-
lib/ - optional Bash library modules (see "Modules" section)
288+
lib/ - publicly-exported Bash library modules (see "Modules" section)
288289
libexec/ - builtin ./go command scripts
289290
```
290291

@@ -293,11 +294,20 @@ This structure implies that the first line of your `./go` script will be:
293294
. "${0%/*}/scripts/go-script-bash/go-core.bash" "scripts"
294295
```
295296

296-
The precedence for discovering commands is:
297+
#### Variables and plugin scoping
297298

298-
- aliases/builtins (provided by this framework)
299-
- plugins (in `scripts/plugins` above)
300-
- project scripts (in `scripts` above)
299+
The following variables are set by the framework based on the above example
300+
(note there are many other variables set in `go-core.bash` and elsewhere; see
301+
`./go help vars`):
302+
303+
* `_GO_ROOTDIR`: `/absolute/path/to/project-root`
304+
* `_GO_CORE_DIR`: `/absolute/path/to/project-root/scripts/go-script-bash`
305+
* `_GO_SCRIPTS_DIR`: `$_GO_ROOTDIR/scripts`
306+
* `_GO_PLUGINS_DIR`: `/absolute/path/to/project-root/plugins`
307+
308+
For plugins, `_GO_ROOTDIR` and `_GO_SCRIPTS_DIR` will be scoped to the root
309+
directory of the plugin installation; the other variables will remain the same.
310+
See `./go help plugins` for more details.
301311

302312
#### Command scripts
303313

@@ -316,6 +326,9 @@ need not be written in Bash.__ Bash scripts will be sourced (i.e. imported into
316326
the same process running the `./go` script itself). Other languages will use the
317327
`PATH` environment variable to discover the interpreter for the script.
318328

329+
See `./go help commands` for details on the algorithm used to discover command
330+
scripts for execution.
331+
319332
#### Command summaries and help text
320333

321334
The builtin `./go help` command will parse command script summaries and help
@@ -417,14 +430,15 @@ For more information, run `./go modules --help log`.
417430
#### Bats test assertions and helpers
418431

419432
The assertions and helpers from the test suite have been extracted into the
420-
`lib/bats/assertions`, `lib/bats/helpers`, and `lib/bats/assertion-test-helpers`
421-
libraries. While these are not modules you can import with `_GO_USE_MODULES`,
422-
they are completely independent of the rest of the core framework and you may
423-
source them in your own Bats tests. (Whether or not these will ever become a
424-
separate library remains an open question.)
433+
`lib/bats` libraries. While these are not modules you can import with
434+
`_GO_USE_MODULES`, they are completely independent of the rest of the core
435+
framework and you may source them in your own Bats tests. (Whether or not these
436+
will ever become a separate library remains an open question.)
425437

426438
Variables, helper functions, and assertions for testing features based on the
427-
core framework are available in the `lib/testing` directory.
439+
core framework are available in the `lib/testing` directory. The `lib/bats-main`
440+
library makes it easy to write a `./go test` command script with the same
441+
interface and features as the core framework's `./go test` command.
428442

429443
Read the comments from each file for more information.
430444

go-core.bash

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,11 @@ declare _GO_INJECT_MODULE_PATH="$_GO_INJECT_MODULE_PATH"
291291
# fi
292292
# }
293293
#
294+
# Note that this algorithm is modeled after the `node_modules` search algorithm
295+
# used by `npm`. See:
296+
#
297+
# https://docs.npmjs.com/files/folders#cycles-conflicts-and-folder-parsimony
298+
#
294299
# Arguments:
295300
# search_func: Helper function implementing the search operation
296301
#

lib/internal/use

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
# Usage:
66
# . "$_GO_USE_MODULES" <module> [<module>...]
77
#
8-
# NOTE: It's important to wrap `$_GO_USE_MODULES` in double-quotes to ensure
9-
# the statement is portable to environments in which the file paths may
10-
# contain spaces. It's good practice to wrap each `<module>` in
11-
# single-quotes as well.
8+
# NOTE: It's important to wrap `$_GO_USE_MODULES` in double-quotes to ensure the
9+
# statement is portable to environments in which the file paths may contain
10+
# spaces. It's good practice to wrap each `<module>` in single-quotes as well.
1211
#
1312
# Where:
1413
# <module> The name of an optional Bash library module
@@ -40,17 +39,20 @@
4039
# require the functionality can use `_GO_CORE_MODULES` on an as-needed basis,
4140
# rather than using it in the top-level `./go` script.
4241
#
43-
# The precedence for discovering modules is (with examples from the "Directory
44-
# structure" example from README.md):
42+
# The precedence for discovering modules is similar to that for discovering
43+
# command scripts:
4544
#
46-
# - the `_GO_INJECT_MODULE_PATH` directory
47-
# - the `lib/` directory of the framework (`scripts/go-script-bash/lib`)
48-
# - the `lib/` directory in your project scripts directory (`scripts/lib`)
49-
# - the `lib/` directory of `_GO_ROOTDIR` (i.e. exported scripts)
50-
# - the `lib/` directory of installed plugins (`scripts/plugins/*/lib`)
45+
# - `_GO_INJECT_MODULE_PATH` for module stubs injected during testing;
46+
# see `lib/testing/stubbing`
47+
# - `_GO_CORE_DIR/lib/` for core library modules
48+
# - `_GO_SCRIPTS_DIR/lib` for project-internal modules
49+
# - `_GO_ROOTDIR/lib` for publicly-exported modules (`./go` script plugins)
50+
# - `_GO_SCRIPTS_DIR/plugins/*/lib` for installed plugin modules
51+
# - Parent plugin dirs up to `_GO_PLUGINS_DIR/*/lib` for plugin modules
52+
# installed in parent directories
5153
#
52-
# For modules contained in plugin directories, you must specify the path as
53-
# `<plugin-name>/<module-name>`. There is no need to include the `lib/`
54+
# To import a module exported from an installed plugin, you must specify the
55+
# path as `<plugin-name>/<module-name>`. There is no need to include the `lib/`
5456
# component. For example, if you have a plugin called `foo` and it contains a
5557
# module file `lib/bar` (installed as `scripts/plugins/foo/lib/bar` in your
5658
# project repository), you could import the module via:
@@ -59,11 +61,15 @@
5961
#
6062
# Note that if there is a module with the relative path `foo/bar` in one of the
6163
# other directories, such as `_GO_ROOTDIR/lib/foo/bar`, it will take precedence
62-
# over the plugin `scripts/plugins/foo/lib/bar`.
64+
# over the plugin `scripts/plugins/foo/lib/bar`. See `{{go}} help plugins` for
65+
# more information on plugins and their operating constraints.
6366
#
6467
# Module loading is idempotent, as the names of imported modules are added to
6568
# the `_GO_IMPORTED_MODULES` array and are not sourced again if their names are
66-
# already in the array.
69+
# already in the array. If a potential collision between installed module names
70+
# is detected (possible with installed plugins), a verbose warning pinpointing
71+
# the collision points will be printed to standard error, but execution will
72+
# continue.
6773
#
6874
# To see what modules are currently imported and their corresponding files, use:
6975
#

libexec/commands

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,21 @@
99
# --paths List the path of each command script
1010
# --summaries List the summary of each command script
1111
#
12+
# The precedence for discovering commands executed via `@go` is:
13+
#
14+
# - Command aliases; see `{{go}} help aliases`
15+
# - `_GO_INJECT_SEARCH_PATH` for command script stubs injected during testing;
16+
# see `lib/testing/stubbing`
17+
# - `_GO_CORE_DIR/libexec` for core library command scripts
18+
# - `_GO_SCRIPTS_DIR` for project command scripts
19+
# - `_GO_SCRIPTS_DIR/plugins/*/bin` for installed plugin command scripts
20+
# - Parent plugin dirs up to `_GO_PLUGINS_DIR/*/bin` for plugin command
21+
# scripts
22+
#
1223
# If no <command-name> or <script-path> is given, lists all top-level builtins,
13-
# plugins, and user-defined commands. If <command-name> is given, lists the
14-
# subcommands for that command. If <script-paths> is given, lists top-level
15-
# commands within those directories.
24+
# plugins, and user-defined commands discovered via the above algorithm. If
25+
# <command-name> is given, lists the subcommands for that command. If
26+
# <script-paths> is given, lists top-level commands within those directories.
1627
#
1728
# Only one of <command-name> or <script-paths> may be specified. <command-name>
1829
# can be a multiple-word subcommand name, in which case its subcommands, if any,
@@ -21,6 +32,10 @@
2132
#
2233
# NOTE: This command will not return the names of shell aliases; use `{{go}}
2334
# aliases` for those.
35+
#
36+
# While executing a plugin command script, `_GO_ROOTDIR` and `_GO_SCRIPTS_DIR`
37+
# are scoped to the top-level directory of the plugin. See `{{go}} help plugins`
38+
# for more information on plugins and their operating constraints.
2439

2540
_@go.summarize_commands() {
2641
. "$_GO_CORE_DIR/lib/internal/command_descriptions"

libexec/plugins

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,38 @@
99
# --summaries List all plugin command summaries
1010
#
1111
# To install plugins, first create a subdirectory of your scripts directory
12-
# called "plugins". Then add any third-party scripts to this new directory.
12+
# called "plugins". Then copy, clone, or add submodules for `./go` script
13+
# plugins inside this new directory. The `./go get git-repo` command may be used
14+
# for this purpose.
1315
#
14-
# As with your project-specific scripts, any scripts in this directory must be
15-
# executable and the first line must be of the form: '#!/path/to/interpreter'
16+
# A plugin must have a top-level `bin/` directory for its exported command
17+
# scripts, a top-level `lib/` directory for its exported library modules, or
18+
# both.
1619
#
17-
# Plugins that are installed as directories (possibly as git submodules) should
18-
# contain a `bin/` subdirectory containing its command scripts.
20+
# `_GO_ROOTDIR` and `_GO_SCRIPTS_DIR` are scoped to each installed plugin's
21+
# top-level directory during both command script execution and library module
22+
# importation. This enables a plugin's code to refer to its own relative paths
23+
# and to give its own command scripts and library modules priority in these
24+
# contexts.
25+
#
26+
# Note that plugin module code that isn't executed during importation WILL NOT
27+
# have these variables scoped to its installation directory. If a library module
28+
# needs to refer to its own relative paths when executed outside of these
29+
# contexts, it should calculate them based on the `BASH_SOURCE` variable.
30+
# Alternatively, it might capture them during importation using its own
31+
# uniquely-named variables, possibly with safety checks to ensure the variables
32+
# are not yet defined.
33+
#
34+
# Also, if a plugin is intended to operate on the files and directories of a
35+
# project that's installed it, the plugin must provide an interface to receive
36+
# file paths from the project.
37+
#
38+
# See `{{go}} help commands` for more information on command script execution,
39+
# and `{{go}} modules -h` for more information on library module importation.
40+
# See the comments for `@go.search_plugins` from `go-core.bash` for details on
41+
# the plugin search algorithm used by command script execution and library
42+
# module importation, which is modeled after the `node_modules` search algorithm
43+
# used by `npm`.
1944

2045
_@go.plugins_pathspec() {
2146
local IFS=':'

0 commit comments

Comments
 (0)