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

Báo cáo vấn đề Xem nguồn Hằng đêm · 7,4 của Google. 7.3 · 7.2 · 7.1 · 7 · 6,5

Lệnh aquery cho phép bạn truy vấn các hành động trong biểu đồ bản dựng. Hoạt động trên Biểu đồ mục tiêu được đị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 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à đầu vào/đầu ra/bộ nhớ 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 aquery chạy trên một 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 hàm cũng có sẵn cho các công cụ truyền thống query nhưng siblings, buildfilestests.

Ví dụ về kết quả aquery (không có thông tin chi tiết 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

Sau đây là ví dụ đơn giản về cú pháp của aquery:

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

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

  • aquery_function(...): các hàm dành riêng cho aquery. Xem thêm thông tin bên dưới.
  • function(...): Các 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ó 3 hàm aquery:

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

expr ::= inputs(word, expr)

Toán tử inputs trả về các thao tác được tạo từ bản dựng expr, có 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))'

Hàm outputsmnemonic có cú pháp tương tự nhau.

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 thấy tất cả các hành động liên quan đến việc tạo //src/target_a, trong đó ký hiệu ghi nhớ khớp với "Cpp.*" và dữ liệu đầu vào khớp với mẫu ".*cpp""foo.*".

Ví dụ về lỗi cú pháp:

        $ 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

Tuỳ chọn bản dựng

aquery chạy trên bản dựng Bazel thông thường và do đó kế thừa tập hợp tuỳ chọn trong quá trình tạo 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) mà con người có thể đọc được, sử dụng proto, textproto hoặc jsonproto cho định dạng mà máy có thể đọ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 các đầu vào và đầu ra hành động ở đầu ra (có thể lớn).

--include_aspects, default=true

Liệu có đưa các hành động do Aspect tạo vào đầu ra hay không.

--include_param_files, default=false

Bao gồm nội dung của các tệp thông số được 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 hành động SourceSymlinkManifest. Nội dung tệp là trả về trong trường file_contents với --output=xxxproto. Với --output=text, dữ liệu đầu ra có FileWriteContents: [<base64-encoded file contents>] đường kẻ

--skyframe_state, default=false

Không cần thực hiện thêm phân tích, hãy 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 Skyframe

Skyframe là mô hình đánh giá và tăng dần 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, việc truy vấn Biểu đồ hành động trên Skyframe sẽ rất hữu ích. 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ạo tệp foo.out.

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

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 tạo foo.out và theo đó là mục tiêu. Tuy nhiên, số lượng mục tiêu khác nhau được tạo trước đó có thể lớn hơn 2, khiến việc chạy nhiều lệnh aquery trở nên phiền phức.

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 thực thể của Bazel, (không bắt buộc) thực hiện lọc trên biểu đồ đó và xuất nội dung mà không cần chạy lại giai đoạn phân tích.

Những điểm cần cân nhắc đặc biệt

Định dạng đầu ra

--skyframe_state hiện chỉ có 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. Có nhãn mục tiêu được chỉ định trong truy vấn cùng với --skyframe_state bị coi 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ả của một truy vấn

Bạn có thể so sánh kết quả của 2 lệnh gọi aquery khác nhau bằng công cụ aquery_differ. Ví dụ: khi bạn thực hiện một số thay đổi đối với đị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 là công cụ cho việc đó.

Công cụ này có trong kho lưu trữ bazelbuild/bazel. Để sử dụng, hãy nhân bản kho lưu trữ này 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 các kết quả aquery beforeafter: những hành động có trong một kết quả nhưng không có trong kết quả còn lại, những hành động có dòng lệnh/dữ liệu đầu vào khác nhau trong mỗi kết quả aquery, v.v. 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/
    ...

Tuỳ chọn lệnh

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

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

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

Tỷ lệ khung hình trên tỷ lệ khung hình

Có thể dùng Các khía cạnh để áp dụng chồng lên nhau. Sau đó, kết quả truy vấn của hành động 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ế độ Aspect-on-Aspect:

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

Giả sử ti là mục tiêu của quy tắc ri, áp dụng một khía cạnh ai cho các phần phụ thuộc của nó.

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. Kết quả văn bản của bazel aquery --include_aspects 'deps(//t2)' cho hành động 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à hành động X được tạo bởi Phương diện a2 áp dụng cho a1(t0), trong đó a1(t0) là kết quả của Phương diện a1 áp dụng cho mục tiêu t0.

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

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

AspectClass có thể là tên của lớp Aspect (đối với các Aspect gốc) hoặc bzl_file%aspect_name (đối với các khía cạnh Starlark). AspectDescriptor là được sắp xếp theo thứ tự tôpô biểu đồ phần phụ thuộc.

Liên kết với hồ sơ JSON

Mặc dù truy vấn cung cấp thông tin về các hành động đang được chạy trong một bản dựng (lý do chúng được chạy, đầu vào/đầu ra), hồ sơ JSON cho chúng tôi biết thời gian và thời lượng thực thi các URL đó. 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: đầu ra chính của một hành động.

Để bao gồm hành động đầu ra trong 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 thêm dữ liệu đầu ra chính. Kết quả chính của một hành động được đưa vào theo mặc định bởi một truy vấn.

Chúng tôi hiện không cung cấp công cụ chuẩn để kết hợp 2 nguồn dữ liệu này, nhưng bạn nên tạo tập lệnh của riêng bạn với thông tin trên.

Vấn đề đã biết

Xử lý các thao tác được chia sẻ

Đô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, những hành động chung đó chỉ được coi là một và chỉ được thực thi một lần. Tuy nhiên, truy vấn hoạt động trên biểu đồ hành động trước khi thực thi và sau khi phân tích, do đó, truy vấn này xử lý chẳng hạn như các thao tác riêng biệt có Cấu phần phần mềm đầu ra có cùng execPath. Do đó, cấu phần phần mềm tương đương có vẻ bị trùng lặp.

Bạn có thể xem danh sách các vấn đề/tính năng dự kiến của aquery trên GitHub.

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

ActionKey vẫn giữ nguyên ngay cả khi nội dung của tệp nhập đã thay đổi.

Trong ngữ cảnh của truy vấn, ActionKey tham chiếu đến String lấy 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.

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

Nội dung cập nhật

Nếu bạn có vấn đề/yêu cầu về tính năng, vui lòng báo cáo vấn đề tại đây.