为何迁移
新的 FHO 子工具库提供了一些有用的宏,可帮助您将现有插件迁移到新的子工具接口。将插件迁移到子工具有以下好处:
- 让错误的接口边界更加清晰。
- 类型安全的机器 writer 输出并最终进行架构验证。
- 可以更灵活地从紫红和
ffx
环境获取子工具的输入类型(请参阅上面链接的 FHO 文档)。 - 更少的宏观魔力。
- 如果与
ffx
本身分开构建,则构建时间更短。
请注意,如果您要启动一个新的子工具,可以跳过旧版插件系统涉及的许多步骤,因此您应该按照使用入门说明进行操作。
非递归插件
对于不含子插件的插件,如果其 ffx_plugin()
操作中没有 plugin_deps
部分,则迁移起来相对简单。迁移具有子插件的插件被视为一项单独的任务。
以下说明主要基于最初编写的 ffx daemon echo
插件与在开发新的子工具接口时用作概念验证的 ffx echo
子工具之间的差异。
迁移 Rust lib.rs
:
假设插件 lib.rs
文件如下所示:
use anyhow::Result;
use ffx_core::ffx_plugin;
use ffx_echo_args::EchoCommand;
use ffx_writer::Writer;
use fidl_fuchsia_developer_ffx::EchoProxy;
#[ffx_plugin(EchoProxy = "daemon::protocol")]
pub async fn echo(echo_proxy: EchoProxy, cmd: EchoCommand, #[ffx(machine = String)] mut writer: Writer) -> Result<()> {
// implementation here
Ok(())
}
如要迁移到新插件系统,最简单的方法是移除 #[ffx_plugin]
宏,然后添加以下基于宏的派生代码:
use fho::{FfxTool, FfxMain, MachineWriter, Result};
use ffx_echo_args::EchoCommand;
use fidl_fuchsia_developer_ffx::EchoProxy;
#[derive(FfxTool)]
pub struct EchoTool {
#[command]
cmd: EchoCommand,
#[with(fho::daemon_protocol())]
echo_proxy: ffx::EchoProxy,
}
#[async_trait(?Send)]
impl FfxMain for EchoTool {
type Writer = MachineWriter<String>;
async fn main(self, writer: MachineWriter<String>) -> Result<()> {
// implementation here
Ok(())
}
}
与前面的宏不同,在命名 EchoTool
结构体的成员时没有任何限制,如果您想执行更复杂的操作,甚至可以通过从 FHO 派生一个特征来实现自己的加载器。
main()
函数被赋予此结构体和写入器作为移动对象,因此您可以随意解构它们。
另请注意,Result
类型来自 FHO,而不是 anyhow
。在此边界上,现在有一种特定的错误类型,其中包含有关错误是否可由用户呈现以及如何显示的信息。如需详细了解如何处理此错误类型及其与 ffx_error
和 ffx_bail
宏的交互,请参阅错误。
目前,大多数迁移的插件仍然需要添加到主 ffx
二进制文件中,这意味着您还需要添加以下宏调用,以生成旧版插件入口点:
fho::embedded_plugin!(EchoTool);
添加 main.rs
由于您的子工具现在可以独立运行,因此您需要添加一个简单的 main.rs
,它会调用 FHO 和您的插件库,以便在 ffx
调用它时正常运行:
use ffx_tool_echo::EchoTool;
use fho::FfxTool;
#[fuchsia_async::run_singlethreaded]
async fn main() {
EchoTool::execute_tool().await
}
一般来说,main.rs
不会比这更复杂。
BUILD.gn(用于顶级插件)
对于仍需要与现有 ffx
插件系统集成的现有插件,这些插件将继续使用 ffx_plugin
GN 操作,因为它会正确设置所有依赖项以包含在 ffx
二进制文件中。
如果插件是 ffx
的顶级子命令,那么我们还将添加 ffx_tool()
操作,以构建单独编译的插件:
# Existing import for the plugin action
import("//src/developer/ffx/build/ffx_plugin.gni")
# New import for the ffx_tool action.
import("//src/developer/ffx/build/ffx_tool.gni")
ffx_plugin("ffx_echo") {
version = "0.1.0"
edition = "2021"
with_unit_tests = true
args_sources = [ "src/args.rs" ]
sources = [ "src/lib.rs" ]
deps = [ "//src/developer/ffx/fidl:fuchsia.developer.ffx_rust" ]
test_deps = [ "//src/lib/fuchsia-async" ]
}
# This will generate the executable file for your plugin.
ffx_tool("ffx_echo_tool") {
edition = "2021"
output_name = "ffx-echo"
deps = [
":ffx_echo",
"//src/developer/ffx/lib/fho:lib",
"//src/lib/fuchsia-async",
]
sources = [ "src/main.rs" ]
# To be included in the sdk in the future, add this:
sdk_category = "partner"
sdk_target_name = "ffx_echo_tool_sdk"
}
向 SDK 添加单独的子工具构建
此时,您可以构建子工具,但不会主动构建。为此,您需要将其添加到 ffx
config.gni 中的“双模式插件”列表中:
# ...snip...
dual_mode_plugins = [
# ...
"//path/to/your/plugin:ffx_echo_tool",
# ...
]
# ...snip...
现在,运行 fx build ffx
应该会重新构建 ffx
和您的插件,如果运行 ffx commands
,您应该能够在“Workspace Commands”列表中看到您的命令。