FFX Subtools 是 ffx cli 的頂層指令
這個 API 可以執行這些程式碼可以直接編譯為 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 subtool 範例為基礎。 但為求簡潔,部分零件可能會遭到移除或簡化。看看 。
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,
}
這樣的結構可保留工具所需的背景資訊。包括 例如上述定義的引數結構,任何指向 Daemon 或 或是其他可自行定義的內容
這個結構中必須包含參照引數類型的元素
而且其中應包含 #[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 Proxy 是
TryFromEnv
特徵,FHO 架構會建立並初始化欄位 不必確保憑證管理是否適當 因為 Google Cloud 會為您管理安全性#[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
相關特徵,該類型 (透過 TryFromEnv
) 將會是
已根據執行 ffx
的結構定義為您初始化。大多數新的子工具
使用 MachineWriter<>
類型,並指定比範例更籠統的類型
上述的 String
,但每種工具的意義都不同。日後
但所有新工具都必須實作機器介面。
此外,這個函式的結果類型預設為使用 fho Error
類型。
可區分因使用者造成的錯誤
發生非預期的互動和錯誤請前往
錯誤文件中。
單元測試
如果您想要對子工具進行單元測試,只要遵循
在主機上測試信任程式碼。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 因此效能相當卓越這可讓您從呼叫,傳回各種不同的結果 而不用處理複雜的整合程序 測試。
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
應該能在清單中看到你的工具
的 Workspace Commands
輸出內容中,您應該可以ffx commands
來執行
實驗性子工具和子指令
建議子工具一開始不要將 sdk_category
他們的 BUILD.gn
。如未指定類別,系統會採用這些子工具
而且不會納入 SDK 版本如果使用者希望
使用者必須直接獲得二進位資料。
不過子指令的處理方式不同。
子指令需要在工具中新增 AvailabilityFlag
屬性 (請參閱修訂版本
從ffx target update
的歷史記錄
範例)。如果使用者想要使用子指令,就必須將
來叫用該子指令
但這種方法有問題,例如缺少任何驗證資訊。 寫入子指令的 FIDL 依附元件因此 子指令。
與子工具類似,子指令將能宣告 SDK 類別 (使用 ,以判斷是否有可用的子指令。 建立子工具時,只會使用子工具類別 (或更高) 的子指令 第二,自訂角色只能 套用至專案或機構FIDL 依附元件檢查會正確驗證子指令的需求。
新增至 SDK
當您的工具穩定且準備加入 SDK 後, 將二進位檔加入 SDK 版本請注意,在執行這個步驟前 必須是相對穩定且經過充分測試 (若沒有 務必已將其納入 SDK),接下來請務必 相容性問題。
相容性
將子工具加到 SDK 和 IDK:
FIDL 程式庫:您必須新增所有相依的 FIDL 程式庫 導入子工具(詳情請參閱 將 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 規範。