FFX 子工具是 ffx cli 可執行的頂層指令。這些指令可以直接編譯至 ffx
和/或建構為可在建構輸出目錄或 SDK 中找到的個別指令,然後使用 FHO 工具介面叫用。
放置地點
首先,請在 fuchsia.git 樹狀結構的某處建立目錄,用於儲存子工具。目前子工具位於以下位置:
- ffx 外掛程式樹狀結構,其中僅內建且 混合型外掛程式/子工具 go新的子工具通常不應放在這裡。
- ffx 工具樹狀結構,這是專門用於外部執行的子工具。將子工具放在這個位置,
ffx
維護者就能更輕鬆地協助處理任何問題,或在ffx
與工具之間的介面有任何變更時更新子工具。如果將說明放在這裡,但 FFX 團隊不是這項工具的主要維護人員 您必須將OWNERS
檔案存放在加入 因此能瞭解團隊的元件和部分個別擁有者,因此說明如何將問題分類 你的工具。 - 專案樹狀結構中的某處。如果 ffx 工具
只是用於現有程式的包裝函式,但建立後,您必須
將您的
OWNERS
檔案設定成 FFX 團隊可以核准 與ffx
互動的部分方法是新增file:/src/developer/ffx/OWNERS
至OWNERS
檔案
除非在外掛程式中導入新工具,否則將決定特定位置 可能需要與工具團隊討論,決定最適合的場所。
哪些檔案
確定要導入工具的位置後,請建立來源
檔案。最佳做法是將工具的程式碼拆分為實作項目的程式庫,以及只呼叫該程式庫的 main.rs
。
下列檔案集是正常的起點:
BUILD.gn
src/lib.rs
src/main.rs
OWNERS
當然,你當然也可以視需要將項目拆分為多個程式庫。請注意,這些範例皆以 echo 子工具範例為基礎,但為了簡化內容,部分內容可能已移除或簡化。如果這個目錄中的任何內容無法運作或不清楚,請查看該目錄中的檔案。
BUILD.gn
以下是簡單子工具的 BUILD.gn
檔案範例。注意事項
因此,如果你習慣使用舊版外掛程式介面,ffx_tool
動作就不會
定義資料庫結構
或執行真正複雜的工作這個原則相當公平
rustc_binary
動作周圍的簡易包裝函式,但已加上一些額外目標
產生中繼資料、產生主機工具,以及產生 SDK Atom。
# Copyright 2022 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/host.gni")
import("//build/rust/rustc_library.gni")
import("//src/developer/ffx/build/ffx_tool.gni")
import("//src/developer/ffx/lib/version/build/ffx_apply_version.gni")
rustc_library("lib") {
# This is named as such to avoid a conflict with an existing ffx echo command.
name = "ffx_tool_echo"
edition = "2021"
with_unit_tests = true
deps = [
"//src/developer/ffx/fidl:fuchsia.developer.ffx_rust",
"//src/developer/ffx/lib/fho:lib",
"//third_party/rust_crates:argh",
"//third_party/rust_crates:async-trait",
]
test_deps = [
"//src/lib/fidl/rust/fidl",
"//src/lib/fuchsia",
"//src/lib/fuchsia-async",
"//third_party/rust_crates:futures-lite",
]
sources = [ "src/lib.rs" ]
}
ffx_tool("ffx_echo") {
edition = "2021"
output_name = "ffx-echo"
deps = [
":lib",
"//src/developer/ffx/lib/fho:lib",
"//src/lib/fuchsia-async",
]
sources = [ "src/main.rs" ]
}
group("echo") {
public_deps = [
":ffx_echo",
":ffx_echo_host_tool",
]
}
group("bin") {
public_deps = [ ":ffx_echo_versioned" ]
}
group("tests") {
testonly = true
deps = [ ":lib_test($host_toolchain)" ]
}
main.rs
主要 rust 檔案通常較為簡單,只需透過
正確類型來做為進入點,ffx
知道如何
取代為:
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use ffx_tool_echo::EchoTool;
use fho::FfxTool;
#[fuchsia_async::run_singlethreaded]
async fn main() {
EchoTool::execute_tool().await
}
lib.rs
這是工具主要程式碼的儲存位置。您將設定一個
用於指令引數及衍生 FfxTool
和 FfxMain
的 argh 結構體
其導入方式必須保留工具執行時的背景脈絡。
引數
#[derive(ArgsInfo, FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "echo", description = "run echo test against the daemon")]
pub struct EchoCommand {
#[argh(positional)]
/// text string to echo back and forth
pub text: Option<String>,
}
這個結構體會定義子工具在子指令名稱後方所需的任何引數。
工具結構
#[derive(FfxTool)]
pub struct EchoTool {
#[command]
cmd: EchoCommand,
#[with(daemon_protocol())]
echo_proxy: ffx::EchoProxy,
}
這樣的結構可保留工具所需的背景資訊。包括上述定義的引數結構、您可能需要的守護程式或裝置的任何 Proxy,或是您可能自行定義的其他項目。
這個結構體中必須包含參照上述引數類型的元素,且應具有 #[command]
屬性,以便為 FfxTool
實作設定正確的關聯類型。
這個結構中的任何項目都必須實作 TryFromEnv
或具有 #[with()]
註解,指向函式,該函式會傳回實作
TryFromEnvWith
。您也可以使用
fho
程式庫或其他 ffx
程式庫
此外,工具上方的 #[check()]
註解會使用 CheckEnv
的實作項目,驗證指令應在未為結構體本身產生項目的情況下執行。這裡的 AvailabilityFlag
會檢查實驗狀態,並在未啟用實驗功能時提早退出。撰寫新的
子指令,因此應在其中加入這項宣告,以免員工
之後才會擴大運用
FIDL 通訊協定
FFX 子工具可以透過 FIDL 通訊協定與目標裝置通訊,包括 Overnet:如要從子工具存取 FIDL 通訊協定,請按照下列步驟操作:
將 FIDL Rust 繫結項目新增為子工具的
BUILD.gn
檔案依附元件。以下範例會為fuchsia.device
FIDL 程式庫新增繫結:deps = [ "//sdk/fidl/fuchsia.device:fuchsia.device_rust", ]
將必要的繫結匯入子工具實作項目。下列 範例會從
fuchsia.device
匯入NameProviderProxy
:use fidl_fuchsia_device::NameProviderProxy;
宣告工具結構的成員欄位。由於 FIDL 代理程式會實作
TryFromEnv
特徵,FHO 架構會為您建立並初始化欄位。#[derive(FfxTool)] pub struct EchoTool { #[command] cmd: EchoCommand, name_proxy: NameProviderProxy, }
FfxMain
實作
#[async_trait(?Send)]
impl FfxMain for EchoTool {
type Writer = MachineWriter<String>;
async fn main(self, mut writer: Self::Writer) -> Result<()> {
let text = self.cmd.text.as_deref().unwrap_or("FFX");
let echo_out = self
.echo_proxy
.echo_string(text)
.await
.user_message("Error returned from echo service")?;
writer.item(&echo_out)?;
Ok(())
}
}
您可以在這裡實作實際的工具邏輯。您可以為 Writer
關聯特徵指定類型,系統會根據執行 ffx
的內容,透過 TryFromEnv
為該類型進行初始化。大多數的新子工具應使用 MachineWriter<>
類型,指定比上述 String
範例更不通用的類型,但實際情況會因工具而異。日後
但所有新工具都必須實作機器介面。
此外,這個函式的結果類型預設為使用 fho Error
類型。
可區分因使用者造成的錯誤
發生非預期的互動和錯誤如需進一步瞭解,請參閱「錯誤」文件。
單元測試
如果您想對子工具進行單元測試,只要按照標準方法在主機上測試Rust 程式碼即可。ffx_plugin()
GN 範本
產生單元測試時,產生 <target_name>_lib_test
程式庫目標
with_unit_tests
參數已設為 true
。
如果 lib.rs
包含測試,則可使用 fx test
叫用:
fx test ffx_example_lib_test
如果 fx 測試找不到您的測試,請檢查產品設定是否包含您的測試。您可以使用下列指令納入所有 ffx 測試:
fx set ... --with=//src/developer/ffx:tests
在測試中使用偽造的 FIDL Proxy
測試子工具的常見模式,就是為 FIDL 通訊協定建立假的 Proxy。這樣一來,您就能透過呼叫 Proxy 傳回各種結果,而無須實際處理整合測試的複雜性。
fn setup_fake_echo_proxy() -> ffx::EchoProxy {
let (proxy, mut stream) =
fidl::endpoints::create_proxy_and_stream::<ffx::EchoMarker>().unwrap();
fuchsia_async::Task::local(async move {
while let Ok(Some(req)) = stream.try_next().await {
match req {
ffx::EchoRequest::EchoString { value, responder } => {
responder.send(value.as_ref()).unwrap();
}
}
}
})
.detach();
proxy
}
接著在單元測試中使用這個假 Proxy
#[fuchsia::test]
async fn test_regular_run() {
const ECHO: &'static str = "foo";
let cmd = EchoCommand { text: Some(ECHO.to_owned()) };
let echo_proxy = setup_fake_echo_proxy();
let test_stdout = TestBuffer::default();
let writer = MachineWriter::new_buffers(None, test_stdout.clone(), Vec::new());
let tool = EchoTool { cmd, echo_proxy };
tool.main(writer).await.unwrap();
assert_eq!(format!("{ECHO}\n"), test_stdout.into_string());
}
OWNERS
如果這個子工具位於 ffx
樹狀結構中,您必須新增 OWNERS
檔案,告訴我們誰負責這個程式碼,以及如何在分類中將問題導向該程式碼。如下所示:
file:/path/to/authoritative/OWNERS
建議你將其新增為參照 (使用 file:
或可能為 include
)
視為人員直接清單,以免因為不在
。
新增至版本
如要將工具新增至 GN 建構圖做為主機工具,會需要參照
在 ffx
工具 gn 檔案中的主要清單,
已新增至 tools
和 test
群組的 public_deps
。
完成後,如果您 fx build ffx
,應該會在 ffx commands
的輸出內容中,在 Workspace Commands
的清單中看到您的工具,並且可以執行該工具。
實驗性子工具和子指令
建議子工具一開始不要將 sdk_category
他們的 BUILD.gn
。如未指定類別,系統會採用這些子工具
而且不會納入 SDK 版本如果使用者希望
使用者必須直接獲得二進位資料。
不過,子指令的處理方式有所不同。
子指令需要在工具中新增 AvailabilityFlag
屬性 (請參閱修訂版本
從ffx target update
的歷史記錄
範例)。如果使用者想要使用子指令,就必須將
來叫用該子指令
但這種方法有問題,例如缺少任何驗證資訊。 寫入子指令的 FIDL 依附元件因此,自 2023 年 12 月起,我們將改變處理子指令的機制。
與子工具類似,子指令將能宣告 SDK 類別 (使用 ,以判斷是否有可用的子指令。 建立子工具時,只會使用子工具類別 (或更高) 的子指令 第二,自訂角色只能 套用至專案或機構FIDL 依附元件檢查會正確驗證子指令的要求。
新增至 SDK
工具穩定後,您就可以將其納入 SDK,並將二進位檔新增至 SDK 建構。請注意,在執行這個步驟前 必須是相對穩定且經過充分測試 (若沒有 務必已將其納入 SDK),接下來請務必 相容性問題。
相容性
將子工具加到 SDK 和 IDK:
FIDL 程式庫:將子工具新增至 SDK 時,您必須將依附於 SDK 的任何 FIDL 程式庫新增至 SDK。(詳情請參閱 將 API 升級為 partner_internal)。
指令列引數 - 用於測試因指令列造成的破壞性變更 選項變更,則 ArgsInfo 衍生巨集可用來產生 JSON 表示法 建立服務帳戶
這項功能會用於黃金檔案測試,用來偵測差異。Golden 檔案。最後,這項測試將強化,以偵測及警告 導致回溯相容性發生異動
機器友善輸出 - 工具和子指令需有機器輸出內容 ,特別是用於測試或建構指令碼的工具。 MachineWriter 物件可用於以 JSON 格式編碼輸出內容,並提供用於偵測輸出結構變更的結構定義。
機器輸出內容必須在目前的相容性時間窗格內保持穩定。最後,系統會檢查機器輸出格式是否符合標準。使用機器寫入器輸出的優點是,您可以自由使用自由文字輸出不穩定的輸出內容。
更新子工具
如要將子工具新增至 SDK,請在其 BUILD.gn
中將 sdk_category
設為
適當的類別 (例如 partner
)。如果子工具包含子指令
不再處於實驗階段,請移除其 AvailabilityFlag
屬性,
因此不再需要特殊的設定選項就能叫用。
納入 SDK
你也需要將子工具新增到host_tools
分子
SDK GN 檔案,例如:
sdk_molecule("host_tools") {
visibility = [ ":*" ]
_host_tools = [
...
"//path/to/your/tool:sdk", # <-- insert this
...
]
]
使用者體驗和 SDK 審查
子工具必須遵循 CLI 指南。