リポジトリのルール

問題を報告 ソースを表示 毎晩

このページでは、リポジトリ ルールの定義方法と、詳細な例について説明します。

外部リポジトリは、Bazel ビルドで使用可能なソースファイルを含むディレクトリ ツリーです。これは、対応するリポルールを実行してオンデマンドで生成されます。Repo はさまざまな方法で定義できますが、最終的には、ビルドルールを呼び出してビルド ターゲットを定義するのと同じように、リポジトリ ルールを呼び出すことで各リポジトリを定義します。これらは、サードパーティのライブラリ(Maven パッケージ ライブラリなど)に依存するためだけでなく、Bazel が実行されているホストに固有の BUILD ファイルを生成することもできます。

リポジトリ ルールの定義

.bzl ファイルで、repository_rule 関数を使用して新しいリポジトリ ルールを定義し、グローバル変数に格納します。リポジトリ ルールを定義したら、リポジトリを定義する関数として呼び出すことができます。この呼び出しは通常、モジュール拡張の実装関数内から実行されます。

リポジトリ ルールの定義を構成する主な 2 つのコンポーネントは、属性スキーマと実装関数です。属性スキーマによって、リポジトリ ルールの呼び出しに渡される属性の名前とタイプが決まります。実装関数は、リポジトリをフェッチする必要がある場合に実行されます。

属性

属性は、リポジトリ ルールの呼び出しに渡される引数です。Repo ルールで受け入れられる属性のスキーマは、repository_rule の呼び出しによってリポジトリ ルールを定義するときに、attrs 引数を使用して指定されます。url 属性と sha256 属性を文字列として定義する例を次に示します。

http_archive = repository_rule(
    implementation=_impl,
    attrs={
        "url": attr.string(mandatory=True)
        "sha256": attr.string(mandatory=True)
    }
)

実装関数内の属性にアクセスするには、repository_ctx.attr.<attribute_name> を使用します。

def _impl(repository_ctx):
    url = repository_ctx.attr.url
    checksum = repository_ctx.attr.sha256

すべての repository_rule には、暗黙的に定義された属性 name があります。これは、魔法のように動作する文字列属性です。リポジトリ ルールの呼び出しの入力として指定すると、見かけ上のリポジトリ名が使用されますが、repository_ctx.attr.name を使用してリポジトリ ルールの実装関数から読み取ると、正規のリポジトリ名が返されます。

実装関数

すべてのリポジトリ ルールに implementation 関数が必要です。これにはルールの実際のロジックが含まれており、読み込みフェーズでのみ実行されます。

この関数には、入力パラメータ repository_ctx が 1 つだけあります。この関数は、指定されたパラメータでルールが再現可能であることを示す None を返すか、ルールを再現可能なルールに変換して同じリポジトリを生成するパラメータ セットを含む辞書を返します。たとえば、Git リポジトリをトラッキングするルールの場合、最初に指定されたフローティング ブランチではなく、特定の commit ID を返すことになります。

入力パラメータ repository_ctx を使用して、属性値や非密閉機能(バイナリの検出、バイナリの実行、リポジトリへのファイルの作成、インターネットからのファイルのダウンロード)にアクセスできます。詳しくは、API ドキュメントをご覧ください。例:

def _impl(repository_ctx):
  repository_ctx.symlink(repository_ctx.attr.path, "")

local_repository = repository_rule(
    implementation=_impl,
    ...)

実装関数はいつ実行されますか。

リポジトリ ルールの実装関数は、Bazel がそのリポジトリのターゲットを必要とする場合(別のリポジトリの別のターゲットが依存している場合や、コマンドラインで言及されている場合など)に実行されます。実装関数では、ファイル システムにリポジトリが作成されます。これをリポジトリの「フェッチ」と呼びます。

通常のターゲットとは対照的に、変更によってリポジトリが変化した場合、リポジトリは必ずしも再取得されません。これは、Bazel が変更を検出できない場合や、すべてのビルドで過剰なオーバーヘッドが発生するためです(ネットワークから取得されるものなど)。したがって、リポジトリは次のいずれかが変更された場合にのみ再取得されます。

  • Repo ルールの呼び出しに渡される属性。
  • Repo ルールの実装を構成する Starlark コード。
  • repository_ctxgetenv() メソッドに渡されるか、repository_ruleenviron 属性で宣言された任意の環境変数の値。これらの環境変数の値は、--repo_env フラグを指定してコマンドラインに直接接続できます。
  • read()execute() など、ラベルによって参照される repository_ctx の同様のメソッドに渡されるファイルのコンテンツ(例: //mypkg:label.txt で、mypkg/label.txt ではない)
  • bazel fetch --force が実行されたとき。

リポジトリが再取得されるタイミングを制御する repository_rule の 2 つのパラメータがあります。

  • configure フラグが設定されている場合、--configure パラメータが渡された場合にのみ、bazel fetch でリポジトリが再取得されます(この属性が設定されていない場合、このコマンドによる再取得は行われません)。
  • local フラグが設定されている場合、上記の場合に加えて、Bazel サーバーの再起動時にリポジトリが再取得されます。

実装関数の再起動

実装関数でリクエストする依存関係が欠落している場合、リポジトリの取得中に実装関数を再起動できます。その場合、実装関数の実行は停止し、欠落している依存関係が解決され、依存関係の解決後に関数が再実行されます。不要な再起動(ネットワーク アクセスを繰り返す必要があるためコストがかかる)を回避するため、すべてのラベル引数を既存のファイルに解決できる場合は、ラベル引数がプリフェッチされます。関数の実行中にのみ作成された文字列またはラベルからパスを解決しても、再起動が必要になる可能性があるので注意してください。

外部リポジトリの強制再取得

外部リポジトリは、定義や依存関係を変更せずに古いものになる場合があります。たとえば、ソースをフェッチするリポジトリがサードパーティ リポジトリの特定のブランチの後に続く場合、そのブランチで新しい commit を利用できます。この場合、bazel fetch --force --all を呼び出して、すべての外部リポジトリを無条件に再取得するように bazel に指示できます。

さらに、一部のリポジトリ ルールはローカルマシンを検査するため、ローカルマシンがアップグレードされると古くなる可能性があります。ここでは、repository_rule 定義で configure 属性が設定されている外部リポジトリのみを再取得するよう Bazel に指示し、bazel fetch --all --configure を使用します。

  • C++ 自動構成ツールチェーン: リポジトリ ルールを使用して、ローカル C++ コンパイラ、環境、C++ コンパイラがサポートするフラグを検索することで、Bazel 用の C++ 構成ファイルを自動的に作成します。

  • Go リポジトリは、複数の repository_rule を使用して、Go ルールを使用するために必要な依存関係のリストを定義します。

  • rules_jvm_external は、デフォルトで @maven という外部リポジトリを作成します。このリポジトリは、推移的依存関係ツリー内のすべての Maven アーティファクトのビルド ターゲットを生成します。