xref: /aosp_15_r20/external/bazelbuild-rules_testing/lib/private/action_subject.bzl (revision d605057434dcabba796c020773aab68d9790ff9f)
1*d6050574SRomain Jobredeaux# Copyright 2023 The Bazel Authors. All rights reserved.
2*d6050574SRomain Jobredeaux#
3*d6050574SRomain Jobredeaux# Licensed under the Apache License, Version 2.0 (the "License");
4*d6050574SRomain Jobredeaux# you may not use this file except in compliance with the License.
5*d6050574SRomain Jobredeaux# You may obtain a copy of the License at
6*d6050574SRomain Jobredeaux#
7*d6050574SRomain Jobredeaux#     http://www.apache.org/licenses/LICENSE-2.0
8*d6050574SRomain Jobredeaux#
9*d6050574SRomain Jobredeaux# Unless required by applicable law or agreed to in writing, software
10*d6050574SRomain Jobredeaux# distributed under the License is distributed on an "AS IS" BASIS,
11*d6050574SRomain Jobredeaux# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*d6050574SRomain Jobredeaux# See the License for the specific language governing permissions and
13*d6050574SRomain Jobredeaux# limitations under the License.
14*d6050574SRomain Jobredeaux
15*d6050574SRomain Jobredeaux"""# ActionSubject"""
16*d6050574SRomain Jobredeaux
17*d6050574SRomain Jobredeauxload(":collection_subject.bzl", "CollectionSubject")
18*d6050574SRomain Jobredeauxload(":depset_file_subject.bzl", "DepsetFileSubject")
19*d6050574SRomain Jobredeauxload(":dict_subject.bzl", "DictSubject")
20*d6050574SRomain Jobredeauxload(
21*d6050574SRomain Jobredeaux    ":failure_messages.bzl",
22*d6050574SRomain Jobredeaux    "format_failure_missing_all_values",
23*d6050574SRomain Jobredeaux    "format_failure_unexpected_value",
24*d6050574SRomain Jobredeaux    "format_failure_unexpected_values",
25*d6050574SRomain Jobredeaux)
26*d6050574SRomain Jobredeauxload(":str_subject.bzl", "StrSubject")
27*d6050574SRomain Jobredeauxload(":truth_common.bzl", "enumerate_list_as_lines", "mkmethod")
28*d6050574SRomain Jobredeaux
29*d6050574SRomain Jobredeauxdef _action_subject_new(action, meta):
30*d6050574SRomain Jobredeaux    """Creates an "ActionSubject" struct.
31*d6050574SRomain Jobredeaux
32*d6050574SRomain Jobredeaux    Method: ActionSubject.new
33*d6050574SRomain Jobredeaux
34*d6050574SRomain Jobredeaux    Example usage:
35*d6050574SRomain Jobredeaux
36*d6050574SRomain Jobredeaux        expect(env).that_action(action).not_contains_arg("foo")
37*d6050574SRomain Jobredeaux
38*d6050574SRomain Jobredeaux    Args:
39*d6050574SRomain Jobredeaux        action: ([`Action`]) value to check against.
40*d6050574SRomain Jobredeaux        meta: ([`ExpectMeta`]) of call chain information.
41*d6050574SRomain Jobredeaux
42*d6050574SRomain Jobredeaux    Returns:
43*d6050574SRomain Jobredeaux        [`ActionSubject`] object.
44*d6050574SRomain Jobredeaux    """
45*d6050574SRomain Jobredeaux
46*d6050574SRomain Jobredeaux    # buildifier: disable=uninitialized
47*d6050574SRomain Jobredeaux    self = struct(
48*d6050574SRomain Jobredeaux        action = action,
49*d6050574SRomain Jobredeaux        meta = meta,
50*d6050574SRomain Jobredeaux        # Dict[str, list[str]] of flags. The keys must be in the same order
51*d6050574SRomain Jobredeaux        # as found in argv to allow ordering asserts of them.
52*d6050574SRomain Jobredeaux        parsed_flags = _action_subject_parse_flags(action.argv),
53*d6050574SRomain Jobredeaux    )
54*d6050574SRomain Jobredeaux    public = struct(
55*d6050574SRomain Jobredeaux        # keep sorted start
56*d6050574SRomain Jobredeaux        actual = action,
57*d6050574SRomain Jobredeaux        argv = mkmethod(self, _action_subject_argv),
58*d6050574SRomain Jobredeaux        contains_at_least_args = mkmethod(self, _action_subject_contains_at_least_args),
59*d6050574SRomain Jobredeaux        contains_at_least_inputs = mkmethod(self, _action_subject_contains_at_least_inputs),
60*d6050574SRomain Jobredeaux        contains_flag_values = mkmethod(self, _action_subject_contains_flag_values),
61*d6050574SRomain Jobredeaux        contains_none_of_flag_values = mkmethod(self, _action_subject_contains_none_of_flag_values),
62*d6050574SRomain Jobredeaux        content = mkmethod(self, _action_subject_content),
63*d6050574SRomain Jobredeaux        env = mkmethod(self, _action_subject_env),
64*d6050574SRomain Jobredeaux        has_flags_specified = mkmethod(self, _action_subject_has_flags_specified),
65*d6050574SRomain Jobredeaux        inputs = mkmethod(self, _action_subject_inputs),
66*d6050574SRomain Jobredeaux        mnemonic = mkmethod(self, _action_subject_mnemonic),
67*d6050574SRomain Jobredeaux        not_contains_arg = mkmethod(self, _action_subject_not_contains_arg),
68*d6050574SRomain Jobredeaux        substitutions = mkmethod(self, _action_subject_substitutions),
69*d6050574SRomain Jobredeaux        # keep sorted end
70*d6050574SRomain Jobredeaux    )
71*d6050574SRomain Jobredeaux    return public
72*d6050574SRomain Jobredeaux
73*d6050574SRomain Jobredeauxdef _action_subject_parse_flags(argv):
74*d6050574SRomain Jobredeaux    parsed_flags = {}
75*d6050574SRomain Jobredeaux
76*d6050574SRomain Jobredeaux    # argv might be none for e.g. builtin actions
77*d6050574SRomain Jobredeaux    if argv == None:
78*d6050574SRomain Jobredeaux        return parsed_flags
79*d6050574SRomain Jobredeaux    for i, arg in enumerate(argv):
80*d6050574SRomain Jobredeaux        if not arg.startswith("--"):
81*d6050574SRomain Jobredeaux            continue
82*d6050574SRomain Jobredeaux        if "=" in arg:
83*d6050574SRomain Jobredeaux            name, value = arg.split("=", 1)
84*d6050574SRomain Jobredeaux        else:
85*d6050574SRomain Jobredeaux            name = arg
86*d6050574SRomain Jobredeaux
87*d6050574SRomain Jobredeaux            # Handle a flag being the last arg in argv
88*d6050574SRomain Jobredeaux            if (i + 1) < len(argv):
89*d6050574SRomain Jobredeaux                value = argv[i + 1]
90*d6050574SRomain Jobredeaux            else:
91*d6050574SRomain Jobredeaux                value = None
92*d6050574SRomain Jobredeaux        parsed_flags.setdefault(name, []).append(value)
93*d6050574SRomain Jobredeaux    return parsed_flags
94*d6050574SRomain Jobredeaux
95*d6050574SRomain Jobredeauxdef _action_subject_argv(self):
96*d6050574SRomain Jobredeaux    """Returns a CollectionSubject for the action's argv.
97*d6050574SRomain Jobredeaux
98*d6050574SRomain Jobredeaux    Method: ActionSubject.argv
99*d6050574SRomain Jobredeaux
100*d6050574SRomain Jobredeaux    Returns:
101*d6050574SRomain Jobredeaux        [`CollectionSubject`] object.
102*d6050574SRomain Jobredeaux    """
103*d6050574SRomain Jobredeaux    meta = self.meta.derive("argv()")
104*d6050574SRomain Jobredeaux    return CollectionSubject.new(
105*d6050574SRomain Jobredeaux        self.action.argv,
106*d6050574SRomain Jobredeaux        meta,
107*d6050574SRomain Jobredeaux        container_name = "argv",
108*d6050574SRomain Jobredeaux        sortable = False,
109*d6050574SRomain Jobredeaux    )
110*d6050574SRomain Jobredeaux
111*d6050574SRomain Jobredeauxdef _action_subject_contains_at_least_args(self, args):
112*d6050574SRomain Jobredeaux    """Assert that an action contains at least the provided args.
113*d6050574SRomain Jobredeaux
114*d6050574SRomain Jobredeaux    Method: ActionSubject.contains_at_least_args
115*d6050574SRomain Jobredeaux
116*d6050574SRomain Jobredeaux    Example usage:
117*d6050574SRomain Jobredeaux        expect(env).that_action(action).contains_at_least_args(["foo", "bar"]).
118*d6050574SRomain Jobredeaux
119*d6050574SRomain Jobredeaux    Args:
120*d6050574SRomain Jobredeaux        self: implicitly added.
121*d6050574SRomain Jobredeaux        args: ([`list`] of [`str`]) all the args must be in the argv exactly
122*d6050574SRomain Jobredeaux            as provided. Multiplicity is respected.
123*d6050574SRomain Jobredeaux
124*d6050574SRomain Jobredeaux    Returns:
125*d6050574SRomain Jobredeaux        [`Ordered`] (see `_ordered_incorrectly_new`).
126*d6050574SRomain Jobredeaux    """
127*d6050574SRomain Jobredeaux    return CollectionSubject.new(
128*d6050574SRomain Jobredeaux        self.action.argv,
129*d6050574SRomain Jobredeaux        self.meta,
130*d6050574SRomain Jobredeaux        container_name = "argv",
131*d6050574SRomain Jobredeaux        element_plural_name = "args",
132*d6050574SRomain Jobredeaux        sortable = False,  # Preserve argv ordering
133*d6050574SRomain Jobredeaux    ).contains_at_least(args)
134*d6050574SRomain Jobredeaux
135*d6050574SRomain Jobredeauxdef _action_subject_not_contains_arg(self, arg):
136*d6050574SRomain Jobredeaux    """Assert that an action does not contain an arg.
137*d6050574SRomain Jobredeaux
138*d6050574SRomain Jobredeaux    Example usage:
139*d6050574SRomain Jobredeaux        expect(env).that_action(action).not_contains_arg("should-not-exist")
140*d6050574SRomain Jobredeaux
141*d6050574SRomain Jobredeaux    Args:
142*d6050574SRomain Jobredeaux        self: implicitly added.
143*d6050574SRomain Jobredeaux        arg: ([`str`]) the arg that cannot be present in the argv.
144*d6050574SRomain Jobredeaux    """
145*d6050574SRomain Jobredeaux    if arg in self.action.argv:
146*d6050574SRomain Jobredeaux        problem, actual = format_failure_unexpected_value(
147*d6050574SRomain Jobredeaux            container_name = "argv",
148*d6050574SRomain Jobredeaux            unexpected = arg,
149*d6050574SRomain Jobredeaux            actual = self.action.argv,
150*d6050574SRomain Jobredeaux            sort = False,  # Preserve argv ordering
151*d6050574SRomain Jobredeaux        )
152*d6050574SRomain Jobredeaux        self.meta.add_failure(problem, actual)
153*d6050574SRomain Jobredeaux
154*d6050574SRomain Jobredeauxdef _action_subject_substitutions(self):
155*d6050574SRomain Jobredeaux    """Creates a `DictSubject` to assert on the substitutions dict.
156*d6050574SRomain Jobredeaux
157*d6050574SRomain Jobredeaux    Method: ActionSubject.substitutions.
158*d6050574SRomain Jobredeaux
159*d6050574SRomain Jobredeaux    Args:
160*d6050574SRomain Jobredeaux        self: implicitly added
161*d6050574SRomain Jobredeaux
162*d6050574SRomain Jobredeaux    Returns:
163*d6050574SRomain Jobredeaux        `DictSubject` struct.
164*d6050574SRomain Jobredeaux    """
165*d6050574SRomain Jobredeaux    return DictSubject.new(
166*d6050574SRomain Jobredeaux        actual = self.action.substitutions,
167*d6050574SRomain Jobredeaux        meta = self.meta.derive("substitutions()"),
168*d6050574SRomain Jobredeaux    )
169*d6050574SRomain Jobredeaux
170*d6050574SRomain Jobredeauxdef _action_subject_has_flags_specified(self, flags):
171*d6050574SRomain Jobredeaux    """Assert that an action has the given flags present (but ignore any value).
172*d6050574SRomain Jobredeaux
173*d6050574SRomain Jobredeaux    Method: ActionSubject.has_flags_specified
174*d6050574SRomain Jobredeaux
175*d6050574SRomain Jobredeaux    This parses the argv, assuming the typical formats (`--flag=value`,
176*d6050574SRomain Jobredeaux    `--flag value`, and `--flag`). Any of the formats will be matched.
177*d6050574SRomain Jobredeaux
178*d6050574SRomain Jobredeaux    Example usage, given `argv = ["--a", "--b=1", "--c", "2"]`:
179*d6050574SRomain Jobredeaux        expect(env).that_action(action).has_flags_specified([
180*d6050574SRomain Jobredeaux            "--a", "--b", "--c"])
181*d6050574SRomain Jobredeaux
182*d6050574SRomain Jobredeaux    Args:
183*d6050574SRomain Jobredeaux        self: implicitly added.
184*d6050574SRomain Jobredeaux        flags: ([`list`] of [`str`]) The flags to check for. Include the leading "--".
185*d6050574SRomain Jobredeaux            Multiplicity is respected. A flag is considered present if any of
186*d6050574SRomain Jobredeaux            these forms are detected: `--flag=value`, `--flag value`, or a lone
187*d6050574SRomain Jobredeaux            `--flag`.
188*d6050574SRomain Jobredeaux
189*d6050574SRomain Jobredeaux    Returns:
190*d6050574SRomain Jobredeaux        [`Ordered`] (see `_ordered_incorrectly_new`).
191*d6050574SRomain Jobredeaux    """
192*d6050574SRomain Jobredeaux    return CollectionSubject.new(
193*d6050574SRomain Jobredeaux        # Starlark dict keys maintain insertion order, so it's OK to
194*d6050574SRomain Jobredeaux        # pass keys directly and return Ordered.
195*d6050574SRomain Jobredeaux        self.parsed_flags.keys(),
196*d6050574SRomain Jobredeaux        meta = self.meta,
197*d6050574SRomain Jobredeaux        container_name = "argv",
198*d6050574SRomain Jobredeaux        element_plural_name = "specified flags",
199*d6050574SRomain Jobredeaux        sortable = False,  # Preserve argv ordering
200*d6050574SRomain Jobredeaux    ).contains_at_least(flags)
201*d6050574SRomain Jobredeaux
202*d6050574SRomain Jobredeauxdef _action_subject_mnemonic(self):
203*d6050574SRomain Jobredeaux    """Returns a `StrSubject` for the action's mnemonic.
204*d6050574SRomain Jobredeaux
205*d6050574SRomain Jobredeaux    Method: ActionSubject.mnemonic
206*d6050574SRomain Jobredeaux
207*d6050574SRomain Jobredeaux    Returns:
208*d6050574SRomain Jobredeaux        [`StrSubject`] object.
209*d6050574SRomain Jobredeaux    """
210*d6050574SRomain Jobredeaux    return StrSubject.new(
211*d6050574SRomain Jobredeaux        self.action.mnemonic,
212*d6050574SRomain Jobredeaux        meta = self.meta.derive("mnemonic()"),
213*d6050574SRomain Jobredeaux    )
214*d6050574SRomain Jobredeaux
215*d6050574SRomain Jobredeauxdef _action_subject_inputs(self):
216*d6050574SRomain Jobredeaux    """Returns a DepsetFileSubject for the action's inputs.
217*d6050574SRomain Jobredeaux
218*d6050574SRomain Jobredeaux    Method: ActionSubject.inputs
219*d6050574SRomain Jobredeaux
220*d6050574SRomain Jobredeaux    Returns:
221*d6050574SRomain Jobredeaux        `DepsetFileSubject` of the action's inputs.
222*d6050574SRomain Jobredeaux    """
223*d6050574SRomain Jobredeaux    meta = self.meta.derive("inputs()")
224*d6050574SRomain Jobredeaux    return DepsetFileSubject.new(self.action.inputs, meta)
225*d6050574SRomain Jobredeaux
226*d6050574SRomain Jobredeauxdef _action_subject_contains_flag_values(self, flag_values):
227*d6050574SRomain Jobredeaux    """Assert that an action's argv has the given ("--flag", "value") entries.
228*d6050574SRomain Jobredeaux
229*d6050574SRomain Jobredeaux    Method: ActionSubject.contains_flag_values
230*d6050574SRomain Jobredeaux
231*d6050574SRomain Jobredeaux    This parses the argv, assuming the typical formats (`--flag=value`,
232*d6050574SRomain Jobredeaux    `--flag value`, and `--flag`). Note, however, that for the `--flag value`
233*d6050574SRomain Jobredeaux    and `--flag` forms, the parsing can't know how many args, if any, a flag
234*d6050574SRomain Jobredeaux    actually consumes, so it simply takes the first following arg, if any, as
235*d6050574SRomain Jobredeaux    the matching value.
236*d6050574SRomain Jobredeaux
237*d6050574SRomain Jobredeaux    NOTE: This function can give misleading results checking flags that don't
238*d6050574SRomain Jobredeaux    consume any args (e.g. boolean flags). Use `has_flags_specified()` to test
239*d6050574SRomain Jobredeaux    for such flags. Such cases will either show the subsequent arg as the value,
240*d6050574SRomain Jobredeaux    or None if the flag was the last arg in argv.
241*d6050574SRomain Jobredeaux
242*d6050574SRomain Jobredeaux    Example usage, given `argv = ["--b=1", "--c", "2"]`:
243*d6050574SRomain Jobredeaux        expect(env).that_action(action).contains_flag_values([
244*d6050574SRomain Jobredeaux            ("--b", "1"),
245*d6050574SRomain Jobredeaux            ("--c", "2")
246*d6050574SRomain Jobredeaux        ])
247*d6050574SRomain Jobredeaux
248*d6050574SRomain Jobredeaux    Args:
249*d6050574SRomain Jobredeaux        self: implicitly added.
250*d6050574SRomain Jobredeaux        flag_values: ([`list`] of ([`str`] name, [`str`]) tuples) Include the
251*d6050574SRomain Jobredeaux            leading "--" in the flag name. Order and duplicates aren't checked.
252*d6050574SRomain Jobredeaux            Flags without a value found use `None` as their value.
253*d6050574SRomain Jobredeaux    """
254*d6050574SRomain Jobredeaux    missing = []
255*d6050574SRomain Jobredeaux    for flag, value in sorted(flag_values):
256*d6050574SRomain Jobredeaux        if flag not in self.parsed_flags:
257*d6050574SRomain Jobredeaux            missing.append("'{}' (not specified)".format(flag))
258*d6050574SRomain Jobredeaux        elif value not in self.parsed_flags[flag]:
259*d6050574SRomain Jobredeaux            missing.append("'{}' with value '{}'".format(flag, value))
260*d6050574SRomain Jobredeaux    if not missing:
261*d6050574SRomain Jobredeaux        return
262*d6050574SRomain Jobredeaux    problem, actual = format_failure_missing_all_values(
263*d6050574SRomain Jobredeaux        element_plural_name = "flags with values",
264*d6050574SRomain Jobredeaux        container_name = "argv",
265*d6050574SRomain Jobredeaux        missing = missing,
266*d6050574SRomain Jobredeaux        actual = self.action.argv,
267*d6050574SRomain Jobredeaux        sort = False,  # Preserve argv ordering
268*d6050574SRomain Jobredeaux    )
269*d6050574SRomain Jobredeaux    self.meta.add_failure(problem, actual)
270*d6050574SRomain Jobredeaux
271*d6050574SRomain Jobredeauxdef _action_subject_contains_none_of_flag_values(self, flag_values):
272*d6050574SRomain Jobredeaux    """Assert that an action's argv has none of the given ("--flag", "value") entries.
273*d6050574SRomain Jobredeaux
274*d6050574SRomain Jobredeaux    Method: ActionSubject.contains_none_of_flag_values
275*d6050574SRomain Jobredeaux
276*d6050574SRomain Jobredeaux    This parses the argv, assuming the typical formats (`--flag=value`,
277*d6050574SRomain Jobredeaux    `--flag value`, and `--flag`). Note, however, that for the `--flag value`
278*d6050574SRomain Jobredeaux    and `--flag` forms, the parsing can't know how many args, if any, a flag
279*d6050574SRomain Jobredeaux    actually consumes, so it simply takes the first following arg, if any, as
280*d6050574SRomain Jobredeaux    the matching value.
281*d6050574SRomain Jobredeaux
282*d6050574SRomain Jobredeaux    NOTE: This function can give misleading results checking flags that don't
283*d6050574SRomain Jobredeaux    consume any args (e.g. boolean flags). Use `has_flags_specified()` to test
284*d6050574SRomain Jobredeaux    for such flags.
285*d6050574SRomain Jobredeaux
286*d6050574SRomain Jobredeaux    Args:
287*d6050574SRomain Jobredeaux        self: implicitly added.
288*d6050574SRomain Jobredeaux        flag_values: ([`list`] of ([`str`] name, [`str`] value) tuples) Include
289*d6050574SRomain Jobredeaux            the leading "--" in the flag name. Order and duplicates aren't
290*d6050574SRomain Jobredeaux            checked.
291*d6050574SRomain Jobredeaux    """
292*d6050574SRomain Jobredeaux    unexpected = []
293*d6050574SRomain Jobredeaux    for flag, value in sorted(flag_values):
294*d6050574SRomain Jobredeaux        if flag not in self.parsed_flags:
295*d6050574SRomain Jobredeaux            continue
296*d6050574SRomain Jobredeaux        elif value in self.parsed_flags[flag]:
297*d6050574SRomain Jobredeaux            unexpected.append("'{}' with value '{}'".format(flag, value))
298*d6050574SRomain Jobredeaux    if not unexpected:
299*d6050574SRomain Jobredeaux        return
300*d6050574SRomain Jobredeaux
301*d6050574SRomain Jobredeaux    problem, actual = format_failure_unexpected_values(
302*d6050574SRomain Jobredeaux        none_of = "\n" + enumerate_list_as_lines(sorted(unexpected), prefix = "  "),
303*d6050574SRomain Jobredeaux        unexpected = unexpected,
304*d6050574SRomain Jobredeaux        actual = self.action.argv,
305*d6050574SRomain Jobredeaux        sort = False,  # Preserve argv ordering
306*d6050574SRomain Jobredeaux    )
307*d6050574SRomain Jobredeaux    self.meta.add_failure(problem, actual)
308*d6050574SRomain Jobredeaux
309*d6050574SRomain Jobredeauxdef _action_subject_contains_at_least_inputs(self, inputs):
310*d6050574SRomain Jobredeaux    """Assert the action's inputs contains at least all of `inputs`.
311*d6050574SRomain Jobredeaux
312*d6050574SRomain Jobredeaux    Method: ActionSubject.contains_at_least_inputs
313*d6050574SRomain Jobredeaux
314*d6050574SRomain Jobredeaux    Example usage:
315*d6050574SRomain Jobredeaux        expect(env).that_action(action).contains_at_least_inputs([<some file>])
316*d6050574SRomain Jobredeaux
317*d6050574SRomain Jobredeaux    Args:
318*d6050574SRomain Jobredeaux        self: implicitly added.
319*d6050574SRomain Jobredeaux        inputs: (collection of [`File`]) All must be present. Multiplicity
320*d6050574SRomain Jobredeaux            is respected.
321*d6050574SRomain Jobredeaux
322*d6050574SRomain Jobredeaux    Returns:
323*d6050574SRomain Jobredeaux        [`Ordered`] (see `_ordered_incorrectly_new`).
324*d6050574SRomain Jobredeaux    """
325*d6050574SRomain Jobredeaux    return DepsetFileSubject.new(
326*d6050574SRomain Jobredeaux        self.action.inputs,
327*d6050574SRomain Jobredeaux        meta = self.meta,
328*d6050574SRomain Jobredeaux        container_name = "action inputs",
329*d6050574SRomain Jobredeaux        element_plural_name = "inputs",
330*d6050574SRomain Jobredeaux    ).contains_at_least(inputs)
331*d6050574SRomain Jobredeaux
332*d6050574SRomain Jobredeauxdef _action_subject_content(self):
333*d6050574SRomain Jobredeaux    """Returns a `StrSubject` for `Action.content`.
334*d6050574SRomain Jobredeaux
335*d6050574SRomain Jobredeaux    Method: ActionSubject.content
336*d6050574SRomain Jobredeaux
337*d6050574SRomain Jobredeaux    Returns:
338*d6050574SRomain Jobredeaux        [`StrSubject`] object.
339*d6050574SRomain Jobredeaux    """
340*d6050574SRomain Jobredeaux    return StrSubject.new(
341*d6050574SRomain Jobredeaux        self.action.content,
342*d6050574SRomain Jobredeaux        self.meta.derive("content()"),
343*d6050574SRomain Jobredeaux    )
344*d6050574SRomain Jobredeaux
345*d6050574SRomain Jobredeauxdef _action_subject_env(self):
346*d6050574SRomain Jobredeaux    """Returns a `DictSubject` for `Action.env`.
347*d6050574SRomain Jobredeaux
348*d6050574SRomain Jobredeaux    Method: ActionSubject.env
349*d6050574SRomain Jobredeaux
350*d6050574SRomain Jobredeaux    Args:
351*d6050574SRomain Jobredeaux        self: implicitly added.
352*d6050574SRomain Jobredeaux    """
353*d6050574SRomain Jobredeaux    return DictSubject.new(
354*d6050574SRomain Jobredeaux        self.action.env,
355*d6050574SRomain Jobredeaux        self.meta.derive("env()"),
356*d6050574SRomain Jobredeaux        container_name = "environment",
357*d6050574SRomain Jobredeaux        key_plural_name = "envvars",
358*d6050574SRomain Jobredeaux    )
359*d6050574SRomain Jobredeaux
360*d6050574SRomain Jobredeaux# We use this name so it shows up nice in docs.
361*d6050574SRomain Jobredeaux# buildifier: disable=name-conventions
362*d6050574SRomain JobredeauxActionSubject = struct(
363*d6050574SRomain Jobredeaux    new = _action_subject_new,
364*d6050574SRomain Jobredeaux    parse_flags = _action_subject_parse_flags,
365*d6050574SRomain Jobredeaux    argv = _action_subject_argv,
366*d6050574SRomain Jobredeaux    contains_at_least_args = _action_subject_contains_at_least_args,
367*d6050574SRomain Jobredeaux    not_contains_arg = _action_subject_not_contains_arg,
368*d6050574SRomain Jobredeaux    substitutions = _action_subject_substitutions,
369*d6050574SRomain Jobredeaux    has_flags_specified = _action_subject_has_flags_specified,
370*d6050574SRomain Jobredeaux    mnemonic = _action_subject_mnemonic,
371*d6050574SRomain Jobredeaux    inputs = _action_subject_inputs,
372*d6050574SRomain Jobredeaux    contains_flag_values = _action_subject_contains_flag_values,
373*d6050574SRomain Jobredeaux    contains_none_of_flag_values = _action_subject_contains_none_of_flag_values,
374*d6050574SRomain Jobredeaux    contains_at_least_inputs = _action_subject_contains_at_least_inputs,
375*d6050574SRomain Jobredeaux    content = _action_subject_content,
376*d6050574SRomain Jobredeaux    env = _action_subject_env,
377*d6050574SRomain Jobredeaux)
378