リポジトリのルール

問題を報告 ソースを表示

このページでは、リポジトリ ルールの作成方法について説明し、具体例を示します。

外部リポジトリWORKSPACE ファイルでのみ使用できるルールで、Bazel の読み込みフェーズで非密閉オペレーションを有効にします。各外部リポジトリ ルールでは、独自の BUILD ファイルとアーティファクトを含む独自のワークスペースが作成されます。サードパーティ ライブラリ(Maven パッケージ化ライブラリなど)への依存にだけでなく、Bazel が実行されているホストに固有の BUILD ファイルを生成するためにも使用できます。

リポジトリ ルールの作成

.bzl ファイルで、repository_rule 関数を使用して新しいリポジトリ ルールを作成し、グローバル変数に格納します。

カスタム リポジトリ ルールは、ネイティブ リポジトリ ルールと同様に使用できます。これには必須の name 属性があり、ビルドファイルに存在するすべてのターゲットを @<name>//package:target として参照できます(<name>name 属性の値)。

ルールは、明示的にビルドしたとき、またはビルドの依存関係である場合に読み込まれます。この場合、Bazel は implementation 関数を実行します。この関数では、リポジトリ、そのコンテンツ、BUILD ファイルの作成方法を記述します。

属性

Attribute は、辞書として 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 には(ビルドルールと同様に)暗黙的に属性が定義されています。2 つの暗黙的な属性は、name(ビルドルールの場合と同様)と repo_mapping です。リポジトリ ルールの名前は、repository_ctx.name でアクセスできます。repo_mapping の意味は、ネイティブ リポジトリ ルールの local_repositorynew_local_repository と同じです。

先頭が _ の属性名は非公開であり、ユーザーが設定することはできません。

実装関数

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

この関数には、repository_ctx という 1 つの入力パラメータがあります。この関数は、指定されたパラメータに基づいてルールが再現可能であることを示す None か、このルールを同じリポジトリを生成する再現可能なルールに変換する一連のパラメータを含む dict を返します。たとえば、Git リポジトリを追跡するルールの場合、最初に指定されたフローティング ブランチではなく、特定の commit 識別子が返されます。

入力パラメータ repository_ctx は、属性値と非密閉関数(バイナリの検索、バイナリの実行、リポジトリ内でのファイルの作成、インターネットからのファイルのダウンロード)にアクセスするために使用できます。詳細については、ライブラリをご覧ください。例:

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

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

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

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

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

  • WORKSPACE ファイル内のリポジトリの宣言に渡されるパラメータ。
  • リポジトリの実装を構成する Starlark コード。
  • repository_ctxgetenv() メソッドに渡されるか、repository_ruleenviron 属性で宣言された、任意の環境変数の値。これらの環境変数の値は、コマンドラインで --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 アーティファクトのビルド ターゲットを生成します。