| # 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. | |