การค้นหากราฟการดำเนินการ (Aquery)

วันที่ รายงานปัญหา ดูแหล่งที่มา ตอนกลางคืน · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

คำสั่ง aquery ช่วยให้คุณค้นหาการดำเนินการในกราฟบิลด์ได้ โดยจะดำเนินการกับกราฟเป้าหมายที่กำหนดค่าไว้หลังการวิเคราะห์ และแสดง ข้อมูลเกี่ยวกับการกระทำ อาร์ติแฟกต์ และความสัมพันธ์

aquery จะมีประโยชน์เมื่อสนใจคุณสมบัติของการดำเนินการ/อาร์ติแฟกต์ ที่สร้างขึ้นจากกราฟเป้าหมายที่กำหนดค่าแล้ว ตัวอย่างเช่น คำสั่งจริงที่เรียกใช้ และอินพุต/เอาต์พุต/ช่วยจำ

เครื่องมือยอมรับตัวเลือกบรรทัดคำสั่งหลายรายการ สิ่งที่ควรทราบคือ คำสั่ง 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 3 รายการดังนี้

  • inputs: กรองการดำเนินการตามอินพุต
  • outputs: กรองการดำเนินการตามเอาต์พุต
  • mnemonic: กรองการทำงานตามการจำ

expr ::= inputs(word, expr)

โอเปอเรเตอร์ inputs จะแสดงผลการดำเนินการที่สร้างจากอาคาร expr ซึ่งมีชื่อไฟล์อินพุตตรงกับนิพจน์ทั่วไปโดย word

$ bazel aquery 'inputs(".*cpp", deps(//src/target_a))'

ฟังก์ชัน outputs และ mnemonic ใช้ไวยากรณ์ที่คล้ายกัน

นอกจากนี้ คุณยังสามารถรวมฟังก์ชันต่างๆ เข้าด้วยกันเพื่อให้ดำเนินการ "และ" ได้ เช่น

  $ 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 ปกติ จึงรับค่าชุดของ ตัวเลือก ที่ใช้ได้ระหว่างบิลด์

ตัวเลือกคำค้นหา

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

ดัมพ์ Action Graph จาก Skyframe โดยไม่ต้องทำการวิเคราะห์เพิ่มเติม

เครื่องมือและฟีเจอร์อื่นๆ

การค้นหาเกี่ยวกับสถานะของ Skyframe

Skyframe คือการประเมินและ โมเดลส่วนเพิ่มของ Bazel Skyframe จะเก็บกราฟทรัพยากร Dependency ไว้ในอินสแตนซ์ของเซิร์ฟเวอร์ Bazel แต่ละรายการ สร้างขึ้นจากการเรียกใช้ก่อนหน้าของระยะการวิเคราะห์

ในบางกรณี การค้นหากราฟการดำเนินการใน Skyframe นั้นมีประโยชน์ ตัวอย่างกรณีการใช้งานมีดังนี้

  1. เรียกใช้ bazel build //target_a
  2. เรียกใช้ bazel build //target_b
  3. สร้างไฟล์ 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")'

การเปรียบเทียบเอาต์พุตคำค้นหา

คุณสามารถเปรียบเทียบเอาต์พุตของการเรียกใช้คำค้นหาที่แตกต่างกัน 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

คำสั่งข้างต้นแสดงผลความแตกต่างระหว่างเอาต์พุตคำค้นหา before และ after ดังนี้ การกระทำใดอยู่ในอย่างหนึ่ง แต่อีกอย่างหนึ่งมีการกระทำต่างกัน บรรทัดคำสั่ง/อินพุตในเอาต์พุตคำค้นหาแต่ละรายการ...) ผลลัพธ์ของการเรียกใช้คำสั่งด้านบนจะเป็นดังนี้

  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: รูปแบบของอินพุต การสนับสนุนสำหรับเอาต์พุตคำค้นหา proto และ textproto

--attrs=(cmdline|inputs), default=cmdline: แอตทริบิวต์ของการดำเนินการ ที่จะเปรียบเทียบ

อัตราส่วนภาพ

สำหรับ Aspects เพื่อนำไปปรับใช้ควบคู่กันไป เอาต์พุตคำค้นหาของการดำเนินการที่สร้างขึ้นโดย ส่วนเหล่านี้ก็จะรวมเส้นทางของ Aspect ซึ่งเป็นลำดับของ มีการใช้สัดส่วนกับเป้าหมายที่สร้างการดำเนินการแล้ว

ตัวอย่างของ Aspect-on-Aspect

  t0
  ^
  | <- a1
  t1
  ^
  | <- a2
  t2

ให้iเป็นเป้าหมายของกฎi ซึ่งจะใช้ 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 Aspects) AspectDescriptor จัดเรียงตามลำดับโทโพโลยีของ กราฟการขึ้นต่อกัน

การลิงก์กับโปรไฟล์ JSON

ขณะที่คำค้นหาจะให้ข้อมูลเกี่ยวกับการทำงานที่เรียกใช้ในบิลด์ (สาเหตุที่เรียกใช้ อินพุต/เอาต์พุต) และโปรไฟล์ JSON จะบอกระยะเวลาและระยะเวลาในการดำเนินการ คุณเลือกที่จะรวมชุดข้อมูล 2 ชุดนี้ผ่านตัวส่วนร่วมได้ ซึ่งก็คือผลลัพธ์หลักของการดำเนินการ

เพื่อรวมการกระทำ ในโปรไฟล์ JSON ให้สร้างโปรไฟล์ด้วย --experimental_include_primary_output --noexperimental_slim_json_profile โปรไฟล์แบบสลิมไม่สามารถใช้กับการรวมเอาต์พุตหลัก เอาต์พุตหลักของการดำเนินการ รวมโดยค่าเริ่มต้นด้วยคำค้นหา

ปัจจุบันเราไม่มีเครื่องมือ Canonical ที่จะรวมแหล่งข้อมูล 2 แหล่งเข้าด้วยกัน แต่คุณควรจะ สามารถสร้างสคริปต์ของคุณเองด้วยข้อมูลข้างต้น

ปัญหาที่ทราบ

การจัดการการดำเนินการที่แชร์

บางครั้งการกระทำ แชร์แล้ว ระหว่างเป้าหมายที่กำหนดค่าไว้

ในขั้นตอนการดำเนินการ การดำเนินการที่แชร์เหล่านั้นจะ พิจารณาง่ายๆ ว่าเป็น 1 และดำเนินการเพียงครั้งเดียว อย่างไรก็ตาม คำค้นหาจะทำงานในกราฟก่อนการดำเนินการ กราฟการทำงานหลังการวิเคราะห์ จึงประมวลผล เช่น การดำเนินการแยกต่างหากที่อาร์ติแฟกต์เอาต์พุตมี execPath เหมือนกัน ด้วยเหตุนี้ อาร์ติแฟกต์ที่เทียบเท่ากันจะปรากฏเป็นรายการที่ซ้ำกัน

ดูรายการปัญหาในการค้นหา/ฟีเจอร์ที่วางแผนไว้ได้ใน GitHub

คำถามที่พบบ่อย

ActionKey ยังคงเหมือนเดิม แม้ว่าเนื้อหาของไฟล์อินพุตจะเปลี่ยนไปก็ตาม

ในบริบทของคำค้นหา 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

อัปเดต

สำหรับปัญหา/คำขอฟีเจอร์ โปรดส่งปัญหาที่นี่