開發 ffx 外掛程式

本頁說明為 ffx 建立外掛程式的基本步驟。

外掛程式系統會搭配使用 GN 建構規則和 Rust 屬性,將外掛程式程式碼與 ffx 內部元件分離。

GN 建立規則

使用專案 BUILD.gn 檔案中的 ffx_plugin() 建構規則範本,為外掛程式建立建構目標。

您的 BUILD.gn 檔案應類似以下範例:

import("//src/developer/ffx/build/ffx_plugin.gni")

ffx_plugin("ffx_example") {
  version = "0.1.0"
  edition = "2021"
  with_unit_tests = true
  deps = []
  args_sources = [
    "src/args.rs",
  ]
  sources = [
    "src/lib.rs",
  ]
}

src/ 目錄中,專案應包含兩個來源檔案:

  • src/args.rs:定義外掛程式的 CLI 參數。
  • src/lib.rs:包含主要外掛程式的原始碼實作。

引數

建立包含外掛程式支援引數的檔案 src/args.rs

use {argh::FromArgs, ffx_core::ffx_command};

#[ffx_command()]
#[derive(FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "example", description = "an example")]
pub struct ExampleCommand {}

這會使用 argh Crate,這裡提供了更多說明文件。這個結構是透過 ffx_command 屬性裝飾,表示當使用者輸入下列指令時,外掛程式應執行:

fx ffx example

如要為外掛程式新增更多參數,請將參數新增至此結構。

範例參數看起來會像這樣:

use {argh::FromArgs, ffx_core::ffx_command};

#[ffx_command()]
#[derive(FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "example", description = "an example")]
pub struct ExampleCommand {
    #[argh(positional)]
    /// example optional positional string parameter
    pub example: Option<String>,
}

查看更多說明文件: - Argh

外掛程式

建立包含外掛程式實作的檔案 src/lib.rs

use {
    anyhow::Result,
    ffx_core::ffx_plugin,
    ffx_example_args::ExampleCommand,
};

#[ffx_plugin()]
pub async fn example(_cmd: ExampleCommand) -> Result<()> {
    println!("Hello from the example plugin :)");
    Ok(())
}

外掛程式方法必須接受在 src/args.rs 檔案中建立的 argh 指令做為參數,即使這些指令並未使用亦然。

整合

將外掛程式程式庫新增為 ffx 的依附元件,將其納入建構作業中。編輯 ffx 建構目標中的 plugin_deps 陣列,將 ffx_plugin() 目標新增至頂層:

  plugin_deps = [
    "//path/to/your/plugin/dir:ffx_example",
    ...
  ]

如要建構及測試外掛程式,請建構 ffx

fx build ffx

現在執行範例指令時,應該會看到輸出內容:

$ fx ffx example
Hello from the example plugin :)

單元測試

如要對外掛程式進行單元測試,只要按照在主機上測試 rust 程式碼的標準方法操作即可。當 with_unit_tests 參數設為 true 時,ffx_plugin() GN 範本會為單元測試產生 <target_name>_lib_test 程式庫目標。

如果您的 lib.rs 包含測試,則可使用 fx test 叫用:

fx test ffx_example_lib_test

如果 fx 測試找不到您的測試,請檢查產品設定是否包含測試內容。您可以使用下列指令納入所有 ffx 測試:

fx set ... --with=//src/developer/ffx:tests

FIDL 通訊協定

FFX 外掛程式可以透過 Overnet 使用 FIDL 通訊協定與目標裝置進行通訊。如要從外掛程式存取 FIDL 通訊協定,請按照本節的說明操作。

  1. 將 FIDL Rust 繫結新增為外掛程式 BUILD.gn 檔案的依附元件。以下範例會為 fuchsia.device FIDL 程式庫新增繫結:

    import("//src/developer/ffx/build/ffx_plugin.gni")
    
    ffx_plugin("ffx_example") {
      version = "0.1.0"
      edition = "2021"
      with_unit_tests = true
      deps = [
        "//sdk/fidl/fuchsia.device:fuchsia.device_rust",
      ]
      args_sources = [
        "src/args.rs",
      ]
      sources = [
        "src/lib.rs",
      ]
    }
    
  2. 在外掛程式實作中匯入必要的繫結。以下範例會從 fuchsia.device 匯入 NameProviderProxy

    use {
        anyhow::Result,
        ffx_core::ffx_plugin,
        ffx_example_args::ExampleCommand,
        fidl_fuchsia_device::NameProviderProxy,
    };
    
  3. 您可以在外掛程式實作中使用 FIDL Proxy。外掛程式可接受參數清單中的 Proxy:

    pub async fn example(
        name_proxy: NameProviderProxy,
        _cmd: ExampleCommand,
    ) -> Result<()> { }
    
  4. 將 Proxy 類型對應至元件選取器,這個元件代表在 ffx_plugin() 註解中提供 FIDL 通訊協定的元件:

    #[ffx_plugin(
        NameProviderProxy = "bootstrap/device_name_provider:out:fuchsia.device.NameProvider"
    )]
    

src/lib.rs 中的外掛程式實作範例現在應如下所示:

use {
    anyhow::Result,
    ffx_core::ffx_plugin,
    ffx_example_args::ExampleCommand,
    fidl_fuchsia_device::NameProviderProxy,
};

#[ffx_plugin(
    NameProviderProxy = "bootstrap/device_name_provider:out:fuchsia.device.NameProvider"
)]
pub async fn example(
    name_proxy: NameProviderProxy,
    _cmd: ExampleCommand,
) -> Result<()> {
    if let Ok(name) = name_proxy.get_device_name().await? {
        println!("Hello, {}", name);
    }
    Ok(())
}

如要將其他 FIDL Proxy 加入 ffx 外掛程式,請重複上述步驟。

下列 FIDL Proxy 內建於 ffx,不需要其他依附元件或對應:

只要將上述 Proxy 新增至外掛程式的參數清單,即可在實作中存取這些 Proxy。

Proxy 路徑名稱地圖

如果路徑名稱代表特定 FIDL Proxy 變更,ffx 和遠端控制服務 (RCS) 提供了一種機制,用於維持與 ffx 外掛程式所用現有項目的相容性。例如:

  • FIDL Proxy 是由新元件提供
  • FIDL 通訊協定名稱已變更
  • 不同產品版本的代言詞

RCS 支援使用單複數形式地圖,覆寫 ffx 外掛程式來源中定義的警告器,並將其對應至其他值。如要覆寫特定路徑名稱,請以下列格式在 //src/developer/remote-control/data/moniker-map.json 中新增項目:

{
  ...
  "original/moniker:out:fuchsia.MyService": "some/new/moniker:expose:fuchsia.MyOtherService"
}

這個範例可讓 RCS 覆寫 ffx 外掛程式中 original/moniker:out:fuchsia.MyService 的參照,並將參照轉送至任何包含對應項目的建構中的 some/new/moniker:expose:fuchsia.MyOtherService