From e1c7ebb858f888991618db4e440aa6e45968b9b3 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 25 Jul 2024 20:13:10 -0700 Subject: [PATCH] Add support for select'ing on cc_args(args=...). This CL is an alternative to unknown commit. I left the other CL seperately, because I wasn't 100% sure that we'd agree to this, since this is an API change. I did it this way because I believe it's much less hacky, and it also allows us to format things that aren't variables. BEGIN_PUBLIC Add support for select'ing on cc_args(args=...). This is quite tricky because the one parameter was being split into two in a macro, one of type label and the other of type string. For example, `args = ["--foo", format_arg("--bar=%s", "//path/to:bar")]` was rewritten by the macro to `args = [json.encode(struct(format_type="raw", format="foo")), json.encode(struct(format_type="format_arg", format="--bar=%s", value=0))], variables = ["//path/to:bar"]`. To allow it to work with selects, we need to ensure that we don't perform post-processing on the inside of the select. To solve this, we: * Ensure that args only take strings * Provide a seperate parameter for substitutions. This new mechanism also has the useful property that we can now format things that are not variables. For example, I can do the following: ``` directory(name = "sysroot", ...) cc_args( name = "sysroot_arg", args = ["--sysroot={sysroot}"], format = { ":sysroot": "sysroot" } ) ``` END_PUBLIC PiperOrigin-RevId: 656211278 Change-Id: If83f1ea5a99090c18f2a561c51ec6d39ce9fe419 --- cc/toolchains/args.bzl | 11 +- cc/toolchains/format.bzl | 26 -- cc/toolchains/impl/nested_args.bzl | 294 ++++++++---------- cc/toolchains/nested_args.bzl | 8 +- tests/rule_based_toolchain/args/args_test.bzl | 2 +- tests/rule_based_toolchain/nested_args/BUILD | 5 + .../nested_args/nested_args_test.bzl | 156 +++++----- tests/rule_based_toolchain/variables/BUILD | 27 +- 8 files changed, 253 insertions(+), 276 deletions(-) delete mode 100644 cc/toolchains/format.bzl diff --git a/cc/toolchains/args.bzl b/cc/toolchains/args.bzl index 1df3333..2f624f3 100644 --- a/cc/toolchains/args.bzl +++ b/cc/toolchains/args.bzl @@ -23,7 +23,6 @@ load( load( "//cc/toolchains/impl:nested_args.bzl", "NESTED_ARGS_ATTRS", - "args_wrapper_macro", "nested_args_provider_from_ctx", ) load( @@ -40,9 +39,6 @@ visibility("public") def _cc_args_impl(ctx): actions = collect_action_types(ctx.attr.actions) - if not ctx.attr.args and not ctx.attr.nested and not ctx.attr.env: - fail("cc_args requires at least one of args, nested, and env") - nested = None if ctx.attr.args or ctx.attr.nested: nested = nested_args_provider_from_ctx(ctx) @@ -117,4 +113,9 @@ Examples: """, ) -cc_args = lambda **kwargs: args_wrapper_macro(rule = _cc_args, **kwargs) +def cc_args(name, format = {}, **kwargs): + return _cc_args( + name = name, + format = {k: v for v, k in format.items()}, + **kwargs + ) diff --git a/cc/toolchains/format.bzl b/cc/toolchains/format.bzl deleted file mode 100644 index bdbb0c8..0000000 --- a/cc/toolchains/format.bzl +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2024 The Bazel Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Functions to format arguments for the cc toolchain""" - -def format_arg(format, value = None): - """Generate metadata to format a variable with a given value. - - Args: - format: (str) The format string - value: (Optional[Label]) The variable to format. Any is used because it can - be any representation of a variable. - Returns: - A struct corresponding to the formatted variable. - """ - return struct(format_type = "format_arg", format = format, value = value) diff --git a/cc/toolchains/impl/nested_args.bzl b/cc/toolchains/impl/nested_args.bzl index ed83cf1..2a5fb07 100644 --- a/cc/toolchains/impl/nested_args.bzl +++ b/cc/toolchains/impl/nested_args.bzl @@ -13,7 +13,7 @@ # limitations under the License. """Helper functions for working with args.""" -load("@bazel_skylib//lib:structs.bzl", "structs") +load("@bazel_skylib//rules/directory:providers.bzl", "DirectoryInfo") load("//cc:cc_toolchain_config_lib.bzl", "flag_group", "variable_with_value") load("//cc/toolchains:cc_toolchain_info.bzl", "NestedArgsInfo", "VariableInfo") load(":collect.bzl", "collect_files", "collect_provider") @@ -30,25 +30,7 @@ REQUIRES_TRUE_ERR = "requires_true only works on bools" REQUIRES_FALSE_ERR = "requires_false only works on bools" REQUIRES_EQUAL_ERR = "requires_equal only works on strings" REQUIRES_EQUAL_VALUE_ERR = "When requires_equal is provided, you must also provide requires_equal_value to specify what it should be equal to" -FORMAT_ARGS_ERR = "format_args can only format strings, files, or directories" - -_NOT_ESCAPED_FMT = "%% should always either of the form %%s, or escaped with %%%%. Instead, got %r" - -_EXAMPLE = """ - -cc_args( - ..., - args = [format_arg("--foo=%s", "//cc/toolchains/variables:foo")] -) - -or - -cc_args( - ..., - # If foo_list contains ["a", "b"], then this expands to ["--foo", "+a", "--foo", "+b"]. - args = ["--foo", format_arg("+%s")], - iterate_over = "//toolchains/variables:foo_list", -""" +FORMAT_ARGS_ERR = "format only works on string, file, or directory type variables" # @unsorted-dict-items. NESTED_ARGS_ATTRS = { @@ -58,7 +40,10 @@ NESTED_ARGS_ATTRS = { Usage: cc_args( ..., - args = ["--foo", format_arg("%s", "//cc/toolchains/variables:foo")] + args = ["--foo={foo}"], + format = { + "//cc/toolchains/variables:foo": "foo" + }, ) This is equivalent to flag_group(flags = ["--foo", "%{foo}"]) @@ -80,8 +65,7 @@ For example, a flag that sets the header directory might add the headers in that directory as additional files. """, ), - "variables": attr.label_list( - providers = [VariableInfo], + "format": attr.label_keyed_string_dict( doc = "Variables to be used in substitutions", ), "iterate_over": attr.label(providers = [VariableInfo], doc = "Replacement for flag_group.iterate_over"), @@ -93,45 +77,6 @@ directory as additional files. "requires_equal_value": attr.string(), } -def args_wrapper_macro(*, name, rule, args = [], **kwargs): - """Invokes a rule by converting args to attributes. - - Args: - name: (str) The name of the target. - rule: (rule) The rule to invoke. Either cc_args or cc_nested_args. - args: (List[str|Formatted]) A list of either strings, or function calls - from format.bzl. For example: - ["--foo", format_arg("--sysroot=%s", "//cc/toolchains/variables:sysroot")] - **kwargs: kwargs to pass through into the rule invocation. - """ - out_args = [] - vars = [] - if type(args) != "list": - fail("Args must be a list in %s" % native.package_relative_label(name)) - for arg in args: - if type(arg) == "string": - out_args.append(raw_string(arg)) - elif getattr(arg, "format_type") == "format_arg": - arg = structs.to_dict(arg) - if arg["value"] == None: - out_args.append(arg) - else: - var = arg.pop("value") - - # Swap the variable from a label to an index. This allows us to - # actually get the providers in a rule. - out_args.append(struct(value = len(vars), **arg)) - vars.append(var) - else: - fail("Invalid type of args in %s. Expected either a string or format_args(format_string, variable_label), got value %r" % (native.package_relative_label(name), arg)) - - rule( - name = name, - args = [json.encode(arg) for arg in out_args], - variables = vars, - **kwargs - ) - def _var(target): if target == None: return None @@ -147,21 +92,13 @@ def nested_args_provider_from_ctx(ctx): Returns: NestedArgsInfo """ - variables = collect_provider(ctx.attr.variables, VariableInfo) - args = [] - for arg in ctx.attr.args: - arg = json.decode(arg) - if "value" in arg: - if arg["value"] != None: - arg["value"] = variables[arg["value"]] - args.append(struct(**arg)) - return nested_args_provider( label = ctx.label, - args = args, + args = ctx.attr.args, + format = ctx.attr.format, nested = collect_provider(ctx.attr.nested, NestedArgsInfo), files = collect_files(ctx.attr.data), - iterate_over = _var(ctx.attr.iterate_over), + iterate_over = ctx.attr.iterate_over, requires_not_none = _var(ctx.attr.requires_not_none), requires_none = _var(ctx.attr.requires_none), requires_true = _var(ctx.attr.requires_true), @@ -170,85 +107,12 @@ def nested_args_provider_from_ctx(ctx): requires_equal_value = ctx.attr.requires_equal_value, ) -def raw_string(s): - """Constructs metadata for creating a raw string. - - Args: - s: (str) The string to input. - Returns: - Metadata suitable for format_variable. - """ - return struct(format_type = "raw", format = s) - -def format_string_indexes(s, fail = fail): - """Gets the index of a '%s' in a string. - - Args: - s: (str) The string - fail: The fail function. Used for tests - - Returns: - List[int] The indexes of the '%s' in the string - """ - indexes = [] - escaped = False - for i in range(len(s)): - if not escaped and s[i] == "%": - escaped = True - elif escaped: - if s[i] == "{": - fail('Using the old mechanism for variables, %%{variable}, but we instead use format_arg("--foo=%%s", "//cc/toolchains/variables:"). Got %r' % s) - elif s[i] == "s": - indexes.append(i - 1) - elif s[i] != "%": - fail(_NOT_ESCAPED_FMT % s) - escaped = False - if escaped: - return fail(_NOT_ESCAPED_FMT % s) - return indexes - -def format_variable(arg, iterate_over, fail = fail): - """Lists all of the variables referenced by an argument. - - Eg: referenced_variables([ - format_arg("--foo", None), - format_arg("--bar=%s", ":bar") - ]) => ["--foo", "--bar=%{bar}"] - - Args: - arg: [Formatted] The command-line arguments, as created by the format_arg function. - iterate_over: (Optional[str]) The name of the variable we're iterating over. - fail: The fail function. Used for tests - - Returns: - A string defined to be compatible with flag groups. - """ - indexes = format_string_indexes(arg.format, fail = fail) - if arg.format_type == "raw": - if indexes: - return fail("Can't use %s with a raw string. Either escape it with %%s or use format_arg, like the following examples:" + _EXAMPLE) - return arg.format - else: - if len(indexes) == 0: - return fail('format_arg requires a "%%s" in the format string, but got %r' % arg.format) - elif len(indexes) > 1: - return fail("Only one %%s can be used in a format string, but got %r" % arg.format) - - if arg.value == None: - if iterate_over == None: - return fail("format_arg requires either a variable to format, or iterate_over must be provided. For example:" + _EXAMPLE) - var = iterate_over - else: - var = arg.value.name - - index = indexes[0] - return arg.format[:index] + "%{" + var + "}" + arg.format[index + 2:] - def nested_args_provider( *, label, args = [], nested = [], + format = {}, files = depset([]), iterate_over = None, requires_not_none = None, @@ -269,8 +133,9 @@ def nested_args_provider( error messages. args: (List[str]) The command-line arguments to add. nested: (List[NestedArgsInfo]) command-line arguments to expand. + format: (dict[Target, str]) A mapping from target to format string name files: (depset[File]) Files required for this set of command-line args. - iterate_over: (Optional[str]) Variable to iterate over + iterate_over: (Optional[Target]) Target for the variable to iterate over requires_not_none: (Optional[str]) If provided, this NestedArgsInfo will be ignored if the variable is None requires_none: (Optional[str]) If provided, this NestedArgsInfo will @@ -287,8 +152,38 @@ def nested_args_provider( Returns: NestedArgsInfo """ - if bool(args) == bool(nested): - fail("Exactly one of args and nested must be provided") + if bool(args) and bool(nested): + fail("Args and nested are mutually exclusive") + + replacements = {} + if iterate_over: + # Since the user didn't assign a name to iterate_over, allow them to + # reference it as "--foo={}" + replacements[""] = iterate_over + + # Intentionally ensure that {} clashes between an explicit user format + # string "" and the implicit one provided by iterate_over. + for target, name in format.items(): + if name in replacements: + fail("Both %s and %s have the format string name %r" % ( + target.label, + replacements[name].label, + name, + )) + replacements[name] = target + + # Intentionally ensure that we do not have to use the variable provided by + # iterate_over in the format string. + # For example, a valid use case is: + # cc_args( + # nested = ":nested", + # iterate_over = "//cc/toolchains/variables:libraries_to_link", + # ) + # cc_nested_args( + # args = ["{}"], + # iterate_over = "//cc/toolchains/variables:libraries_to_link.object_files", + # ) + args = format_args(args, replacements, must_use = format.values(), fail = fail) transitive_files = [ea.files for ea in nested] transitive_files.append(files) @@ -307,6 +202,10 @@ def nested_args_provider( fail(REQUIRES_MUTUALLY_EXCLUSIVE_ERR) kwargs = {} + + if args: + kwargs["flags"] = args + requires_types = {} if nested: kwargs["flag_groups"] = [ea.legacy_flag_group for ea in nested] @@ -314,7 +213,7 @@ def nested_args_provider( unwrap_options = [] if iterate_over: - kwargs["iterate_over"] = iterate_over + kwargs["iterate_over"] = _var(iterate_over) if requires_not_none: kwargs["expand_if_available"] = requires_not_none @@ -361,27 +260,98 @@ def nested_args_provider( after_option_unwrap = True, )) - for arg in args: - if arg.format_type != "raw": - var_name = arg.value.name if arg.value != None else iterate_over - requires_types.setdefault(var_name, []).append(struct( + for arg in format: + if VariableInfo in arg: + requires_types.setdefault(arg[VariableInfo].name, []).append(struct( msg = FORMAT_ARGS_ERR, valid_types = ["string", "file", "directory"], after_option_unwrap = True, )) - if args: - kwargs["flags"] = [ - format_variable(arg, iterate_over = iterate_over, fail = fail) - for arg in args - ] - return NestedArgsInfo( label = label, nested = nested, files = depset(transitive = transitive_files), - iterate_over = iterate_over, + iterate_over = _var(iterate_over), unwrap_options = unwrap_options, requires_types = requires_types, legacy_flag_group = flag_group(**kwargs), ) + +def _escape(s): + return s.replace("%", "%%") + +def _format_target(target, fail = fail): + if VariableInfo in target: + return "%%{%s}" % target[VariableInfo].name + elif DirectoryInfo in target: + return _escape(target[DirectoryInfo].path) + + files = target[DefaultInfo].files.to_list() + if len(files) == 1: + return _escape(files[0].path) + + fail("%s should be either a variable, a directory, or a single file." % target.label) + +def format_args(args, format, must_use = [], fail = fail): + """Lists all of the variables referenced by an argument. + + Eg: format_args(["--foo", "--bar={bar}"], {"bar": VariableInfo(name="bar")}) + => ["--foo", "--bar=%{bar}"] + + Args: + args: (List[str]) The command-line arguments. + format: (Dict[str, Target]) A mapping of substitutions from key to target. + must_use: (List[str]) A list of substitutions that must be used. + fail: The fail function. Used for tests + + Returns: + A string defined to be compatible with flag groups. + """ + formatted = [] + used_vars = {} + + for arg in args: + upto = 0 + out = [] + has_format = False + + # This should be "while true". I used this number because it's an upper + # bound of the number of iterations. + for _ in range(len(arg)): + if upto >= len(arg): + break + + # Escaping via "{{" and "}}" + if arg[upto] in "{}" and upto + 1 < len(arg) and arg[upto + 1] == arg[upto]: + out.append(arg[upto]) + upto += 2 + elif arg[upto] == "{": + chunks = arg[upto + 1:].split("}", 1) + if len(chunks) != 2: + fail("Unmatched { in %r" % arg) + variable = chunks[0] + + if variable not in format: + fail('Unknown variable %r in format string %r. Try using cc_args(..., format = {"//path/to:variable": %r})' % (variable, arg, variable)) + elif has_format: + fail("The format string %r contained multiple variables, which is unsupported." % arg) + else: + used_vars[variable] = None + has_format = True + out.append(_format_target(format[variable], fail = fail)) + upto += len(variable) + 2 + + elif arg[upto] == "}": + fail("Unexpected } in %r" % arg) + else: + out.append(_escape(arg[upto])) + upto += 1 + + formatted.append("".join(out)) + + unused_vars = [var for var in must_use if var not in used_vars] + if unused_vars: + fail("The variable %r was not used in the format string." % unused_vars[0]) + + return formatted diff --git a/cc/toolchains/nested_args.bzl b/cc/toolchains/nested_args.bzl index e4e3d53..1d31275 100644 --- a/cc/toolchains/nested_args.bzl +++ b/cc/toolchains/nested_args.bzl @@ -16,7 +16,6 @@ load( "//cc/toolchains/impl:nested_args.bzl", "NESTED_ARGS_ATTRS", - "args_wrapper_macro", "nested_args_provider_from_ctx", ) load( @@ -42,4 +41,9 @@ Examples: """, ) -cc_nested_args = lambda **kwargs: args_wrapper_macro(rule = _cc_nested_args, **kwargs) +def cc_nested_args(name, format = {}, **kwargs): + return _cc_nested_args( + name = name, + format = {k: v for v, k in format.items()}, + **kwargs + ) diff --git a/tests/rule_based_toolchain/args/args_test.bzl b/tests/rule_based_toolchain/args/args_test.bzl index fbd4ce9..226aadb 100644 --- a/tests/rule_based_toolchain/args/args_test.bzl +++ b/tests/rule_based_toolchain/args/args_test.bzl @@ -109,5 +109,5 @@ TARGETS = [ # @unsorted-dict-items TESTS = { "simple_test": _simple_test, - "env_only_test_test": _env_only_test, + "env_only_test": _env_only_test, } diff --git a/tests/rule_based_toolchain/nested_args/BUILD b/tests/rule_based_toolchain/nested_args/BUILD index 30e75ed..491ed0b 100644 --- a/tests/rule_based_toolchain/nested_args/BUILD +++ b/tests/rule_based_toolchain/nested_args/BUILD @@ -7,6 +7,11 @@ cc_variable( type = types.string, ) +cc_variable( + name = "my_list", + type = types.list(types.string), +) + analysis_test_suite( name = "test_suite", targets = TARGETS, diff --git a/tests/rule_based_toolchain/nested_args/nested_args_test.bzl b/tests/rule_based_toolchain/nested_args/nested_args_test.bzl index 96a361c..e39a850 100644 --- a/tests/rule_based_toolchain/nested_args/nested_args_test.bzl +++ b/tests/rule_based_toolchain/nested_args/nested_args_test.bzl @@ -13,19 +13,16 @@ # limitations under the License. """Tests for the cc_args rule.""" +load("@bazel_skylib//rules/directory:providers.bzl", "DirectoryInfo") load("//cc:cc_toolchain_config_lib.bzl", "flag_group", "variable_with_value") -load("//cc/toolchains:cc_toolchain_info.bzl", "VariableInfo") -load("//cc/toolchains:format.bzl", "format_arg") load( "//cc/toolchains/impl:nested_args.bzl", "FORMAT_ARGS_ERR", "REQUIRES_EQUAL_ERR", "REQUIRES_MUTUALLY_EXCLUSIVE_ERR", "REQUIRES_NONE_ERR", - "format_string_indexes", - "format_variable", + "format_args", "nested_args_provider", - "raw_string", ) load("//tests/rule_based_toolchain:subjects.bzl", "result_fn_wrapper", "subjects") @@ -41,83 +38,101 @@ def _expect_that_nested(env, expr = None, **kwargs): factory = subjects.result(subjects.NestedArgsInfo), ) -def _expect_that_formatted(env, var, iterate_over = None, expr = None): +def _expect_that_formatted(env, args, format, must_use = [], expr = None): return env.expect.that_value( - result_fn_wrapper(format_variable)(var, iterate_over), - factory = subjects.result(subjects.str), - expr = expr or "format_variable(var=%r, iterate_over=%r" % (var, iterate_over), - ) - -def _expect_that_format_string_indexes(env, var, expr = None): - return env.expect.that_value( - result_fn_wrapper(format_string_indexes)(var), + result_fn_wrapper(format_args)(args, format, must_use = must_use), factory = subjects.result(subjects.collection), - expr = expr or "format_string_indexes(%r)" % var, + expr = expr or "format_args(%r, %r)" % (args, format), ) -def _format_string_indexes_test(env, _): - _expect_that_format_string_indexes(env, "foo").ok().contains_exactly([]) - _expect_that_format_string_indexes(env, "%%").ok().contains_exactly([]) - _expect_that_format_string_indexes(env, "%").err().equals( - '% should always either of the form %s, or escaped with %%. Instead, got "%"', - ) - _expect_that_format_string_indexes(env, "%a").err().equals( - '% should always either of the form %s, or escaped with %%. Instead, got "%a"', - ) - _expect_that_format_string_indexes(env, "%s").ok().contains_exactly([0]) - _expect_that_format_string_indexes(env, "%%%s%s").ok().contains_exactly([2, 4]) - _expect_that_format_string_indexes(env, "%%{").ok().contains_exactly([]) - _expect_that_format_string_indexes(env, "%%s").ok().contains_exactly([]) - _expect_that_format_string_indexes(env, "%{foo}").err().equals( - 'Using the old mechanism for variables, %{variable}, but we instead use format_arg("--foo=%s", "//cc/toolchains/variables:"). Got "%{foo}"', - ) - -def _formats_raw_strings_test(env, _): +def _format_args_test(env, targets): _expect_that_formatted( env, - raw_string("foo"), - ).ok().equals("foo") - _expect_that_formatted( - env, - raw_string("%s"), - ).err().contains("Can't use %s with a raw string. Either escape it with %%s or use format_arg") - -def _formats_variables_test(env, targets): - _expect_that_formatted( - env, - format_arg("ab %s cd", targets.foo[VariableInfo]), - ).ok().equals("ab %{foo} cd") + [ + "a % b", + "a {{", + "}} b", + "a {{ b }}", + ], + {}, + ).ok().contains_exactly([ + "a %% b", + "a {", + "} b", + "a { b }", + ]).in_order() _expect_that_formatted( env, - format_arg("foo", targets.foo[VariableInfo]), - ).err().equals('format_arg requires a "%s" in the format string, but got "foo"') - _expect_that_formatted( - env, - format_arg("%s%s", targets.foo[VariableInfo]), - ).err().equals('Only one %s can be used in a format string, but got "%s%s"') + ["{foo"], + {}, + ).err().equals('Unmatched { in "{foo"') _expect_that_formatted( env, - format_arg("%s"), - iterate_over = "foo", - ).ok().equals("%{foo}") + ["foo}"], + {}, + ).err().equals('Unexpected } in "foo}"') _expect_that_formatted( env, - format_arg("%s"), - ).err().contains("format_arg requires either a variable to format, or iterate_over must be provided") + ["{foo}"], + {}, + ).err().contains('Unknown variable "foo" in format string "{foo}"') -def _iterate_over_test(env, _): + _expect_that_formatted( + env, + [ + "a {var}", + "b {directory}", + "c {file}", + ], + { + "directory": targets.directory, + "file": targets.bin_wrapper, + "var": targets.foo, + }, + ).ok().contains_exactly([ + "a %{foo}", + "b " + targets.directory[DirectoryInfo].path, + "c " + targets.bin_wrapper[DefaultInfo].files.to_list()[0].path, + ]).in_order() + + _expect_that_formatted( + env, + ["{var}", "{var}"], + {"var": targets.foo}, + ).ok().contains_exactly(["%{foo}", "%{foo}"]) + + _expect_that_formatted( + env, + [], + {"var": targets.foo}, + must_use = ["var"], + ).err().contains('"var" was not used') + + _expect_that_formatted( + env, + ["{var} {var}"], + {"var": targets.foo}, + ).err().contains('"{var} {var}" contained multiple variables') + + _expect_that_formatted( + env, + ["{foo} {bar}"], + {"foo": targets.foo, "bar": targets.foo}, + ).err().contains('"{foo} {bar}" contained multiple variables') + +def _iterate_over_test(env, targets): inner = _expect_that_nested( env, - args = [raw_string("--foo")], + args = ["--foo"], ).ok().actual env.expect.that_str(inner.legacy_flag_group).equals(flag_group(flags = ["--foo"])) nested = _expect_that_nested( env, nested = [inner], - iterate_over = "my_list", + iterate_over = targets.my_list, ).ok() nested.iterate_over().some().equals("my_list") nested.legacy_flag_group().equals(flag_group( @@ -131,14 +146,14 @@ def _requires_types_test(env, targets): env, requires_not_none = "abc", requires_none = "def", - args = [raw_string("--foo")], + args = ["--foo"], expr = "mutually_exclusive", ).err().equals(REQUIRES_MUTUALLY_EXCLUSIVE_ERR) _expect_that_nested( env, requires_none = "var", - args = [raw_string("--foo")], + args = ["--foo"], expr = "requires_none", ).ok().requires_types().contains_exactly( {"var": [struct( @@ -150,13 +165,8 @@ def _requires_types_test(env, targets): _expect_that_nested( env, - args = [raw_string("foo %s baz")], - expr = "no_variable", - ).err().contains("Can't use %s with a raw string") - - _expect_that_nested( - env, - args = [format_arg("foo %s baz", targets.foo[VariableInfo])], + args = ["foo {foo} baz"], + format = {targets.foo: "foo"}, expr = "type_validation", ).ok().requires_types().contains_exactly( {"foo": [struct( @@ -170,7 +180,8 @@ def _requires_types_test(env, targets): env, requires_equal = "foo", requires_equal_value = "value", - args = [format_arg("--foo=%s", targets.foo[VariableInfo])], + args = ["--foo={foo}"], + format = {targets.foo: "foo"}, expr = "type_and_requires_equal_validation", ).ok() nested.requires_types().contains_exactly( @@ -194,12 +205,13 @@ def _requires_types_test(env, targets): TARGETS = [ ":foo", + ":my_list", + "//tests/rule_based_toolchain/testdata:directory", + "//tests/rule_based_toolchain/testdata:bin_wrapper", ] TESTS = { - "format_string_indexes_test": _format_string_indexes_test, - "formats_raw_strings_test": _formats_raw_strings_test, - "formats_variables_test": _formats_variables_test, + "format_args_test": _format_args_test, "iterate_over_test": _iterate_over_test, "requires_types_test": _requires_types_test, } diff --git a/tests/rule_based_toolchain/variables/BUILD b/tests/rule_based_toolchain/variables/BUILD index 5f7a5a6..2e9d480 100644 --- a/tests/rule_based_toolchain/variables/BUILD +++ b/tests/rule_based_toolchain/variables/BUILD @@ -1,4 +1,3 @@ -load("//cc/toolchains:format.bzl", "format_arg") load("//cc/toolchains:nested_args.bzl", "cc_nested_args") load("//cc/toolchains/impl:variables.bzl", "cc_builtin_variables", "cc_variable", "types") load("//tests/rule_based_toolchain:analysis_test_suite.bzl", "analysis_test_suite") @@ -56,17 +55,19 @@ alias( cc_nested_args( name = "simple_str", - args = [format_arg("%s", ":str")], + args = ["{str}"], + format = {"str": ":str"}, ) cc_nested_args( name = "list_not_allowed", - args = [format_arg("%s", ":str_list")], + args = ["{s}"], + format = {"s": ":str_list"}, ) cc_nested_args( name = "iterate_over_list", - args = [format_arg("%s")], + args = ["{}"], iterate_over = ":str_list", ) @@ -91,7 +92,7 @@ cc_nested_args( cc_nested_args( name = "inner_iter", - args = [format_arg("%s")], + args = ["{}"], iterate_over = ":struct_list.nested_str_list", ) @@ -103,7 +104,8 @@ cc_nested_args( cc_nested_args( name = "bad_inner_iter", - args = [format_arg("%s", ":struct_list.nested_str_list")], + args = ["{s}"], + format = {"s": ":struct_list.nested_str_list"}, ) cc_nested_args( @@ -114,12 +116,14 @@ cc_nested_args( cc_nested_args( name = "bad_nested_optional", - args = [format_arg("%s", ":str_option")], + args = ["{s}"], + format = {"s": ":str_option"}, ) cc_nested_args( name = "good_nested_optional", - args = [format_arg("%s", ":str_option")], + args = ["{s}"], + format = {"s": ":str_option"}, requires_not_none = ":str_option", ) @@ -141,6 +145,13 @@ cc_builtin_variables( ], ) +cc_builtin_variables( + name = "nested_variables", + srcs = [ + ":struct_list.nested_str_list", + ], +) + analysis_test_suite( name = "test_suite", targets = TARGETS,