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