278 lines
4.6 KiB
C++
278 lines
4.6 KiB
C++
/*
|
|
* Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
|
|
|
|
#include "BaseJob.h"
|
|
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <Message.h>
|
|
|
|
#include "Conditions.h"
|
|
#include "Events.h"
|
|
|
|
|
|
BaseJob::BaseJob(const char* name)
|
|
:
|
|
BJob(name),
|
|
fCondition(NULL),
|
|
fEvent(NULL)
|
|
{
|
|
}
|
|
|
|
|
|
BaseJob::~BaseJob()
|
|
{
|
|
delete fCondition;
|
|
}
|
|
|
|
|
|
const char*
|
|
BaseJob::Name() const
|
|
{
|
|
return Title().String();
|
|
}
|
|
|
|
|
|
const ::Condition*
|
|
BaseJob::Condition() const
|
|
{
|
|
return fCondition;
|
|
}
|
|
|
|
|
|
::Condition*
|
|
BaseJob::Condition()
|
|
{
|
|
return fCondition;
|
|
}
|
|
|
|
|
|
void
|
|
BaseJob::SetCondition(::Condition* condition)
|
|
{
|
|
fCondition = condition;
|
|
}
|
|
|
|
|
|
bool
|
|
BaseJob::CheckCondition(ConditionContext& context) const
|
|
{
|
|
if (fCondition != NULL)
|
|
return fCondition->Test(context);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
const ::Event*
|
|
BaseJob::Event() const
|
|
{
|
|
return fEvent;
|
|
}
|
|
|
|
|
|
::Event*
|
|
BaseJob::Event()
|
|
{
|
|
return fEvent;
|
|
}
|
|
|
|
|
|
void
|
|
BaseJob::SetEvent(::Event* event)
|
|
{
|
|
fEvent = event;
|
|
if (event != NULL)
|
|
event->SetOwner(this);
|
|
}
|
|
|
|
|
|
/*! Determines whether the events of this job has been triggered
|
|
already or not.
|
|
Note, if this job does not have any events, this method returns
|
|
\c true.
|
|
*/
|
|
bool
|
|
BaseJob::EventHasTriggered() const
|
|
{
|
|
return Event() == NULL || Event()->Triggered();
|
|
}
|
|
|
|
|
|
const BStringList&
|
|
BaseJob::Environment() const
|
|
{
|
|
return fEnvironment;
|
|
}
|
|
|
|
|
|
BStringList&
|
|
BaseJob::Environment()
|
|
{
|
|
return fEnvironment;
|
|
}
|
|
|
|
|
|
const BStringList&
|
|
BaseJob::EnvironmentSourceFiles() const
|
|
{
|
|
return fSourceFiles;
|
|
}
|
|
|
|
|
|
BStringList&
|
|
BaseJob::EnvironmentSourceFiles()
|
|
{
|
|
return fSourceFiles;
|
|
}
|
|
|
|
|
|
void
|
|
BaseJob::SetEnvironment(const BMessage& message)
|
|
{
|
|
char* name;
|
|
type_code type;
|
|
int32 count;
|
|
for (int32 index = 0; message.GetInfo(B_STRING_TYPE, index, &name, &type,
|
|
&count) == B_OK; index++) {
|
|
if (strcmp(name, "from_script") == 0) {
|
|
const char* fromScript;
|
|
for (int32 scriptIndex = 0; message.FindString(name, scriptIndex,
|
|
&fromScript) == B_OK; scriptIndex++) {
|
|
fSourceFiles.Add(fromScript);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
BString variable = name;
|
|
variable << "=";
|
|
|
|
const char* argument;
|
|
for (int32 argumentIndex = 0; message.FindString(name, argumentIndex,
|
|
&argument) == B_OK; argumentIndex++) {
|
|
if (argumentIndex > 0)
|
|
variable << " ";
|
|
variable += argument;
|
|
}
|
|
|
|
fEnvironment.Add(variable);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BaseJob::GetSourceFilesEnvironment(BStringList& environment)
|
|
{
|
|
int32 count = fSourceFiles.CountStrings();
|
|
for (int32 index = 0; index < count; index++) {
|
|
_GetSourceFileEnvironment(fSourceFiles.StringAt(index), environment);
|
|
}
|
|
}
|
|
|
|
|
|
/*! Gets the environment by evaluating the source files, and move that
|
|
environment to the static environment.
|
|
|
|
When this method returns, the source files list will be empty.
|
|
*/
|
|
void
|
|
BaseJob::ResolveSourceFiles()
|
|
{
|
|
if (fSourceFiles.IsEmpty())
|
|
return;
|
|
|
|
GetSourceFilesEnvironment(fEnvironment);
|
|
fSourceFiles.MakeEmpty();
|
|
}
|
|
|
|
|
|
void
|
|
BaseJob::_GetSourceFileEnvironment(const char* script, BStringList& environment)
|
|
{
|
|
int pipes[2];
|
|
if (pipe(&pipes[0]) != 0) {
|
|
// TODO: log error
|
|
return;
|
|
}
|
|
|
|
pid_t child = fork();
|
|
if (child < 0) {
|
|
// TODO: log error
|
|
debug_printf("could not fork: %s\n", strerror(errno));
|
|
} else if (child == 0) {
|
|
// We're the child, redirect stdout
|
|
close(STDOUT_FILENO);
|
|
close(STDERR_FILENO);
|
|
dup2(pipes[1], STDOUT_FILENO);
|
|
dup2(pipes[1], STDERR_FILENO);
|
|
|
|
for (int32 i = 0; i < 2; i++)
|
|
close(pipes[i]);
|
|
|
|
BString command;
|
|
command.SetToFormat(". \"%s\"; export -p", script);
|
|
execl("/bin/sh", "/bin/sh", "-c", command.String(), NULL);
|
|
exit(1);
|
|
} else {
|
|
// Retrieve environment from child
|
|
|
|
close(pipes[1]);
|
|
|
|
BString line;
|
|
char buffer[4096];
|
|
while (true) {
|
|
ssize_t bytesRead = read(pipes[0], buffer, sizeof(buffer) - 1);
|
|
if (bytesRead <= 0)
|
|
break;
|
|
|
|
// Make sure the buffer is null terminated
|
|
buffer[bytesRead] = 0;
|
|
|
|
const char* chunk = buffer;
|
|
while (true) {
|
|
const char* separator = strchr(chunk, '\n');
|
|
if (separator == NULL) {
|
|
line.Append(chunk, bytesRead);
|
|
break;
|
|
}
|
|
line.Append(chunk, separator - chunk);
|
|
chunk = separator + 1;
|
|
|
|
_ParseExportVariable(environment, line);
|
|
line.Truncate(0);
|
|
}
|
|
}
|
|
if (!line.IsEmpty())
|
|
_ParseExportVariable(environment, line);
|
|
|
|
close(pipes[0]);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BaseJob::_ParseExportVariable(BStringList& environment, const BString& line)
|
|
{
|
|
if (!line.StartsWith("export "))
|
|
return;
|
|
|
|
int separator = line.FindFirst("=\"");
|
|
if (separator < 0)
|
|
return;
|
|
|
|
BString variable;
|
|
line.CopyInto(variable, 7, separator - 7);
|
|
|
|
BString value;
|
|
line.CopyInto(value, separator + 2, line.Length() - separator - 3);
|
|
|
|
variable << "=" << value;
|
|
environment.Add(variable);
|
|
}
|