Add option to supply multiple comma-separated types in --type This refactors --type parsing in commands.cc to accept a comma-separated list of target types. The is needed to efficiently filter test targets in `autotest.py` script in Chromium: http://crrev.com/c/8139431 Bug: 534608615 Change-Id: Iea625b69218583734b4ea4786788168e6a6a6964 Reviewed-on: https://gn-review.googlesource.com/c/gn/+/24360 Commit-Queue: Zgroza (Luke) Klimek <zgroza@chromium.org> Reviewed-by: Andrew Grieve <agrieve@google.com> Reviewed-by: Takuto Ikuta <tikuta@google.com>
diff --git a/docs/reference.md b/docs/reference.md index 3dcefac..75d3b42 100644 --- a/docs/reference.md +++ b/docs/reference.md
@@ -675,7 +675,8 @@ generated_file|group|loadable_module|rust_library| rust_proc_macro|shared_library|source_set|static_library) Restrict outputs to targets matching the given type. If - unspecified, no filtering will be performed. + unspecified, no filtering will be performed. You can specify + a comma-separated list of types to match multiple types. ``` #### **Note** @@ -1088,7 +1089,8 @@ generated_file|group|loadable_module|rust_library| rust_proc_macro|shared_library|source_set|static_library) Restrict outputs to targets matching the given type. If - unspecified, no filtering will be performed. + unspecified, no filtering will be performed. You can specify + a comma-separated list of types to match multiple types. ``` #### **Examples** @@ -1351,7 +1353,8 @@ generated_file|group|loadable_module|rust_library| rust_proc_macro|shared_library|source_set|static_library) Restrict outputs to targets matching the given type. If - unspecified, no filtering will be performed. + unspecified, no filtering will be performed. You can specify + a comma-separated list of types to match multiple types. --relation=(source|public|input|data|script|output) Restricts output to targets which refer to input files by a specific
diff --git a/src/gn/commands.cc b/src/gn/commands.cc index bae4c4a..a2cca9a 100644 --- a/src/gn/commands.cc +++ b/src/gn/commands.cc
@@ -145,11 +145,11 @@ // current process. Returns true on success. On error, prints a message to the // console and returns false. // -// Target::UNKNOWN will be set if there is no filter. Target::ACTION_FOREACH +// The vector will be empty if there is no filter. Target::ACTION_FOREACH // will never be returned. Code applying the filters should apply Target::ACTION // to both ACTION and ACTION_FOREACH. -bool GetTargetTypeFilter(Target::OutputType* type) { - *type = CommandSwitches::Get().target_type(); +bool GetTargetTypeFilter(std::vector<Target::OutputType>* types) { + *types = CommandSwitches::Get().target_types(); return true; } @@ -180,10 +180,10 @@ // Applies any target type filtering specified on the command line to the given // target set. On failure, prints an error and returns false. bool ApplyTypeFilter(std::vector<const Target*>* targets) { - Target::OutputType type = Target::UNKNOWN; - if (!GetTargetTypeFilter(&type)) + std::vector<Target::OutputType> types; + if (!GetTargetTypeFilter(&types)) return false; - if (targets->empty() || type == Target::UNKNOWN) + if (targets->empty() || types.empty()) return true; // Nothing to filter out. // Filter into a copy of the vector, then replace the output. @@ -191,11 +191,14 @@ result.reserve(targets->size()); for (const Target* target : *targets) { - // Make "action" also apply to ACTION_FOREACH. - if (target->output_type() == type || - (type == Target::ACTION && - target->output_type() == Target::ACTION_FOREACH)) + if (std::ranges::any_of(types, [target](Target::OutputType type) { + // Make "action" also apply to ACTION_FOREACH. + return target->output_type() == type || + (type == Target::ACTION && + target->output_type() == Target::ACTION_FOREACH); + })) { result.push_back(target); + } } *targets = std::move(result); @@ -463,6 +466,8 @@ std::string_view target_type_switch = "type"; if (cmdline.HasSwitch(target_type_switch)) { std::string value = cmdline.GetSwitchValueString(target_type_switch); + std::vector<std::string> tokens = base::SplitString( + value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); static const struct { const char* name; Target::OutputType type; @@ -481,17 +486,20 @@ {"bundle_data", Target::BUNDLE_DATA}, {"create_bundle", Target::CREATE_BUNDLE}, }; - bool found = false; - for (const auto& type : kTypes) { - if (value == type.name) { - result.target_type_ = type.type; - found = true; - break; + for (const std::string& token : tokens) { + bool found = false; + for (const auto& type : kTypes) { + if (token == type.name) { + result.target_types_.push_back(type.type); + found = true; + break; + } } - } - if (!found) { - Err(Location(), "Invalid value for \"--type\".").PrintToStdout(); - return false; + if (!found) { + Err(Location(), "Invalid value \"" + token + "\" for \"--type\".") + .PrintToStdout(); + return false; + } } } std::string_view testonly_switch = "testonly";
diff --git a/src/gn/commands.h b/src/gn/commands.h index 9a996b1..27fd81e 100644 --- a/src/gn/commands.h +++ b/src/gn/commands.h
@@ -198,7 +198,9 @@ TargetPrintMode target_print_mode() const { return target_print_mode_; } // For --type=TARGET_TYPE - Target::OutputType target_type() const { return target_type_; } + const std::vector<Target::OutputType>& target_types() const { + return target_types_; + } enum TestonlyMode { TESTONLY_NONE, // no --testonly used. @@ -245,7 +247,7 @@ bool has_with_data_ = false; TargetPrintMode target_print_mode_ = TARGET_PRINT_LABEL; - Target::OutputType target_type_ = Target::UNKNOWN; + std::vector<Target::OutputType> target_types_; TestonlyMode testonly_mode_ = TESTONLY_NONE; std::string meta_rebase_dir_; @@ -365,7 +367,8 @@ " generated_file|group|loadable_module|rust_library|\n" \ " rust_proc_macro|shared_library|source_set|static_library)\n" \ " Restrict outputs to targets matching the given type. If\n" \ - " unspecified, no filtering will be performed.\n" + " unspecified, no filtering will be performed. You can specify\n" \ + " a comma-separated list of types to match multiple types.\n" #define TARGET_TESTONLY_FILTER_COMMAND_LINE_HELP \ " --testonly=(true|false)\n" \ " Restrict outputs to targets with the testonly flag set\n" \
diff --git a/src/gn/commands_unittest.cc b/src/gn/commands_unittest.cc index fe27816..eb95f68 100644 --- a/src/gn/commands_unittest.cc +++ b/src/gn/commands_unittest.cc
@@ -83,4 +83,30 @@ commands::CommandSwitches empty_switches; commands::CommandSwitches::Set(empty_switches); } + + // Test multiple types separated by a comma. + { + std::vector<const Target*> targets_to_filter = all_targets; + + base::CommandLine cmdline(base::CommandLine::NO_PROGRAM); + cmdline.AppendSwitch("type", "executable,rust_library"); + + commands::CommandSwitches::Init(cmdline); + + base::ListValue out; + commands::FilterAndPrintTargets(&targets_to_filter, &out); + + ASSERT_EQ(2u, targets_to_filter.size()); + EXPECT_TRUE( + std::ranges::any_of(targets_to_filter, [](const Target* target) { + return target->output_type() == Target::EXECUTABLE; + })); + EXPECT_TRUE( + std::ranges::any_of(targets_to_filter, [](const Target* target) { + return target->output_type() == Target::RUST_LIBRARY; + })); + + commands::CommandSwitches empty_switches; + commands::CommandSwitches::Set(empty_switches); + } }