N3G7LLGEYREJGGZFBFN4W3LPXQO4LPLTEATUFMUSNA3HXXH5KKKAC
ZMICO7M6COWUZLYQ5MV374BQJLWROSTEORLTOINSU4UGB7TJKJTAC
5JMO43B45WLRDAZJ4QIDFHSI7BVESV7CJ4BYXPJ5Q3MILZ23SECAC
MHVIT4JYWUYD4UCGB2AHLXWLX6B5SYE22BREERNGANT7RGGDUFOAC
24BMQDZAWDQ7VNIA7TIROXSOYLOJBNZ2E4264WHWNJAEN6ZB3UOAC
YSZQ3ORRQ6ELPGEQMXO4IEVD5BT2JRXUPJ44K52DLDFTAJLHKQVAC
G7KWXSFMFPFSCJ7ZD4Z6RNZSDHMHTOUDO3G6R6GYO6VDUDPMIKDQC
5AIYUMTBY6TFQTBRP3MJ2PYWUMRF57I77NIVWYE74UMEVQMBWZVQC
BYVRA54QBKHLFOPIRBJKZZI7JYBYHSOK7MIA3TUZTALZQJGG3G7QC
2GRQJZT6YNH32ZAXX3OALH7Z3XU3YTPH4SBTMG5ZZ373KHYFXZ7AC
BAFICF73XUYNAYT6T6X7GQIFHG6CLGPYYNFBMC6ON6SVPNOXO6RAC
WV4SSAIYM4SVBQ2VISDTAXQJCPKRGTLSVFH44CQFEMC4COWG5OKQC
EBJP3MNAC4CRYGMJJHMKUYWTXP3N4WMMORRLDSDHQVF5ZLOTIENQC
WHULPA6SJJVCXISPL3GAQIRIKQN2DTUSMWGP2ECITWYMLHOON3SQC
T5BIOVJEMBIASP7EKQVV2N3VD6I56UXH6LCD5I33BDQEVHJAMGKQC
YHP5DSOOKAXAYHUDMYO6EKX2YAN7DLDQPJX5K52TCP7EXQVP6JAAC
YNO7CQ6P56YQP7UMGQFL4AZED7DBXE32U7TI6OMOKT6GMWZDMWWQC
UVNTWTWGQOFKDAJ2ROJYT4U2N4EUXKNWZWPHOM42WPLUL4ALXRJQC
WDGARQ76X6RLSFPJTW52BZYFKBC7DPSTABI7HHIKNYHBYXSUNTHQC
ACBS7C6QGXAMPLQ336WAQMMGLZXBDNNYPE26ZBPUQ24GL4BF643AC
SL3WSRACCX2IMJHHLTRAUQT7QDLCOKYLVO2FEHWIHXM5GPKSRJTQC
HJOEIMLRDVQ2KZI5HGL2HKGBM3AHP7YIKGKDAGFUNKRUXVRB24NAC
N4IROACVZ4MU73J5SM6WXJMKQSFR3VN5SOKENNNZNEGMTGB2Q3HAC
destStore->addToStore(info, from);
/* Receive the NAR from the remote and add it to the
destination store. Meanwhile, extract all the info from the
NAR that getBuildOutput() needs. */
auto source2 = sinkToSource([&](Sink & sink)
{
TeeSource tee(from, sink);
extractNarData(tee, localStore->printStorePath(path), narMembers);
});
destStore->addToStore(info, *source2);
}
/* Fetch missing data. Usually buildRemote() will have extracted
this data from the incoming NARs. */
for (auto & output : outputs) {
auto outputS = store->printStorePath(output);
if (!narMembers.count(outputS)) {
printInfo("fetching NAR contents of '%s'...", outputS);
auto source = sinkToSource([&](Sink & sink)
{
store->narFromPath(output, sink);
});
extractNarData(*source, outputS, narMembers);
}
Path failedFile = outputS + "/nix-support/failed";
if (accessor->stat(failedFile).type == FSAccessor::Type::tRegular)
if (narMembers.count(outputS + "/nix-support/failed"))
Path productsFile = outputS + "/nix-support/hydra-build-products";
if (accessor->stat(productsFile).type != FSAccessor::Type::tRegular)
auto productsFile = narMembers.find(outputS + "/nix-support/hydra-build-products");
if (productsFile == narMembers.end() ||
productsFile->second.type != FSAccessor::Type::tRegular)
product.fileSize = st.fileSize;
auto contents = accessor->readFile(product.path);
product.sha256hash = hashString(htSHA256, contents);
product.fileSize = file->second.fileSize.value();
product.sha256hash = file->second.sha256.value();
auto st = accessor->stat(product.path);
if (st.type == FSAccessor::Type::tMissing)
throw Error("getting status of ‘%s’", product.path);
if (st.type == FSAccessor::Type::tDirectory)
auto file = narMembers.find(product.path);
assert(file != narMembers.end());
if (file->second.type == FSAccessor::Type::tDirectory)
auto p = store->printStorePath(output) + "/nix-support/hydra-release-name";
if (accessor->stat(p).type != FSAccessor::Type::tRegular) continue;
try {
res.releaseName = trim(accessor->readFile(p));
} catch (Error & e) { continue; }
auto file = narMembers.find(store->printStorePath(output) + "/nix-support/hydra-release-name");
if (file == narMembers.end() ||
file->second.type != FSAccessor::Type::tRegular)
continue;
res.releaseName = trim(file->second.contents.value());
auto metricsFile = store->printStorePath(output) + "/nix-support/hydra-metrics";
if (accessor->stat(metricsFile).type != FSAccessor::Type::tRegular) continue;
for (auto & line : tokenizeString<Strings>(accessor->readFile(metricsFile), "\n")) {
auto file = narMembers.find(store->printStorePath(output) + "/nix-support/hydra-metrics");
if (file == narMembers.end() ||
file->second.type != FSAccessor::Type::tRegular)
continue;
for (auto & line : tokenizeString<Strings>(file->second.contents.value(), "\n")) {
#include "nar-extractor.hh"
#include "archive.hh"
#include <unordered_set>
using namespace nix;
struct Extractor : ParseSink
{
std::unordered_set<Path> filesToKeep {
"/nix-support/hydra-build-products",
"/nix-support/hydra-release-name",
"/nix-support/hydra-metrics",
};
NarMemberDatas & members;
NarMemberData * curMember = nullptr;
Path prefix;
Extractor(NarMemberDatas & members, const Path & prefix)
: members(members), prefix(prefix)
{ }
void createDirectory(const Path & path) override
{
members.insert_or_assign(prefix + path, NarMemberData { .type = FSAccessor::Type::tDirectory });
}
void createRegularFile(const Path & path) override
{
curMember = &members.insert_or_assign(prefix + path, NarMemberData {
.type = FSAccessor::Type::tRegular,
.fileSize = 0,
.contents = filesToKeep.count(path) ? std::optional("") : std::nullopt,
}).first->second;
}
std::optional<unsigned long long> expectedSize;
std::unique_ptr<HashSink> hashSink;
void preallocateContents(unsigned long long size) override
{
expectedSize = size;
hashSink = std::make_unique<HashSink>(htSHA256);
}
void receiveContents(unsigned char * data, unsigned int len) override
{
assert(expectedSize);
assert(curMember);
assert(hashSink);
*curMember->fileSize += len;
(*hashSink)(data, len);
if (curMember->contents) {
curMember->contents->append((char *) data, len);
}
assert(curMember->fileSize <= expectedSize);
if (curMember->fileSize == expectedSize) {
auto [hash, len] = hashSink->finish();
assert(curMember->fileSize == len);
curMember->sha256 = hash;
hashSink.reset();
}
}
void createSymlink(const Path & path, const string & target) override
{
members.insert_or_assign(prefix + path, NarMemberData { .type = FSAccessor::Type::tSymlink });
}
};
void extractNarData(
Source & source,
const Path & prefix,
NarMemberDatas & members)
{
Extractor extractor(members, prefix);
parseDump(extractor, source);
// Note: this point may not be reached if we're in a coroutine.
}
#pragma once
#include "fs-accessor.hh"
#include "types.hh"
#include "serialise.hh"
#include "hash.hh"
struct NarMemberData
{
nix::FSAccessor::Type type;
std::optional<unsigned long long> fileSize;
std::optional<std::string> contents;
std::optional<nix::Hash> sha256;
};
typedef std::map<nix::Path, NarMemberData> NarMemberDatas;
/* Read a NAR from a source and get to some info about every file
inside the NAR. */
void extractNarData(
nix::Source & source,
const nix::Path & prefix,
NarMemberDatas & members);