0

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:
tsniatowski
2015-09-22 23:44:15 -07:00
committed by Commit bot
parent e732db5866
commit b52c507ecb
9 changed files with 98 additions and 6 deletions

@ -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[];