2017-01-24 00:32:16 +01:00
|
|
|
#include <utility>
|
|
|
|
#include <thread>
|
|
|
|
#include <mutex>
|
|
|
|
#include <condition_variable>
|
|
|
|
#include <atomic>
|
2017-01-31 19:30:40 +01:00
|
|
|
#include <unordered_map>
|
2017-01-24 00:32:16 +01:00
|
|
|
|
2015-08-16 02:06:42 +02:00
|
|
|
#include <ostd/types.hh>
|
2017-01-24 00:32:16 +01:00
|
|
|
#include <ostd/vector.hh>
|
2015-08-16 02:06:42 +02:00
|
|
|
#include <ostd/string.hh>
|
2017-02-20 18:43:00 +01:00
|
|
|
#include <ostd/format.hh>
|
2015-09-04 19:59:05 +02:00
|
|
|
#include <ostd/filesystem.hh>
|
2016-02-28 23:21:47 +01:00
|
|
|
#include <ostd/io.hh>
|
2015-09-26 16:13:17 +02:00
|
|
|
#include <ostd/platform.hh>
|
2016-03-18 22:54:24 +01:00
|
|
|
#include <ostd/environ.hh>
|
2017-03-18 18:37:15 +01:00
|
|
|
#include <ostd/thread_pool.hh>
|
2015-08-14 03:54:00 +02:00
|
|
|
|
2016-09-10 23:10:23 +02:00
|
|
|
#include <cubescript/cubescript.hh>
|
2015-08-14 03:54:00 +02:00
|
|
|
|
2017-02-16 20:05:00 +01:00
|
|
|
using ostd::string_range;
|
2015-09-01 19:50:00 +02:00
|
|
|
using ostd::slice_until;
|
2015-08-31 15:47:39 +02:00
|
|
|
|
2017-02-13 18:14:19 +01:00
|
|
|
using cscript::cs_state;
|
|
|
|
using cscript::cs_value_r;
|
|
|
|
using cscript::cs_value;
|
|
|
|
using cscript::cs_stacked_value;
|
|
|
|
using cscript::cs_bcode_ref;
|
|
|
|
using cscript::cs_bcode;
|
2015-10-13 22:23:41 +02:00
|
|
|
|
2017-03-10 20:38:57 +01:00
|
|
|
namespace fs = ostd::filesystem;
|
|
|
|
|
2016-08-02 23:37:26 +02:00
|
|
|
/* glob matching code */
|
|
|
|
|
|
|
|
static void ob_get_path_parts(
|
2017-02-16 20:05:00 +01:00
|
|
|
std::vector<string_range> &parts, string_range elem
|
2016-08-02 23:37:26 +02:00
|
|
|
) {
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range star = ostd::find(elem, '*');
|
2016-08-02 23:37:26 +02:00
|
|
|
while (!star.empty()) {
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range ep = slice_until(elem, star);
|
2016-08-02 23:37:26 +02:00
|
|
|
if (!ep.empty()) {
|
2017-01-25 01:57:40 +01:00
|
|
|
parts.push_back(ep);
|
2016-08-02 23:37:26 +02:00
|
|
|
}
|
2017-01-25 01:57:40 +01:00
|
|
|
parts.push_back("*");
|
2016-08-02 23:37:26 +02:00
|
|
|
elem = star;
|
|
|
|
++elem;
|
|
|
|
star = ostd::find(elem, '*');
|
|
|
|
}
|
|
|
|
if (!elem.empty()) {
|
2017-01-25 01:57:40 +01:00
|
|
|
parts.push_back(elem);
|
2016-08-02 23:37:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ob_path_matches(
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range fn, std::vector<string_range> const &parts
|
2016-08-02 23:37:26 +02:00
|
|
|
) {
|
2017-01-25 01:57:40 +01:00
|
|
|
for (auto it = ostd::iter(parts); !it.empty(); ++it) {
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range elem = it.front();
|
2016-08-02 23:37:26 +02:00
|
|
|
if (elem == "*") {
|
|
|
|
++it;
|
|
|
|
/* skip multiple stars if present */
|
|
|
|
while (!it.empty() && ((elem = it.front()) == "*")) {
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
/* trailing stars, we match */
|
|
|
|
if (it.empty()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
/* skip about as much as we can until the elem part matches */
|
|
|
|
while (fn.size() > elem.size()) {
|
|
|
|
if (fn.slice(0, elem.size()) == elem) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++fn;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* non-star here */
|
|
|
|
if (fn.size() < elem.size()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (fn.slice(0, elem.size()) != elem) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
fn += elem.size();
|
|
|
|
}
|
|
|
|
/* if there are no chars in the fname remaining, we fully matched */
|
|
|
|
return fn.empty();
|
|
|
|
}
|
|
|
|
|
2017-01-30 01:18:44 +01:00
|
|
|
static bool ob_expand_glob(
|
2017-02-16 20:05:00 +01:00
|
|
|
std::string &ret, string_range src, bool ne = false
|
2017-01-30 01:18:44 +01:00
|
|
|
);
|
2016-08-02 23:37:26 +02:00
|
|
|
|
|
|
|
static bool ob_expand_dir(
|
2017-02-16 20:05:00 +01:00
|
|
|
std::string &ret, string_range dir,
|
|
|
|
std::vector<string_range> const &parts, string_range slash
|
2016-08-02 23:37:26 +02:00
|
|
|
) {
|
2017-03-10 20:38:57 +01:00
|
|
|
fs::directory_iterator d;
|
|
|
|
try {
|
|
|
|
d = fs::directory_iterator{std::string{dir}};
|
|
|
|
} catch (fs::filesystem_error const &) {
|
2016-08-02 23:37:26 +02:00
|
|
|
return false;
|
|
|
|
}
|
2017-03-10 20:38:57 +01:00
|
|
|
bool appended = false;
|
|
|
|
for (auto &fi: d) {
|
|
|
|
std::string fn = fs::path{fi}.filename().string();
|
2016-08-02 23:37:26 +02:00
|
|
|
/* check if filename matches */
|
|
|
|
if (!ob_path_matches(fn, parts)) {
|
|
|
|
continue;
|
|
|
|
}
|
2017-01-30 01:18:44 +01:00
|
|
|
std::string afn((dir == ".") ? "" : "./");
|
2016-08-02 23:37:26 +02:00
|
|
|
afn.append(fn);
|
|
|
|
/* if we reach this, we match; try recursively matching */
|
|
|
|
if (!slash.empty()) {
|
|
|
|
afn.append(slash);
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range psl = slash + 1;
|
2016-08-02 23:37:26 +02:00
|
|
|
if (!ostd::find(psl, '*').empty()) {
|
|
|
|
if (!appended) {
|
2017-01-30 01:18:44 +01:00
|
|
|
appended = ob_expand_glob(ret, ostd::iter(afn));
|
2016-08-02 23:37:26 +02:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* no further star, just do file test */
|
2017-02-16 20:53:14 +01:00
|
|
|
if (!ostd::file_stream{afn, ostd::stream_mode::READ}.is_open()) {
|
2016-08-02 23:37:26 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!ret.empty()) {
|
2017-01-30 01:18:44 +01:00
|
|
|
ret.push_back(' ');
|
2016-08-02 23:37:26 +02:00
|
|
|
}
|
|
|
|
ret.append(afn);
|
|
|
|
appended = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!ret.empty()) {
|
2017-01-30 01:18:44 +01:00
|
|
|
ret.push_back(' ');
|
2016-08-02 23:37:26 +02:00
|
|
|
}
|
|
|
|
ret.append(afn);
|
|
|
|
appended = true;
|
|
|
|
}
|
|
|
|
return appended;
|
|
|
|
}
|
|
|
|
|
2017-02-16 20:05:00 +01:00
|
|
|
static bool ob_expand_glob(std::string &ret, string_range src, bool ne) {
|
|
|
|
string_range star = ostd::find(src, '*');
|
2016-08-02 23:37:26 +02:00
|
|
|
/* no star use as-is */
|
|
|
|
if (star.empty()) {
|
|
|
|
if (ne) return false;
|
|
|
|
if (!ret.empty()) {
|
2017-01-30 01:18:44 +01:00
|
|
|
ret.push_back(' ');
|
2016-08-02 23:37:26 +02:00
|
|
|
}
|
|
|
|
ret.append(src);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
/* part before star */
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range prestar = slice_until(src, star);
|
2016-08-02 23:37:26 +02:00
|
|
|
/* try finding slash before star */
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range slash = ostd::find_last(prestar, '/');
|
2016-08-02 23:37:26 +02:00
|
|
|
/* directory to scan */
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range dir = ".";
|
2016-08-02 23:37:26 +02:00
|
|
|
/* part of name before star */
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range fnpre = prestar;
|
2016-08-02 23:37:26 +02:00
|
|
|
if (!slash.empty()) {
|
|
|
|
/* there was slash, adjust directory + prefix accordingly */
|
|
|
|
dir = slice_until(src, slash);
|
|
|
|
fnpre = slash + 1;
|
|
|
|
}
|
|
|
|
/* part after star */
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range fnpost = star + 1;
|
2016-08-02 23:37:26 +02:00
|
|
|
/* if a slash follows, adjust */
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range nslash = ostd::find(fnpost, '/');
|
2016-08-02 23:37:26 +02:00
|
|
|
if (!nslash.empty()) {
|
|
|
|
fnpost = slice_until(fnpost, nslash);
|
|
|
|
}
|
|
|
|
/* retrieve the single element with whatever stars in it, chop it up */
|
2017-02-16 20:05:00 +01:00
|
|
|
std::vector<string_range> parts;
|
|
|
|
ob_get_path_parts(parts, string_range(&fnpre[0], &fnpost[fnpost.size()]));
|
2016-08-02 23:37:26 +02:00
|
|
|
/* do a directory scan and match */
|
|
|
|
if (!ob_expand_dir(ret, dir, parts, nslash)) {
|
|
|
|
if (ne) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!ret.empty()) {
|
2017-01-30 01:18:44 +01:00
|
|
|
ret.push_back(' ');
|
2016-08-02 23:37:26 +02:00
|
|
|
}
|
|
|
|
ret.append(src);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-08-22 09:31:33 +02:00
|
|
|
/* check funcs */
|
2015-08-14 03:54:00 +02:00
|
|
|
|
2017-01-30 01:18:44 +01:00
|
|
|
static bool ob_check_ts(
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range tname, std::vector<std::string> const &deps
|
2017-01-30 01:18:44 +01:00
|
|
|
) {
|
2017-02-16 20:05:00 +01:00
|
|
|
auto get_ts = [](string_range fname) {
|
2017-03-10 20:38:57 +01:00
|
|
|
fs::path p{std::string{fname}};
|
|
|
|
if (!fs::is_regular_file(p)) {
|
|
|
|
return fs::file_time_type{};
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2017-03-10 20:38:57 +01:00
|
|
|
return fs::last_write_time(p);
|
2015-08-22 09:31:33 +02:00
|
|
|
};
|
2017-03-10 20:38:57 +01:00
|
|
|
auto tts = get_ts(tname);
|
|
|
|
if (tts == fs::file_time_type{}) {
|
2016-08-01 01:09:29 +02:00
|
|
|
return true;
|
|
|
|
}
|
2017-01-25 01:57:40 +01:00
|
|
|
for (auto &dep: deps) {
|
2017-03-10 20:38:57 +01:00
|
|
|
auto sts = get_ts(dep);
|
|
|
|
if ((sts != fs::file_time_type{}) && (tts < sts)) {
|
2016-08-01 01:09:29 +02:00
|
|
|
return true;
|
|
|
|
}
|
2015-08-14 03:54:00 +02:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-02-16 20:05:00 +01:00
|
|
|
static bool ob_check_file(string_range fname) {
|
2017-02-16 20:53:14 +01:00
|
|
|
return ostd::file_stream{fname, ostd::stream_mode::READ}.is_open();
|
2015-08-14 03:54:00 +02:00
|
|
|
}
|
|
|
|
|
2017-01-25 01:57:40 +01:00
|
|
|
static bool ob_check_exec(
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range tname, std::vector<std::string> const &deps
|
2017-01-25 01:57:40 +01:00
|
|
|
) {
|
2016-08-01 01:09:29 +02:00
|
|
|
if (!ob_check_file(tname)) {
|
2015-08-16 02:06:42 +02:00
|
|
|
return true;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2017-01-25 01:57:40 +01:00
|
|
|
for (auto &dep: deps) {
|
2016-08-01 01:09:29 +02:00
|
|
|
if (!ob_check_file(dep)) {
|
2015-08-16 02:06:42 +02:00
|
|
|
return true;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
|
|
|
}
|
2015-08-16 02:06:42 +02:00
|
|
|
return ob_check_ts(tname, deps);
|
|
|
|
}
|
|
|
|
|
2015-08-22 09:31:33 +02:00
|
|
|
/* this lets us properly match % patterns in target names */
|
2017-02-16 20:05:00 +01:00
|
|
|
static string_range ob_compare_subst(
|
|
|
|
string_range expanded, string_range toexpand
|
2016-08-01 01:09:29 +02:00
|
|
|
) {
|
2015-08-14 03:54:00 +02:00
|
|
|
auto rep = ostd::find(toexpand, '%');
|
|
|
|
/* no subst found */
|
2016-08-01 01:09:29 +02:00
|
|
|
if (rep.empty()) {
|
2015-08-21 20:14:24 +02:00
|
|
|
return nullptr;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2015-08-14 03:54:00 +02:00
|
|
|
/* get the part before % */
|
2015-09-01 19:50:00 +02:00
|
|
|
auto fp = slice_until(toexpand, rep);
|
2015-08-14 03:54:00 +02:00
|
|
|
/* part before % does not compare, so ignore */
|
2016-08-01 01:09:29 +02:00
|
|
|
if (expanded.size() <= fp.size()) {
|
2015-08-21 20:14:24 +02:00
|
|
|
return nullptr;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
|
|
|
if (expanded.slice(0, fp.size()) != fp) {
|
2015-08-21 20:14:24 +02:00
|
|
|
return nullptr;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2015-08-14 03:54:00 +02:00
|
|
|
/* pop out front part */
|
2015-12-14 20:20:43 +01:00
|
|
|
expanded += fp.size();
|
2015-08-14 03:54:00 +02:00
|
|
|
/* part after % */
|
2015-12-14 20:20:43 +01:00
|
|
|
++rep;
|
2016-08-01 01:09:29 +02:00
|
|
|
if (rep.empty()) {
|
2015-08-14 03:54:00 +02:00
|
|
|
return expanded;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2015-08-14 03:54:00 +02:00
|
|
|
/* part after % does not compare, so ignore */
|
2016-08-01 01:09:29 +02:00
|
|
|
if (expanded.size() <= rep.size()) {
|
2015-08-21 20:14:24 +02:00
|
|
|
return nullptr;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2017-01-25 02:11:44 +01:00
|
|
|
size_t es = expanded.size();
|
2016-08-01 01:09:29 +02:00
|
|
|
if (expanded.slice(es - rep.size(), es) != rep) {
|
2015-08-21 20:14:24 +02:00
|
|
|
return nullptr;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2015-08-14 03:54:00 +02:00
|
|
|
/* cut off latter part */
|
|
|
|
expanded.pop_back_n(rep.size());
|
|
|
|
/* we got what we wanted... */
|
|
|
|
return expanded;
|
|
|
|
}
|
|
|
|
|
2017-02-13 18:14:19 +01:00
|
|
|
struct ObState: cs_state {
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range progname;
|
2015-10-16 00:09:16 +02:00
|
|
|
bool ignore_env = false;
|
2015-08-21 21:02:31 +02:00
|
|
|
|
2015-10-16 00:36:39 +02:00
|
|
|
/* represents a rule definition, possibly with a function */
|
|
|
|
struct Rule {
|
2017-01-30 01:18:44 +01:00
|
|
|
std::string target;
|
|
|
|
std::vector<std::string> deps;
|
2017-02-13 18:14:19 +01:00
|
|
|
cs_bcode_ref func;
|
2015-10-26 18:58:47 +01:00
|
|
|
bool action;
|
2015-10-16 00:36:39 +02:00
|
|
|
|
2015-12-19 16:06:11 +01:00
|
|
|
Rule(): target(), deps(), func(), action(false) {}
|
2016-08-01 01:09:29 +02:00
|
|
|
Rule(Rule const &r):
|
|
|
|
target(r.target), deps(r.deps), func(r.func), action(r.action)
|
|
|
|
{}
|
2015-10-16 00:36:39 +02:00
|
|
|
};
|
|
|
|
|
2017-01-25 01:57:40 +01:00
|
|
|
std::vector<Rule> rules;
|
2015-10-16 00:36:39 +02:00
|
|
|
|
2015-08-22 09:31:33 +02:00
|
|
|
struct SubRule {
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range sub;
|
2015-08-22 09:31:33 +02:00
|
|
|
Rule *rule;
|
|
|
|
};
|
|
|
|
|
2017-02-16 20:05:00 +01:00
|
|
|
std::unordered_map<string_range, std::vector<SubRule>> cache;
|
2015-10-15 10:42:43 +02:00
|
|
|
|
2015-10-16 00:36:39 +02:00
|
|
|
struct RuleCounter {
|
2016-08-02 20:54:05 +02:00
|
|
|
RuleCounter(): p_cond(), p_mtx(), p_counter(0), p_result(0) {}
|
2015-10-16 00:36:39 +02:00
|
|
|
|
|
|
|
void wait() {
|
2017-01-24 00:32:16 +01:00
|
|
|
std::unique_lock<std::mutex> l(p_mtx);
|
2016-08-02 20:54:05 +02:00
|
|
|
while (p_counter) {
|
|
|
|
p_cond.wait(l);
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2015-10-16 00:36:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void incr() {
|
2017-01-24 00:32:16 +01:00
|
|
|
std::unique_lock<std::mutex> l(p_mtx);
|
2016-08-02 20:54:05 +02:00
|
|
|
++p_counter;
|
2015-10-16 00:36:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void decr() {
|
2017-01-24 00:32:16 +01:00
|
|
|
std::unique_lock<std::mutex> l(p_mtx);
|
2016-08-02 20:54:05 +02:00
|
|
|
if (!--p_counter) {
|
2016-01-23 23:38:59 +01:00
|
|
|
l.unlock();
|
2017-01-24 00:32:16 +01:00
|
|
|
p_cond.notify_all();
|
2016-01-23 23:38:59 +01:00
|
|
|
}
|
2015-10-16 00:36:39 +02:00
|
|
|
}
|
|
|
|
|
2017-01-24 00:32:16 +01:00
|
|
|
std::atomic_int &get_result() { return p_result; }
|
2016-08-02 20:54:05 +02:00
|
|
|
|
2016-08-02 23:49:21 +02:00
|
|
|
private:
|
2017-01-24 00:32:16 +01:00
|
|
|
std::condition_variable p_cond;
|
|
|
|
std::mutex p_mtx;
|
2016-08-02 20:54:05 +02:00
|
|
|
int p_counter;
|
2017-01-24 00:32:16 +01:00
|
|
|
std::atomic_int p_result;
|
2015-10-16 00:36:39 +02:00
|
|
|
};
|
|
|
|
|
2017-01-25 01:57:40 +01:00
|
|
|
std::vector<RuleCounter *> counters;
|
2015-10-16 00:36:39 +02:00
|
|
|
|
2015-11-04 18:46:01 +01:00
|
|
|
template<typename F>
|
|
|
|
int wait_result(F func) {
|
|
|
|
RuleCounter ctr;
|
2017-01-25 01:57:40 +01:00
|
|
|
counters.push_back(&ctr);
|
2015-11-04 18:46:01 +01:00
|
|
|
int ret = func();
|
2017-01-25 01:57:40 +01:00
|
|
|
counters.pop_back();
|
2016-08-01 01:09:29 +02:00
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
2015-11-04 18:46:01 +01:00
|
|
|
ctr.wait();
|
2016-08-02 20:54:05 +02:00
|
|
|
return ctr.get_result();
|
2015-11-04 18:46:01 +01:00
|
|
|
}
|
|
|
|
|
2015-08-21 21:02:31 +02:00
|
|
|
template<typename ...A>
|
2017-02-16 20:05:00 +01:00
|
|
|
int error(int retcode, string_range fmt, A &&...args) {
|
2017-03-10 20:38:57 +01:00
|
|
|
ostd::cerr.write(progname, ": ");
|
|
|
|
ostd::cerr.writefln(fmt, std::forward<A>(args)...);
|
2015-08-21 21:02:31 +02:00
|
|
|
return retcode;
|
|
|
|
}
|
|
|
|
|
2016-08-01 01:09:29 +02:00
|
|
|
int exec_list(
|
2017-01-30 01:18:44 +01:00
|
|
|
std::vector<SubRule> const &rlist, std::vector<std::string> &subdeps,
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range tname
|
2016-08-01 01:09:29 +02:00
|
|
|
) {
|
2017-01-30 01:18:44 +01:00
|
|
|
std::string repd;
|
2017-01-25 01:57:40 +01:00
|
|
|
for (auto &sr: rlist) {
|
|
|
|
for (auto &target: sr.rule->deps) {
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range atgt = ostd::iter(target);
|
2016-08-02 23:40:24 +02:00
|
|
|
repd.clear();
|
|
|
|
auto lp = ostd::find(atgt, '%');
|
2016-08-01 01:09:29 +02:00
|
|
|
if (!lp.empty()) {
|
2016-08-02 23:40:24 +02:00
|
|
|
repd.append(slice_until(atgt, lp));
|
|
|
|
repd.append(sr.sub);
|
|
|
|
++lp;
|
|
|
|
if (!lp.empty()) {
|
|
|
|
repd.append(lp);
|
|
|
|
}
|
2017-01-30 01:18:44 +01:00
|
|
|
atgt = ostd::iter(repd);
|
2016-08-02 23:40:24 +02:00
|
|
|
}
|
2017-01-30 01:18:44 +01:00
|
|
|
subdeps.push_back(std::string{atgt});
|
2016-08-02 23:40:24 +02:00
|
|
|
int r = exec_rule(atgt, tname);
|
|
|
|
if (r) {
|
|
|
|
return r;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
|
|
|
}
|
2015-11-05 19:43:58 +01:00
|
|
|
}
|
2015-08-21 21:02:31 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-16 20:05:00 +01:00
|
|
|
int exec_func(string_range tname, std::vector<SubRule> const &rlist) {
|
2017-01-30 01:18:44 +01:00
|
|
|
std::vector<std::string> subdeps;
|
2015-11-04 18:46:01 +01:00
|
|
|
int ret = wait_result([&rlist, &subdeps, &tname, this]() {
|
|
|
|
return exec_list(rlist, subdeps, tname);
|
|
|
|
});
|
2017-02-13 18:14:19 +01:00
|
|
|
cs_bcode_ref *func = nullptr;
|
2015-11-21 19:30:11 +01:00
|
|
|
bool act = false;
|
2017-01-25 01:57:40 +01:00
|
|
|
for (auto &sr: rlist) {
|
2016-08-01 01:09:29 +02:00
|
|
|
if (sr.rule->func) {
|
|
|
|
func = &sr.rule->func;
|
|
|
|
act = sr.rule->action;
|
|
|
|
break;
|
|
|
|
}
|
2015-11-21 19:30:11 +01:00
|
|
|
}
|
|
|
|
if ((!ret && (act || ob_check_exec(tname, subdeps))) && func) {
|
2017-02-13 18:14:19 +01:00
|
|
|
cs_stacked_value targetv, sourcev, sourcesv;
|
2015-11-21 19:30:11 +01:00
|
|
|
|
2016-08-18 00:07:00 +02:00
|
|
|
if (!targetv.set_alias(new_ident("target"))) {
|
2015-11-21 19:30:11 +01:00
|
|
|
return 1;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2015-11-21 19:30:11 +01:00
|
|
|
targetv.set_cstr(tname);
|
|
|
|
targetv.push();
|
|
|
|
|
2015-12-23 13:52:27 +01:00
|
|
|
if (!subdeps.empty()) {
|
2016-08-18 00:07:00 +02:00
|
|
|
if (!sourcev.set_alias(new_ident("source"))) {
|
2015-11-21 19:30:11 +01:00
|
|
|
return 1;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2016-08-18 00:07:00 +02:00
|
|
|
if (!sourcesv.set_alias(new_ident("sources"))) {
|
2015-08-21 21:02:31 +02:00
|
|
|
return 1;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2015-11-21 19:30:11 +01:00
|
|
|
|
|
|
|
sourcev.set_cstr(subdeps[0]);
|
|
|
|
sourcev.push();
|
|
|
|
|
2017-02-18 17:29:15 +01:00
|
|
|
auto dsv = ostd::appender_range<std::string>{};
|
2017-02-20 18:43:00 +01:00
|
|
|
ostd::format(dsv, "%(%s %)", subdeps);
|
2017-01-24 00:32:16 +01:00
|
|
|
sourcesv.set_str(std::move(dsv.get()));
|
2015-11-21 19:30:11 +01:00
|
|
|
sourcesv.push();
|
2015-08-21 21:02:31 +02:00
|
|
|
}
|
2015-11-21 19:30:11 +01:00
|
|
|
|
2015-12-20 00:21:39 +01:00
|
|
|
return run_int(*func);
|
2015-08-14 03:54:00 +02:00
|
|
|
}
|
2015-11-03 19:34:16 +01:00
|
|
|
return ret;
|
2015-08-14 03:54:00 +02:00
|
|
|
}
|
2015-08-21 21:02:31 +02:00
|
|
|
|
2015-10-26 18:58:47 +01:00
|
|
|
int exec_action(Rule *rule) {
|
2015-12-07 23:37:38 +01:00
|
|
|
return run_int(rule->func);
|
2015-10-26 18:58:47 +01:00
|
|
|
}
|
|
|
|
|
2017-02-16 20:05:00 +01:00
|
|
|
int find_rules(string_range target, std::vector<SubRule> &rlist) {
|
2016-08-01 01:09:29 +02:00
|
|
|
if (!rlist.empty()) {
|
2015-10-15 10:42:43 +02:00
|
|
|
return 0;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2015-10-03 18:25:52 +02:00
|
|
|
SubRule *frule = nullptr;
|
|
|
|
bool exact = false;
|
2017-01-25 01:57:40 +01:00
|
|
|
for (auto &rule: rules) {
|
2017-02-16 20:05:00 +01:00
|
|
|
if (target == string_range{rule.target}) {
|
2017-01-25 01:57:40 +01:00
|
|
|
rlist.emplace_back();
|
|
|
|
rlist.back().rule = &rule;
|
2015-10-03 18:25:52 +02:00
|
|
|
if (rule.func) {
|
2016-08-01 01:09:29 +02:00
|
|
|
if (frule && exact) {
|
|
|
|
return error(1, "redefinition of rule '%s'", target);
|
|
|
|
}
|
|
|
|
if (!frule) {
|
2015-10-03 18:25:52 +02:00
|
|
|
frule = &rlist.back();
|
2016-08-01 01:09:29 +02:00
|
|
|
} else {
|
2015-10-03 18:25:52 +02:00
|
|
|
*frule = rlist.back();
|
2017-01-25 01:57:40 +01:00
|
|
|
rlist.pop_back();
|
2015-10-03 18:25:52 +02:00
|
|
|
}
|
|
|
|
exact = true;
|
|
|
|
}
|
2015-08-21 21:02:31 +02:00
|
|
|
continue;
|
|
|
|
}
|
2016-08-01 01:09:29 +02:00
|
|
|
if (exact || !rule.func) {
|
2015-10-03 18:25:52 +02:00
|
|
|
continue;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range sub = ob_compare_subst(target, rule.target);
|
2015-08-21 21:02:31 +02:00
|
|
|
if (!sub.empty()) {
|
2017-01-25 01:57:40 +01:00
|
|
|
rlist.emplace_back();
|
|
|
|
SubRule &sr = rlist.back();
|
2015-08-21 21:02:31 +02:00
|
|
|
sr.rule = &rule;
|
|
|
|
sr.sub = sub;
|
2015-10-03 18:25:52 +02:00
|
|
|
if (frule) {
|
2016-08-01 01:09:29 +02:00
|
|
|
if (sub.size() == frule->sub.size()) {
|
|
|
|
return error(1, "redefinition of rule '%s'", target);
|
|
|
|
}
|
2015-10-03 18:25:52 +02:00
|
|
|
if (sub.size() < frule->sub.size()) {
|
2015-11-14 02:08:27 +01:00
|
|
|
*frule = sr;
|
2017-01-25 01:57:40 +01:00
|
|
|
rlist.pop_back();
|
2015-10-03 18:25:52 +02:00
|
|
|
}
|
2016-08-01 01:09:29 +02:00
|
|
|
} else {
|
|
|
|
frule = &sr;
|
|
|
|
}
|
2015-08-21 21:02:31 +02:00
|
|
|
}
|
|
|
|
}
|
2015-10-15 10:42:43 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-16 20:05:00 +01:00
|
|
|
int exec_rule(string_range target, string_range from = nullptr) {
|
2017-01-25 01:57:40 +01:00
|
|
|
std::vector<SubRule> &rlist = cache[target];
|
2015-10-15 10:42:43 +02:00
|
|
|
int fret = find_rules(target, rlist);
|
2016-08-01 01:09:29 +02:00
|
|
|
if (fret) {
|
2015-10-15 10:42:43 +02:00
|
|
|
return fret;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
|
|
|
if ((rlist.size() == 1) && rlist[0].rule->action) {
|
2015-10-26 18:58:47 +01:00
|
|
|
return exec_action(rlist[0].rule);
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2015-08-21 21:02:31 +02:00
|
|
|
if (rlist.empty() && !ob_check_file(target)) {
|
2016-08-01 01:09:29 +02:00
|
|
|
if (from.empty()) {
|
2015-08-21 21:02:31 +02:00
|
|
|
return error(1, "no rule to run target '%s'", target);
|
2016-08-01 01:09:29 +02:00
|
|
|
} else {
|
|
|
|
return error(
|
|
|
|
1, "no rule to run target '%s' (needed by '%s')",
|
|
|
|
target, from
|
|
|
|
);
|
|
|
|
}
|
2015-08-21 21:02:31 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return exec_func(target, rlist);
|
2015-08-16 02:06:42 +02:00
|
|
|
}
|
2015-10-16 00:36:39 +02:00
|
|
|
|
2017-02-16 20:05:00 +01:00
|
|
|
int exec_main(string_range target) {
|
2015-11-04 18:46:01 +01:00
|
|
|
return wait_result([&target, this]() { return exec_rule(target); });
|
2015-10-21 22:09:21 +02:00
|
|
|
}
|
|
|
|
|
2016-08-01 01:09:29 +02:00
|
|
|
void rule_add(
|
2017-02-16 20:05:00 +01:00
|
|
|
cs_state &cs, string_range tgt, string_range dep, cs_bcode *body,
|
2016-08-01 01:09:29 +02:00
|
|
|
bool action = false
|
|
|
|
) {
|
2016-10-23 19:31:48 +02:00
|
|
|
cscript::util::ListParser p{cs, tgt};
|
|
|
|
while (p.parse()) {
|
2017-01-25 01:57:40 +01:00
|
|
|
rules.emplace_back();
|
|
|
|
Rule &r = rules.back();
|
2017-01-24 00:07:41 +01:00
|
|
|
r.target = p.get_item();
|
2015-10-26 18:58:47 +01:00
|
|
|
r.action = action;
|
2016-08-29 19:18:18 +02:00
|
|
|
r.func = cscript::cs_code_is_empty(body) ? nullptr : body;
|
2016-10-23 19:31:48 +02:00
|
|
|
cscript::util::ListParser lp{cs, dep};
|
|
|
|
while (lp.parse()) {
|
2017-01-25 01:57:40 +01:00
|
|
|
r.deps.push_back(lp.get_item());
|
2016-10-23 19:31:48 +02:00
|
|
|
}
|
2015-10-16 00:36:39 +02:00
|
|
|
}
|
|
|
|
}
|
2015-11-14 02:28:07 +01:00
|
|
|
|
2016-08-01 01:09:29 +02:00
|
|
|
void rule_dup(
|
2017-02-16 20:05:00 +01:00
|
|
|
cs_state &cs, string_range tgt, string_range ptgt,
|
|
|
|
string_range dep, bool inherit_deps
|
2016-08-01 01:09:29 +02:00
|
|
|
) {
|
2015-11-14 02:28:07 +01:00
|
|
|
Rule *oldr = nullptr;
|
2017-01-25 01:57:40 +01:00
|
|
|
for (auto &rule: rules) {
|
2017-02-16 20:05:00 +01:00
|
|
|
if (ptgt == string_range{rule.target}) {
|
2015-11-14 02:28:07 +01:00
|
|
|
oldr = &rule;
|
2015-12-27 18:20:47 +01:00
|
|
|
break;
|
|
|
|
}
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
|
|
|
if (!oldr) {
|
2015-11-14 02:28:07 +01:00
|
|
|
return;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2017-01-25 01:57:40 +01:00
|
|
|
rules.emplace_back();
|
|
|
|
Rule &r = rules.back();
|
2015-11-14 02:28:07 +01:00
|
|
|
r.target = tgt;
|
|
|
|
r.action = oldr->action;
|
2015-12-19 16:06:11 +01:00
|
|
|
r.func = oldr->func;
|
2016-10-08 14:38:07 +02:00
|
|
|
if (inherit_deps) {
|
|
|
|
r.deps = oldr->deps;
|
|
|
|
} else {
|
2016-10-23 19:31:48 +02:00
|
|
|
cscript::util::ListParser p{cs, dep};
|
|
|
|
while (p.parse()) {
|
2017-01-25 01:57:40 +01:00
|
|
|
r.deps.push_back(p.get_item());
|
2016-10-23 19:31:48 +02:00
|
|
|
}
|
2016-10-08 14:38:07 +02:00
|
|
|
}
|
2015-11-14 02:28:07 +01:00
|
|
|
}
|
2015-11-25 21:36:46 +01:00
|
|
|
|
|
|
|
void register_rulecmds() {
|
2016-10-16 22:00:07 +02:00
|
|
|
new_command("rule", "sse", [this](auto &cs, auto args, auto &) {
|
2017-01-24 00:07:41 +01:00
|
|
|
this->rule_add(
|
2016-10-09 15:38:53 +02:00
|
|
|
cs, args[0].get_strr(), args[1].get_strr(), args[2].get_code()
|
2016-07-31 01:50:00 +02:00
|
|
|
);
|
2015-11-25 21:36:46 +01:00
|
|
|
});
|
|
|
|
|
2016-10-16 22:00:07 +02:00
|
|
|
new_command("action", "se", [this](auto &cs, auto args, auto &) {
|
2017-01-24 00:07:41 +01:00
|
|
|
this->rule_add(
|
|
|
|
cs, args[0].get_strr(), nullptr, args[1].get_code(), true
|
|
|
|
);
|
2015-11-25 21:36:46 +01:00
|
|
|
});
|
|
|
|
|
2016-10-16 22:00:07 +02:00
|
|
|
new_command("depend", "ss", [this](auto &cs, auto args, auto &) {
|
2017-01-24 00:07:41 +01:00
|
|
|
this->rule_add(cs, args[0].get_strr(), args[1].get_strr(), nullptr);
|
2015-11-25 21:36:46 +01:00
|
|
|
});
|
|
|
|
|
2016-10-16 22:00:07 +02:00
|
|
|
new_command("duprule", "sssN", [this](auto &cs, auto args, auto &) {
|
2017-01-24 00:07:41 +01:00
|
|
|
this->rule_dup(
|
2016-10-09 15:38:53 +02:00
|
|
|
cs, args[0].get_strr(), args[1].get_strr(),
|
2016-07-31 01:50:00 +02:00
|
|
|
args[2].get_strr(), args[3].get_int() <= 2
|
|
|
|
);
|
2015-11-25 21:36:46 +01:00
|
|
|
});
|
|
|
|
}
|
2015-11-09 19:51:55 +01:00
|
|
|
|
2017-02-16 20:05:00 +01:00
|
|
|
int print_help(bool is_error, string_range deffile) {
|
2017-03-10 20:38:57 +01:00
|
|
|
ostd::stream &os = is_error ? ostd::cerr : ostd::cout;
|
2016-08-01 01:09:29 +02:00
|
|
|
os.writeln(
|
|
|
|
"Usage: ", progname, " [options] [action]\n",
|
|
|
|
"Options:\n"
|
|
|
|
" -C DIRECTORY\tChange to DIRECTORY before running.\n",
|
|
|
|
" -f FILE\tSpecify the file to run (default: ", deffile, ").\n"
|
|
|
|
" -h\t\tPrint this message.\n"
|
|
|
|
" -j N\t\tSpecify the number of jobs to use (default: 1).\n"
|
|
|
|
" -e STR\tEvaluate a string instead of a file.\n"
|
|
|
|
" -E\t\tIgnore environment variables."
|
|
|
|
);
|
2017-01-24 00:07:41 +01:00
|
|
|
return is_error;
|
2015-12-03 20:09:44 +01:00
|
|
|
}
|
|
|
|
};
|
2015-08-24 05:54:03 +02:00
|
|
|
|
2015-08-14 03:54:00 +02:00
|
|
|
int main(int argc, char **argv) {
|
2016-08-01 20:17:44 +02:00
|
|
|
ObState os;
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range pn = argv[0];
|
|
|
|
string_range lslash = ostd::find_last(pn, '/');
|
2016-08-01 20:17:44 +02:00
|
|
|
os.progname = lslash.empty() ? pn : (lslash + 1);
|
2015-08-16 02:06:42 +02:00
|
|
|
|
2016-08-18 20:47:46 +02:00
|
|
|
os.init_libs();
|
2015-08-16 02:06:42 +02:00
|
|
|
|
2017-01-24 00:32:16 +01:00
|
|
|
int ncpus = std::thread::hardware_concurrency();
|
2016-09-02 19:03:42 +02:00
|
|
|
os.new_ivar("numcpus", 4096, 1, ncpus);
|
2015-09-26 16:13:17 +02:00
|
|
|
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range fcont;
|
|
|
|
string_range deffile = "obuild.cfg";
|
2015-08-24 05:54:03 +02:00
|
|
|
|
2016-10-17 20:01:57 +02:00
|
|
|
int jobs = 1, posarg = argc;
|
2016-08-01 01:09:29 +02:00
|
|
|
for (int i = 1; i < argc; ++i) {
|
|
|
|
if (argv[i][0] == '-') {
|
|
|
|
char argn = argv[i][1];
|
|
|
|
if (argn == 'E') {
|
2016-08-01 20:17:44 +02:00
|
|
|
os.ignore_env = true;
|
2016-08-01 01:09:29 +02:00
|
|
|
continue;
|
|
|
|
} else if ((argn == 'h') || (!argv[i][2] && ((i + 1) >= argc))) {
|
2016-08-01 20:51:07 +02:00
|
|
|
return os.print_help(argn != 'h', deffile);
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range val = (argv[i][2] == '\0') ? argv[++i] : &argv[i][2];
|
2016-08-01 01:09:29 +02:00
|
|
|
switch (argn) {
|
2016-08-03 17:50:37 +02:00
|
|
|
case 'C':
|
2017-03-10 20:38:57 +01:00
|
|
|
try {
|
|
|
|
fs::current_path(std::string{val});
|
|
|
|
} catch (fs::filesystem_error const &e) {
|
|
|
|
return os.error(
|
|
|
|
1, "failed changing directory: %s (%s)",
|
|
|
|
val, e.what()
|
|
|
|
);
|
2016-08-03 17:50:37 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
deffile = val;
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
fcont = val;
|
|
|
|
break;
|
|
|
|
case 'j': {
|
|
|
|
int ival = atoi(val.data());
|
|
|
|
if (!ival) {
|
|
|
|
ival = ncpus;
|
|
|
|
}
|
2017-02-18 17:46:35 +01:00
|
|
|
jobs = std::max(1, ival);
|
2016-08-03 17:50:37 +02:00
|
|
|
break;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2016-08-03 17:50:37 +02:00
|
|
|
default:
|
|
|
|
return os.print_help(true, deffile);
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
posarg = i;
|
2015-08-24 05:54:03 +02:00
|
|
|
break;
|
2015-09-26 16:13:17 +02:00
|
|
|
}
|
2015-08-24 05:54:03 +02:00
|
|
|
}
|
2016-09-02 19:03:42 +02:00
|
|
|
os.new_ivar("numjobs", 4096, 1, jobs);
|
2016-08-22 19:44:21 +02:00
|
|
|
|
2017-03-18 18:37:15 +01:00
|
|
|
ostd::thread_pool tpool;
|
|
|
|
tpool.start(jobs);
|
2015-08-24 20:16:55 +02:00
|
|
|
|
2016-08-01 20:17:44 +02:00
|
|
|
os.register_rulecmds();
|
2015-11-25 21:36:46 +01:00
|
|
|
|
2016-10-16 22:00:07 +02:00
|
|
|
os.new_command("echo", "C", [](auto &, auto args, auto &) {
|
2016-09-20 22:12:19 +02:00
|
|
|
writeln(args[0].get_strr());
|
2016-09-07 18:59:22 +02:00
|
|
|
});
|
|
|
|
|
2016-10-16 22:00:07 +02:00
|
|
|
os.new_command("shell", "C", [&os, &tpool](auto &, auto args, auto &res) {
|
2015-12-08 22:36:55 +01:00
|
|
|
auto cnt = os.counters.back();
|
2015-08-24 20:16:55 +02:00
|
|
|
cnt->incr();
|
2017-01-30 01:18:44 +01:00
|
|
|
tpool.push([cnt, ds = std::string(args[0].get_strr())]() {
|
2015-11-01 19:45:03 +01:00
|
|
|
int ret = system(ds.data());
|
2016-08-02 20:54:05 +02:00
|
|
|
if (ret && !cnt->get_result()) {
|
|
|
|
cnt->get_result() = ret;
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2015-08-24 20:16:55 +02:00
|
|
|
cnt->decr();
|
|
|
|
});
|
2016-08-11 19:14:42 +02:00
|
|
|
res.set_int(0);
|
2015-08-14 03:54:00 +02:00
|
|
|
});
|
|
|
|
|
2016-10-16 22:00:07 +02:00
|
|
|
os.new_command("getenv", "ss", [&os](auto &, auto args, auto &res) {
|
2015-12-08 22:36:55 +01:00
|
|
|
if (os.ignore_env) {
|
2016-08-11 19:14:42 +02:00
|
|
|
res.set_cstr("");
|
2015-09-21 21:44:48 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-01-24 00:32:16 +01:00
|
|
|
res.set_str(std::move(
|
2016-08-01 01:09:29 +02:00
|
|
|
ostd::env_get(args[0].get_str()).value_or(args[1].get_str())
|
|
|
|
));
|
2015-09-21 21:44:48 +02:00
|
|
|
});
|
|
|
|
|
2016-10-16 22:00:07 +02:00
|
|
|
os.new_command("extreplace", "sss", [](auto &cs, auto args, auto &res) {
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range lst = args[0].get_strr();
|
|
|
|
string_range oldext = args[1].get_strr();
|
|
|
|
string_range newext = args[2].get_strr();
|
2017-01-30 01:18:44 +01:00
|
|
|
std::string ret;
|
2016-08-01 01:16:22 +02:00
|
|
|
if (oldext.front() == '.') {
|
|
|
|
oldext.pop_front();
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2016-08-01 01:16:22 +02:00
|
|
|
if (newext.front() == '.') {
|
|
|
|
newext.pop_front();
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2016-10-23 19:31:48 +02:00
|
|
|
cscript::util::ListParser p{cs, lst};
|
|
|
|
while (p.parse()) {
|
2017-01-24 00:07:41 +01:00
|
|
|
auto elem = p.get_item();
|
2017-02-16 20:05:00 +01:00
|
|
|
string_range it = ostd::iter(elem);
|
2016-08-01 01:09:29 +02:00
|
|
|
if (!ret.empty()) {
|
|
|
|
ret += ' ';
|
|
|
|
}
|
2015-11-07 17:57:29 +01:00
|
|
|
auto dot = ostd::find_last(it, '.');
|
|
|
|
if (!dot.empty() && ((dot + 1) == oldext)) {
|
2016-08-05 17:59:17 +02:00
|
|
|
ret += slice_until(it, dot);
|
2015-11-07 17:57:29 +01:00
|
|
|
ret += '.';
|
|
|
|
ret += newext;
|
|
|
|
} else {
|
|
|
|
ret += it;
|
|
|
|
}
|
|
|
|
}
|
2017-01-24 00:32:16 +01:00
|
|
|
res.set_str(std::move(ret));
|
2015-11-07 17:57:29 +01:00
|
|
|
});
|
|
|
|
|
2016-10-16 22:00:07 +02:00
|
|
|
os.new_command("invoke", "s", [&os](auto &, auto args, auto &res) {
|
2016-08-11 19:14:42 +02:00
|
|
|
res.set_int(os.exec_main(args[0].get_strr()));
|
2015-10-29 18:34:33 +01:00
|
|
|
});
|
|
|
|
|
2016-10-16 22:00:07 +02:00
|
|
|
os.new_command("glob", "C", [&os](auto &cs, auto args, auto &res) {
|
2017-01-30 01:18:44 +01:00
|
|
|
std::string ret;
|
2016-10-23 19:31:48 +02:00
|
|
|
cscript::util::ListParser p{cs, args[0].get_strr()};
|
|
|
|
while (p.parse()) {
|
2017-01-24 00:07:41 +01:00
|
|
|
ob_expand_glob(ret, p.get_item());
|
2016-10-23 19:31:48 +02:00
|
|
|
}
|
2017-01-24 00:32:16 +01:00
|
|
|
res.set_str(std::move(ret));
|
2016-08-02 23:37:26 +02:00
|
|
|
});
|
2015-08-23 10:03:30 +02:00
|
|
|
|
2016-08-01 20:17:44 +02:00
|
|
|
if ((!fcont.empty() && !os.run_bool(fcont)) || !os.run_file(deffile)) {
|
|
|
|
return os.error(1, "failed creating rules");
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2015-08-16 02:06:42 +02:00
|
|
|
|
2016-08-01 20:17:44 +02:00
|
|
|
if (os.rules.empty()) {
|
|
|
|
return os.error(1, "no targets");
|
2016-08-01 01:09:29 +02:00
|
|
|
}
|
2015-08-16 02:06:42 +02:00
|
|
|
|
2016-08-01 20:17:44 +02:00
|
|
|
return os.exec_main((posarg < argc) ? argv[posarg] : "default");
|
2016-02-07 22:20:28 +01:00
|
|
|
}
|