このページでは、リポジトリ ルールの作成方法について説明し、詳細な例を示します。
外部リポジトリは、WORKSPACE
ファイル内でのみ使用できるルールで、Bazel の読み込みフェーズで非密閉オペレーションを有効にします。各外部リポジトリ ルールは、独自の BUILD
ファイルとアーティファクトを含む独自のワークスペースを作成します。これらは、サードパーティ ライブラリ(Maven パッケージ ライブラリなど)に依存するためだけでなく、Bazel が実行されているホストに固有の BUILD
ファイルを生成することもできます。
リポジトリ ルールの作成
.bzl
ファイルで、repository_rule 関数を使用して新しいリポジトリ ルールを作成し、グローバル変数に格納します。
カスタム リポジトリ ルールは、ネイティブ リポジトリ ルールと同様に使用できます。これには必須の name
属性があり、そのビルドファイルに存在するすべてのターゲットは @<name>//package:target
として参照できます。ここで、<name>
は name
属性の値です。
ルールは、明示的にビルドする場合、またはビルドの依存関係である場合に読み込まれます。この場合、Bazel は implementation
関数を実行します。この関数では、リポジトリ、そのコンテンツ、BUILD
ファイルの作成方法を記述します。
属性
属性は、attrs
ルール引数に辞書として渡されるルール引数です。
属性とそのタイプは、リポジトリ ルールを定義するときにリストされます。url
属性と sha256
属性を文字列として定義する例を次に示します。
local_repository = repository_rule(
implementation=_impl,
local=True,
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
(ビルドルールと同様)と repo_mapping
の 2 つです。リポジトリ ルールの名前は、repository_ctx.name
でアクセスできます。repo_mapping
の意味は、ネイティブ リポジトリ ルール local_repository
および new_local_repository
の場合と同じです。
属性名が _
で始まる場合、その属性は非公開であり、ユーザーが設定することはできません。
実装関数
すべてのリポジトリ ルールに implementation
関数が必要です。これにはルールの実際のロジックが含まれており、読み込みフェーズでのみ実行されます。
この関数には、入力パラメータ repository_ctx
が 1 つだけあります。この関数は、指定されたパラメータでルールが再現可能であることを示す None
を返すか、ルールを再現可能なルールに変換して同じリポジトリを生成するパラメータ セットを含む辞書を返します。たとえば、Git リポジトリをトラッキングするルールの場合、最初に指定されたフローティング ブランチではなく、特定の commit ID を返すことになります。
入力パラメータ repository_ctx
を使用して、属性値や非密閉機能(バイナリの検出、バイナリの実行、リポジトリへのファイルの作成、インターネットからのファイルのダウンロード)にアクセスできます。詳しくは、ライブラリをご覧ください。例:
def _impl(repository_ctx):
repository_ctx.symlink(repository_ctx.attr.path, "")
local_repository = repository_rule(
implementation=_impl,
...)
実装関数はいつ実行されますか。
リポジトリの実装関数は、Bazel がそのリポジトリのターゲットを必要とする場合(別のリポジトリ内の別のターゲットが依存している場合や、コマンドラインで言及されている場合など)に実行されます。その後、実装関数はファイル システムにリポジトリを作成することが想定されています。これをリポジトリの「フェッチ」と呼びます。
通常のターゲットとは対照的に、リポジトリに変更が生じるような変更があった場合でも、リポジトリは必ずしも再取得されるわけではありません。これは、Bazel が変更を検出できない場合や、すべてのビルドで過剰なオーバーヘッドが発生するためです(ネットワークから取得されるものなど)。したがって、リポジトリは次のいずれかが変更された場合にのみ再取得されます。
WORKSPACE
ファイル内のリポジトリの宣言に渡されるパラメータ。- リポジトリの実装を構成する Starlark コード。
repository_ctx
のgetenv()
メソッドに渡されるか、repository_rule
のenviron
属性で宣言された任意の環境変数の値。これらの環境変数の値は、--repo_env
フラグを指定してコマンドラインに直接接続できます。read()
やexecute()
など、ラベルによって参照されるrepository_ctx
の同様のメソッドに渡されるファイルのコンテンツ(例://mypkg:label.txt
で、mypkg/label.txt
ではない)bazel sync
が実行されたとき。
リポジトリが再取得されるタイミングを制御する repository_rule
の 2 つのパラメータがあります。
configure
フラグが設定されている場合、--configure
パラメータが渡された場合にのみ、bazel sync
でリポジトリが再取得されます(この属性が設定されていない場合、このコマンドによる再取得は行われません)。local
フラグが設定されている場合は、上記のケースに加えて、Bazel サーバーの再起動時や、リポジトリの宣言に影響するファイル(WORKSPACE
ファイルや読み込まれるファイルなど)が変更されたときも、リポジトリの宣言やコードの宣言が変更されたかどうかに関係なく、リポジトリが再取得されます。この場合、ローカル以外のリポジトリは再取得されません。これは、これらのリポジトリがネットワークと通信するか、コストが高いと想定されるためです。
実装関数の再起動
実装関数では、リポジトリの取得中に、リクエストする依存関係が欠落している場合、再開できます。その場合、実装関数の実行は停止し、欠落している依存関係が解決され、依存関係の解決後に関数が再実行されます。不要な再起動(ネットワーク アクセスを繰り返す必要があるためコストがかかる)を回避するため、すべてのラベル引数を既存のファイルに解決できる場合は、ラベル引数がプリフェッチされます。関数の実行中にのみ作成された文字列またはラベルからパスを解決しても、再起動が必要になる可能性があるので注意してください。
外部リポジトリの強制再取得
外部リポジトリは、定義や依存関係を変更せずに古くなることがあります。たとえば、ソースを取得するリポジトリがサードパーティ リポジトリの特定のブランチに従い、そのブランチで新しい commit を利用できる場合があります。この場合、bazel sync
を呼び出して、すべての外部リポジトリを無条件に再取得するように bazel に指示できます。
さらに、一部のルールはローカルマシンを検査するため、ローカルマシンがアップグレードされると古いものになる可能性があります。ここでは、repository_rule
定義で configure
属性が設定されている外部リポジトリのみを再取得するよう、bazel に指示できます。bazel sync --configure
を使用します。
例
C++ 自動構成ツールチェーン: リポジトリ ルールを使用して、ローカル C++ コンパイラ、環境、C++ コンパイラがサポートするフラグを検索することで、Bazel 用の C++ 構成ファイルを自動的に作成します。
Go リポジトリは、複数の
repository_rule
を使用して、Go ルールを使用するために必要な依存関係のリストを定義します。rules_jvm_external は、デフォルトで
@maven
という外部リポジトリを作成します。このリポジトリは、推移的依存関係ツリー内のすべての Maven アーティファクトのビルド ターゲットを生成します。