2017-03-28 14 views
5

Poszukuję dobrego przepisu, aby uruchomić kroki "sprawdzenia" lub "weryfikacji" w Bazelu, takie jak go vet, gofmt, pylint, cppcheck. Te kroki nie tworzą żadnego pliku wyjściowego. Liczy się tylko kod powrotu (jak test).Weryfikacja kroku w Bazel

Teraz używam następujący przepis:

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

I verify-pylint.sh wygląda tak:

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

ten ma dwa problemy:

  • Verify logika jest podzielona pomiędzy skryptem powłoki a plikiem BUILD. Idealnie chciałbym mieć oba w tym samym miejscu (w pliku BUILD)
  • Za każdym razem jeden z plików źródłowych zmienia się (w //:all-srcs), bazel test verify-pylint ponownie uruchamia pylint na każdym pojedynczym pliku (i może być drogi/wolny) .

Jaki jest sposób idiomatyczny w Bazel, aby uruchomić te kroki?

Odpowiedz

3

Istnieje więcej niż jedno rozwiązanie.

Najczystszym sposobem jest wykonanie weryfikacji w czasie kompilacji: tworzysz plik genrule dla każdego pliku (lub partii plików), który chcesz zweryfikować, a jeśli weryfikacja się powiedzie, wynik zostanie wygenerowany, jeśli się nie powiedzie, nie generuje niczego, co automatycznie kończy się niepowodzeniem.

Ponieważ powodzenie weryfikacji zależy od zawartości pliku, a to samo wejście powinno dać ten sam wynik, genrules powinien wytworzyć plik wyjściowy, który zależy od zawartości danych wejściowych. Najwygodniejszą rzeczą jest zapisanie skrótu pliku (ów) na wyjściu, jeśli weryfikacja się powiedzie, i brak danych wyjściowych, jeśli weryfikacja nie powiedzie się.

Aby umożliwić ponowne użycie weryfikatora, można utworzyć numer Skylark macro i używać go we wszystkich swoich pakietach.

Aby umieścić to wszystko razem, należy napisać coś takiego.

Zawartość //tools:py_verify_test.bzl:

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, 
    ) 

zawartość //tools:build_test.sh:

#!/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. 

zawartość //tools:BUILD:

# 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"], 
) 

Zawartość każdego pakietu, który chce zweryfikować pliki:

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

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

Proste rozwiązanie.

W pliku produkcji:

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

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

W 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"], 
) 

Kilka uwag:

  • Jeśli skrypt otoki rośnie, należy umieścić ją w osobnym .SH plik.
  • W poleceniu genrule musimy $$ zamiast $ powodu ucieczki (patrz documentation)
  • gofmt_test faktycznie nie test i będzie działać z bazel build :all. Jeśli naprawdę potrzebujesz testu, zobacz przykład Laszlo i zadzwoń pod numer sh_test.
  • Zadzwoń pod touch, aby utworzyć plik, ponieważ genrule wymaga wyjścia do powodzenia.
  • export TMPDIR=. jest potrzebna, ponieważ domyślnie sandbox zapobiega zapisywaniu w innych katalogach.

Aby cache wyniki dla każdego pliku (i uniknąć ponownego sprawdzenia pliku, który się nie zmienił), należy utworzyć wiele działań. Zobacz pętlę Laszlo: for.

Aby uprościć kod, możemy podać ogólną regułę. Może to jest coś, co powinniśmy umieścić w standardowej bibliotece.