Truy vấn biểu đồ hành động (truy vấn)

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Báo cáo vấn đề Xem nguồn

Lệnh aquery cho phép bạn truy vấn các hành động trong biểu đồ bản dựng. Nó hoạt động trên Biểu đồ mục tiêu đã định cấu hình sau khi phân tích và hiển thị thông tin về Hành động, Cấu phần phần mềm và mối quan hệ của chúng.

aquery rất hữu ích khi bạn quan tâm đến các thuộc tính của Hành động/Cấu phần phần mềm được tạo từ Biểu đồ mục tiêu đã định cấu hình. Ví dụ: các lệnh thực tế chạy và giá trị đầu vào/đầu ra/phương diện của chúng.

Công cụ này chấp nhận một số tuỳ chọn dòng lệnh. Đáng chú ý là lệnh truy vấn chạy trên bản dựng Bazel thông thường và kế thừa bộ tuỳ chọn có sẵn trong một bản dựng.

API này hỗ trợ cùng một tập hợp các hàm cũng có sẵn cho query truyền thống nhưng siblings, buildfilestests.

Ví dụ về kết quả aquery (không có thông tin cụ thể):

$ bazel aquery 'deps(//some:label)'
action 'Writing file some_file_name'
  Mnemonic: ...
  Target: ...
  Configuration: ...
  ActionKey: ...
  Inputs: [...]
  Outputs: [...]

Cú pháp cơ bản

Ví dụ đơn giản về cú pháp cho aquery như sau:

bazel aquery "aquery_function(function(//target))"

Biểu thức truy vấn (trong dấu ngoặc kép) bao gồm:

  • aquery_function(...): hàm dành riêng cho aquery. Bạn có thể xem thêm thông tin chi tiết bên dưới.
  • function(...): hàm chuẩn như query truyền thống.
  • //target là nhãn cho mục tiêu quan tâm.
# 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))'

Sử dụng các hàm truy vấn

Có ba hàm aquery:

  • inputs: lọc các hành động theo dữ liệu đầu vào.
  • outputs: lọc các hành động theo đầu ra
  • mnemonic: lọc các hành động theo cách ghi nhớ

expr ::= inputs(word, expr)

Toán tử inputs trả về các thao tác được tạo từ việc xây dựng expr, trong đó tên tệp đầu vào khớp với biểu thức chính quy do word cung cấp.

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

Các hàm outputsmnemonic có cùng cú pháp.

Bạn cũng có thể kết hợp các hàm để thực hiện phép toán AND. Ví dụ:

  $ bazel aquery 'mnemonic("Cpp.*", (inputs(".*cpp", inputs("foo.*", //src/target_a))))'

Lệnh trên sẽ tìm tất cả các hành động có liên quan đến việc xây dựng //src/target_a, trong đó các thuộc tính riêng khớp với "Cpp.*" và dữ liệu đầu vào khớp với các mẫu ".*cpp""foo.*".

Ví dụ về lỗi cú pháp đã tạo ra:

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

Tùy chọn

Xây dựng các lựa chọn

aquery chạy trên một bản dựng Bazel thông thường và do đó kế thừa tập hợp tuỳ chọn có sẵn trong bản dựng.

Tuỳ chọn truy vấn

--output=(text|summary|proto|jsonproto|textproto), default=text

Định dạng đầu ra mặc định (text) có thể đọc được, sử dụng proto, textproto hoặc jsonproto để định dạng mà máy đọc được. Thông báo proto là analysis.ActionGraphContainer.

--include_commandline, default=true

Bao gồm nội dung của các dòng lệnh hành động trong đầu ra (có thể lớn).

--include_artifacts, default=true

Bao gồm tên của đầu vào và đầu ra của hành động trong đầu ra (có thể lớn).

--include_aspects, default=true

Liệu có đưa các hành động do Aspect tạo ra trong kết quả hay không.

--include_param_files, default=false

Bao gồm nội dung của các tệp thông số được sử dụng trong lệnh (có thể lớn).

--include_file_write_contents, default=false

Bao gồm nội dung tệp cho thao tác actions.write() và nội dung của tệp kê khai cho thao tác SourceSymlinkManifest. Nội dung tệp được trả về trong trường file_contents bằng --output=xxxproto. Với --output=text, đầu ra có dòng FileWriteContents: [<base64-encoded file contents>]

--skyframe_state, default=false

Không thực hiện phân tích bổ sung, kết xuất Biểu đồ hành động từ Skyframe.

Các công cụ và tính năng khác

Truy vấn dựa trên trạng thái của Skyframe

Skyframe là mô hình đánh giá và mức độ gia tăng của Bazel. Trên mỗi thực thể của máy chủ Bazel, Skyframe lưu trữ biểu đồ phần phụ thuộc được tạo từ các lần chạy trước của giai đoạn Phân tích.

Trong một số trường hợp, bạn nên truy vấn Action Graph trên Skyframe. Ví dụ về trường hợp sử dụng:

  1. Chạy bazel build //target_a
  2. Chạy bazel build //target_b
  3. Tệp foo.out đã được tạo.

Là một người dùng Bazel, tôi muốn xác định xem foo.out được tạo từ việc tạo //target_a hay //target_b.

Bạn có thể chạy bazel aquery 'outputs("foo.out", //target_a)'bazel aquery 'outputs("foo.out", //target_b)' để tìm ra hành động chịu trách nhiệm về việc tạo foo.out, sau đó nhắm đến mục tiêu. Tuy nhiên, số lượng mục tiêu khác nhau đã tạo trước đó có thể lớn hơn 2, điều này khiến việc chạy nhiều lệnh aquery trở nên rắc rối.

Ngoài ra, bạn có thể sử dụng cờ --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")'

Với chế độ --skyframe_state, aquery sẽ lấy nội dung của Biểu đồ hành động mà Skyframe lưu giữ trên phiên bản của Bazel, (không bắt buộc) lọc nội dung và xuất nội dung mà không cần chạy lại giai đoạn phân tích.

Các điểm cần cân nhắc đặc biệt

Định dạng đầu ra

--skyframe_state hiện chỉ có sẵn cho --output=proto--output=textproto

Không bao gồm nhãn mục tiêu trong biểu thức truy vấn

Hiện tại, --skyframe_state truy vấn toàn bộ biểu đồ hành động tồn tại trên Skyframe, bất kể mục tiêu là gì. Việc chỉ định nhãn mục tiêu được chỉ định trong truy vấn cùng với --skyframe_state được xem là lỗi cú pháp:

  # 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")'

So sánh kết quả truy vấn

Bạn có thể so sánh kết quả của hai lệnh gọi truy vấn khác nhau bằng công cụ aquery_differ. Ví dụ: khi bạn thực hiện một số thay đổi cho định nghĩa quy tắc và muốn xác minh rằng các dòng lệnh đang chạy không thay đổi. aquery_differ chính là công cụ giúp bạn làm việc đó.

Công cụ này có sẵn trong kho lưu trữ bazelbuild/bazel. Để sử dụng tệp này, hãy sao chép kho lưu trữ vào máy cục bộ. Ví dụ về cách sử dụng:

  $ bazel run //tools/aquery_differ -- \
  --before=/path/to/before.proto \
  --after=/path/to/after.proto \
  --input_type=proto \
  --attrs=cmdline \
  --attrs=inputs

Lệnh trên trả về sự khác biệt giữa kết quả truy vấn beforeafter: hành động nào hiển thị trong một hoạt động nhưng không có hoạt động khác, hành động nào có các dòng lệnh/đầu vào khác nhau trong mỗi đầu ra truy vấn, ...). Kết quả của việc chạy lệnh trên sẽ là:

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

Tùy chọn lệnh

--before, --after: Các tệp đầu ra truy vấn cần so sánh

--input_type=(proto|text_proto), default=proto: định dạng của các tệp đầu vào. Hỗ trợ được cung cấp cho đầu ra truy vấn prototextproto.

--attrs=(cmdline|inputs), default=cmdline: các thuộc tính của hành động sẽ được so sánh.

Phương diện trên khung hình

Các khía cạnh có thể được áp dụng với nhau. Sau đó, kết quả truy vấn của thao tác do các Phương diện này tạo ra sẽ bao gồm đường dẫn Phương diện, là trình tự của các Phương diện được áp dụng cho mục tiêu đã tạo hành động.

Ví dụ về chương trình Aspect-on-Aspect:

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

Hãy đặt i là mục tiêu của quy tắc ri, áp dụng Phương diện ai cho các phần phụ thuộc.

Giả sử rằng a2 tạo ra một hành động X khi được áp dụng cho mục tiêu t0. Đầu ra văn bản của bazel aquery --include_aspects 'deps(//t2)' cho thao tác X sẽ là:

  action ...
  Mnemonic: ...
  Target: //my_pkg:t0
  Configuration: ...
  AspectDescriptors: [//my_pkg:rule.bzl%**a2**(foo=...)
    -> //my_pkg:rule.bzl%**a1**(bar=...)]
  ...

Điều này có nghĩa là thao tác X đã được Phương diện a2 tạo ra được áp dụng cho a1(t0), trong đó a1(t0) là kết quả của Phương diện a1 được áp dụng lên t0 mục tiêu.

Mỗi AspectDescriptor có định dạng như sau:

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

AspectClass có thể là tên của lớp Aspect (cho Aspects gốc) hoặc bzl_file%aspect_name (cho Starlark Aspects). AspectDescriptor được sắp xếp theo thứ tự cấu trúc liên kết của biểu đồ phần phụ thuộc.

Liên kết với cấu hình JSON

Mặc dù truy vấn cung cấp thông tin về các thao tác đang được chạy trong một bản dựng (lý do chúng đang được chạy, dữ liệu đầu vào/đầu ra của chúng), hồ sơ JSON sẽ cho chúng ta biết thời gian và thời lượng thực thi các thao tác đó. Bạn có thể kết hợp 2 nhóm thông tin này thông qua một mẫu số chung: thông tin đầu ra chính của một hành động.

Để đưa kết quả của hành động vào hồ sơ JSON, hãy tạo hồ sơ bằng --experimental_include_primary_output --noexperimental_slim_json_profile. Hồ sơ mỏng không tương thích với việc đưa kết quả chính vào. Đầu ra chính của một hành động được đưa vào theo mặc định bằng một truy vấn.

Hiện tại, chúng tôi không cung cấp công cụ chính tắc để kết hợp 2 nguồn dữ liệu này, nhưng bạn có thể xây dựng tập lệnh của riêng mình với các thông tin trên.

Vấn đề đã biết

Xử lý các thao tác dùng chung

Đôi khi, các hành động được chia sẻ giữa các mục tiêu đã định cấu hình.

Trong giai đoạn thực thi, các thao tác chia sẻ đó chỉ được coi là một và chỉ được thực hiện một lần. Tuy nhiên, một truy vấn hoạt động trên biểu đồ hành động trước khi thực thi, sau khi phân tích và do đó, xử lý các hành động này giống như các hành động riêng biệt có các Cấu phần phần mềm đầu ra có cùng execPath. Do đó, các Cấu phần phần mềm tương đương sẽ xuất hiện trùng lặp.

Bạn có thể xem danh sách vấn đề về truy vấn/tính năng được lập kế hoạch trên GitHub.

Câu hỏi thường gặp

ActionKey vẫn giữ nguyên mặc dù nội dung của tệp nhập đã thay đổi.

Trong bối cảnh truy vấn, ActionKey đề cập đến String thu được từ 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.

Thao tác này không bao gồm những thay đổi đối với nội dung của các tệp đầu vào và đừng để nhầm lẫn với RemoteCacheClient#ActionKey.

Nội dung cập nhật

Nếu bạn gặp vấn đề/yêu cầu tính năng, vui lòng gửi vấn đề tại đây.