2017-03-28 1 views
5

go vet, gofmt, pylint, cppcheck과 같은 Bazel에서 "확인"또는 "확인"단계를 실행하는 좋은 방법을 찾고 있습니다. 이 단계는 출력 파일을 만들지 않습니다. 중요한 것은 반환 코드 (테스트와 같은)뿐입니다.바젤 단계 확인

지금 나는 다음과 같은 조리법 사용하고 있습니다 :

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

그리고 verify-pylint.sh은 다음과 같습니다

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

이 두 가지 문제가 있습니다

  • 확인 논리 분할입니다 쉘 스크립트와 BUILD 파일 사이. 이상적으로는 같은 위치에 BUILD 파일을 둘 다 갖고 싶습니다.
  • 소스 파일 중 하나가 변경 될 때 (//:all-srcs), bazel test verify-pylint은 모든 파일에서 pylint을 재실행합니다 (비싸거나 느릴 수 있음) .

이 단계를 실행하는 bazel의 관용구적인 방법은 무엇입니까?

답변

3

하나 이상의 솔루션이 있습니다.

가장 깨끗한 방법은 빌드 할 때 확인을하는 것입니다. 확인하려는 각 파일 (또는 파일 묶음)에 대해 genrule을 만들고 검증에 성공하면 genrule이 결과를 출력하고 실패하면 규칙은 아무것도 출력하지 않으며 자동으로 빌드를 실패시킵니다.

검증 성공 여부는 파일의 내용에 따라 다르며 동일한 입력이 동일한 출력을 가져야하므로 genrules은 입력 내용에 종속 된 출력 파일을 생성해야합니다. 가장 편리한 방법은 확인이 성공하면 파일의 요약을 출력에 쓰고 확인이 실패하면 출력을 출력하지 않는 것입니다.

Verifier를 다시 사용할 수있게하려면 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

간단한 해결책.

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

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

gofmt.bzl에서 : 빌드 파일에서

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 참조)로 인해 탈출 대신 $$$이 필요합니다. 테스트가 정말로 필요한 경우 라즐로의 예를보고 sh_test으로 전화하십시오.
  • genrule 출력이 성공해야하므로 touch을 호출하여 파일을 만듭니다.
  • export TMPDIR=.은 기본적으로 샌드 박스가 다른 디렉토리에 쓰는 것을 방지하기 때문에 필요합니다.

각 파일의 결과를 캐시하고 (변경되지 않은 파일을 다시 검사하지 않으려면) 여러 작업을 만들어야합니다. Laszlo의 for 루프를 참조하십시오.

코드를 단순화하기 위해 일반 규칙을 제공 할 수 있습니다. 어쩌면 표준 라이브러리에 넣어야 할 것입니다.

관련 문제