| # Plugins |
| |
| This page will walk you through how to create a plugin for FFX. If you are |
| looking for a more advanced look into the internals of FFX plugins, visit |
| [Plugin Internals](plugin-internals.md) page. |
| |
| The plugin system employs a combination of GN build rules and Rust attributes |
| to decouple plugin code from FFX internals. |
| |
| First, create a directory to store your plugin. Next, create a BUILD.gn in that |
| directory. |
| |
| ## GN Build Rule |
| |
| You will need to create a GN build target for your plugin. You"ll need to use |
| to use the "ffx_plugin" build rule template defined |
| [here](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/master/src/developer/ffx/build/ffx_plugin.gni). |
| |
| Your BUILD.gn file should look something like this: |
| |
| ```GN |
| import("//src/developer/ffx/build/ffx_plugin.gni") |
| |
| ffx_plugin("ffx_example") { |
| version = "0.1.0" |
| edition = "2018" |
| with_unit_tests = true |
| deps = [] |
| sources = [ |
| "src/args.rs", |
| "src/lib.rs", |
| ] |
| } |
| ``` |
| |
| Next, create a "src" directory to store your code in the same directory as your |
| BUILD.gn file (ffx_plugin wraps the rustc_library build template - so if you |
| are familiar with that template, you should be familiar with this template). |
| |
| ## Args |
| |
| Inside the "src" directory, there needs to be two files. The first file will |
| define the CLI params for your plugin. Create a file "src/args.rs": |
| |
| ```rust |
| use {argh::FromArgs, ffx_core::ffx_command}; |
| |
| #[ffx_command()] |
| #[derive(FromArgs, Debug, PartialEq)] |
| #[argh(subcommand, name = "example", description = "an example")] |
| pub struct ExampleCommand {} |
| ``` |
| |
| This uses the [argh](https://docs.rs/argh/0.1.3/argh/) crate and more |
| documentation can be found [here](https://docs.rs/argh/0.1.3/argh/). This |
| struct has been decorated by the "ffx_command" attribute which signifies that |
| your plugin should run when someone types the following command: |
| |
| ```sh |
| $fx ffx example |
| ``` |
| |
| ## Plugin |
| |
| Next, you will define the plugin execution code. Create a file "src/lib.rs": |
| |
| ```rust |
| use { |
| anyhow::Error, |
| ffx_core::ffx_plugin, |
| ffx_example_args::ExampleCommand, |
| }; |
| |
| #[ffx_plugin()] |
| pub async fn example(_cmd: ExampleCommand) -> Result<(), Error> { |
| println!("Hello from the example plugin :)"); |
| Ok(()) |
| } |
| ``` |
| |
| Plugin methods need to accept the argh command created in the 'src/args.rs' |
| file as a parameter even if they do not use them. |
| |
| If you want to unit tests your plugin, just follow the standard method for |
| testing [rust code](fuchsia.dev/fuchsia-src/development/languages/rust/testing) |
| on a host. The ffx_plugin GN template will generate a library name |
| "<target_name>_lib_test" for unit tests if the "with_unit_tests" parameter is |
| set to "true". |
| |
| Lastly, you"ll need to add the plugin as a dependency to FFX to include it in |
| the build. You"ll need to edit this |
| [file](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/master/src/developer/ffx/BUILD.gn#23) |
| to add your ffx_plugin target. |
| |
| And that"s it! You should now see the output: |
| ```sh |
| $fx ffx example |
| Hello from the example plugin :) |
| ``` |
| |
| Note: If this is the start of a larger project, introduce the new plugin by |
| marking it experimental. This will allow for work-in-progress commits and |
| allow others to try out your plugin by opting-in. See more at the |
| [Experimental Plugins](plugin-experimental.md) page. |
| |
| You may notice that we imported the ExampleCommand in the "src/lib.rs" via a |
| library that was automatically generated by the ffx_plugin template, |
| "ffx_example_args". The ExampleCommand struct gets compiled into its own |
| library due to the internal dependency graph of FFX which you can read more |
| about in the [Plugin Internals](plugin-internals.md) page. This is why there |
| must be two different files for the two parts of the plugin. The name of this |
| library will always be the name of your plugin library concatenated with |
| "_args". If you want to run the unit tests for this library, the test libraries |
| name will be "<target_name>_args_lib_test". For this example it would be |
| "ffx_example_args_lib_test". |
| |
| Plugins can also use FIDL proxies to communicate with a target device through |
| Overnet. For more information, see the [Proxy Plugin](proxy-plugin.md) page. |
| |
| |
| |