Tutorial ini membahas cara menggunakan Bazel untuk melacak dependensi dalam kode Anda menggunakan project Bazel yang telah dibuat sebelumnya.
Untuk mengetahui detail bahasa dan flag --output
, lihat manual Referensi kueri Bazel dan Referensi kueri Bazel. Dapatkan bantuan di IDE Anda dengan mengetikkan bazel help query
atau bazel help cquery
di command line.
Tujuan
Panduan ini membahas serangkaian kueri dasar yang dapat Anda gunakan untuk mempelajari lebih lanjut dependensi file project Anda. Panduan ini ditujukan bagi developer Bazel baru yang memiliki pengetahuan dasar tentang cara kerja file Bazel dan BUILD
.
Prasyarat
Mulailah dengan menginstal Bazel, jika Anda belum melakukannya. Tutorial ini menggunakan Git untuk kontrol sumber, jadi untuk hasil terbaik, instal juga Git.
Untuk memvisualisasikan grafik dependensi, alat yang disebut Graphviz digunakan, yang dapat Anda download untuk mengikutinya.
Mendapatkan project contoh
Selanjutnya, ambil aplikasi contoh dari repositori Contoh Bazel dengan menjalankan perintah berikut di alat command line pilihan Anda:
git clone https://github.com/bazelbuild/examples.git
Project contoh untuk tutorial ini ada di direktori examples/query-quickstart
.
Memulai
Apa itu kueri Bazel?
Kueri membantu Anda mempelajari codebase Bazel dengan menganalisis hubungan antara file BUILD
dan memeriksa output yang dihasilkan untuk informasi yang berguna. Panduan ini menampilkan pratinjau beberapa fungsi kueri dasar, tetapi untuk opsi lainnya, lihat panduan kueri. Kueri membantu Anda mempelajari dependensi dalam project skala besar tanpa menavigasi file BUILD
secara manual.
Untuk menjalankan kueri, buka terminal command line dan masukkan:
bazel query 'query_function'
Skenario
Bayangkan sebuah skenario yang mempelajari hubungan antara Cafe Bazel dan kokinya masing-masing. Kafe ini khusus menjual pizza, mac, dan keju. Lihat struktur project berikut di bawah:
bazelqueryguide
├── BUILD
├── src
│ └── main
│ └── java
│ └── com
│ └── example
│ ├── customers
│ │ ├── Jenny.java
│ │ ├── Amir.java
│ │ └── BUILD
│ ├── dishes
│ │ ├── Pizza.java
│ │ ├── MacAndCheese.java
│ │ └── BUILD
│ ├── ingredients
│ │ ├── Cheese.java
│ │ ├── Tomatoes.java
│ │ ├── Dough.java
│ │ ├── Macaroni.java
│ │ └── BUILD
│ ├── restaurant
│ │ ├── Cafe.java
│ │ ├── Chef.java
│ │ └── BUILD
│ ├── reviews
│ │ ├── Review.java
│ │ └── BUILD
│ └── Runner.java
└── WORKSPACE
Sepanjang tutorial ini, kecuali jika diarahkan sebaliknya, coba untuk tidak melihat dalam file BUILD
untuk menemukan informasi yang Anda butuhkan dan sebagai gantinya gunakan fungsi kueri saja.
Sebuah project terdiri dari berbagai paket yang membentuk Cafe. Keduanya dibagi menjadi: restaurant
, ingredients
, dishes
, customers
, dan reviews
. Aturan dalam paket ini mendefinisikan berbagai komponen Cafe dengan berbagai tag dan dependensi.
Menjalankan build
Project ini berisi metode utama di dalam Runner.java
yang dapat Anda eksekusi
untuk mencetak menu Cafe. Build project menggunakan Bazel dengan perintah bazel build
dan gunakan :
untuk memberi sinyal bahwa target tersebut bernama runner
. Lihat nama target untuk mempelajari cara mereferensikan target.
Untuk mem-build project ini, tempel perintah ini ke terminal:
bazel build :runner
Output Anda akan terlihat seperti ini jika build berhasil.
INFO: Analyzed target //:runner (49 packages loaded, 784 targets configured).
INFO: Found 1 target...
Target //:runner up-to-date:
bazel-bin/runner.jar
bazel-bin/runner
INFO: Elapsed time: 16.593s, Critical Path: 4.32s
INFO: 23 processes: 4 internal, 10 darwin-sandbox, 9 worker.
INFO: Build completed successfully, 23 total actions
Setelah berhasil dibuat, jalankan aplikasi dengan menempelkan perintah ini:
bazel-bin/runner
--------------------- MENU -------------------------
Pizza - Cheesy Delicious Goodness
Macaroni & Cheese - Kid-approved Dinner
----------------------------------------------------
Tindakan ini akan memberi Anda daftar item menu yang diberikan beserta deskripsi singkat.
Menjelajahi target
Project mencantumkan bahan dan hidangan dalam paketnya sendiri. Untuk menggunakan kueri guna melihat aturan paket, jalankan perintah bazel query package/…
Dalam hal ini, Anda dapat menggunakannya untuk mencari bahan dan hidangan yang dimiliki Kafe ini dengan menjalankan:
bazel query //src/main/java/com/example/dishes/...
bazel query //src/main/java/com/example/ingredients/...
Jika Anda membuat kueri untuk target paket bahan, output-nya akan terlihat seperti:
//src/main/java/com/example/ingredients:cheese
//src/main/java/com/example/ingredients:dough
//src/main/java/com/example/ingredients:macaroni
//src/main/java/com/example/ingredients:tomato
Menemukan dependensi
Target apa yang diandalkan pelari Anda?
Misalnya, Anda ingin mempelajari struktur project Anda lebih dalam tanpa mempelajari sistem file (yang mungkin tidak dapat dipertahankan untuk project besar). Aturan apa yang digunakan Cafe Bazel?
Jika, seperti dalam contoh ini, target untuk runner Anda adalah runner
, temukan dependensi target yang mendasarinya dengan menjalankan perintah:
bazel query --noimplicit_deps "deps(target)"
bazel query --noimplicit_deps "deps(:runner)"
//:runner
//:src/main/java/com/example/Runner.java
//src/main/java/com/example/dishes:MacAndCheese.java
//src/main/java/com/example/dishes:Pizza.java
//src/main/java/com/example/dishes:macAndCheese
//src/main/java/com/example/dishes:pizza
//src/main/java/com/example/ingredients:Cheese.java
//src/main/java/com/example/ingredients:Dough.java
//src/main/java/com/example/ingredients:Macaroni.java
//src/main/java/com/example/ingredients:Tomato.java
//src/main/java/com/example/ingredients:cheese
//src/main/java/com/example/ingredients:dough
//src/main/java/com/example/ingredients:macaroni
//src/main/java/com/example/ingredients:tomato
//src/main/java/com/example/restaurant:Cafe.java
//src/main/java/com/example/restaurant:Chef.java
//src/main/java/com/example/restaurant:cafe
//src/main/java/com/example/restaurant:chef
Dalam sebagian besar kasus, gunakan fungsi kueri deps()
untuk melihat dependensi output individual target tertentu.
Memvisualisasikan grafik dependensi (opsional)
Bagian ini menjelaskan cara memvisualisasikan jalur dependensi untuk kueri tertentu. Graphviz membantu melihat jalur sebagai gambar grafik asiklik terarah, bukan daftar yang diratakan. Anda dapat mengubah tampilan grafik kueri Bazel menggunakan berbagai opsi command line --output
. Lihat Format Output untuk melihat opsi.
Mulai dengan menjalankan kueri yang diinginkan dan tambahkan flag --noimplicit_deps
untuk menghapus dependensi alat yang berlebihan. Kemudian, ikuti kueri dengan flag output dan simpan grafik ke dalam file bernama graph.in
untuk membuat representasi teks dari grafik tersebut.
Untuk menelusuri semua dependensi :runner
target dan memformat output sebagai grafik:
bazel query --noimplicit_deps 'deps(:runner)' --output graph > graph.in
Tindakan ini akan membuat file bernama graph.in
, yang merupakan representasi teks dari grafik build. Graphviz menggunakan dot
–alat yang memproses teks menjadi visualisasi—untuk membuat png:
dot -Tpng < graph.in > graph.png
Jika membuka graph.png
, Anda akan melihat tampilan seperti ini. Grafik di bawah ini telah disederhanakan agar detail jalur penting lebih jelas dalam panduan ini.
Ini membantu saat Anda ingin melihat output dari berbagai fungsi kueri di seluruh panduan ini.
Menemukan dependensi terbalik
Jika memiliki target yang ingin digunakan untuk menganalisis target lain yang menggunakannya, Anda dapat menggunakan kueri untuk memeriksa target apa yang bergantung pada aturan tertentu. Ini disebut “dependensi terbalik”. Menggunakan rdeps()
dapat berguna saat mengedit file dalam codebase yang tidak Anda pahami, dan dapat menghindarkan Anda dari file lain yang tidak diketahui secara bergantung padanya.
Misalnya, Anda ingin mengedit beberapa bahan cheese
. Untuk menghindari masalah bagi Cafe Bazel, Anda perlu memeriksa hidangan apa yang mengandalkan cheese
.
Untuk melihat target yang bergantung pada target/paket tertentu, Anda dapat menggunakan rdeps(universe_scope, target)
. Fungsi kueri rdeps()
menggunakan setidaknya dua argumen: universe_scope
— direktori yang relevan — dan target
. Bazel menelusuri dependensi terbalik target dalam universe_scope
yang disediakan. Operator rdeps()
menerima argumen ketiga opsional: literal integer yang menentukan batas atas pada kedalaman penelusuran.
Untuk mencari dependensi terbalik target cheese
dalam cakupan seluruh project '//...', jalankan perintah:
bazel query "rdeps(universe_scope, target)"
ex) bazel query "rdeps(//... , //src/main/java/com/example/ingredients:cheese)"
//:runner
//src/main/java/com/example/dishes:macAndCheese
//src/main/java/com/example/dishes:pizza
//src/main/java/com/example/ingredients:cheese
//src/main/java/com/example/restaurant:cafe
//src/main/java/com/example/restaurant:chef
Hasil kueri menunjukkan bahwa keju diandalkan oleh pizza dan macAndCheese. Mengejutkan sekali!
Menemukan target berdasarkan tag
Dua pelanggan berjalan ke Bazel Cafe: Amir dan Jenny. Tidak ada yang diketahui tentang nama-nama tersebut kecuali namanya. Untungnya, pesanan mereka telah diberi tag di file BUILD
'pelanggan'. Bagaimana cara mengakses tag ini?
Developer dapat memberi tag pada target Bazel dengan ID yang berbeda, biasanya untuk tujuan pengujian. Misalnya, tag pada pengujian dapat menganotasi peran pengujian dalam proses debug dan rilis, terutama untuk pengujian C++ dan Python, yang tidak memiliki kemampuan anotasi runtime. Penggunaan tag dan elemen ukuran akan memberikan fleksibilitas dalam menyatukan rangkaian pengujian berdasarkan kebijakan check-in codebase.
Dalam contoh ini, tag adalah salah satu dari pizza
atau macAndCheese
untuk mewakili item menu. Perintah ini mengirim kueri untuk target yang memiliki tag yang cocok dengan ID Anda dalam paket tertentu.
bazel query 'attr(tags, "pizza", //src/main/java/com/example/customers/...)'
Kueri ini menampilkan semua target dalam paket 'customer' yang memiliki tag "pizza".
Uji diri Anda
Gunakan kueri ini untuk mempelajari apa yang ingin Yeni pesan.
Jawaban
Mac dan Keju
Menambahkan dependensi baru
Cafe Bazel telah menambah menunya — pelanggan kini dapat memesan Smoothie! Smoothie khusus ini terdiri dari bahan Strawberry
dan Banana
.
Pertama, tambahkan bahan-bahan yang digunakan smoothie: Strawberry.java
dan Banana.java
. Tambahkan class Java kosong.
src/main/java/com/example/ingredients/Strawberry.java
package com.example.ingredients;
public class Strawberry {
}
src/main/java/com/example/ingredients/Banana.java
package com.example.ingredients;
public class Banana {
}
Selanjutnya, tambahkan Smoothie.java
ke direktori yang sesuai: dishes
.
src/main/java/com/example/dishes/Smoothie.java
package com.example.dishes;
public class Smoothie {
public static final String DISH_NAME = "Smoothie";
public static final String DESCRIPTION = "Yummy and Refreshing";
}
Terakhir, tambahkan file ini sebagai aturan di file BUILD
yang sesuai. Buat library java baru untuk setiap elemen baru, termasuk nama, visibilitas publik, dan file 'src' yang baru dibuat. Nantikan file BUILD
yang telah diperbarui ini:
src/main/java/com/example/ingredients/BUILD
java_library(
name = "cheese",
visibility = ["//visibility:public"],
srcs = ["Cheese.java"],
)
java_library(
name = "dough",
visibility = ["//visibility:public"],
srcs = ["Dough.java"],
)
java_library(
name = "macaroni",
visibility = ["//visibility:public"],
srcs = ["Macaroni.java"],
)
java_library(
name = "tomato",
visibility = ["//visibility:public"],
srcs = ["Tomato.java"],
)
java_library(
name = "strawberry",
visibility = ["//visibility:public"],
srcs = ["Strawberry.java"],
)
java_library(
name = "banana",
visibility = ["//visibility:public"],
srcs = ["Banana.java"],
)
Di file BUILD
untuk hidangan, Anda ingin menambahkan aturan baru untuk Smoothie
. Cara ini mencakup file Java yang dibuat untuk Smoothie
sebagai file 'src', dan aturan baru yang Anda buat untuk setiap bahan smoothie.
src/main/java/com/example/dishes/BUILD
java_library(
name = "macAndCheese",
visibility = ["//visibility:public"],
srcs = ["MacAndCheese.java"],
deps = [
"//src/main/java/com/example/ingredients:cheese",
"//src/main/java/com/example/ingredients:macaroni",
],
)
java_library(
name = "pizza",
visibility = ["//visibility:public"],
srcs = ["Pizza.java"],
deps = [
"//src/main/java/com/example/ingredients:cheese",
"//src/main/java/com/example/ingredients:dough",
"//src/main/java/com/example/ingredients:tomato",
],
)
java_library(
name = "smoothie",
visibility = ["//visibility:public"],
srcs = ["Smoothie.java"],
deps = [
"//src/main/java/com/example/ingredients:strawberry",
"//src/main/java/com/example/ingredients:banana",
],
)
Terakhir, Anda ingin menyertakan smoothie sebagai dependensi dalam file BUILD
Chef.
src/main/java/com/example/restaurant/BUILD
java\_library(
name = "chef",
visibility = ["//visibility:public"],
srcs = [
"Chef.java",
],
deps = [
"//src/main/java/com/example/dishes:macAndCheese",
"//src/main/java/com/example/dishes:pizza",
"//src/main/java/com/example/dishes:smoothie",
],
)
java\_library(
name = "cafe",
visibility = ["//visibility:public"],
srcs = [
"Cafe.java",
],
deps = [
":chef",
],
)
Build cafe
lagi untuk mengonfirmasi bahwa tidak ada error. Jika berhasil dibuat, selamat! Anda telah menambahkan dependensi baru untuk 'Cafe'. Jika tidak, perhatikan kesalahan ejaan dan penamaan paket. Untuk informasi selengkapnya tentang penulisan file BUILD
, lihat Panduan Gaya BUILD.
Sekarang, visualisasikan grafik dependensi baru dengan penambahan Smoothie
untuk dibandingkan dengan grafik sebelumnya. Agar lebih jelas, beri nama input grafik sebagai graph2.in
dan graph2.png
.
bazel query --noimplicit_deps 'deps(:runner)' --output graph > graph2.in
dot -Tpng < graph2.in > graph2.png
Dengan melihat graph2.png
, Anda dapat melihat bahwa Smoothie
tidak memiliki dependensi bersama dengan hidangan lainnya, tetapi hanya target lain yang diandalkan Chef
.
somepath() dan allpaths()
Bagaimana jika Anda ingin mengetahui alasan satu paket bergantung pada paket lain? Menampilkan jalur dependensi di antara keduanya merupakan jawaban.
Dua fungsi dapat membantu Anda menemukan jalur dependensi: somepath()
dan allpaths()
. Dengan target awal S dan titik akhir E, temukan jalur antara S dan E menggunakan somepath(S,E)
.
Pelajari perbedaan antara kedua fungsi ini dengan melihat hubungan antara target 'Chef' dan 'Cheese'. Ada berbagai jalur yang mungkin dilalui dari satu target ke target lainnya:
- Koki → MacAndCheese → Keju
- Koki → Pizza → Keju
somepath()
memberi Anda satu jalur dari dua opsi, sedangkan 'allpaths()' menghasilkan setiap jalur yang memungkinkan.
Dengan menggunakan Cafe Bazel, jalankan perintah berikut:
bazel query "somepath(//src/main/java/com/example/restaurant/..., //src/main/java/com/example/ingredients:cheese)"
//src/main/java/com/example/restaurant:cafe
//src/main/java/com/example/restaurant:chef
//src/main/java/com/example/dishes:macAndCheese
//src/main/java/com/example/ingredients:cheese
Outputnya mengikuti jalur pertama Cafe → Chef → MacAndCheese → Cheese. Jika menggunakan allpaths()
, Anda akan mendapatkan:
bazel query "allpaths(//src/main/java/com/example/restaurant/..., //src/main/java/com/example/ingredients:cheese)"
//src/main/java/com/example/dishes:macAndCheese
//src/main/java/com/example/dishes:pizza
//src/main/java/com/example/ingredients:cheese
//src/main/java/com/example/restaurant:cafe
//src/main/java/com/example/restaurant:chef
Output allpaths()
sedikit lebih sulit dibaca karena merupakan daftar dependensi yang diratakan. Memvisualisasikan grafik ini menggunakan Graphviz membuat hubungan lebih jelas untuk dipahami.
Uji diri Anda
Salah satu pelanggan Cafe Bazel memberikan ulasan pertama restoran ini! Sayangnya, ulasan tidak memiliki beberapa detail seperti identitas pengulas dan hidangan yang dirujuk. Untungnya, Anda dapat mengakses informasi ini dengan Bazel. Paket reviews
berisi program yang mencetak ulasan dari pelanggan misterius. Build dan jalankan dengan:
bazel build //src/main/java/com/example/reviews:review
bazel-bin/src/main/java/com/example/reviews/review
Membuka kueri Bazel saja, mencoba mencari tahu siapa yang menulis ulasan, dan hidangan apa yang mereka deskripsikan.
Petunjuk
Periksa tag dan dependensi untuk mendapatkan informasi yang berguna.
Jawaban
Ulasan ini mendeskripsikan Pizza dan Amir adalah pengulas. Jika melihat dependensi yang dimiliki aturan ini menggunakan
bazel query --noimplicit\_deps 'deps(//src/main/java/com/example/reviews:review)'
Hasil perintah ini menunjukkan bahwa Amir adalah peninjau.
Selanjutnya, karena mengetahui pengulas tersebut adalah Amir, Anda dapat menggunakan fungsi kueri untuk mencari tag yang dimiliki Amir dalam file `BUILD` untuk melihat hidangan apa yang ada di sana.
Perintah bazel query 'attr(tags, "pizza", //src/main/java/com/example/customers/...)'
menampilkan bahwa Amir adalah satu-satunya pelanggan yang memesan pizza dan merupakan pengulas yang memberi kita jawaban.
Menyelesaikan
Selamat! Sekarang Anda telah menjalankan beberapa kueri dasar, yang dapat Anda coba pada project sendiri. Untuk mempelajari sintaksis bahasa kueri lebih lanjut, lihat halaman Referensi kueri. Ingin kueri lanjutan lainnya? Panduan kueri menampilkan daftar mendalam tentang lebih banyak kasus penggunaan daripada yang dibahas dalam panduan ini.