Add ninja console pool support to GN
Allow GN actions to specify "console = true", which will translate into a "pool = console" setting in the generated ninja files. The console pool allows a ninja target to have unbuffered io, access to standard input, and is limited to one target at a time. R=brettw@chromium.org BUG= Review URL: https://codereview.chromium.org/1358803002 Cr-Commit-Position: refs/heads/master@{#350321}
This commit is contained in:
@ -54,6 +54,9 @@ void ActionTargetGenerator::DoRun() {
|
||||
if (!FillDepfile())
|
||||
return;
|
||||
|
||||
if (!FillConsole())
|
||||
return;
|
||||
|
||||
if (!FillCheckIncludes())
|
||||
return;
|
||||
|
||||
@ -107,6 +110,16 @@ bool ActionTargetGenerator::FillDepfile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ActionTargetGenerator::FillConsole() {
|
||||
const Value* value = scope_->GetValue(variables::kConsole, true);
|
||||
if (!value)
|
||||
return true;
|
||||
if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
|
||||
return false;
|
||||
target_->action_values().set_console(value->boolean_value());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ActionTargetGenerator::CheckOutputs() {
|
||||
const SubstitutionList& outputs = target_->action_values().outputs();
|
||||
if (outputs.list().empty()) {
|
||||
|
@ -26,6 +26,7 @@ class ActionTargetGenerator : public TargetGenerator {
|
||||
bool FillScript();
|
||||
bool FillScriptArgs();
|
||||
bool FillDepfile();
|
||||
bool FillConsole();
|
||||
|
||||
// Checks for errors in the outputs variable.
|
||||
bool CheckOutputs();
|
||||
|
@ -8,11 +8,9 @@
|
||||
#include "tools/gn/substitution_writer.h"
|
||||
#include "tools/gn/target.h"
|
||||
|
||||
ActionValues::ActionValues() {
|
||||
}
|
||||
ActionValues::ActionValues() : console_(false) {}
|
||||
|
||||
ActionValues::~ActionValues() {
|
||||
}
|
||||
ActionValues::~ActionValues() {}
|
||||
|
||||
void ActionValues::GetOutputsAsSourceFiles(
|
||||
const Target* target,
|
||||
|
@ -43,11 +43,16 @@ class ActionValues {
|
||||
bool has_depfile() const { return !depfile_.ranges().empty(); }
|
||||
void set_depfile(const SubstitutionPattern& depfile) { depfile_ = depfile; }
|
||||
|
||||
// Console pool option
|
||||
bool is_console() const { return console_; }
|
||||
void set_console(bool value) { console_ = value; }
|
||||
|
||||
private:
|
||||
SourceFile script_;
|
||||
SubstitutionList args_;
|
||||
SubstitutionList outputs_;
|
||||
SubstitutionPattern depfile_;
|
||||
bool console_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ActionValues);
|
||||
};
|
||||
|
@ -127,7 +127,7 @@ const char kAction_Help[] =
|
||||
"\n"
|
||||
"Variables\n"
|
||||
"\n"
|
||||
" args, data, data_deps, depfile, deps, outputs*, script*,\n"
|
||||
" args, console, data, data_deps, depfile, deps, outputs*, script*,\n"
|
||||
" inputs, sources\n"
|
||||
" * = required\n"
|
||||
"\n"
|
||||
@ -198,7 +198,7 @@ const char kActionForEach_Help[] =
|
||||
"\n"
|
||||
"Variables\n"
|
||||
"\n"
|
||||
" args, data, data_deps, depfile, deps, outputs*, script*,\n"
|
||||
" args, console, data, data_deps, depfile, deps, outputs*, script*,\n"
|
||||
" inputs, sources*\n"
|
||||
" * = required\n"
|
||||
"\n"
|
||||
|
@ -74,6 +74,10 @@ void NinjaActionTargetWriter::Run() {
|
||||
WriteDepfile(SourceFile());
|
||||
out_ << std::endl;
|
||||
}
|
||||
if (target_->action_values().is_console()) {
|
||||
out_ << " pool = console";
|
||||
out_ << std::endl;
|
||||
}
|
||||
}
|
||||
out_ << std::endl;
|
||||
|
||||
|
@ -76,6 +76,49 @@ TEST(NinjaActionTargetWriter, ActionNoSources) {
|
||||
EXPECT_EQ(expected, out.str());
|
||||
}
|
||||
|
||||
|
||||
// Tests an action with no sources and console = true
|
||||
TEST(NinjaActionTargetWriter, ActionNoSourcesConsole) {
|
||||
TestWithScope setup;
|
||||
Err err;
|
||||
|
||||
setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
|
||||
Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
|
||||
target.set_output_type(Target::ACTION);
|
||||
|
||||
target.action_values().set_script(SourceFile("//foo/script.py"));
|
||||
target.inputs().push_back(SourceFile("//foo/included.txt"));
|
||||
|
||||
target.action_values().outputs() =
|
||||
SubstitutionList::MakeForTest("//out/Debug/foo.out");
|
||||
target.action_values().set_console(true);
|
||||
|
||||
target.SetToolchain(setup.toolchain());
|
||||
ASSERT_TRUE(target.OnResolved(&err));
|
||||
|
||||
setup.settings()->set_target_os(Settings::LINUX);
|
||||
setup.build_settings()->set_python_path(base::FilePath(FILE_PATH_LITERAL(
|
||||
"/usr/bin/python")));
|
||||
|
||||
std::ostringstream out;
|
||||
NinjaActionTargetWriter writer(&target, out);
|
||||
writer.Run();
|
||||
|
||||
const char expected[] =
|
||||
"rule __foo_bar___rule\n"
|
||||
" command = /usr/bin/python ../../foo/script.py\n"
|
||||
" description = ACTION //foo:bar()\n"
|
||||
" restat = 1\n"
|
||||
"build obj/foo/bar.inputdeps.stamp: stamp ../../foo/script.py "
|
||||
"../../foo/included.txt\n"
|
||||
"\n"
|
||||
"build foo.out: __foo_bar___rule | obj/foo/bar.inputdeps.stamp\n"
|
||||
" pool = console\n"
|
||||
"\n"
|
||||
"build obj/foo/bar.stamp: stamp foo.out\n";
|
||||
EXPECT_EQ(expected, out.str());
|
||||
}
|
||||
|
||||
// Makes sure that we write sources as input dependencies for actions with
|
||||
// both sources and inputs (ACTION_FOREACH treats the sources differently).
|
||||
TEST(NinjaActionTargetWriter, ActionWithSources) {
|
||||
|
@ -574,6 +574,29 @@ const char kConfigs_Help[] =
|
||||
" }\n"
|
||||
" }\n";
|
||||
|
||||
const char kConsole[] = "console";
|
||||
const char kConsole_HelpShort[] =
|
||||
"console [boolean]: Run this action in the console pool.";
|
||||
const char kConsole_Help[] =
|
||||
"console: Run this action in the console pool.\n"
|
||||
"\n"
|
||||
" Boolean. Defaults to false.\n"
|
||||
"\n"
|
||||
" Actions marked \"console = true\" will be run in the built-in ninja\n"
|
||||
" \"console\" pool. They will have access to real stdin and stdout, and\n"
|
||||
" output will not be buffered by ninja. This can be useful for\n"
|
||||
" long-running actions with progress logs, or actions that require user \n"
|
||||
" input.\n"
|
||||
"\n"
|
||||
" Only one console pool target can run at any one time in Ninja. Refer\n"
|
||||
" to the Ninja documentation on the console pool for more info.\n"
|
||||
"\n"
|
||||
"Example\n"
|
||||
"\n"
|
||||
" action(\"long_action_with_progress_logs\") {\n"
|
||||
" console = true\n"
|
||||
" }\n";
|
||||
|
||||
const char kData[] = "data";
|
||||
const char kData_HelpShort[] =
|
||||
"data: [file list] Runtime data file dependencies.";
|
||||
@ -1246,6 +1269,7 @@ const VariableInfoMap& GetTargetVariables() {
|
||||
INSERT_VARIABLE(CheckIncludes)
|
||||
INSERT_VARIABLE(CompleteStaticLib)
|
||||
INSERT_VARIABLE(Configs)
|
||||
INSERT_VARIABLE(Console)
|
||||
INSERT_VARIABLE(Data)
|
||||
INSERT_VARIABLE(DataDeps)
|
||||
INSERT_VARIABLE(Defines)
|
||||
|
@ -115,6 +115,10 @@ extern const char kConfigs[];
|
||||
extern const char kConfigs_HelpShort[];
|
||||
extern const char kConfigs_Help[];
|
||||
|
||||
extern const char kConsole[];
|
||||
extern const char kConsole_HelpShort[];
|
||||
extern const char kConsole_Help[];
|
||||
|
||||
extern const char kData[];
|
||||
extern const char kData_HelpShort[];
|
||||
extern const char kData_Help[];
|
||||
|
Reference in New Issue
Block a user