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

รายงานปัญหา ดูแหล่งที่มา Nightly · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

คำสั่ง 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

aquery ฟังก์ชันมี 3 อย่างดังนี้

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

expr ::= inputs(word, expr)

โอเปอเรเตอร์ inputs จะแสดงผลการดำเนินการที่สร้างขึ้นจากการสร้าง expr ซึ่งชื่อไฟล์อินพุตตรงกับนิพจน์ทั่วไปที่ 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

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

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

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

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

ในบางกรณี การค้นหากราฟการดำเนินการใน 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 จะนำเนื้อหาของ Action Graph ที่ 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

คำสั่งข้างต้นจะแสดงความแตกต่างระหว่างเอาต์พุต before และ after ของ Aquery (การดำเนินการใดที่อยู่ในเอาต์พุตหนึ่งแต่ไม่อยู่ในอีกเอาต์พุตหนึ่ง การดำเนินการใดที่มีบรรทัดคำสั่ง/อินพุตแตกต่างกันในเอาต์พุต 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: รูปแบบของไฟล์ อินพุต เราให้การสนับสนุนสำหรับเอาต์พุต proto และ textproto aquery

--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 กับการขึ้นต่อกัน

สมมติว่า 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 เกิดจากลักษณะ a2 ที่ใช้กับ a1(t0) โดย a1(t0) คือผลลัพธ์ของลักษณะ a1 ที่ใช้กับ เป้าหมาย t0

AspectDescriptor แต่ละรายการมีรูปแบบดังนี้

  AspectClass([param=value,...])

AspectClass อาจเป็นชื่อของคลาส Aspect (สำหรับ Aspect เนทีฟ) หรือ bzl_file%aspect_name (สำหรับ Aspect ของ Starlark) AspectDescriptor จะ เรียงตามลำดับโทโพโลยีของ กราฟการอ้างอิง

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

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

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

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

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

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

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

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

ดูรายการปัญหาเกี่ยวกับ aquery/ฟีเจอร์ที่วางแผนไว้ได้ที่ 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

อัปเดต

หากมีปัญหาหรือต้องการขอฟีเจอร์ใดๆ โปรดแจ้งปัญหาที่นี่