launch_daemon: Added run directive.

* Allows to conditionally (or unconditionally) launch targets.
* Including tests for the settings parser.
* FirstBootPrompt is now launched when deemed necessary (as in
  the Bootscript).
This commit is contained in:
Axel Dörfler 2015-06-24 18:00:32 +02:00
parent d91addd24c
commit 004cd6709d
5 changed files with 268 additions and 7 deletions

View File

@ -1,9 +1,33 @@
service x-vnd.Be-TRAK {
launch /system/Tracker
legacy
target desktop {
service x-vnd.Be-TRAK {
launch /system/Tracker
legacy
}
service x-vnd.Be-TSKB {
launch /system/Deskbar
legacy
}
}
service x-vnd.Be-TSKB {
launch /system/Deskbar
legacy
target first_boot {
job x-vnd.Haiku-FirstBootPrompt {
launch /system/apps/FirstBootPrompt
legacy
}
}
run {
if {
or {
not file_exists /boot/home/config/settings/Locale\ settings
read_only
}
}
then {
first_boot
}
else {
desktop
}
}

View File

@ -93,6 +93,9 @@ private:
void _AddJobs(Target* target, BMessage& message);
void _AddTargets(BMessage& message);
void _AddRunTargets(BMessage& message);
void _AddRunTargets(BMessage& message,
const char* name);
void _AddJob(Target* target, bool service,
BMessage& message);
void _InitJobs();
@ -112,6 +115,7 @@ private:
private:
JobMap fJobs;
TargetMap fTargets;
BStringList fRunTargets;
JobQueue fJobQueue;
SessionMap fSessions;
MainWorker* fMainWorker;
@ -237,6 +241,13 @@ LaunchDaemon::ReadyToRun()
_InitJobs();
_LaunchJobs(NULL);
// Launch run targets
for (int32 index = 0; index < fRunTargets.CountStrings(); index++) {
Target* target = FindTarget(fRunTargets.StringAt(index));
if (target != NULL)
_LaunchJobs(target);
}
}
@ -457,6 +468,7 @@ LaunchDaemon::_ReadFile(const char* context, BEntry& entry)
if (status == B_OK) {
_AddJobs(NULL, message);
_AddTargets(message);
_AddRunTargets(message);
}
return status;
@ -516,6 +528,50 @@ LaunchDaemon::_AddTargets(BMessage& message)
}
void
LaunchDaemon::_AddRunTargets(BMessage& message)
{
BMessage runMessage;
for (int32 index = 0; message.FindMessage("run", index,
&runMessage) == B_OK; index++) {
BMessage conditions;
bool pass = true;
if (runMessage.FindMessage("if", &conditions) == B_OK) {
Condition* condition = Conditions::FromMessage(conditions);
if (condition != NULL) {
pass = condition->Test(*this);
debug_printf("Test: %s -> %d\n", condition->ToString().String(),
pass);
delete condition;
} else
debug_printf("Could not parse condition!\n");
}
if (pass) {
_AddRunTargets(runMessage, NULL);
_AddRunTargets(runMessage, "then");
} else {
_AddRunTargets(runMessage, "else");
}
}
}
void
LaunchDaemon::_AddRunTargets(BMessage& message, const char* name)
{
BMessage targets;
if (name != NULL && message.FindMessage(name, &targets) != B_OK)
return;
const char* target;
for (int32 index = 0; targets.FindString("target", index, &target) == B_OK;
index++) {
fRunTargets.Add(target);
}
}
void
LaunchDaemon::_AddJob(Target* target, bool service, BMessage& message)
{

View File

@ -74,6 +74,29 @@ private:
};
class RunConverter : public DriverSettingsConverter {
public:
status_t ConvertFromDriverSettings(const driver_parameter& parameter,
const char* name, int32 index, uint32 type, BMessage& target)
{
if (parameter.parameter_count == 0)
return target.AddString("target", parameter.values[index]);
return B_NOT_SUPPORTED;
}
status_t ConvertEmptyFromDriverSettings(
const driver_parameter& parameter, const char* name, uint32 type,
BMessage& target)
{
if (parameter.parameter_count != 0)
return B_OK;
return target.AddString("target", name);
}
};
const static settings_template kConditionTemplate[] = {
{B_STRING_TYPE, NULL, NULL, true, new ConditionConverter()},
{B_MESSAGE_TYPE, "not", kConditionTemplate},
@ -108,10 +131,24 @@ const static settings_template kTargetTemplate[] = {
{0, NULL, NULL}
};
const static settings_template kRunConditionalTemplate[] = {
{B_STRING_TYPE, NULL, NULL, true, new RunConverter()},
{0, NULL, NULL}
};
const static settings_template kRunTemplate[] = {
{B_STRING_TYPE, NULL, NULL, true, new RunConverter()},
{B_MESSAGE_TYPE, "if", kConditionTemplate},
{B_MESSAGE_TYPE, "then", kRunConditionalTemplate},
{B_MESSAGE_TYPE, "else", kRunConditionalTemplate},
{0, NULL, NULL}
};
const static settings_template kSettingsTemplate[] = {
{B_MESSAGE_TYPE, "target", kTargetTemplate},
{B_MESSAGE_TYPE, "job", kJobTemplate},
{B_MESSAGE_TYPE, "service", kJobTemplate},
{B_MESSAGE_TYPE, "run", kRunTemplate},
{0, NULL, NULL}
};

View File

@ -153,7 +153,8 @@ SettingsParserTest::TestConditionsMultiLineFlatNotWithArgs()
BString(args.GetString("args", 0, "-")));
CPPUNIT_ASSERT_EQUAL(BString("two"),
BString(args.GetString("args", 1, "-")));
CPPUNIT_ASSERT_EQUAL(2, args.CountNames(B_ANY_TYPE));
CPPUNIT_ASSERT_EQUAL(1, args.CountNames(B_ANY_TYPE));
CPPUNIT_ASSERT_EQUAL(2, _ArrayCount(args, "args"));
}
@ -177,11 +178,122 @@ SettingsParserTest::TestConditionsMultiLineNot()
}
void
SettingsParserTest::TestRunFlat()
{
SettingsParser parser;
BMessage jobs;
CPPUNIT_ASSERT_EQUAL(B_OK, parser.Parse("run me", jobs));
CPPUNIT_ASSERT_EQUAL(1, jobs.CountNames(B_ANY_TYPE));
BMessage message;
CPPUNIT_ASSERT_EQUAL(B_OK, jobs.FindMessage("run", &message));
CPPUNIT_ASSERT_EQUAL(BString("me"),
BString(message.GetString("target", "-")));
CPPUNIT_ASSERT_EQUAL(1, _ArrayCount(message, "target"));
CPPUNIT_ASSERT_EQUAL(1, message.CountNames(B_ANY_TYPE));
}
void
SettingsParserTest::TestRunMultiLine()
{
SettingsParser parser;
BMessage jobs;
status_t status = parser.Parse("run {\n"
"\tme\n"
"\tyou\n"
"}\n", jobs);
CPPUNIT_ASSERT_EQUAL(B_OK, status);
CPPUNIT_ASSERT_EQUAL(1, jobs.CountNames(B_ANY_TYPE));
BMessage message;
CPPUNIT_ASSERT_EQUAL(B_OK, jobs.FindMessage("run", &message));
CPPUNIT_ASSERT_EQUAL(BString("me"),
BString(message.GetString("target", 0, "-")));
CPPUNIT_ASSERT_EQUAL(BString("you"),
BString(message.GetString("target", 1, "-")));
CPPUNIT_ASSERT_EQUAL(2, _ArrayCount(message, "target"));
CPPUNIT_ASSERT_EQUAL(1, message.CountNames(B_ANY_TYPE));
}
void
SettingsParserTest::TestRunIfThenElseFlat()
{
SettingsParser parser;
BMessage jobs;
status_t status = parser.Parse("run {\n"
"\tif safemode\n"
"\tthen this\n"
"\telse that\n"
"}\n", jobs);
CPPUNIT_ASSERT_EQUAL(B_OK, status);
BMessage message;
CPPUNIT_ASSERT_EQUAL(B_OK, jobs.FindMessage("run", &message));
CPPUNIT_ASSERT_EQUAL(3, message.CountNames(B_ANY_TYPE));
BMessage then;
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("then", &then));
CPPUNIT_ASSERT_EQUAL(BString("this"),
BString(then.GetString("target", "-")));
CPPUNIT_ASSERT_EQUAL(1, _ArrayCount(then, "target"));
CPPUNIT_ASSERT_EQUAL(1, then.CountNames(B_ANY_TYPE));
BMessage otherwise;
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("else", &otherwise));
CPPUNIT_ASSERT_EQUAL(BString("that"),
BString(otherwise.GetString("target", "-")));
CPPUNIT_ASSERT_EQUAL(1, _ArrayCount(otherwise, "target"));
CPPUNIT_ASSERT_EQUAL(1, otherwise.CountNames(B_ANY_TYPE));
}
void
SettingsParserTest::TestRunIfThenElseMultiLine()
{
SettingsParser parser;
BMessage jobs;
status_t status = parser.Parse("run {\n"
"\tif {\n"
"\t\tread_only\n"
"\t}\n"
"\tthen {\n"
"\t\tthis\n"
"\t}\n"
"\telse {\n"
"\t\tthat\n"
"\t}\n"
"}\n", jobs);
CPPUNIT_ASSERT_EQUAL(B_OK, status);
BMessage message;
CPPUNIT_ASSERT_EQUAL(B_OK, jobs.FindMessage("run", &message));
CPPUNIT_ASSERT_EQUAL(3, message.CountNames(B_ANY_TYPE));
BMessage then;
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("then", &then));
CPPUNIT_ASSERT_EQUAL(BString("this"),
BString(then.GetString("target", "-")));
CPPUNIT_ASSERT_EQUAL(1, _ArrayCount(then, "target"));
CPPUNIT_ASSERT_EQUAL(1, then.CountNames(B_ANY_TYPE));
BMessage otherwise;
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("else", &otherwise));
CPPUNIT_ASSERT_EQUAL(BString("that"),
BString(otherwise.GetString("target", "-")));
CPPUNIT_ASSERT_EQUAL(1, _ArrayCount(otherwise, "target"));
CPPUNIT_ASSERT_EQUAL(1, otherwise.CountNames(B_ANY_TYPE));
}
/*static*/ void
SettingsParserTest::AddTests(BTestSuite& parent)
{
CppUnit::TestSuite& suite = *new CppUnit::TestSuite("SettingsParserTest");
// Conditions
suite.addTest(new CppUnit::TestCaller<SettingsParserTest>(
"SettingsParserTest::TestConditionsMultiLine",
&SettingsParserTest::TestConditionsMultiLine));
@ -207,6 +319,20 @@ SettingsParserTest::AddTests(BTestSuite& parent)
"SettingsParserTest::TestConditionsMultiLineNot",
&SettingsParserTest::TestConditionsMultiLineNot));
// Run
suite.addTest(new CppUnit::TestCaller<SettingsParserTest>(
"SettingsParserTest::TestRunFlat",
&SettingsParserTest::TestRunFlat));
suite.addTest(new CppUnit::TestCaller<SettingsParserTest>(
"SettingsParserTest::TestRunMultiLine",
&SettingsParserTest::TestRunMultiLine));
suite.addTest(new CppUnit::TestCaller<SettingsParserTest>(
"SettingsParserTest::TestRunIfThenElseFlat",
&SettingsParserTest::TestRunIfThenElseFlat));
suite.addTest(new CppUnit::TestCaller<SettingsParserTest>(
"SettingsParserTest::TestRunIfThenElseMultiLine",
&SettingsParserTest::TestRunIfThenElseMultiLine));
parent.addTest("SettingsParserTest", &suite);
}
@ -233,3 +359,14 @@ SettingsParserTest::_ParseCondition(const char* text, BMessage& message)
return job.FindMessage("if", &message);
}
int32
SettingsParserTest::_ArrayCount(BMessage& message, const char* name)
{
int32 found;
if (message.GetInfo(name, NULL, &found, NULL) != B_OK)
return 0;
return found;
}

View File

@ -26,11 +26,18 @@ public:
void TestConditionsMultiLineFlatNotWithArgs();
void TestConditionsMultiLineNot();
void TestRunFlat();
void TestRunMultiLine();
void TestRunIfThenElseFlat();
void TestRunIfThenElseMultiLine();
static void AddTests(BTestSuite& suite);
private:
status_t _ParseCondition(const char* text,
BMessage& message);
int32 _ArrayCount(BMessage& message,
const char* name);
};