151 lines
4.8 KiB
C++
151 lines
4.8 KiB
C++
#include "build-result.hh"
|
||
#include "store-api.hh"
|
||
#include "util.hh"
|
||
#include "regex.hh"
|
||
|
||
using namespace nix;
|
||
|
||
|
||
static std::tuple<bool, string> secureRead(Path fileName)
|
||
{
|
||
auto fail = std::make_tuple(false, "");
|
||
|
||
if (!pathExists(fileName)) return fail;
|
||
|
||
try {
|
||
/* For security, resolve symlinks. */
|
||
fileName = canonPath(fileName, true);
|
||
if (!isInStore(fileName)) return fail;
|
||
return std::make_tuple(true, readFile(fileName));
|
||
} catch (Error & e) { return fail; }
|
||
}
|
||
|
||
|
||
BuildOutput getBuildOutput(nix::ref<Store> store, const Derivation & drv)
|
||
{
|
||
BuildOutput res;
|
||
|
||
/* Compute the closure size. */
|
||
PathSet outputs;
|
||
for (auto & output : drv.outputs)
|
||
outputs.insert(output.second.path);
|
||
PathSet closure;
|
||
for (auto & output : outputs)
|
||
store->computeFSClosure(output, closure);
|
||
for (auto & path : closure) {
|
||
auto info = store->queryPathInfo(path);
|
||
res.closureSize += info.narSize;
|
||
if (outputs.find(path) != outputs.end()) res.size += info.narSize;
|
||
}
|
||
|
||
/* Get build products. */
|
||
bool explicitProducts = false;
|
||
|
||
#if 0
|
||
Regex regex(
|
||
"(([a-zA-Z0-9_-]+)" // type (e.g. "doc")
|
||
"[[:space:]]+"
|
||
"([a-zA-Z0-9_-]+)" // subtype (e.g. "readme")
|
||
"[[:space:]]+"
|
||
"(\"[^\"]+\"|[^[:space:]\"]+))" // path (may be quoted)
|
||
"([[:space:]]+([^[:space:]]+))?" // entry point
|
||
, true);
|
||
|
||
for (auto & output : outputs) {
|
||
Path failedFile = output + "/nix-support/failed";
|
||
if (pathExists(failedFile)) res.failed = true;
|
||
|
||
auto file = secureRead(output + "/nix-support/hydra-build-products");
|
||
if (!std::get<0>(file)) continue;
|
||
|
||
explicitProducts = true;
|
||
|
||
for (auto & line : tokenizeString<Strings>(std::get<1>(file), "\n")) {
|
||
BuildProduct product;
|
||
|
||
Regex::Subs subs;
|
||
if (!regex.matches(line, subs)) continue;
|
||
|
||
product.type = subs[1];
|
||
product.subtype = subs[2];
|
||
product.path = subs[3][0] == '"' ? string(subs[3], 1, subs[3].size() - 2) : subs[3];
|
||
product.defaultPath = subs[5];
|
||
|
||
/* Ensure that the path exists and points into the Nix
|
||
store. */
|
||
if (product.path == "" || product.path[0] != '/') continue;
|
||
try {
|
||
product.path = canonPath(product.path, true);
|
||
} catch (Error & e) { continue; }
|
||
if (!isInStore(product.path) || !pathExists(product.path)) continue;
|
||
|
||
/* FIXME: check that the path is in the input closure
|
||
of the build? */
|
||
|
||
product.name = product.path == output ? "" : baseNameOf(product.path);
|
||
|
||
struct stat st;
|
||
if (stat(product.path.c_str(), &st))
|
||
throw SysError(format("getting status of ‘%1%’") % product.path);
|
||
|
||
if (S_ISREG(st.st_mode)) {
|
||
product.isRegular = true;
|
||
product.fileSize = st.st_size;
|
||
product.sha1hash = hashFile(htSHA1, product.path);
|
||
product.sha256hash = hashFile(htSHA256, product.path);
|
||
}
|
||
|
||
res.products.push_back(product);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/* If no build products were explicitly declared, then add all
|
||
outputs as a product of type "nix-build". */
|
||
if (!explicitProducts) {
|
||
for (auto & output : drv.outputs) {
|
||
BuildProduct product;
|
||
product.path = output.second.path;
|
||
product.type = "nix-build";
|
||
product.subtype = output.first == "out" ? "" : output.first;
|
||
product.name = storePathToName(product.path);
|
||
|
||
#if 0
|
||
struct stat st;
|
||
if (stat(product.path.c_str(), &st))
|
||
throw SysError(format("getting status of ‘%1%’") % product.path);
|
||
if (S_ISDIR(st.st_mode))
|
||
#endif
|
||
res.products.push_back(product);
|
||
}
|
||
}
|
||
|
||
#if 0
|
||
/* Get the release name from $output/nix-support/hydra-release-name. */
|
||
for (auto & output : outputs) {
|
||
Path p = output + "/nix-support/hydra-release-name";
|
||
if (!pathExists(p)) continue;
|
||
try {
|
||
res.releaseName = trim(readFile(p));
|
||
} catch (Error & e) { continue; }
|
||
// FIXME: validate release name
|
||
}
|
||
|
||
/* Get metrics. */
|
||
for (auto & output : outputs) {
|
||
auto file = secureRead(output + "/nix-support/hydra-metrics");
|
||
for (auto & line : tokenizeString<Strings>(std::get<1>(file), "\n")) {
|
||
auto fields = tokenizeString<std::vector<std::string>>(line);
|
||
if (fields.size() < 2) continue;
|
||
BuildMetric metric;
|
||
metric.name = fields[0]; // FIXME: validate
|
||
metric.value = atof(fields[1].c_str()); // FIXME
|
||
metric.unit = fields.size() >= 3 ? fields[2] : "";
|
||
res.metrics[metric.name] = metric;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
return res;
|
||
}
|