mirror of
https://github.com/ohwgiles/laminar.git
synced 2024-10-27 20:34:20 +00:00
fix pedantic compiler warnings
This commit is contained in:
parent
e0a130f33d
commit
3129f0e73b
@ -30,8 +30,8 @@ StringMap parseConfFile(const char* path) {
|
|||||||
while(std::getline(f, line)) {
|
while(std::getline(f, line)) {
|
||||||
if(line[0] == '#')
|
if(line[0] == '#')
|
||||||
continue;
|
continue;
|
||||||
int p = line.find('=');
|
size_t p = line.find('=');
|
||||||
if(p > 0) {
|
if(p != std::string::npos) {
|
||||||
result.emplace(line.substr(0, p), line.substr(p+1));
|
result.emplace(line.substr(0, p), line.substr(p+1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,10 @@ Database::~Database() {
|
|||||||
sqlite3_close(hdl);
|
sqlite3_close(hdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
Database::Statement::Statement(sqlite3 *db, const char *query) {
|
Database::Statement::Statement(sqlite3 *db, const char *query) :
|
||||||
sqlite3_prepare_v2(db, query, -1, &stmt, NULL);
|
stmt(nullptr)
|
||||||
|
{
|
||||||
|
sqlite3_prepare_v2(db, query, -1, &stmt, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Database::Statement::~Statement() {
|
Database::Statement::~Statement() {
|
||||||
@ -46,33 +48,54 @@ void Database::Statement::bindValue(int i, int e) {
|
|||||||
sqlite3_bind_int(stmt, i, e);
|
sqlite3_bind_int(stmt, i, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Database::Statement::bindValue(int i, uint e) {
|
||||||
|
sqlite3_bind_int(stmt, i, static_cast<int32_t>(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Database::Statement::bindValue(int i, int64_t e) {
|
||||||
|
sqlite3_bind_int64(stmt, i, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Database::Statement::bindValue(int i, uint64_t e) {
|
||||||
|
sqlite3_bind_int64(stmt, i, static_cast<int64_t>(e));
|
||||||
|
}
|
||||||
|
|
||||||
void Database::Statement::bindValue(int i, const char* e) {
|
void Database::Statement::bindValue(int i, const char* e) {
|
||||||
sqlite3_bind_text(stmt, i, e, -1, NULL);
|
sqlite3_bind_text(stmt, i, e, -1, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::Statement::bindValue(int i, const std::string& e) {
|
void Database::Statement::bindValue(int i, const std::string& e) {
|
||||||
sqlite3_bind_text(stmt, i, e.data(), e.size(), NULL);
|
sqlite3_bind_text(stmt, i, e.data(), static_cast<int>(e.size()), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> std::string Database::Statement::fetchColumn(int col) {
|
template<> std::string Database::Statement::fetchColumn(int col) {
|
||||||
int sz = sqlite3_column_bytes(stmt, col);
|
uint sz = static_cast<uint>(sqlite3_column_bytes(stmt, col)); // according to documentation will never be negative
|
||||||
std::string res(sz, '\0');
|
std::string res(sz, '\0');
|
||||||
memcpy(&res[0], sqlite3_column_text(stmt, col), sz);
|
memcpy(&res[0], sqlite3_column_text(stmt, col), sz);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> const char* Database::Statement::fetchColumn(int col) {
|
template<> const char* Database::Statement::fetchColumn(int col) {
|
||||||
return (char*)sqlite3_column_text(stmt, col);
|
// while sqlite3_column_text maybe more correctly returns an unsigned const char*, signed const char* is more consistent
|
||||||
|
return reinterpret_cast<const char*>(sqlite3_column_text(stmt, col));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> int Database::Statement::fetchColumn(int col) {
|
template<> int Database::Statement::fetchColumn(int col) {
|
||||||
return sqlite3_column_int(stmt, col);
|
return sqlite3_column_int(stmt, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> time_t Database::Statement::fetchColumn(int col) {
|
template<> uint Database::Statement::fetchColumn(int col) {
|
||||||
|
return static_cast<uint>(sqlite3_column_int(stmt, col));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> int64_t Database::Statement::fetchColumn(int col) {
|
||||||
return sqlite3_column_int64(stmt, col);
|
return sqlite3_column_int64(stmt, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<> uint64_t Database::Statement::fetchColumn(int col) {
|
||||||
|
return static_cast<uint64_t>(sqlite3_column_int64(stmt, col));
|
||||||
|
}
|
||||||
|
|
||||||
bool Database::Statement::row() {
|
bool Database::Statement::row() {
|
||||||
return sqlite3_step(stmt) == SQLITE_ROW;
|
return sqlite3_step(stmt) == SQLITE_ROW;
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,11 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Statement(sqlite3* db, const char* query);
|
Statement(sqlite3* db, const char* query);
|
||||||
|
Statement(const Statement&) =delete;
|
||||||
|
Statement(Statement&& other) {
|
||||||
|
stmt = other.stmt;
|
||||||
|
other.stmt = nullptr;
|
||||||
|
}
|
||||||
~Statement();
|
~Statement();
|
||||||
|
|
||||||
// Bind several parameters in a single call. They are bound
|
// Bind several parameters in a single call. They are bound
|
||||||
@ -98,7 +103,7 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<typename...Args>
|
template<typename...Args>
|
||||||
friend class FetchMarshaller;
|
friend struct FetchMarshaller;
|
||||||
|
|
||||||
bool row();
|
bool row();
|
||||||
|
|
||||||
@ -114,6 +119,9 @@ private:
|
|||||||
|
|
||||||
// Bind value specializations
|
// Bind value specializations
|
||||||
void bindValue(int i, int e);
|
void bindValue(int i, int e);
|
||||||
|
void bindValue(int i, uint e);
|
||||||
|
void bindValue(int i, int64_t e);
|
||||||
|
void bindValue(int i, uint64_t e);
|
||||||
void bindValue(int i, const char* e);
|
void bindValue(int i, const char* e);
|
||||||
void bindValue(int i, const std::string& e);
|
void bindValue(int i, const std::string& e);
|
||||||
|
|
||||||
@ -140,6 +148,8 @@ private:
|
|||||||
template<> std::string Database::Statement::fetchColumn(int col);
|
template<> std::string Database::Statement::fetchColumn(int col);
|
||||||
template<> const char* Database::Statement::fetchColumn(int col);
|
template<> const char* Database::Statement::fetchColumn(int col);
|
||||||
template<> int Database::Statement::fetchColumn(int col);
|
template<> int Database::Statement::fetchColumn(int col);
|
||||||
template<> time_t Database::Statement::fetchColumn(int col);
|
template<> uint Database::Statement::fetchColumn(int col);
|
||||||
|
template<> int64_t Database::Statement::fetchColumn(int col);
|
||||||
|
template<> uint64_t Database::Statement::fetchColumn(int col);
|
||||||
|
|
||||||
#endif // LAMINAR_DATABASE_H_
|
#endif // LAMINAR_DATABASE_H_
|
||||||
|
@ -39,33 +39,34 @@ struct MonitorScope {
|
|||||||
LOG // a run's log page
|
LOG // a run's log page
|
||||||
};
|
};
|
||||||
|
|
||||||
MonitorScope(Type type = HOME, std::string job = std::string(), int num = 0) :
|
MonitorScope(Type type = HOME, std::string job = std::string(), uint num = 0) :
|
||||||
type(type),
|
type(type),
|
||||||
job(job),
|
job(job),
|
||||||
num(num)
|
num(num)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// whether this scope wants status information about the given job or run
|
// whether this scope wants status information about the given job or run
|
||||||
bool wantsStatus(std::string ajob, int anum = 0) const {
|
bool wantsStatus(std::string ajob, uint anum = 0) const {
|
||||||
if(type == HOME || type == ALL) return true;
|
if(type == HOME || type == ALL) return true;
|
||||||
if(type == JOB) return ajob == job;
|
if(type == JOB) return ajob == job;
|
||||||
if(type == RUN) return ajob == job && anum == num;
|
if(type == RUN) return ajob == job && anum == num;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wantsLog(std::string ajob, int anum) const {
|
bool wantsLog(std::string ajob, uint anum) const {
|
||||||
return type == LOG && ajob == job && anum == num;
|
return type == LOG && ajob == job && anum == num;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type type;
|
Type type;
|
||||||
std::string job;
|
std::string job;
|
||||||
int num = 0;
|
uint num = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Represents a (websocket) client that wants to be notified about events
|
// Represents a (websocket) client that wants to be notified about events
|
||||||
// matching the supplied scope. Pass instances of this to LaminarInterface
|
// matching the supplied scope. Pass instances of this to LaminarInterface
|
||||||
// registerClient and deregisterClient
|
// registerClient and deregisterClient
|
||||||
struct LaminarClient {
|
struct LaminarClient {
|
||||||
|
virtual ~LaminarClient() =default;
|
||||||
virtual void sendMessage(std::string payload) = 0;
|
virtual void sendMessage(std::string payload) = 0;
|
||||||
MonitorScope scope;
|
MonitorScope scope;
|
||||||
};
|
};
|
||||||
@ -74,6 +75,7 @@ struct LaminarClient {
|
|||||||
// Pass instances of this to LaminarInterface registerWaiter and
|
// Pass instances of this to LaminarInterface registerWaiter and
|
||||||
// deregisterWaiter
|
// deregisterWaiter
|
||||||
struct LaminarWaiter {
|
struct LaminarWaiter {
|
||||||
|
virtual ~LaminarWaiter() =default;
|
||||||
virtual void complete(const Run*) = 0;
|
virtual void complete(const Run*) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -81,6 +83,8 @@ struct LaminarWaiter {
|
|||||||
// logic. These methods fulfil the requirements of both the HTTP/Websocket
|
// logic. These methods fulfil the requirements of both the HTTP/Websocket
|
||||||
// and RPC interfaces.
|
// and RPC interfaces.
|
||||||
struct LaminarInterface {
|
struct LaminarInterface {
|
||||||
|
virtual ~LaminarInterface() =default;
|
||||||
|
|
||||||
// Queues a job, returns immediately. Return value will be nullptr if
|
// Queues a job, returns immediately. Return value will be nullptr if
|
||||||
// the supplied name is not a known job.
|
// the supplied name is not a known job.
|
||||||
virtual std::shared_ptr<Run> queueJob(std::string name, ParamMap params = ParamMap()) = 0;
|
virtual std::shared_ptr<Run> queueJob(std::string name, ParamMap params = ParamMap()) = 0;
|
||||||
@ -110,7 +114,7 @@ struct LaminarInterface {
|
|||||||
// Implements the laminar client interface allowing the setting of
|
// Implements the laminar client interface allowing the setting of
|
||||||
// arbitrary parameters on a run (usually itself) to be available in
|
// arbitrary parameters on a run (usually itself) to be available in
|
||||||
// the environment of subsequent scripts.
|
// the environment of subsequent scripts.
|
||||||
virtual bool setParam(std::string job, int buildNum, std::string param, std::string value) = 0;
|
virtual bool setParam(std::string job, uint buildNum, std::string param, std::string value) = 0;
|
||||||
|
|
||||||
// Fetches the content of an artifact given its filename relative to
|
// Fetches the content of an artifact given its filename relative to
|
||||||
// $LAMINAR_HOME/archive. This shouldn't be used, because the sysadmin
|
// $LAMINAR_HOME/archive. This shouldn't be used, because the sysadmin
|
||||||
|
@ -51,6 +51,7 @@ private:
|
|||||||
template<> Json& Json::set(const char* key, const char* value) { String(key); String(value); return *this; }
|
template<> Json& Json::set(const char* key, const char* value) { String(key); String(value); return *this; }
|
||||||
template<> Json& Json::set(const char* key, std::string value) { String(key); String(value.c_str()); return *this; }
|
template<> Json& Json::set(const char* key, std::string value) { String(key); String(value.c_str()); return *this; }
|
||||||
template<> Json& Json::set(const char* key, int value) { String(key); Int(value); return *this; }
|
template<> Json& Json::set(const char* key, int value) { String(key); Int(value); return *this; }
|
||||||
|
template<> Json& Json::set(const char* key, uint value) { String(key); Int(static_cast<int>(value)); return *this; }
|
||||||
template<> Json& Json::set(const char* key, time_t value) { String(key); Int64(value); return *this; }
|
template<> Json& Json::set(const char* key, time_t value) { String(key); Int64(value); return *this; }
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -89,7 +90,7 @@ Laminar::Laminar() {
|
|||||||
|
|
||||||
// retrieve the last build numbers
|
// retrieve the last build numbers
|
||||||
db->stmt("SELECT name, MAX(number) FROM builds GROUP BY name")
|
db->stmt("SELECT name, MAX(number) FROM builds GROUP BY name")
|
||||||
.fetch<str,int>([this](str name, int build){
|
.fetch<str,uint>([this](str name, uint build){
|
||||||
buildNums[name] = build;
|
buildNums[name] = build;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ void Laminar::deregisterWaiter(LaminarWaiter *waiter) {
|
|||||||
waiters.erase(waiter);
|
waiters.erase(waiter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Laminar::setParam(std::string job, int buildNum, std::string param, std::string value) {
|
bool Laminar::setParam(std::string job, uint buildNum, std::string param, std::string value) {
|
||||||
if(Run* run = activeRun(job, buildNum)) {
|
if(Run* run = activeRun(job, buildNum)) {
|
||||||
run->params[param] = value;
|
run->params[param] = value;
|
||||||
return true;
|
return true;
|
||||||
@ -125,11 +126,11 @@ bool Laminar::setParam(std::string job, int buildNum, std::string param, std::st
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Laminar::populateArtifacts(Json &j, std::string job, int num) const {
|
void Laminar::populateArtifacts(Json &j, std::string job, uint num) const {
|
||||||
fs::path dir(fs::path(homeDir)/"archive"/job/std::to_string(num));
|
fs::path dir(fs::path(homeDir)/"archive"/job/std::to_string(num));
|
||||||
if(fs::is_directory(dir)) {
|
if(fs::is_directory(dir)) {
|
||||||
int prefixLen = (fs::path(homeDir)/"archive").string().length();
|
size_t prefixLen = (fs::path(homeDir)/"archive").string().length();
|
||||||
int scopeLen = dir.string().length();
|
size_t scopeLen = dir.string().length();
|
||||||
for(fs::recursive_directory_iterator it(dir); it != fs::recursive_directory_iterator(); ++it) {
|
for(fs::recursive_directory_iterator it(dir); it != fs::recursive_directory_iterator(); ++it) {
|
||||||
if(!fs::is_regular_file(*it))
|
if(!fs::is_regular_file(*it))
|
||||||
continue;
|
continue;
|
||||||
@ -150,10 +151,10 @@ void Laminar::sendStatus(LaminarClient* client) {
|
|||||||
db->stmt("SELECT output, outputLen FROM builds WHERE name = ? AND number = ?")
|
db->stmt("SELECT output, outputLen FROM builds WHERE name = ? AND number = ?")
|
||||||
.bind(client->scope.job, client->scope.num)
|
.bind(client->scope.job, client->scope.num)
|
||||||
.fetch<str,int>([=](str maybeZipped, unsigned long sz) {
|
.fetch<str,int>([=](str maybeZipped, unsigned long sz) {
|
||||||
std::string log(sz+1,'\0');
|
str log(sz+1,'\0');
|
||||||
if(sz >= COMPRESS_LOG_MIN_SIZE) {
|
if(sz >= COMPRESS_LOG_MIN_SIZE) {
|
||||||
int res = ::uncompress((unsigned char*)&log[0], &sz,
|
int res = ::uncompress((uint8_t*) log.data(), &sz,
|
||||||
(unsigned char*)maybeZipped.data(), maybeZipped.size());
|
(const uint8_t*) maybeZipped.data(), maybeZipped.size());
|
||||||
if(res == Z_OK)
|
if(res == Z_OK)
|
||||||
client->sendMessage(log);
|
client->sendMessage(log);
|
||||||
else
|
else
|
||||||
@ -187,7 +188,7 @@ void Laminar::sendStatus(LaminarClient* client) {
|
|||||||
j.set("result", to_string(RunState::RUNNING));
|
j.set("result", to_string(RunState::RUNNING));
|
||||||
db->stmt("SELECT completedAt - startedAt FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT 1")
|
db->stmt("SELECT completedAt - startedAt FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT 1")
|
||||||
.bind(run->name)
|
.bind(run->name)
|
||||||
.fetch<int>([&](int lastRuntime){
|
.fetch<uint>([&](uint lastRuntime){
|
||||||
j.set("etc", run->startedAt + lastRuntime);
|
j.set("etc", run->startedAt + lastRuntime);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -199,7 +200,7 @@ void Laminar::sendStatus(LaminarClient* client) {
|
|||||||
j.startArray("recent");
|
j.startArray("recent");
|
||||||
db->stmt("SELECT number,startedAt,completedAt,result,reason FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT 25")
|
db->stmt("SELECT number,startedAt,completedAt,result,reason FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT 25")
|
||||||
.bind(client->scope.job)
|
.bind(client->scope.job)
|
||||||
.fetch<int,time_t,time_t,int,str>([&](int build,time_t started,time_t completed,int result,str reason){
|
.fetch<uint,time_t,time_t,int,str>([&](uint build,time_t started,time_t completed,int result,str reason){
|
||||||
j.StartObject();
|
j.StartObject();
|
||||||
j.set("number", build)
|
j.set("number", build)
|
||||||
.set("completed", completed)
|
.set("completed", completed)
|
||||||
@ -223,7 +224,7 @@ void Laminar::sendStatus(LaminarClient* client) {
|
|||||||
}
|
}
|
||||||
j.EndArray();
|
j.EndArray();
|
||||||
int nQueued = 0;
|
int nQueued = 0;
|
||||||
for(const std::shared_ptr<Run> run : queuedJobs) {
|
for(const auto& run : queuedJobs) {
|
||||||
if (run->name == client->scope.job) {
|
if (run->name == client->scope.job) {
|
||||||
nQueued++;
|
nQueued++;
|
||||||
}
|
}
|
||||||
@ -247,7 +248,7 @@ void Laminar::sendStatus(LaminarClient* client) {
|
|||||||
} else if(client->scope.type == MonitorScope::ALL) {
|
} else if(client->scope.type == MonitorScope::ALL) {
|
||||||
j.startArray("jobs");
|
j.startArray("jobs");
|
||||||
db->stmt("SELECT name,number,startedAt,completedAt,result FROM builds GROUP BY name ORDER BY number DESC")
|
db->stmt("SELECT name,number,startedAt,completedAt,result FROM builds GROUP BY name ORDER BY number DESC")
|
||||||
.fetch<str,int,time_t,time_t,int>([&](str name,int number, time_t started, time_t completed, int result){
|
.fetch<str,uint,time_t,time_t,int>([&](str name,uint number, time_t started, time_t completed, int result){
|
||||||
j.StartObject();
|
j.StartObject();
|
||||||
j.set("name", name);
|
j.set("name", name);
|
||||||
j.set("number", number);
|
j.set("number", number);
|
||||||
@ -263,7 +264,7 @@ void Laminar::sendStatus(LaminarClient* client) {
|
|||||||
});
|
});
|
||||||
j.EndArray();
|
j.EndArray();
|
||||||
j.startArray("running");
|
j.startArray("running");
|
||||||
for(const std::shared_ptr<Run> run : activeJobs.byStartedAt()) {
|
for(const auto& run : activeJobs.byStartedAt()) {
|
||||||
j.StartObject();
|
j.StartObject();
|
||||||
j.set("name", run->name);
|
j.set("name", run->name);
|
||||||
j.set("number", run->build);
|
j.set("number", run->build);
|
||||||
@ -280,7 +281,7 @@ void Laminar::sendStatus(LaminarClient* client) {
|
|||||||
} else { // Home page
|
} else { // Home page
|
||||||
j.startArray("recent");
|
j.startArray("recent");
|
||||||
db->stmt("SELECT * FROM builds ORDER BY completedAt DESC LIMIT 15")
|
db->stmt("SELECT * FROM builds ORDER BY completedAt DESC LIMIT 15")
|
||||||
.fetch<str,int,str,time_t,time_t,time_t,int>([&](str name,int build,str node,time_t,time_t started,time_t completed,int result){
|
.fetch<str,uint,str,time_t,time_t,time_t,int>([&](str name,uint build,str node,time_t,time_t started,time_t completed,int result){
|
||||||
j.StartObject();
|
j.StartObject();
|
||||||
j.set("name", name)
|
j.set("name", name)
|
||||||
.set("number", build)
|
.set("number", build)
|
||||||
@ -292,7 +293,7 @@ void Laminar::sendStatus(LaminarClient* client) {
|
|||||||
});
|
});
|
||||||
j.EndArray();
|
j.EndArray();
|
||||||
j.startArray("running");
|
j.startArray("running");
|
||||||
for(const std::shared_ptr<Run> run : activeJobs.byStartedAt()) {
|
for(const auto& run : activeJobs.byStartedAt()) {
|
||||||
j.StartObject();
|
j.StartObject();
|
||||||
j.set("name", run->name);
|
j.set("name", run->name);
|
||||||
j.set("number", run->build);
|
j.set("number", run->build);
|
||||||
@ -300,14 +301,14 @@ void Laminar::sendStatus(LaminarClient* client) {
|
|||||||
j.set("started", run->startedAt);
|
j.set("started", run->startedAt);
|
||||||
db->stmt("SELECT completedAt - startedAt FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT 1")
|
db->stmt("SELECT completedAt - startedAt FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT 1")
|
||||||
.bind(run->name)
|
.bind(run->name)
|
||||||
.fetch<int>([&](int lastRuntime){
|
.fetch<uint>([&](uint lastRuntime){
|
||||||
j.set("etc", run->startedAt + lastRuntime);
|
j.set("etc", run->startedAt + lastRuntime);
|
||||||
});
|
});
|
||||||
j.EndObject();
|
j.EndObject();
|
||||||
}
|
}
|
||||||
j.EndArray();
|
j.EndArray();
|
||||||
j.startArray("queued");
|
j.startArray("queued");
|
||||||
for(const std::shared_ptr<Run> run : queuedJobs) {
|
for(const auto& run : queuedJobs) {
|
||||||
j.StartObject();
|
j.StartObject();
|
||||||
j.set("name", run->name);
|
j.set("name", run->name);
|
||||||
j.EndObject();
|
j.EndObject();
|
||||||
@ -326,7 +327,7 @@ void Laminar::sendStatus(LaminarClient* client) {
|
|||||||
for(int i = 6; i >= 0; --i) {
|
for(int i = 6; i >= 0; --i) {
|
||||||
j.StartObject();
|
j.StartObject();
|
||||||
db->stmt("SELECT result, COUNT(*) FROM builds WHERE completedAt > ? AND completedAt < ? GROUP by result")
|
db->stmt("SELECT result, COUNT(*) FROM builds WHERE completedAt > ? AND completedAt < ? GROUP by result")
|
||||||
.bind(86400*(time(0)/86400 - i), 86400*(time(0)/86400 - (i-1)))
|
.bind(86400*(time(nullptr)/86400 - i), 86400*(time(nullptr)/86400 - (i-1)))
|
||||||
.fetch<int,int>([&](int result, int num){
|
.fetch<int,int>([&](int result, int num){
|
||||||
j.set(to_string(RunState(result)).c_str(), num);
|
j.set(to_string(RunState(result)).c_str(), num);
|
||||||
});
|
});
|
||||||
@ -335,15 +336,15 @@ void Laminar::sendStatus(LaminarClient* client) {
|
|||||||
j.EndArray();
|
j.EndArray();
|
||||||
j.startObject("buildsPerJob");
|
j.startObject("buildsPerJob");
|
||||||
db->stmt("SELECT name, COUNT(*) FROM builds WHERE completedAt > ? GROUP BY name")
|
db->stmt("SELECT name, COUNT(*) FROM builds WHERE completedAt > ? GROUP BY name")
|
||||||
.bind(time(0) - 86400)
|
.bind(time(nullptr) - 86400)
|
||||||
.fetch<str, int>([&](str job, int count){
|
.fetch<str, int>([&](str job, int count){
|
||||||
j.set(job.c_str(), count);
|
j.set(job.c_str(), count);
|
||||||
});
|
});
|
||||||
j.EndObject();
|
j.EndObject();
|
||||||
j.startObject("timePerJob");
|
j.startObject("timePerJob");
|
||||||
db->stmt("SELECT name, AVG(completedAt-startedAt) FROM builds WHERE completedAt > ? GROUP BY name")
|
db->stmt("SELECT name, AVG(completedAt-startedAt) FROM builds WHERE completedAt > ? GROUP BY name")
|
||||||
.bind(time(0) - 7 * 86400)
|
.bind(time(nullptr) - 7 * 86400)
|
||||||
.fetch<str, int>([&](str job, int time){
|
.fetch<str, uint>([&](str job, uint time){
|
||||||
j.set(job.c_str(), time);
|
j.set(job.c_str(), time);
|
||||||
});
|
});
|
||||||
j.EndObject();
|
j.EndObject();
|
||||||
@ -369,10 +370,10 @@ void Laminar::run() {
|
|||||||
sigset_t mask;
|
sigset_t mask;
|
||||||
sigemptyset(&mask);
|
sigemptyset(&mask);
|
||||||
sigaddset(&mask, SIGCHLD);
|
sigaddset(&mask, SIGCHLD);
|
||||||
sigprocmask(SIG_BLOCK, &mask, NULL);
|
sigprocmask(SIG_BLOCK, &mask, nullptr);
|
||||||
int sigchld = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
|
int sigchld = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
|
||||||
srv->addDescriptor(sigchld, [this](const char* buf, size_t sz){
|
srv->addDescriptor(sigchld, [this](const char* buf, size_t){
|
||||||
struct signalfd_siginfo* siginfo = (struct signalfd_siginfo*) buf;
|
const struct signalfd_siginfo* siginfo = reinterpret_cast<const struct signalfd_siginfo*>(buf);
|
||||||
// TODO: re-enable assertion when the cause for its triggering
|
// TODO: re-enable assertion when the cause for its triggering
|
||||||
// is discovered and solved
|
// is discovered and solved
|
||||||
//KJ_ASSERT(siginfo->ssi_signo == SIGCHLD);
|
//KJ_ASSERT(siginfo->ssi_signo == SIGCHLD);
|
||||||
@ -394,7 +395,7 @@ void Laminar::stop() {
|
|||||||
|
|
||||||
bool Laminar::loadConfiguration() {
|
bool Laminar::loadConfiguration() {
|
||||||
if(const char* ndirs = getenv("LAMINAR_KEEP_RUNDIRS"))
|
if(const char* ndirs = getenv("LAMINAR_KEEP_RUNDIRS"))
|
||||||
numKeepRunDirs = atoi(ndirs);
|
numKeepRunDirs = static_cast<uint>(atoi(ndirs));
|
||||||
|
|
||||||
NodeMap nm;
|
NodeMap nm;
|
||||||
|
|
||||||
@ -467,7 +468,7 @@ std::shared_ptr<Run> Laminar::queueJob(std::string name, ParamMap params) {
|
|||||||
|
|
||||||
std::shared_ptr<Run> run = std::make_shared<Run>();
|
std::shared_ptr<Run> run = std::make_shared<Run>();
|
||||||
run->name = name;
|
run->name = name;
|
||||||
run->queuedAt = time(0);
|
run->queuedAt = time(nullptr);
|
||||||
for(auto it = params.begin(); it != params.end();) {
|
for(auto it = params.begin(); it != params.end();) {
|
||||||
if(it->first[0] == '=') {
|
if(it->first[0] == '=') {
|
||||||
if(it->first == "=parentJob") {
|
if(it->first == "=parentJob") {
|
||||||
@ -525,7 +526,8 @@ void Laminar::handleRunLog(std::shared_ptr<Run> run, std::string s) {
|
|||||||
void Laminar::reapAdvance() {
|
void Laminar::reapAdvance() {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
static thread_local char buf[1024];
|
constexpr int bufsz = 1024;
|
||||||
|
static thread_local char buf[bufsz];
|
||||||
while((pid = waitpid(-1, &ret, WNOHANG)) > 0) {
|
while((pid = waitpid(-1, &ret, WNOHANG)) > 0) {
|
||||||
LLOG(INFO, "Reaping", pid);
|
LLOG(INFO, "Reaping", pid);
|
||||||
auto it = activeJobs.byPid().find(pid);
|
auto it = activeJobs.byPid().find(pid);
|
||||||
@ -535,8 +537,8 @@ void Laminar::reapAdvance() {
|
|||||||
// shared_ptr to the run it would successfully add to the log output buffer,
|
// shared_ptr to the run it would successfully add to the log output buffer,
|
||||||
// but by then reapAdvance would have stored the log and ensured no-one cares.
|
// but by then reapAdvance would have stored the log and ensured no-one cares.
|
||||||
// Preempt this case by forcing a final (non-blocking) read here.
|
// Preempt this case by forcing a final (non-blocking) read here.
|
||||||
for(ssize_t n = read(run->fd, buf, 1024); n > 0; n = read(run->fd, buf, 1024)) {
|
for(ssize_t n = read(run->fd, buf, bufsz); n > 0; n = read(run->fd, buf, bufsz)) {
|
||||||
handleRunLog(run, std::string(buf, n));
|
handleRunLog(run, std::string(buf, static_cast<size_t>(n)));
|
||||||
}
|
}
|
||||||
bool completed = true;
|
bool completed = true;
|
||||||
activeJobs.byPid().modify(it, [&](std::shared_ptr<Run> run){
|
activeJobs.byPid().modify(it, [&](std::shared_ptr<Run> run){
|
||||||
@ -594,7 +596,7 @@ void Laminar::assignNewJobs() {
|
|||||||
run->addScript((cfgDir/"jobs"/run->name+".init").string(), ws.string());
|
run->addScript((cfgDir/"jobs"/run->name+".init").string(), ws.string());
|
||||||
}
|
}
|
||||||
|
|
||||||
int buildNum = buildNums[run->name] + 1;
|
uint buildNum = buildNums[run->name] + 1;
|
||||||
// create the run directory
|
// create the run directory
|
||||||
fs::path rd = fs::path(homeDir)/"run"/run->name/std::to_string(buildNum);
|
fs::path rd = fs::path(homeDir)/"run"/run->name/std::to_string(buildNum);
|
||||||
bool createWorkdir = true;
|
bool createWorkdir = true;
|
||||||
@ -654,7 +656,7 @@ void Laminar::assignNewJobs() {
|
|||||||
// start the job
|
// start the job
|
||||||
node.busyExecutors++;
|
node.busyExecutors++;
|
||||||
run->node = &node;
|
run->node = &node;
|
||||||
run->startedAt = time(0);
|
run->startedAt = time(nullptr);
|
||||||
run->laminarHome = homeDir;
|
run->laminarHome = homeDir;
|
||||||
run->build = buildNum;
|
run->build = buildNum;
|
||||||
// set the last known result if exists
|
// set the last known result if exists
|
||||||
@ -680,8 +682,8 @@ void Laminar::assignNewJobs() {
|
|||||||
.set("reason", run->reason());
|
.set("reason", run->reason());
|
||||||
db->stmt("SELECT completedAt - startedAt FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT 1")
|
db->stmt("SELECT completedAt - startedAt FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT 1")
|
||||||
.bind(run->name)
|
.bind(run->name)
|
||||||
.fetch<int>([&](int etc){
|
.fetch<uint>([&](uint etc){
|
||||||
j.set("etc", time(0) + etc);
|
j.set("etc", time(nullptr) + etc);
|
||||||
});
|
});
|
||||||
j.EndObject();
|
j.EndObject();
|
||||||
const char* msg = j.str();
|
const char* msg = j.str();
|
||||||
@ -722,7 +724,7 @@ void Laminar::runFinished(Run * r) {
|
|||||||
|
|
||||||
node->busyExecutors--;
|
node->busyExecutors--;
|
||||||
LLOG(INFO, "Run completed", r->name, to_string(r->result));
|
LLOG(INFO, "Run completed", r->name, to_string(r->result));
|
||||||
time_t completedAt = time(0);
|
time_t completedAt = time(nullptr);
|
||||||
|
|
||||||
// compress log
|
// compress log
|
||||||
std::string maybeZipped = r->log;
|
std::string maybeZipped = r->log;
|
||||||
@ -730,8 +732,8 @@ void Laminar::runFinished(Run * r) {
|
|||||||
if(r->log.length() >= COMPRESS_LOG_MIN_SIZE) {
|
if(r->log.length() >= COMPRESS_LOG_MIN_SIZE) {
|
||||||
std::string zipped(r->log.size(), '\0');
|
std::string zipped(r->log.size(), '\0');
|
||||||
unsigned long zippedSize = zipped.size();
|
unsigned long zippedSize = zipped.size();
|
||||||
if(::compress((unsigned char*)&zipped[0], &zippedSize,
|
if(::compress((uint8_t*) zipped.data(), &zippedSize,
|
||||||
(unsigned char*)&r->log[0], logsize) == Z_OK) {
|
(const uint8_t*) r->log.data(), logsize) == Z_OK) {
|
||||||
zipped.resize(zippedSize);
|
zipped.resize(zippedSize);
|
||||||
std::swap(maybeZipped, zipped);
|
std::swap(maybeZipped, zipped);
|
||||||
}
|
}
|
||||||
@ -782,7 +784,7 @@ void Laminar::runFinished(Run * r) {
|
|||||||
// finished here.
|
// finished here.
|
||||||
auto it = activeJobs.byJobName().equal_range(r->name);
|
auto it = activeJobs.byJobName().equal_range(r->name);
|
||||||
uint oldestActive = (it.first == it.second)? buildNums[r->name] : (*it.first)->build - 1;
|
uint oldestActive = (it.first == it.second)? buildNums[r->name] : (*it.first)->build - 1;
|
||||||
for(int i = oldestActive - numKeepRunDirs; i > 0; i--) {
|
for(int i = static_cast<int>(oldestActive - numKeepRunDirs); i > 0; i--) {
|
||||||
fs::path d = fs::path(homeDir)/"run"/r->name/std::to_string(i);
|
fs::path d = fs::path(homeDir)/"run"/r->name/std::to_string(i);
|
||||||
// Once the directory does not exist, it's probably not worth checking
|
// Once the directory does not exist, it's probably not worth checking
|
||||||
// any further. 99% of the time this loop should only ever have 1 iteration
|
// any further. 99% of the time this loop should only ever have 1 iteration
|
||||||
@ -806,9 +808,9 @@ bool Laminar::getArtefact(std::string path, std::string& result) {
|
|||||||
return false;
|
return false;
|
||||||
std::ifstream fstr(file.string());
|
std::ifstream fstr(file.string());
|
||||||
fstr.seekg(0, std::ios::end);
|
fstr.seekg(0, std::ios::end);
|
||||||
size_t sz = fstr.tellg();
|
ssize_t sz = fstr.tellg();
|
||||||
if(fstr.rdstate() == 0) {
|
if(fstr.good()) {
|
||||||
result.resize(sz);
|
result.resize(static_cast<size_t>(sz));
|
||||||
fstr.seekg(0);
|
fstr.seekg(0);
|
||||||
fstr.read(&result[0], sz);
|
fstr.read(&result[0], sz);
|
||||||
return true;
|
return true;
|
||||||
|
@ -39,7 +39,7 @@ class Json;
|
|||||||
class Laminar final : public LaminarInterface {
|
class Laminar final : public LaminarInterface {
|
||||||
public:
|
public:
|
||||||
Laminar();
|
Laminar();
|
||||||
~Laminar();
|
~Laminar() override;
|
||||||
|
|
||||||
// Runs the application forever
|
// Runs the application forever
|
||||||
void run();
|
void run();
|
||||||
@ -54,7 +54,7 @@ public:
|
|||||||
void deregisterWaiter(LaminarWaiter* waiter) override;
|
void deregisterWaiter(LaminarWaiter* waiter) override;
|
||||||
|
|
||||||
void sendStatus(LaminarClient* client) override;
|
void sendStatus(LaminarClient* client) override;
|
||||||
bool setParam(std::string job, int buildNum, std::string param, std::string value) override;
|
bool setParam(std::string job, uint buildNum, std::string param, std::string value) override;
|
||||||
bool getArtefact(std::string path, std::string& result) override;
|
bool getArtefact(std::string path, std::string& result) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -66,9 +66,9 @@ private:
|
|||||||
void runFinished(Run*);
|
void runFinished(Run*);
|
||||||
bool nodeCanQueue(const Node&, const Run&) const;
|
bool nodeCanQueue(const Node&, const Run&) const;
|
||||||
// expects that Json has started an array
|
// expects that Json has started an array
|
||||||
void populateArtifacts(Json& out, std::string job, int num) const;
|
void populateArtifacts(Json& out, std::string job, uint num) const;
|
||||||
|
|
||||||
Run* activeRun(std::string name, int num) {
|
Run* activeRun(std::string name, uint num) {
|
||||||
auto it = activeJobs.byRun().find(boost::make_tuple(name, num));
|
auto it = activeJobs.byRun().find(boost::make_tuple(name, num));
|
||||||
return it == activeJobs.byRun().end() ? nullptr : it->get();
|
return it == activeJobs.byRun().end() ? nullptr : it->get();
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,6 @@ std::string to_string(const RunState& rs) {
|
|||||||
case RunState::ABORTED: return "aborted";
|
case RunState::ABORTED: return "aborted";
|
||||||
case RunState::FAILED: return "failed";
|
case RunState::FAILED: return "failed";
|
||||||
case RunState::SUCCESS: return "success";
|
case RunState::SUCCESS: return "success";
|
||||||
case RunState::UNKNOWN:
|
|
||||||
default:
|
default:
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
@ -74,7 +73,7 @@ bool Run::step() {
|
|||||||
sigset_t mask;
|
sigset_t mask;
|
||||||
sigemptyset(&mask);
|
sigemptyset(&mask);
|
||||||
sigaddset(&mask, SIGCHLD);
|
sigaddset(&mask, SIGCHLD);
|
||||||
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
sigprocmask(SIG_UNBLOCK, &mask, nullptr);
|
||||||
|
|
||||||
close(pfd[0]);
|
close(pfd[0]);
|
||||||
dup2(pfd[1], 1);
|
dup2(pfd[1], 1);
|
||||||
|
@ -81,7 +81,7 @@ public:
|
|||||||
std::string parentName;
|
std::string parentName;
|
||||||
int parentBuild = 0;
|
int parentBuild = 0;
|
||||||
std::string reasonMsg;
|
std::string reasonMsg;
|
||||||
int build = 0;
|
uint build = 0;
|
||||||
std::string log;
|
std::string log;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int fd;
|
int fd;
|
||||||
@ -132,7 +132,7 @@ struct _run_index : bmi::indexed_by<
|
|||||||
std::shared_ptr<Run>,
|
std::shared_ptr<Run>,
|
||||||
// a combination of their job name and build number
|
// a combination of their job name and build number
|
||||||
bmi::member<Run, std::string, &Run::name>,
|
bmi::member<Run, std::string, &Run::name>,
|
||||||
bmi::member<Run, int, &Run::build>
|
bmi::member<Run, uint, &Run::build>
|
||||||
>>,
|
>>,
|
||||||
// or a pointer to a Run object.
|
// or a pointer to a Run object.
|
||||||
bmi::hashed_unique<_run_same>,
|
bmi::hashed_unique<_run_same>,
|
||||||
|
@ -83,7 +83,7 @@ public:
|
|||||||
laminar.registerWaiter(this);
|
laminar.registerWaiter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~RpcImpl() {
|
~RpcImpl() override {
|
||||||
laminar.deregisterWaiter(this);
|
laminar.deregisterWaiter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ public:
|
|||||||
// Set a parameter on a running build
|
// Set a parameter on a running build
|
||||||
kj::Promise<void> set(SetContext context) override {
|
kj::Promise<void> set(SetContext context) override {
|
||||||
std::string jobName = context.getParams().getJobName();
|
std::string jobName = context.getParams().getJobName();
|
||||||
int buildNum = context.getParams().getBuildNum();
|
uint buildNum = context.getParams().getBuildNum();
|
||||||
LLOG(INFO, "RPC set", jobName, buildNum);
|
LLOG(INFO, "RPC set", jobName, buildNum);
|
||||||
|
|
||||||
LaminarCi::MethodResult result = laminar.setParam(jobName, buildNum,
|
LaminarCi::MethodResult result = laminar.setParam(jobName, buildNum,
|
||||||
@ -170,7 +170,6 @@ private:
|
|||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
LaminarInterface& laminar;
|
LaminarInterface& laminar;
|
||||||
kj::LowLevelAsyncIoProvider* asyncio;
|
|
||||||
std::unordered_map<std::string, std::list<kj::PromiseFulfillerPair<void>>> locks;
|
std::unordered_map<std::string, std::list<kj::PromiseFulfillerPair<void>>> locks;
|
||||||
std::unordered_map<const Run*, std::list<kj::PromiseFulfillerPair<RunState>>> runWaiters;
|
std::unordered_map<const Run*, std::list<kj::PromiseFulfillerPair<RunState>>> runWaiters;
|
||||||
};
|
};
|
||||||
@ -235,17 +234,17 @@ public:
|
|||||||
c->lc->scope.type = MonitorScope::ALL;
|
c->lc->scope.type = MonitorScope::ALL;
|
||||||
} else {
|
} else {
|
||||||
res = res.substr(5);
|
res = res.substr(5);
|
||||||
int split = res.find('/',1);
|
size_t split = res.find('/',1);
|
||||||
std::string job = res.substr(1,split-1);
|
std::string job = res.substr(1,split-1);
|
||||||
if(!job.empty()) {
|
if(!job.empty()) {
|
||||||
c->lc->scope.job = job;
|
c->lc->scope.job = job;
|
||||||
c->lc->scope.type = MonitorScope::JOB;
|
c->lc->scope.type = MonitorScope::JOB;
|
||||||
}
|
}
|
||||||
if(split != std::string::npos) {
|
if(split != std::string::npos) {
|
||||||
int split2 = res.find('/', split+1);
|
size_t split2 = res.find('/', split+1);
|
||||||
std::string run = res.substr(split+1, split2-split);
|
std::string run = res.substr(split+1, split2-split);
|
||||||
if(!run.empty()) {
|
if(!run.empty()) {
|
||||||
c->lc->scope.num = atoi(run.c_str());
|
c->lc->scope.num = static_cast<uint>(atoi(run.c_str()));
|
||||||
c->lc->scope.type = MonitorScope::RUN;
|
c->lc->scope.type = MonitorScope::RUN;
|
||||||
}
|
}
|
||||||
if(split2 != std::string::npos && res.compare(split2, 4, "/log") == 0) {
|
if(split2 != std::string::npos && res.compare(split2, 4, "/log") == 0) {
|
||||||
@ -311,8 +310,7 @@ struct Server::WebsocketConnection : public LaminarClient {
|
|||||||
cn->start();
|
cn->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~WebsocketConnection() noexcept(true) {
|
virtual ~WebsocketConnection() noexcept(true) override {}
|
||||||
}
|
|
||||||
|
|
||||||
kj::Promise<void> pend() {
|
kj::Promise<void> pend() {
|
||||||
return stream->tryRead(ibuf, 1, sizeof(ibuf)).then([this](size_t sz){
|
return stream->tryRead(ibuf, 1, sizeof(ibuf)).then([this](size_t sz){
|
||||||
@ -413,8 +411,8 @@ void Server::acceptHttpClient(kj::Own<kj::ConnectionReceiver>&& listener) {
|
|||||||
acceptHttpClient(kj::mv(listener));
|
acceptHttpClient(kj::mv(listener));
|
||||||
auto conn = kj::heap<WebsocketConnection>(kj::mv(connection), *httpInterface);
|
auto conn = kj::heap<WebsocketConnection>(kj::mv(connection), *httpInterface);
|
||||||
auto promises = kj::heapArrayBuilder<kj::Promise<void>>(2);
|
auto promises = kj::heapArrayBuilder<kj::Promise<void>>(2);
|
||||||
promises.add(std::move(conn->pend()));
|
promises.add(conn->pend());
|
||||||
promises.add(std::move(conn->writeTask()));
|
promises.add(conn->writeTask());
|
||||||
return kj::joinPromises(promises.finish()).attach(std::move(conn));
|
return kj::joinPromises(promises.finish()).attach(std::move(conn));
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
@ -54,7 +54,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
struct WebsocketConnection;
|
struct WebsocketConnection;
|
||||||
struct HttpImpl;
|
class HttpImpl;
|
||||||
|
|
||||||
int efd_quit;
|
int efd_quit;
|
||||||
capnp::Capability::Client rpcInterface;
|
capnp::Capability::Client rpcInterface;
|
||||||
|
Loading…
Reference in New Issue
Block a user