คำสั่ง aquery ช่วยให้คุณค้นหาการดำเนินการในกราฟการสร้างได้
โดยจะทำงานบนกราฟเป้าหมายที่กำหนดค่าไว้หลังการวิเคราะห์ และแสดงข้อมูลเกี่ยวกับการดำเนินการ อาร์ติแฟกต์ และความสัมพันธ์ระหว่างกัน
aquery มีประโยชน์เมื่อคุณสนใจพร็อพเพอร์ตี้ของการดำเนินการ/อาร์ติแฟกต์ที่สร้างจากกราฟเป้าหมายที่กำหนดค่าไว้ เช่น คำสั่งจริงที่เรียกใช้ รวมถึงอินพุต/เอาต์พุต/นิวมอนิกโค้ด
เครื่องมือนี้ยอมรับตัวเลือกบรรทัดคำสั่งหลายตัวเลือก options โดยเฉพาะอย่างยิ่ง คำสั่ง aquery จะทำงานอยู่เหนือการสร้าง Bazel ปกติ และรับช่วงต่อชุดตัวเลือกที่พร้อมใช้งานระหว่างการสร้าง
เครื่องมือนี้รองรับฟังก์ชันชุดเดียวกับที่พร้อมใช้งานสำหรับ query แบบดั้งเดิม แต่ไม่รวม siblings, buildfiles และ tests
ตัวอย่างเอาต์พุต aquery (ไม่มีรายละเอียดเฉพาะ)
$ bazel aquery 'deps(//some:label)' action 'Writing file some_file_name' Mnemonic: ... Target: ... Configuration: ... ActionKey: ... Inputs: [...] Outputs: [...]
ไวยากรณ์พื้นฐาน
ตัวอย่างไวยากรณ์อย่างง่ายสำหรับ aquery มีดังนี้
bazel aquery "aquery_function(function(//target))"
นิพจน์การค้นหา (ในเครื่องหมายคำพูด) ประกอบด้วยข้อมูลต่อไปนี้
aquery_function(...): ฟังก์ชันเฉพาะสำหรับaqueryดูรายละเอียดเพิ่มเติมด้านล่างfunction(...): ฟังก์ชันมาตรฐานเช่นเดียวกับqueryแบบเดิม//targetคือป้ายกำกับของเป้าหมายที่สนใจ
# aquery examples:
# Get the action graph generated while building //src/target_a
$ bazel aquery '//src/target_a'
# Get the action graph generated while building all dependencies of //src/target_a
$ bazel aquery 'deps(//src/target_a)'
# Get the action graph generated while building all dependencies of //src/target_a
# whose inputs filenames match the regex ".*cpp".
$ bazel aquery 'inputs(".*cpp", deps(//src/target_a))'
การใช้ฟังก์ชัน aquery
ฟังก์ชัน aquery มี 3 ฟังก์ชัน ได้แก่
inputs: กรองการดำเนินการตามอินพุตoutputs: กรองการดำเนินการตามเอาต์พุตmnemonic: กรองการดำเนินการตามนิวมอนิกโค้ด
expr ::= inputs(word, expr)
โอเปอเรเตอร์ inputs จะแสดงการดำเนินการที่สร้างจากการสร้าง expr,
ซึ่งชื่อไฟล์อินพุตตรงกับ Regex ที่ระบุโดย word
$ bazel aquery 'inputs(".*cpp", deps(//src/target_a))'
ฟังก์ชัน outputs และ mnemonic มีไวยากรณ์ที่คล้ายกัน
นอกจากนี้ คุณยังรวมฟังก์ชันต่างๆ เพื่อให้ได้การดำเนินการ AND ได้ด้วย เช่น
$ bazel aquery 'mnemonic("Cpp.*", (inputs(".*cpp", inputs("foo.*", //src/target_a))))'
คำสั่งด้านบนจะค้นหาการดำเนินการทั้งหมดที่เกี่ยวข้องกับการสร้าง //src/target_a,
ซึ่งนิวมอนิกโค้ดตรงกับ "Cpp.*" และอินพุตตรงกับรูปแบบ
".*cpp" และ "foo.*"
ตัวอย่างข้อผิดพลาดทางไวยากรณ์ที่เกิดขึ้น
$ bazel aquery 'deps(inputs(".*cpp", //src/target_a))'
ERROR: aquery filter functions (inputs, outputs, mnemonic) produce actions,
and therefore can't be the input of other function types: deps
deps(inputs(".*cpp", //src/target_a))
ตัวเลือก
ตัวเลือกบิลด์
aquery จะทำงานอยู่เหนือการสร้าง Bazel ปกติ จึงรับช่วงต่อชุด
ตัวเลือก
ที่พร้อมใช้งานระหว่างการสร้าง
ตัวเลือก aquery
--output=(text|summary|proto|jsonproto|textproto), default=text
รูปแบบเอาต์พุตเริ่มต้น (text) เป็นรูปแบบที่มนุษย์อ่านได้
ให้ใช้ proto, textproto หรือ jsonproto สำหรับรูปแบบที่เครื่องอ่านได้
ข้อความ Proto คือ analysis.ActionGraphContainer
--include_commandline, default=true
รวมเนื้อหาของบรรทัดคำสั่งการดำเนินการไว้ในเอาต์พุต (อาจมีขนาดใหญ่)
--include_artifacts, default=true
รวมชื่ออินพุตและเอาต์พุตของการดำเนินการไว้ในเอาต์พุต (อาจมีขนาดใหญ่)
--include_aspects, default=true
เลือกว่าจะรวมการดำเนินการที่ Aspect สร้างขึ้นไว้ในเอาต์พุตหรือไม่
--include_param_files, default=false
รวมเนื้อหาของไฟล์พารามิเตอร์ที่ใช้ในคำสั่ง (อาจมีขนาดใหญ่)
--include_file_write_contents, default=false
รวมเนื้อหาไฟล์สำหรับการดำเนินการ actions.write() และเนื้อหาของไฟล์ Manifest สำหรับการดำเนินการ SourceSymlinkManifest ระบบจะแสดงเนื้อหาไฟล์ในช่อง file_contents พร้อม --output=xxxproto
เมื่อใช้ --output=text เอาต์พุตจะมี
FileWriteContents: [<base64-encoded file contents>]
บรรทัด
--skyframe_state, default=false
แสดงกราฟการดำเนินการจาก Skyframe โดยไม่ต้องทำการวิเคราะห์เพิ่มเติม
เครื่องมือและฟีเจอร์อื่นๆ
การค้นหาเทียบกับสถานะของ Skyframe
Skyframe คือโมเดลการประเมินและ การทำงานแบบเพิ่มของ Bazel ในแต่ละอินสแตนซ์ของเซิร์ฟเวอร์ Bazel, Skyframe จะจัดเก็บกราฟทรัพยากร Dependency ที่สร้างจากการเรียกใช้ระยะการวิเคราะห์ก่อนหน้า
ในบางกรณี การค้นหากราฟการดำเนินการใน Skyframe จะมีประโยชน์ ตัวอย่างกรณีการใช้งานมีดังนี้
- วิ่ง
bazel build //target_a - วิ่ง
bazel build //target_b - ระบบสร้างไฟล์
foo.out
ในฐานะผู้ใช้ Bazel ฉันต้องการทราบว่า foo.out สร้างจากการสร้าง
//target_a หรือ //target_b
คุณสามารถเรียกใช้ bazel aquery 'outputs("foo.out", //target_a)' และ
bazel aquery 'outputs("foo.out", //target_b)' เพื่อค้นหาการดำเนินการที่รับผิดชอบ
ในการสร้าง foo.out และเป้าหมาย อย่างไรก็ตาม จำนวนเป้าหมายต่างๆ ที่สร้างไว้ก่อนหน้านี้อาจมีมากกว่า 2 รายการ ซึ่งทำให้การเรียกใช้คำสั่ง aquery หลายรายการเป็นเรื่องยุ่งยาก
คุณสามารถใช้แฟล็ก --skyframe_state แทนได้
# List all actions on Skyframe's action graph
$ bazel aquery --output=proto --skyframe_state
# or
# List all actions on Skyframe's action graph, whose output matches "foo.out"
$ bazel aquery --output=proto --skyframe_state 'outputs("foo.out")'
ในโหมด --skyframe_state aquery จะใช้เนื้อหาของกราฟการดำเนินการที่ Skyframe เก็บไว้ในอินสแตนซ์ของ Bazel (ไม่บังคับ) ทำการกรองเนื้อหา และแสดงเนื้อหาโดยไม่ต้องเรียกใช้ระยะการวิเคราะห์อีกครั้ง
สิ่งที่ควรพิจารณาเป็นพิเศษ
รูปแบบเอาต์พุต
ปัจจุบัน --skyframe_state ใช้ได้กับ --output=proto และ --output=textproto เท่านั้น
การไม่รวมป้ายกำกับเป้าหมายในนิพจน์การค้นหา
ปัจจุบัน --skyframe_state จะค้นหากราฟการดำเนินการทั้งหมดที่อยู่ใน Skyframe โดยไม่คำนึงถึงเป้าหมาย การระบุป้ายกำกับเป้าหมายในการค้นหาพร้อมกับ --skyframe_state ถือเป็นข้อผิดพลาดทางไวยากรณ์
# WRONG: Target Included
$ bazel aquery --output=proto --skyframe_state **//target_a**
ERROR: Error while parsing '//target_a)': Specifying build target(s) [//target_a] with --skyframe_state is currently not supported.
# WRONG: Target Included
$ bazel aquery --output=proto --skyframe_state 'inputs(".*.java", **//target_a**)'
ERROR: Error while parsing '//target_a)': Specifying build target(s) [//target_a] with --skyframe_state is currently not supported.
# CORRECT: Without Target
$ bazel aquery --output=proto --skyframe_state
$ bazel aquery --output=proto --skyframe_state 'inputs(".*.java")'
การเปรียบเทียบเอาต์พุต aquery
คุณสามารถเปรียบเทียบเอาต์พุตของการเรียกใช้ aquery 2 รายการที่แตกต่างกันได้โดยใช้เครื่องมือ aquery_differ
เช่น เมื่อคุณทำการเปลี่ยนแปลงคำจำกัดความของกฎและต้องการตรวจสอบว่าบรรทัดคำสั่งที่เรียกใช้ไม่ได้เปลี่ยนแปลง aquery_differ คือเครื่องมือที่เหมาะสำหรับกรณีนี้
เครื่องมือนี้พร้อมใช้งานในที่เก็บ bazelbuild/bazel หากต้องการใช้เครื่องมือนี้ ให้โคลนที่เก็บไปยังเครื่องในเครื่อง ตัวอย่างการใช้งาน
$ bazel run //tools/aquery_differ -- \ --before=/path/to/before.proto \ --after=/path/to/after.proto \ --input_type=proto \ --attrs=cmdline \ --attrs=inputs
คำสั่งด้านบนจะแสดงความแตกต่างระหว่างเอาต์พุต aquery before และ after ได้แก่ การดำเนินการที่อยู่ในเอาต์พุตหนึ่งแต่ไม่อยู่ในอีกเอาต์พุตหนึ่ง การดำเนินการที่มีบรรทัดคำสั่ง/อินพุตที่แตกต่างกันในเอาต์พุต aquery แต่ละรายการ เป็นต้น ผลลัพธ์ของการเรียกใช้คำสั่งด้านบนจะเป็นดังนี้
Aquery output 'after' change contains an action that generates the following outputs that aquery output 'before' change doesn't:
...
/list of output files/
...
[cmdline]
Difference in the action that generates the following output(s):
/path/to/abc.out
--- /path/to/before.proto
+++ /path/to/after.proto
@@ -1,3 +1,3 @@
...
/cmdline diff, in unified diff format/
...
ตัวเลือกคำสั่ง
--before, --after: ไฟล์เอาต์พุต aquery ที่จะเปรียบเทียบ
--input_type=(proto|text_proto), default=proto: รูปแบบของไฟล์อินพุต เราให้การสนับสนุนเอาต์พุต aquery proto และ textproto
--attrs=(cmdline|inputs), default=cmdline: แอตทริบิวต์ของการดำเนินการที่จะเปรียบเทียบ
Aspect-on-aspect
คุณสามารถใช้ Aspects ซ้อนกันได้ เอาต์พุต aquery ของการดำเนินการที่ Aspect เหล่านี้สร้างขึ้นจะรวม เส้นทาง Aspect ซึ่งเป็นลำดับของ Aspect ที่ใช้กับเป้าหมายซึ่งสร้างการดำเนินการ
ตัวอย่าง Aspect-on-Aspect
t0 ^ | <- a1 t1 ^ | <- a2 t2
ให้ ti เป็นเป้าหมายของกฎ ri ซึ่งใช้ Aspect ai กับทรัพยากร Dependency
สมมติว่า a2 สร้างการดำเนินการ X เมื่อใช้กับเป้าหมาย t0 เอาต์พุตข้อความของ
bazel aquery --include_aspects 'deps(//t2)' สำหรับการดำเนินการ X จะเป็นดังนี้
action ...
Mnemonic: ...
Target: //my_pkg:t0
Configuration: ...
AspectDescriptors: [//my_pkg:rule.bzl%**a2**(foo=...)
-> //my_pkg:rule.bzl%**a1**(bar=...)]
...
ซึ่งหมายความว่าการดำเนินการ X สร้างโดย Aspect a2 ที่ใช้กับ
a1(t0) โดย a1(t0) คือผลลัพธ์ของ Aspect a1 ที่ใช้
กับเป้าหมาย t0
AspectDescriptor แต่ละรายการมีรูปแบบดังนี้
AspectClass([param=value,...])
AspectClass อาจเป็นชื่อของคลาส Aspect (สำหรับ Aspect ดั้งเดิม) หรือ bzl_file%aspect_name (สำหรับ Starlark Aspect) AspectDescriptor ระบบจะจัดเรียง
ตามลำดับโทโพโลยีของ
กราฟทรัพยากร Dependency
การลิงก์กับโปรไฟล์ JSON
แม้ว่า aquery จะให้ข้อมูลเกี่ยวกับการดำเนินการที่เรียกใช้ในการสร้าง (เหตุผลที่เรียกใช้ อินพุต/เอาต์พุต) แต่โปรไฟล์ JSON จะบอกเวลาและระยะเวลาของการดำเนินการ คุณสามารถรวมข้อมูล 2 ชุดนี้เข้าด้วยกันผ่านตัวหารร่วม นั่นคือ เอาต์พุตหลักของการดำเนินการ
หากต้องการรวมเอาต์พุตของการดำเนินการไว้ในโปรไฟล์ JSON ให้สร้างโปรไฟล์ด้วย --experimental_include_primary_output --noslim_profile
โปรไฟล์ Slim ไม่สามารถใช้งานร่วมกับการรวมเอาต์พุตหลักได้ aquery จะรวมเอาต์พุตหลักของการดำเนินการไว้โดยค่าเริ่มต้น
ปัจจุบันเรายังไม่มีเครื่องมือมาตรฐานสำหรับการรวมแหล่งข้อมูล 2 แหล่งนี้ แต่คุณควรจะสร้างสคริปต์ของคุณเองได้โดยใช้ข้อมูลข้างต้น
ปัญหาที่ทราบ
การจัดการการดำเนินการที่แชร์
บางครั้งการดำเนินการจะ แชร์ ระหว่างเป้าหมายที่กำหนดค่าไว้
ในระยะการดำเนินการ ระบบจะถือว่าการดำเนินการที่แชร์เหล่านั้นเป็นการดำเนินการเดียวและเรียกใช้เพียงครั้งเดียว
อย่างไรก็ตาม aquery จะทำงานบนกราฟการดำเนินการหลังการวิเคราะห์ก่อนการดำเนินการ จึงถือว่าการดำเนินการเหล่านี้เป็นการดำเนินการแยกกันซึ่งอาร์ติแฟกต์เอาต์พุตมี execPath เดียวกันทุกประการ ด้วยเหตุนี้ อาร์ติแฟกต์ที่เทียบเท่าจึงปรากฏซ้ำกัน
คุณสามารถดูรายการปัญหา/ฟีเจอร์ที่วางแผนไว้ของ aquery ได้ใน GitHub
คำถามที่พบบ่อย
ActionKey ยังคงเหมือนเดิมแม้ว่าเนื้อหาของไฟล์อินพุตจะเปลี่ยนไป
ในบริบทของ aquery ActionKey หมายถึง String ที่ได้จาก
ActionAnalysisMetadata#getKey:
Returns a string encoding all of the significant behaviour of this Action that might affect the
output. The general contract of `getKey` is this: if the work to be performed by the
execution of this action changes, the key must change.
...
Examples of changes that should affect the key are:
- Changes to the BUILD file that materially affect the rule which gave rise to this Action.
- Changes to the command-line options, environment, or other global configuration resources
which affect the behaviour of this kind of Action (other than changes to the names of the
input/output files, which are handled externally).
- An upgrade to the build tools which changes the program logic of this kind of Action
(typically this is achieved by incorporating a UUID into the key, which is changed each
time the program logic of this action changes).
Note the following exception: for actions that discover inputs, the key must change if any
input names change or else action validation may falsely validate.
ซึ่งไม่รวมการเปลี่ยนแปลงเนื้อหาของไฟล์อินพุต และไม่ควรสับสนกับ RemoteCacheClient#ActionKey
อัปเดต
หากพบปัญหาหรือต้องการขอฟีเจอร์ โปรดรายงานปัญหาที่นี่ ที่นี่