2017-03-28 1 views
5

go vetgofmtpylintcppcheckのように、Bazelの「チェック」または「ベリファイ」ステップを実行するための良いレシピを探しています。これらの手順では、出力ファイルは作成されません。重要なのはリターンコード(テストのような)だけです。ベゼルのステップを確認する

今、私は次のレシピ使用しています:

sh_test(
    name = "verify-pylint", 
    srcs = ["verify-pylint.sh"], 
    data = ["//:all-srcs"], 
) 

そしてverify-pylint.shは次のようになります。

find . -name '*.py' | xargs pylint 

これは二つの問題があります。

  • 検証ロジックが分割さをシェルスクリプトとBUILDファイルの間にあります。理想的には、同じ場所(ビルドファイル内)にある
  • ソースファイルのいずれかが変更されると(//:all-srcs)、bazel test verify-pylintはすべてを再実行します(高価で遅い場合があります) 。

これらの手順を実行するためのbazelの慣用方法は何ですか?

答えて

3

複数のソリューションがあります。

最もクリーンな方法は、ビルド時に検証を行うことです。検証するファイル(またはファイルのバッチ)ごとにgenruleを作成し、検証が成功するとgenruleは何かを出力します。ルールは何も出力しません。自動的にビルドに失敗します。

検証の成功はファイルの内容に依存し、同じ入力で同じ出力が得られるので、入力の内容に依存する出力ファイルを生成する必要があります。最も便利なのは、検証が成功した場合はファイルのダイジェストを出力に書き出し、検証が失敗した場合は出力を出力しないことです。

検証者を再利用可能にするには、Skylark macroを作成して、すべてのパッケージで使用できます。

これをまとめるには、次のように記述します。 //tools:py_verify_test.bzl

内容://tools:build_test.sh

def py_verify_test(name, srcs, visibility = None): 
    rules = {"%s-file%d" % (name, hash(s)): s for s in srcs} 
    for rulename, src in rules.items(): 
     native.genrule(
      name = rulename, 
      srcs = [s], 
      outs = ["%s.md5" % rulename], 
      cmd = "$(location //tools:py_verifier) $< && md5sum $< > [email protected]", 
      tools = ["//tools:py_verifier"], 
      visibility = ["//visibility:private"], 
     ) 

    native.sh_test(
     name = name, 
     srcs = ["//tools:build_test.sh"], 
     data = rules.keys(), 
     visibility = visibility, 
    ) 

内容://tools:BUILD

#!/bin/true 
# If the test rule's dependencies could be built, 
# then all files were successfully verified at 
# build time, so this test can merely return true. 

内容:ファイルを確認したい任意のパッケージの

# I just use sh_binary as an example, this could 
# be a more complicated rule of course. 
sh_binary(
    name = "py_verifier", 
    srcs = ["py_verifier.sh"], 
    visibility = ["//visibility:public"], 
) 

内容:

load("//tools:py_verify_test.bzl", "py_verify_test") 

py_verify_test(
    name = "verify", 
    srcs = glob(["**/*.py"]), 
) 
1

単純な解決策です。gofmt.bzl

load(":gofmt.bzl", "gofmt_test") 

gofmt_test(
    name = "format_test", 
    srcs = glob(["*.go"]), 
) 

def gofmt_test(name, srcs): 
    cmd = """ 
    export TMPDIR=. 
    out=$$(gofmt -d $(SRCS)) 

    if [ -n "$$out" ]; then 
     echo "gmfmt failed:" 
     echo "$$out" 
     exit 1 
    fi 
    touch [email protected] 
    """ 
    native.genrule(
     name = name, 
     cmd = cmd, 
     srcs = srcs, 
     outs = [name + ".out"], 
     tools = ["gofmt.sh"], 
) 

いくつかの発言:ビルドファイルに

  • あなたのラッパースクリプトが大きくなった場合、あなたは別の.SHにそれを置く必要がありますがファイル。 genruleコマンドで
  • は、我々は
  • gofmt_testは実際の試験ではなく、bazel build :allで実行されます(documentationを参照)によるエスケープに代わり$$$を必要としています。実際にテストが必要な場合は、Laszloの例を参照してsh_testに電話してください。
  • genruleは出力が成功する必要があるため、touchを呼び出してファイルを作成します。
  • export TMPDIR=.が必要です。デフォルトでは、サンドボックスは他のディレクトリへの書き込みを防止するためです。

各ファイルの結果をキャッシュする(変更されていないファイルの再チェックを避ける)には、複数のアクションを作成する必要があります。 Laszloのforループを参照してください。

コードを簡素化するため、一般的なルールを提供することができます。たぶんこれは標準ライブラリに入れなければならないものです。

関連する問題