Commit 8ca5c09b authored by Julie Hockett's avatar Julie Hockett Committed by Commit Bot

[gn] Updating args --list to emit json

Updates the gn args --list command with an additional --json flag, which
emits the same information as the normal --list command but in json
format.

Intended to be used to generate structured documentation for GN build
arguments. The --markdown output is nice, but we want to do more
processing than that to get it into good shape to integrate with our docs.

Also updates the GetContextForValue function to get the file and the
line number separately, rather than as one string, and updates the
callsites with the new parameters.

Change-Id: Id1240c37f835a18a12a6e4f5be58b9f8c7a663d1
Reviewed-on: https://chromium-review.googlesource.com/978423
Commit-Queue: Julie Hockett <juliehockett@google.com>
Reviewed-by: default avatarRoland McGrath <mcgrathr@chromium.org>
Reviewed-by: default avatarDirk Pranke <dpranke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#547759}
parent a6aadcce
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/environment.h" #include "base/environment.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/json/json_writer.h"
#include "base/process/launch.h" #include "base/process/launch.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
...@@ -37,6 +38,7 @@ namespace { ...@@ -37,6 +38,7 @@ namespace {
const char kSwitchList[] = "list"; const char kSwitchList[] = "list";
const char kSwitchShort[] = "short"; const char kSwitchShort[] = "short";
const char kSwitchOverridesOnly[] = "overrides-only"; const char kSwitchOverridesOnly[] = "overrides-only";
const char kSwitchJson[] = "json";
bool DoesLineBeginWithComment(const base::StringPiece& line) { bool DoesLineBeginWithComment(const base::StringPiece& line) {
// Skip whitespace. // Skip whitespace.
...@@ -76,14 +78,15 @@ std::string StripHashFromLine(const base::StringPiece& line) { ...@@ -76,14 +78,15 @@ std::string StripHashFromLine(const base::StringPiece& line) {
// Tries to find the comment before the setting of the given value. // Tries to find the comment before the setting of the given value.
void GetContextForValue(const Value& value, void GetContextForValue(const Value& value,
std::string* location_str, std::string* location_str,
int* line_no,
std::string* comment) { std::string* comment) {
Location location = value.origin()->GetRange().begin(); Location location = value.origin()->GetRange().begin();
const InputFile* file = location.file(); const InputFile* file = location.file();
if (!file) if (!file)
return; return;
*location_str = file->name().value() + ":" + *location_str = file->name().value();
base::IntToString(location.line_number()); *line_no = location.line_number();
const std::string& data = file->contents(); const std::string& data = file->contents();
size_t line_off = size_t line_off =
...@@ -112,9 +115,11 @@ void GetContextForValue(const Value& value, ...@@ -112,9 +115,11 @@ void GetContextForValue(const Value& value,
void PrintDefaultValueInfo(base::StringPiece name, const Value& value) { void PrintDefaultValueInfo(base::StringPiece name, const Value& value) {
OutputString(value.ToString(true) + "\n"); OutputString(value.ToString(true) + "\n");
if (value.origin()) { if (value.origin()) {
int line_no;
std::string location, comment; std::string location, comment;
GetContextForValue(value, &location, &comment); GetContextForValue(value, &location, &line_no, &comment);
OutputString(" From " + location + "\n"); OutputString(" From " + location + ":" + base::IntToString(line_no) +
"\n");
if (!comment.empty()) if (!comment.empty())
OutputString("\n" + comment); OutputString("\n" + comment);
} else { } else {
...@@ -134,9 +139,11 @@ void PrintArgHelp(const base::StringPiece& name, ...@@ -134,9 +139,11 @@ void PrintArgHelp(const base::StringPiece& name,
OutputString(" Current value = " + val.override_value.ToString(true) + OutputString(" Current value = " + val.override_value.ToString(true) +
"\n"); "\n");
if (val.override_value.origin()) { if (val.override_value.origin()) {
int line_no;
std::string location, comment; std::string location, comment;
GetContextForValue(val.override_value, &location, &comment); GetContextForValue(val.override_value, &location, &line_no, &comment);
OutputString(" From " + location + "\n"); OutputString(" From " + location + ":" + base::IntToString(line_no)
+ "\n");
} }
OutputString(" Overridden from the default = "); OutputString(" Overridden from the default = ");
PrintDefaultValueInfo(name, val.default_value); PrintDefaultValueInfo(name, val.default_value);
...@@ -147,6 +154,57 @@ void PrintArgHelp(const base::StringPiece& name, ...@@ -147,6 +154,57 @@ void PrintArgHelp(const base::StringPiece& name,
} }
} }
void BuildArgJson(base::Value& dict,
const base::StringPiece& name,
const Args::ValueWithOverride& arg,
bool short_only) {
assert(dict.is_dict());
// Fetch argument name.
dict.SetKey("name", base::Value(name));
// Fetch overridden value inforrmation (if present).
if (arg.has_override) {
base::DictionaryValue override_dict;
override_dict.SetKey("value",
base::Value(arg.override_value.ToString(true)));
if (arg.override_value.origin() && !short_only) {
int line_no;
std::string location, comment;
GetContextForValue(arg.override_value, &location, &line_no, &comment);
// Omit file and line if set with --args (i.e. no file)
if (!location.empty()) {
override_dict.SetKey("file", base::Value(location));
override_dict.SetKey("line", base::Value(line_no));
}
}
dict.SetKey("current", std::move(override_dict));
}
// Fetch default value information, and comment (if present).
base::DictionaryValue default_dict;
std::string comment;
default_dict.SetKey("value", base::Value(arg.default_value.ToString(true)));
if (arg.default_value.origin() && !short_only) {
int line_no;
std::string location;
GetContextForValue(arg.default_value, &location, &line_no, &comment);
// Only emit file and line if the value is overridden.
if (arg.has_override) {
default_dict.SetKey("file", base::Value(location));
default_dict.SetKey("line", base::Value(line_no));
}
}
dict.SetKey("default", std::move(default_dict));
if (!comment.empty() && !short_only)
dict.SetKey("comment", base::Value(comment));
std::string s;
base::JSONWriter::WriteWithOptions(
dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &s);
OutputString(s);
}
int ListArgs(const std::string& build_dir) { int ListArgs(const std::string& build_dir) {
Setup* setup = new Setup; Setup* setup = new Setup;
if (!setup->DoSetup(build_dir, false) || !setup->Run()) if (!setup->DoSetup(build_dir, false) || !setup->Run())
...@@ -175,8 +233,26 @@ int ListArgs(const std::string& build_dir) { ...@@ -175,8 +233,26 @@ int ListArgs(const std::string& build_dir) {
// Cache this to avoid looking it up for each |arg| in the loops below. // Cache this to avoid looking it up for each |arg| in the loops below.
const bool overrides_only = const bool overrides_only =
base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchOverridesOnly); base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchOverridesOnly);
const bool short_only =
base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchShort);
if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchJson)) {
// Convert all args to JSON, serialize and print them
auto list = std::make_unique<base::ListValue>();
for (const auto& arg : args) {
if (overrides_only && !arg.second.has_override)
continue;
list->GetList().emplace_back(base::DictionaryValue());
BuildArgJson(list->GetList().back(), arg.first, arg.second, short_only);
}
std::string s;
base::JSONWriter::WriteWithOptions(
*list.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &s);
OutputString(s);
return 0;
}
if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchShort)) { if (short_only) {
// Short <key>=<current_value> output. // Short <key>=<current_value> output.
for (const auto& arg : args) { for (const auto& arg : args) {
if (overrides_only && !arg.second.has_override) if (overrides_only && !arg.second.has_override)
...@@ -354,7 +430,7 @@ Usage ...@@ -354,7 +430,7 @@ Usage
Note: you can edit the build args manually by editing the file "args.gn" Note: you can edit the build args manually by editing the file "args.gn"
in the build directory and then running "gn gen <out_dir>". in the build directory and then running "gn gen <out_dir>".
gn args <out_dir> --list[=<exact_arg>] [--short] [--overrides-only] gn args <out_dir> --list[=<exact_arg>] [--short] [--overrides-only] [--json]
Lists all build arguments available in the current configuration, or, if Lists all build arguments available in the current configuration, or, if
an exact_arg is specified for the list flag, just that one build an exact_arg is specified for the list flag, just that one build
argument. argument.
...@@ -370,6 +446,25 @@ Usage ...@@ -370,6 +446,25 @@ Usage
arguments that have been overridden (i.e. non-default arguments) will arguments that have been overridden (i.e. non-default arguments) will
be printed. Overrides come from the <out_dir>/args.gn file and //.gn be printed. Overrides come from the <out_dir>/args.gn file and //.gn
If --json is specified, the output will be emitted in json format.
JSON schema for output:
[
{
"name": variable_name,
"current": {
"value": overridden_value,
"file": file_name,
"line": line_no
},
"default": {
"value": default_value,
"file": file_name,
"line": line_no
},
"comment": comment_string
},
...
]
Examples Examples
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment