Add commands::CommandSwitches class
This class is used to model the command-line switches
that appear in various GN commands, as a set of boolean,
enum or string values, which can be swapped as a whole
globally (which might be useful when implementing a REPL
in GN in the future, since each command evaluation may
need a different set of switches then).
A future CL will modify the command implementation functions
to use the methods on this class, instead of peeking directly
into the current process' base::CommandLine value.
Bug: None
Change-Id: I240778abf9a5e4fba4760f5ca81eb84cebf2c1c8
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/12862
Reviewed-by: Brett Wilson <brettw@chromium.org>
Reviewed-by: David Turner <digit@google.com>
Commit-Queue: David Turner <digit@google.com>
diff --git a/src/gn/commands.cc b/src/gn/commands.cc
index 24a16b1..a5f2ca9 100644
--- a/src/gn/commands.cc
+++ b/src/gn/commands.cc
@@ -19,6 +19,7 @@
#include "gn/label_pattern.h"
#include "gn/setup.h"
#include "gn/standard_out.h"
+#include "gn/switches.h"
#include "gn/target.h"
#include "util/build_config.h"
@@ -127,45 +128,12 @@
return true;
}
-enum TargetPrintingMode {
- TARGET_PRINT_BUILDFILE,
- TARGET_PRINT_LABEL,
- TARGET_PRINT_OUTPUT,
-};
-
// Retrieves the target printing mode based on the command line flags for the
// current process. Returns true on success. On error, prints a message to the
// console and returns false.
-bool GetTargetPrintingMode(TargetPrintingMode* mode) {
- std::string switch_key = "as";
- const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
-
- if (!cmdline->HasSwitch(switch_key)) {
- // Default to labels.
- *mode = TARGET_PRINT_LABEL;
- return true;
- }
-
- std::string value = cmdline->GetSwitchValueASCII(switch_key);
- if (value == "buildfile") {
- *mode = TARGET_PRINT_BUILDFILE;
- return true;
- }
- if (value == "label") {
- *mode = TARGET_PRINT_LABEL;
- return true;
- }
- if (value == "output") {
- *mode = TARGET_PRINT_OUTPUT;
- return true;
- }
-
- Err(Location(), "Invalid value for \"--as\".",
- "I was expecting \"buildfile\", \"label\", or \"output\" but you\n"
- "said \"" +
- value + "\".")
- .PrintToStdout();
- return false;
+bool GetTargetPrintingMode(CommandSwitches::TargetPrintMode* mode) {
+ *mode = CommandSwitches::Get().target_print_mode();
+ return true;
}
// Returns the target type filter based on the command line flags for the
@@ -176,72 +144,20 @@
// will never be returned. Code applying the filters should apply Target::ACTION
// to both ACTION and ACTION_FOREACH.
bool GetTargetTypeFilter(Target::OutputType* type) {
- std::string switch_key = "type";
- const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
-
- if (!cmdline->HasSwitch(switch_key)) {
- // Default to unknown -> no filtering.
- *type = Target::UNKNOWN;
- return true;
- }
-
- std::string value = cmdline->GetSwitchValueASCII(switch_key);
- if (value == "group") {
- *type = Target::GROUP;
- return true;
- }
- if (value == "executable") {
- *type = Target::EXECUTABLE;
- return true;
- }
- if (value == "shared_library") {
- *type = Target::SHARED_LIBRARY;
- return true;
- }
- if (value == "loadable_module") {
- *type = Target::LOADABLE_MODULE;
- return true;
- }
- if (value == "static_library") {
- *type = Target::STATIC_LIBRARY;
- return true;
- }
- if (value == "source_set") {
- *type = Target::SOURCE_SET;
- return true;
- }
- if (value == "copy") {
- *type = Target::COPY_FILES;
- return true;
- }
- if (value == "action") {
- *type = Target::ACTION;
- return true;
- }
-
- Err(Location(), "Invalid value for \"--type\".").PrintToStdout();
- return false;
+ *type = CommandSwitches::Get().target_type();
+ return true;
}
// Applies any testonly filtering specified on the command line to the given
// target set. On failure, prints an error and returns false.
bool ApplyTestonlyFilter(std::vector<const Target*>* targets) {
- const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
- std::string testonly_key = "testonly";
+ CommandSwitches::TestonlyMode testonly_mode =
+ CommandSwitches::Get().testonly_mode();
- if (targets->empty() || !cmdline->HasSwitch(testonly_key))
+ if (targets->empty() || testonly_mode == CommandSwitches::TESTONLY_NONE)
return true;
- std::string testonly_value = cmdline->GetSwitchValueASCII(testonly_key);
- bool testonly = false;
- if (testonly_value == "true") {
- testonly = true;
- } else if (testonly_value != "false") {
- Err(Location(), "Bad value for --testonly.",
- "I was expecting --testonly=true or --testonly=false.")
- .PrintToStdout();
- return false;
- }
+ bool testonly = (testonly_mode == CommandSwitches::TESTONLY_TRUE);
// Filter into a copy of the vector, then replace the output.
std::vector<const Target*> result;
@@ -438,13 +354,119 @@
INSERT_COMMAND(Outputs)
INSERT_COMMAND(Path)
INSERT_COMMAND(Refs)
- INSERT_COMMAND(CleanStale);
+ INSERT_COMMAND(CleanStale)
#undef INSERT_COMMAND
}
return info_map;
}
+// static
+CommandSwitches CommandSwitches::s_global_switches_ = {};
+
+// static
+bool CommandSwitches::Init(const base::CommandLine& cmdline) {
+ return s_global_switches_.InitFrom(cmdline);
+}
+
+// static
+const CommandSwitches& CommandSwitches::Get() {
+ return s_global_switches_;
+}
+
+// static
+CommandSwitches CommandSwitches::Set(CommandSwitches new_switches) {
+ CommandSwitches result = std::move(s_global_switches_);
+ s_global_switches_ = std::move(new_switches);
+ return result;
+}
+
+bool CommandSwitches::InitFrom(const base::CommandLine& cmdline) {
+ CommandSwitches result;
+ result.has_quiet_ = cmdline.HasSwitch("a");
+ result.has_force_ = cmdline.HasSwitch("force");
+ result.has_all_ = cmdline.HasSwitch("all");
+ result.has_blame_ = cmdline.HasSwitch("blame");
+ result.has_tree_ = cmdline.HasSwitch("tree");
+ result.has_format_json_ = cmdline.GetSwitchValueASCII("format") == "json";
+ result.has_default_toolchain_ =
+ cmdline.HasSwitch(switches::kDefaultToolchain);
+
+ result.has_check_generated_ = cmdline.HasSwitch("check-generated");
+ result.has_check_system_ = cmdline.HasSwitch("check-system");
+ result.has_public_ = cmdline.HasSwitch("public");
+ result.has_with_data_ = cmdline.HasSwitch("with-data");
+
+ std::string_view target_print_switch = "as";
+ if (cmdline.HasSwitch(target_print_switch)) {
+ std::string value = cmdline.GetSwitchValueASCII(target_print_switch);
+ if (value == "buildfile") {
+ result.target_print_mode_ = TARGET_PRINT_BUILDFILE;
+ } else if (value == "label") {
+ result.target_print_mode_ = TARGET_PRINT_LABEL;
+ } else if (value == "output") {
+ result.target_print_mode_ = TARGET_PRINT_OUTPUT;
+ } else {
+ Err(Location(), "Invalid value for \"--as\".",
+ "I was expecting \"buildfile\", \"label\", or \"output\" but you\n"
+ "said \"" +
+ value + "\".")
+ .PrintToStdout();
+ return false;
+ }
+ }
+
+ std::string_view target_type_switch = "type";
+ if (cmdline.HasSwitch(target_type_switch)) {
+ std::string value = cmdline.GetSwitchValueASCII(target_type_switch);
+ static const struct {
+ const char* name;
+ Target::OutputType type;
+ } kTypes[] = {
+ {"group", Target::GROUP},
+ {"executable", Target::EXECUTABLE},
+ {"shared_library", Target::SHARED_LIBRARY},
+ {"loadable_module", Target::LOADABLE_MODULE},
+ {"static_library", Target::STATIC_LIBRARY},
+ {"source_set", Target::SOURCE_SET},
+ {"copy", Target::COPY_FILES},
+ {"action", Target::ACTION},
+ };
+ bool found = false;
+ for (const auto& type : kTypes) {
+ if (value == type.name) {
+ result.target_type_ = type.type;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ Err(Location(), "Invalid value for \"--type\".").PrintToStdout();
+ return false;
+ }
+ }
+ std::string_view testonly_switch = "testonly";
+ if (cmdline.HasSwitch(testonly_switch)) {
+ std::string value = cmdline.GetSwitchValueASCII(testonly_switch);
+ if (value == "true") {
+ testonly_mode_ = TESTONLY_TRUE;
+ } else if (value == "false") {
+ testonly_mode_ = TESTONLY_FALSE;
+ } else {
+ Err(Location(), "Bad value for --testonly.",
+ "I was expecting --testonly=true or --testonly=false.")
+ .PrintToStdout();
+ return false;
+ }
+ }
+
+ result.meta_rebase_dir_ = cmdline.GetSwitchValueASCII("rebase");
+ result.meta_data_keys_ = cmdline.GetSwitchValueASCII("data");
+ result.meta_walk_keys_ = cmdline.GetSwitchValueASCII("walk");
+ *this = result;
+ return true;
+}
+
const Target* ResolveTargetFromCommandLineString(
Setup* setup,
const std::string& label_string) {
@@ -583,17 +605,18 @@
if (!ApplyTypeFilter(targets))
return;
- TargetPrintingMode printing_mode = TARGET_PRINT_LABEL;
+ CommandSwitches::TargetPrintMode printing_mode =
+ CommandSwitches::TARGET_PRINT_LABEL;
if (targets->empty() || !GetTargetPrintingMode(&printing_mode))
return;
switch (printing_mode) {
- case TARGET_PRINT_BUILDFILE:
+ case CommandSwitches::TARGET_PRINT_BUILDFILE:
PrintTargetsAsBuildfiles(*targets, out);
break;
- case TARGET_PRINT_LABEL:
+ case CommandSwitches::TARGET_PRINT_LABEL:
PrintTargetsAsLabels(*targets, out);
break;
- case TARGET_PRINT_OUTPUT:
+ case CommandSwitches::TARGET_PRINT_OUTPUT:
PrintTargetsAsOutputs(*targets, out);
break;
}
diff --git a/src/gn/commands.h b/src/gn/commands.h
index 4824b79..049ff85 100644
--- a/src/gn/commands.h
+++ b/src/gn/commands.h
@@ -23,6 +23,10 @@
class Target;
class Toolchain;
+namespace base {
+class CommandLine;
+} // namespace base
+
// Each "Run" command returns the value we should return from main().
namespace commands {
@@ -116,6 +120,120 @@
const CommandInfoMap& GetCommands();
+// Command switches as flags and enums -----------------------------------------
+
+// A class that models a set of command-line flags and values that
+// can affect the output of various GN commands. For example --tree
+// can be used with `gn desc <out_dir> <label> deps --tree`.
+//
+// Each flag or value is checked by an accessor method which returns
+// a boolean or an enum.
+//
+// Use CommandSwitches::Get() to get a reference to the current
+// global set of switches for the process.
+//
+// Use CommandSwitches::Set() to update its value. This may be
+// useful when implementing a REPL in GN, where each evaluation
+// might need a different set of command switches.
+class CommandSwitches {
+ public:
+ // Default constructor.
+ CommandSwitches() = default;
+
+ // For --quiet, used by `refs`.
+ bool has_quiet() const { return has_quiet_; }
+
+ // For --force, used by `check`.
+ bool has_force() const { return has_force_; }
+
+ // For --all, used by `desc` and `refs`.
+ bool has_all() const { return has_all_; }
+
+ // For --blame used by `desc`.
+ bool has_blame() const { return has_blame_; }
+
+ // For --tree used by `desc` and `refs`.
+ bool has_tree() const { return has_tree_; }
+
+ // For --format=json used by `desc`.
+ bool has_format_json() const { return has_format_json_; }
+
+ // For --default-toolchain used by `desc`, `refs`.
+ bool has_default_toolchain() const { return has_default_toolchain_; }
+
+ // For --check-generated
+ bool has_check_generated() const { return has_check_generated_; }
+
+ // For --check-system
+ bool has_check_system() const { return has_check_system_; }
+
+ // For --public
+ bool has_public() const { return has_public_; }
+
+ // For --with-data
+ bool has_with_data() const { return has_with_data_; }
+
+ // For --as=(buildtype|label|output).
+ enum TargetPrintMode {
+ TARGET_PRINT_BUILDFILE,
+ TARGET_PRINT_LABEL,
+ TARGET_PRINT_OUTPUT,
+ };
+ TargetPrintMode target_print_mode() const { return target_print_mode_; }
+
+ // For --type=TARGET_TYPE
+ Target::OutputType target_type() const { return target_type_; }
+
+ enum TestonlyMode {
+ TESTONLY_NONE, // no --testonly used.
+ TESTONLY_FALSE, // --testonly=false
+ TESTONLY_TRUE, // --testonly=true
+ };
+ TestonlyMode testonly_mode() const { return testonly_mode_; }
+
+ // For --rebase, --walk and --data in `gn meta`
+ std::string meta_rebase_dir() const { return meta_rebase_dir_; }
+ std::string meta_data_keys() const { return meta_data_keys_; }
+ std::string meta_walk_keys() const { return meta_walk_keys_; }
+
+ // Initialize the global set from a given command line.
+ // Must be called early from main(). On success return true,
+ // on failure return false after printing an error message.
+ static bool Init(const base::CommandLine& cmdline);
+
+ // Retrieve a reference to the current global set of command switches.
+ static const CommandSwitches& Get();
+
+ // Change the current global set of command switches, and return
+ // the previous value.
+ static CommandSwitches Set(CommandSwitches new_switches);
+
+ private:
+ bool InitFrom(const base::CommandLine&);
+
+ static CommandSwitches s_global_switches_;
+
+ bool has_quiet_ = false;
+ bool has_force_ = false;
+ bool has_all_ = false;
+ bool has_blame_ = false;
+ bool has_tree_ = false;
+ bool has_format_json_ = false;
+ bool has_default_toolchain_ = false;
+ bool has_check_generated_ = false;
+ bool has_check_system_ = false;
+ bool has_public_ = false;
+ bool has_with_data_ = false;
+
+ TargetPrintMode target_print_mode_ = TARGET_PRINT_LABEL;
+ Target::OutputType target_type_ = Target::UNKNOWN;
+ TestonlyMode testonly_mode_ = TESTONLY_NONE;
+
+ std::string meta_rebase_dir_;
+ std::string meta_data_keys_;
+ std::string meta_walk_keys_;
+};
+
// Helper functions for some commands ------------------------------------------
// Given a setup that has already been run and some command-line input,