blob: 17e0f2785c01db3476587ff3c7179afc5da4ac24 [file] [log] [blame] [view] [edit]
# fx subcommands
Subcommands of `fx` are defined in several directories:
`//tools/devshell` contains core scripts that are part of
[fx workflow](/docs/development/workflows/fx.md).
`//tools/devshell/contrib` contains scripts that have been contributed by
project members that have other levels of support, ownership, or both. The
OWNERS file in the contrib directory provides a pointer to the individuals
supporting the scripts there.
`//vendor/*/scripts/devshell` contains scripts that are relevant only to the
particular vendor and will have an ownership and support model documented
there.
Subcommands can be implemented in a number of languages, but it is
recommended to use `bash` at this time, so as to be able to consume some of
the helpers provided by `//tools/devshell/lib/vars.sh`.
It is recommended that scripts be kept short and simple. Authoring large
shell programs without a significant test plan can lead to hard to maintain
tools. If there is a need to produce a more sophisticated program the
recommended approach is to author a host tool program as part of the regular
Fuchsia build, and only to wrap that program in a very slim way in a script.
Examples of such cases can be found in `fx pave` and `fx make-fuchsia-vol`. A
good rule of thumb here is that if a script only needs to launch and manage a
one or a few sub-processes, then shell may be a fine language. If the program
needs to perform any significant string manipulation or business logic, it is
likely better authored in a language that provides more structural
capabilities and standard library.
## Consuming vars.sh and implementing subcommands
Most subcommands start with a pre-amble of this nature (paths vary slightly):
```
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/../lib/vars.sh || exit $?
fx-config-read
```
This pre-amble ensures that the devshell helpers are loaded, and then reads
the active fx configuration from the user-selected Fuchsia build directory.
`fx-config-read` is required for most environment variables to be set, and is
necessary for most scripts.
## Helper functions
`fx-config-read` loads the current user configuration that is either defined
by the fx configuration modulated by `fx set` and `fx use`, or by flags to fx
such as `--config` and `--dir`. It is necessary as a pre-amble for any script
that wants to consume build artifacts, as it defined most of the standard
environment variables such as `$FUCHSIA_BUILD_DIR`.
`fx-error` and `fx-warn` simply print their arguments, prefixing them with
`ERROR: ` or `WARNING: ` respectively. If the output stream supports color,
then these outputs are colored.
`fx-command-run` and `fx-command-exec` execute another `fx` subcommand, for
example, running `fx-command-run shell` will invoke the `fx shell` command.
The run variant executes the subcommand in a subshell and the exec variant
`exec`s the subcommand, replacing the calling process.
`fx-command-help` prints the command output for the currently running
subcommand.
`fx-export-device-address` resolves the current device as currently
configured by set-device, or detected via `device-finder` and
exports:
* `FX_DEVICE_NAME` the device name as either set using `-d`, `fx
set-device`, or resolved by search.
* `FX_DEVICE_ADDR` the device fuchsia address as resolved.
* `FX_SSH_ADDR` the device address formatted as required for `ssh(1)`.
(IPv6 includes `[]`).
* `FX_SSH_PORT` the device SSH port if set via `fx set-device`.
`get-device-name` returns either the device name that the user has set with
`fx set-device` or `fx -d <device-name>`. If the user has not set a default
device, the command will run device discovery, and will return a discovered
device name provided there is only one device discovered.
`get-fuchsia-device-addr` consumes `get-device-name` and returns the Fuchsia
address of the device. The returned address is the "netstack address", not
the "netsvc address".
`get-device-addr-resource` is the same as `get-fuchsia-device-addr`, except
that it ensures the address is correctly formatted for use by tools such as
`ssh(1)`, i.e. for IPv6 addresses, the address is encased in `[]`.
`get-device-addr-url` is the same as `get-device-addr-resource` except that
it ensures that IPv6 scopes are appropriately percent-encoded.
`fx-device-finder` invokes the `device-finder` program with the given
arguments. It reports an error to the user and exits if the program is not
present in the build output. Most scripts should prefer one of the
aforementioned `get-*` functions to perform related operations instead, as
`fx-device-finder` usage will not be `fx set-device` aware.
The `vars.sh` script may define additional functions, however, they are
considered internal and may change more often. Users can request additional
helper functions by contacting the devshell owners, or by defining their own
library scripts in contrib.
## Environment variables
After a successful invocation of `fx-config-read` in a script, one would observe the following environment variables:
```
FUCHSIA_ARCH - The current architecture selected (currently one of x64/arm64)
FUCHSIA_DIR - The path to the root of the Fuchsia source tree
FUCHSIA_BUILD_DIR - The path to the current Fuchsia build directory
HOST_OUT_DIR - The path to the Fuchsia host-tools build directory
(usually $FUCHSIA_BUILD_DIR/host_$HOST_ARCH)
ZIRCON_BUILDROOT - The path to the Zircon build directory
ZIRCON_TOOLS_DIR - The path to the Zircon host-tools build directory.
FUCHSIA_OUT_DIR - (deprecated) "$FUCHSIA_DIR/out"
```
`fx-config-read` and/or `fx` could set additional environment variables, but
users should not rely on them - only the above list are to be preserved
(unless marked deprecated).
## Documenting subcommands
As many `fx` subcommands delegate to sub-programs passing on flags directly
to them, it is prohibitive to always be able to respond to the `-h` or
`--help` flags. As such `fx` subcommands SHOULD implement `-h` and `--help`
if possible, but this is not required.
It is required that all subcommands implement help documentation lines, which
are defined as follows:
```
#### CATEGORY=Category name
### a short one-line (<70 character) description for the command lines
## usage: fx <subcommand> [-a|-b|-c] --foo ...
##
## Long descriptions, flags, and so on
```
The first line starting with `###` is consumed by `fx help` to produce a list
of subcommands with one-line descriptions of what the subcommand does.
These lines should be kept short so as to render well under `fx help`.
Lines starting with `##` are output when a user invokes `fx help subcommand`,
and are used to provide full subcommand help output. The long form output should
document all flags and provide fuller description of the subcommand behaviors as
appropriate.
Lines starting with `####` contain metadata. The following metadata fields are
supported:
* `#### CATEGORY=Category`: the subcommand is grouped under the specified
category in the output of `fx help`. There's no enforcement on the name of
the category, but whenever possible it should be one of the existing
categories.
* `#### DEPRECATED`: deprecated subcommands are not listed by default on
`fx help`.
Where possible, a subcommand can use `fx-command-help` to print out the
long-form help (defined by `##` lines). Many subcommands implement `-h` and
`--help` to invoke `fx-command-help` and this is recommended.
### fx metadata files
When subcommands are scripts, documentation is embedded as comments in
the scripts themselves. However, that's not always possible, for example for
binaries produced by the build, such as `fidldoc`, prebuilt binaries like `gn` and
symlinks like `rustdoc` and `gen-cargo`. In any case where metadata cannot be
in the subcommand itself, `fx` looks for a metadata file with the `.fx` extension
in the same directories where it looks for subcommands. If such a file exists,
it represents a subcommand with the same name without the `.fx` extension.
`<subcommand>.fx` files follow the same format described in
the previous section, with an optional metadata field:
* `#### EXECUTABLE=location_of_executable`: points to the actual executable,
which can be anywhere in the tree or in the build output. It can/must use the
following variables to refer to known paths:
* `${FUCHSIA_DIR}`: root of the Fuchsia source tree
* `${PREBUILT_3P_DIR}`: location of the 3p prebuilts (usually `${FUCHSIA_DIR}/prebuilt/third_party`)
* `${HOST_PLATFORM}`: platform of the host, used to compose prebuilt paths
* `${HOST_TOOLS_DIR}`: path of the host tools produced by the build
Some examples of valid uses of `EXECUTABLE` in `.fx` files:
* `#### EXECUTABLE=${FUCHSIA_DIR}/.jiri_root/bin/cipd`
* `#### EXECUTABLE=${PREBUILT_3P_DIR}/gn/${HOST_PLATFORM}/gn`
* `#### EXECUTABLE=${FUCHSIA_DIR}/.jiri_root/bin/jiri`
* `#### EXECUTABLE=${PREBUILT_3P_DIR}/ninja/${HOST_PLATFORM}/ninja`
## Testing
### Testing shell subcommands
Subcommands that are shell scripts should be tested using the Bash test
framework in `//tools/devshell/tests/lib/bash_test_framework.sh`, which provides
facilities for mocking components and encapsulating the execution context in a
temporary directory without any impact on the working tree.
Each test suite with one or more tests is a Bash script which name ends with
`_test` in a subdirectory of `//tools/devshell/tests`.
**To run** shell tests, execute `fx self-test <tests_script>`.
To find out what test scripts are available, run `fx self-test` without
arguments and they will be listed at the bottom. To run all the tests from
all the test scripts, use `--all`. Other sample invocations are described below:
```
fx self-test --all # run all tests from all tests scripts
fx self-test subcommands # run all tests scripts in //tools/devshell/tests/subcommands
fx self-test subcommands/fx_set_test # run all tests in //tools/devshell/tests/subcommands/fx_set_test
fx self-test fx-internal/fx_test # run all tests in //tools/devshell/tests/fx-internal/fx_test
fx self-test fx-internal/fx_test --test TEST_fx-subcommand-run # run a single test from fx-internal/fx_test
```
**To implement** new shell test scripts, create a new file `*_test` in a
subdirectory of `//tools/devshell/tests` using the Bash test framework
documented in `//tools/devshell/tests/lib/bash_test_framework.sh`.
There are many examples in [`//tools/devshell/tests`](tests/). The test
framework is documented in the [framework script](tests/lib/bash_test_framework.sh).
### Testing non-shell subcommands
Subcommands that are primarily non-shell, for example Rust or Dart, should
have regular tests integrated with the Fuchsia build.
For example, the `fx test` subcommand is written in Dart and has tests
defined in its [BUILD.gn](/scripts/fxtest/BUILD.gn) file.