2015-09-13 20:25:26 +00:00
|
|
|
///
|
2020-04-24 20:49:20 +00:00
|
|
|
/// Copyright 2015-2020 Oliver Giles
|
2015-09-13 20:25:26 +00:00
|
|
|
///
|
|
|
|
/// This file is part of Laminar
|
|
|
|
///
|
|
|
|
/// Laminar is free software: you can redistribute it and/or modify
|
|
|
|
/// it under the terms of the GNU General Public License as published by
|
|
|
|
/// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
/// (at your option) any later version.
|
|
|
|
///
|
|
|
|
/// Laminar is distributed in the hope that it will be useful,
|
|
|
|
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
/// GNU General Public License for more details.
|
|
|
|
///
|
|
|
|
/// You should have received a copy of the GNU General Public License
|
|
|
|
/// along with Laminar. If not, see <http://www.gnu.org/licenses/>
|
|
|
|
///
|
|
|
|
#include "laminar.capnp.h"
|
2020-07-03 03:13:11 +00:00
|
|
|
#include "log.h"
|
2015-09-13 20:25:26 +00:00
|
|
|
|
|
|
|
#include <capnp/ez-rpc.h>
|
|
|
|
#include <kj/vector.h>
|
|
|
|
|
2020-07-03 03:13:11 +00:00
|
|
|
#include <iostream>
|
2015-09-13 20:25:26 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2019-12-21 13:29:37 +00:00
|
|
|
#include <unistd.h>
|
2015-09-13 20:25:26 +00:00
|
|
|
|
2019-04-11 18:00:00 +00:00
|
|
|
#define EXIT_BAD_ARGUMENT 1
|
|
|
|
#define EXIT_OPERATION_FAILED 2
|
|
|
|
#define EXIT_RUN_FAILED 3
|
2015-09-13 20:25:26 +00:00
|
|
|
|
2019-07-04 09:28:33 +00:00
|
|
|
// Definition needed for musl
|
|
|
|
typedef unsigned int uint;
|
|
|
|
|
2015-09-13 20:25:26 +00:00
|
|
|
template<typename T>
|
|
|
|
static int setParams(int argc, char** argv, T& request) {
|
|
|
|
int n = 0;
|
|
|
|
for(int i = 0; i < argc; ++i) {
|
|
|
|
if(strchr(argv[i], '=') == NULL)
|
|
|
|
break;
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
|
2017-08-16 05:24:06 +00:00
|
|
|
char* job = getenv("JOB");
|
|
|
|
char* num = getenv("RUN");
|
2015-09-13 20:25:26 +00:00
|
|
|
char* reason = getenv("LAMINAR_REASON");
|
|
|
|
|
2018-09-30 06:04:17 +00:00
|
|
|
auto params = request.initParams(n + (job&&num?2:0) + (reason?1:0));
|
2015-09-13 20:25:26 +00:00
|
|
|
|
2018-09-30 06:04:17 +00:00
|
|
|
for(int i = 0; i < n; ++i) {
|
2015-09-13 20:25:26 +00:00
|
|
|
char* name = argv[i];
|
|
|
|
char* val = strchr(name, '=');
|
|
|
|
*val++ = '\0';
|
|
|
|
params[i].setName(name);
|
|
|
|
params[i].setValue(val);
|
|
|
|
}
|
|
|
|
|
2018-09-30 06:04:17 +00:00
|
|
|
int argsConsumed = n;
|
|
|
|
|
2015-09-13 20:25:26 +00:00
|
|
|
if(job && num) {
|
2018-09-30 06:04:17 +00:00
|
|
|
params[n].setName("=parentJob");
|
|
|
|
params[n++].setValue(job);
|
|
|
|
params[n].setName("=parentBuild");
|
|
|
|
params[n++].setValue(num);
|
|
|
|
}
|
|
|
|
if(reason) {
|
|
|
|
params[n].setName("=reason");
|
|
|
|
params[n].setValue(reason);
|
2015-09-13 20:25:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return argsConsumed;
|
|
|
|
}
|
|
|
|
|
2018-09-30 06:04:17 +00:00
|
|
|
static void printTriggerLink(const char* job, uint run) {
|
2020-07-03 06:11:29 +00:00
|
|
|
if(getenv("__LAMINAR_SETENV_PIPE")) {
|
|
|
|
// use a private ANSI CSI sequence to mark the JOB:NUM so the
|
|
|
|
// frontend can recognise it and generate a hyperlink.
|
|
|
|
printf("\033[{%s:%d\033\\\n", job, run);
|
|
|
|
} else {
|
|
|
|
// not called from within a laminar job, let's not confuse
|
|
|
|
// scripts with ANSI sequences.
|
|
|
|
printf("%s:%d\n", job, run);
|
|
|
|
}
|
2018-09-30 06:04:17 +00:00
|
|
|
}
|
|
|
|
|
2020-07-03 03:13:11 +00:00
|
|
|
static void usage(std::ostream& out) {
|
|
|
|
out << "laminarc version " << laminar_version() << "\n";
|
|
|
|
out << "Usage: laminarc [-h|--help] COMMAND [PARAMETERS...]]\n";
|
|
|
|
out << " -h|--help show this help message\n";
|
|
|
|
out << "where COMMAND is:\n";
|
|
|
|
out << " queue JOB_LIST... queues one or more jobs for execution and returns immediately.\n";
|
|
|
|
out << " start JOB_LIST... queues one or more jobs for execution and blocks until it starts.\n";
|
|
|
|
out << " run JOB_LIST... queues one or more jobs for execution and blocks until it finishes.\n";
|
|
|
|
out << " set PARAMETER_LIST... sets the given parameters as environment variables in the currently\n";
|
|
|
|
out << " runing job. Fails if run outside of a job context.\n";
|
|
|
|
out << " abort NAME NUMBER aborts the run identified by NAME and NUMBER.\n";
|
|
|
|
out << " show-jobs lists all known jobs.\n";
|
|
|
|
out << " show-queued lists currently queued jobs.\n";
|
|
|
|
out << " show-running lists currently running jobs.\n";
|
|
|
|
out << "JOB_LIST is of the form:\n";
|
|
|
|
out << " [JOB_NAME [PARAMETER_LIST...]]...\n";
|
|
|
|
out << "PARAMETER_LIST is of the form:\n";
|
|
|
|
out << " [KEY=VALUE]...\n";
|
|
|
|
out << "Example:\n";
|
|
|
|
out << " laminarc start \\\n";
|
|
|
|
out << " nightly-build branch=master type=release \\\n";
|
|
|
|
out << " nightly-build branch=master type=debug\n";
|
|
|
|
}
|
|
|
|
|
2015-09-13 20:25:26 +00:00
|
|
|
int main(int argc, char** argv) {
|
2020-07-03 03:13:11 +00:00
|
|
|
if(argc < 2)
|
|
|
|
return usage(std::cerr), EXIT_BAD_ARGUMENT;
|
|
|
|
else if(strcmp("-h", argv[1]) == 0 || strcmp("--help", argv[1]) == 0)
|
|
|
|
return usage(std::cout), EXIT_SUCCESS;
|
2015-09-13 20:25:26 +00:00
|
|
|
|
2020-04-24 20:49:20 +00:00
|
|
|
struct: public kj::TaskSet::ErrorHandler {
|
|
|
|
void taskFailed(kj::Exception&& e) override {
|
|
|
|
fprintf(stderr, "%s\n", e.getDescription().cStr());
|
|
|
|
ret = EXIT_OPERATION_FAILED;
|
|
|
|
}
|
|
|
|
int ret = 0;
|
|
|
|
} errorHandler;
|
|
|
|
kj::TaskSet ts(errorHandler);
|
|
|
|
int& ret = errorHandler.ret;
|
|
|
|
|
2017-08-15 05:41:53 +00:00
|
|
|
const char* address = getenv("LAMINAR_HOST") ?: getenv("LAMINAR_BIND_RPC") ?: "unix-abstract:laminar";
|
2015-11-01 10:25:43 +00:00
|
|
|
|
2015-09-13 20:25:26 +00:00
|
|
|
capnp::EzRpcClient client(address);
|
|
|
|
LaminarCi::Client laminar = client.getMain<LaminarCi>();
|
|
|
|
|
|
|
|
auto& waitScope = client.getWaitScope();
|
|
|
|
|
2018-05-12 14:56:56 +00:00
|
|
|
if(strcmp(argv[1], "queue") == 0) {
|
2015-09-13 20:25:26 +00:00
|
|
|
if(argc < 3) {
|
2018-05-12 14:56:56 +00:00
|
|
|
fprintf(stderr, "Usage %s queue <jobName>\n", argv[0]);
|
2019-04-11 18:00:00 +00:00
|
|
|
return EXIT_BAD_ARGUMENT;
|
2015-09-13 20:25:26 +00:00
|
|
|
}
|
|
|
|
int jobNameIndex = 2;
|
|
|
|
// make a request for each job specified on the commandline
|
|
|
|
do {
|
2018-05-12 14:56:56 +00:00
|
|
|
auto req = laminar.queueRequest();
|
2015-09-13 20:25:26 +00:00
|
|
|
req.setJobName(argv[jobNameIndex]);
|
|
|
|
int n = setParams(argc - jobNameIndex - 1, &argv[jobNameIndex + 1], req);
|
2020-04-24 20:49:20 +00:00
|
|
|
ts.add(req.send().then([&ret,argv,jobNameIndex](capnp::Response<LaminarCi::QueueResults> resp){
|
|
|
|
if(resp.getResult() != LaminarCi::MethodResult::SUCCESS) {
|
|
|
|
fprintf(stderr, "Failed to queue job '%s'\n", argv[jobNameIndex]);
|
|
|
|
ret = EXIT_OPERATION_FAILED;
|
2020-09-25 03:29:30 +00:00
|
|
|
} else
|
|
|
|
printTriggerLink(argv[jobNameIndex], resp.getBuildNum());
|
2020-04-24 20:49:20 +00:00
|
|
|
}));
|
2015-09-13 20:25:26 +00:00
|
|
|
jobNameIndex += n + 1;
|
|
|
|
} while(jobNameIndex < argc);
|
2020-12-05 00:55:07 +00:00
|
|
|
} else if(strcmp(argv[1], "start") == 0) {
|
2015-09-13 20:25:26 +00:00
|
|
|
if(argc < 3) {
|
2018-05-12 14:56:56 +00:00
|
|
|
fprintf(stderr, "Usage %s queue <jobName>\n", argv[0]);
|
2019-04-11 18:00:00 +00:00
|
|
|
return EXIT_BAD_ARGUMENT;
|
2015-09-13 20:25:26 +00:00
|
|
|
}
|
2018-05-12 14:56:56 +00:00
|
|
|
kj::Vector<capnp::RemotePromise<LaminarCi::StartResults>> promises;
|
|
|
|
int jobNameIndex = 2;
|
|
|
|
// make a request for each job specified on the commandline
|
|
|
|
do {
|
|
|
|
auto req = laminar.startRequest();
|
|
|
|
req.setJobName(argv[jobNameIndex]);
|
|
|
|
int n = setParams(argc - jobNameIndex - 1, &argv[jobNameIndex + 1], req);
|
|
|
|
ts.add(req.send().then([&ret,argv,jobNameIndex](capnp::Response<LaminarCi::StartResults> resp){
|
|
|
|
if(resp.getResult() != LaminarCi::MethodResult::SUCCESS) {
|
|
|
|
fprintf(stderr, "Failed to start job '%s'\n", argv[2]);
|
2019-04-11 18:00:00 +00:00
|
|
|
ret = EXIT_OPERATION_FAILED;
|
2020-04-24 20:49:20 +00:00
|
|
|
} else
|
|
|
|
printTriggerLink(argv[jobNameIndex], resp.getBuildNum());
|
2018-05-12 14:56:56 +00:00
|
|
|
}));
|
|
|
|
jobNameIndex += n + 1;
|
|
|
|
} while(jobNameIndex < argc);
|
|
|
|
} else if(strcmp(argv[1], "run") == 0) {
|
|
|
|
if(argc < 3) {
|
|
|
|
fprintf(stderr, "Usage %s run <jobName>\n", argv[0]);
|
2019-04-11 18:00:00 +00:00
|
|
|
return EXIT_BAD_ARGUMENT;
|
2018-04-06 10:43:38 +00:00
|
|
|
}
|
2015-09-13 20:25:26 +00:00
|
|
|
int jobNameIndex = 2;
|
|
|
|
// make a request for each job specified on the commandline
|
|
|
|
do {
|
2018-04-06 10:43:38 +00:00
|
|
|
auto req = laminar.runRequest();
|
2015-09-13 20:25:26 +00:00
|
|
|
req.setJobName(argv[jobNameIndex]);
|
|
|
|
int n = setParams(argc - jobNameIndex - 1, &argv[jobNameIndex + 1], req);
|
2018-04-06 10:43:38 +00:00
|
|
|
ts.add(req.send().then([&ret,argv,jobNameIndex](capnp::Response<LaminarCi::RunResults> resp){
|
2020-04-24 20:49:20 +00:00
|
|
|
if(resp.getResult() == LaminarCi::JobResult::UNKNOWN)
|
|
|
|
fprintf(stderr, "Failed to start job '%s'\n", argv[2]);
|
|
|
|
else
|
|
|
|
printTriggerLink(argv[jobNameIndex], resp.getBuildNum());
|
|
|
|
if(resp.getResult() != LaminarCi::JobResult::SUCCESS)
|
2019-04-11 18:00:00 +00:00
|
|
|
ret = EXIT_RUN_FAILED;
|
2018-04-06 10:35:02 +00:00
|
|
|
}));
|
2015-09-13 20:25:26 +00:00
|
|
|
jobNameIndex += n + 1;
|
|
|
|
} while(jobNameIndex < argc);
|
|
|
|
} else if(strcmp(argv[1], "set") == 0) {
|
|
|
|
if(argc < 3) {
|
|
|
|
fprintf(stderr, "Usage %s set param=value\n", argv[0]);
|
2019-04-11 18:00:00 +00:00
|
|
|
return EXIT_BAD_ARGUMENT;
|
2015-09-13 20:25:26 +00:00
|
|
|
}
|
2019-12-21 13:29:37 +00:00
|
|
|
if(char* pipeNum = getenv("__LAMINAR_SETENV_PIPE")) {
|
2020-07-03 05:31:44 +00:00
|
|
|
LSYSCALL(write(atoi(pipeNum), argv[2], strlen(argv[2])));
|
2015-09-13 20:25:26 +00:00
|
|
|
} else {
|
2019-12-21 13:29:37 +00:00
|
|
|
fprintf(stderr, "Must be run from within a laminar job\n");
|
2019-04-11 18:00:00 +00:00
|
|
|
return EXIT_BAD_ARGUMENT;
|
2015-09-13 20:25:26 +00:00
|
|
|
}
|
2018-10-12 14:22:21 +00:00
|
|
|
} else if(strcmp(argv[1], "abort") == 0) {
|
|
|
|
if(argc != 4) {
|
|
|
|
fprintf(stderr, "Usage %s abort <jobName> <jobNumber>\n", argv[0]);
|
2019-04-11 18:00:00 +00:00
|
|
|
return EXIT_BAD_ARGUMENT;
|
2018-10-12 14:22:21 +00:00
|
|
|
}
|
|
|
|
auto req = laminar.abortRequest();
|
|
|
|
req.getRun().setJob(argv[2]);
|
|
|
|
req.getRun().setBuildNum(atoi(argv[3]));
|
2020-04-24 20:49:20 +00:00
|
|
|
ts.add(req.send().then([&ret](capnp::Response<LaminarCi::AbortResults> resp){
|
|
|
|
if(resp.getResult() != LaminarCi::MethodResult::SUCCESS)
|
|
|
|
ret = EXIT_OPERATION_FAILED;
|
|
|
|
}));
|
2018-10-12 14:22:21 +00:00
|
|
|
} else if(strcmp(argv[1], "show-jobs") == 0) {
|
|
|
|
if(argc != 2) {
|
|
|
|
fprintf(stderr, "Usage: %s show-jobs\n", argv[0]);
|
2019-04-11 18:00:00 +00:00
|
|
|
return EXIT_BAD_ARGUMENT;
|
2018-10-12 14:22:21 +00:00
|
|
|
}
|
2020-06-13 19:48:52 +00:00
|
|
|
auto jobs = laminar.listKnownRequest().send().wait(waitScope);
|
|
|
|
for(auto it : jobs.getResult()) {
|
2018-10-12 14:22:21 +00:00
|
|
|
printf("%s\n", it.cStr());
|
|
|
|
}
|
|
|
|
} else if(strcmp(argv[1], "show-queued") == 0) {
|
|
|
|
if(argc != 2) {
|
|
|
|
fprintf(stderr, "Usage: %s show-queued\n", argv[0]);
|
2019-04-11 18:00:00 +00:00
|
|
|
return EXIT_BAD_ARGUMENT;
|
2018-10-12 14:22:21 +00:00
|
|
|
}
|
2020-06-13 19:48:52 +00:00
|
|
|
auto queued = laminar.listQueuedRequest().send().wait(waitScope);
|
|
|
|
for(auto it : queued.getResult()) {
|
2018-10-12 14:22:21 +00:00
|
|
|
printf("%s\n", it.cStr());
|
|
|
|
}
|
|
|
|
} else if(strcmp(argv[1], "show-running") == 0) {
|
|
|
|
if(argc != 2) {
|
|
|
|
fprintf(stderr, "Usage: %s show-running\n", argv[0]);
|
2019-04-11 18:00:00 +00:00
|
|
|
return EXIT_BAD_ARGUMENT;
|
2018-10-12 14:22:21 +00:00
|
|
|
}
|
2020-06-13 19:48:52 +00:00
|
|
|
auto running = laminar.listRunningRequest().send().wait(waitScope);
|
|
|
|
for(auto it : running.getResult()) {
|
2018-10-12 14:22:21 +00:00
|
|
|
printf("%s:%d\n", it.getJob().cStr(), it.getBuildNum());
|
|
|
|
}
|
2015-09-13 20:25:26 +00:00
|
|
|
} else {
|
2017-11-07 00:37:21 +00:00
|
|
|
fprintf(stderr, "Unknown command %s\n", argv[1]);
|
2019-04-11 18:00:00 +00:00
|
|
|
return EXIT_BAD_ARGUMENT;
|
2015-09-13 20:25:26 +00:00
|
|
|
}
|
|
|
|
|
2020-04-24 20:49:20 +00:00
|
|
|
ts.onEmpty().wait(waitScope);
|
|
|
|
|
2015-11-01 10:25:43 +00:00
|
|
|
return ret;
|
2015-09-13 20:25:26 +00:00
|
|
|
}
|