@@ -1,5 +1,5 @@
 | 
				
			|||||||
bin_PROGRAMS = hydra-eval-jobs
 | 
					bin_PROGRAMS = hydra-eval-jobs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
hydra_eval_jobs_SOURCES = hydra-eval-jobs.cc
 | 
					hydra_eval_jobs_SOURCES = hydra-eval-jobs.cc
 | 
				
			||||||
hydra_eval_jobs_LDADD = $(NIX_LIBS)
 | 
					hydra_eval_jobs_LDADD = $(NIX_LIBS) -lnixrust
 | 
				
			||||||
hydra_eval_jobs_CXXFLAGS = $(NIX_CFLAGS) -I ../libhydra
 | 
					hydra_eval_jobs_CXXFLAGS = $(NIX_CFLAGS) -I ../libhydra
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -147,8 +147,9 @@ static void findJobsWrapped(EvalState & state, JSONObject & top,
 | 
				
			|||||||
               done. */
 | 
					               done. */
 | 
				
			||||||
            auto localStore = state.store.dynamic_pointer_cast<LocalFSStore>();
 | 
					            auto localStore = state.store.dynamic_pointer_cast<LocalFSStore>();
 | 
				
			||||||
            if (gcRootsDir != "" && localStore) {
 | 
					            if (gcRootsDir != "" && localStore) {
 | 
				
			||||||
                Path root = gcRootsDir + "/" + baseNameOf(drvPath);
 | 
					                Path root = gcRootsDir + "/" + std::string(baseNameOf(drvPath));
 | 
				
			||||||
                if (!pathExists(root)) localStore->addPermRoot(drvPath, root, false);
 | 
					                if (!pathExists(root))
 | 
				
			||||||
 | 
					                    localStore->addPermRoot(localStore->parseStorePath(drvPath), root, false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            auto res2 = res.object("outputs");
 | 
					            auto res2 = res.object("outputs");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,5 +3,5 @@ bin_PROGRAMS = hydra-queue-runner
 | 
				
			|||||||
hydra_queue_runner_SOURCES = hydra-queue-runner.cc queue-monitor.cc dispatcher.cc \
 | 
					hydra_queue_runner_SOURCES = hydra-queue-runner.cc queue-monitor.cc dispatcher.cc \
 | 
				
			||||||
 builder.cc build-result.cc build-remote.cc  \
 | 
					 builder.cc build-result.cc build-remote.cc  \
 | 
				
			||||||
 build-result.hh counter.hh token-server.hh state.hh db.hh
 | 
					 build-result.hh counter.hh token-server.hh state.hh db.hh
 | 
				
			||||||
hydra_queue_runner_LDADD = $(NIX_LIBS) -lpqxx
 | 
					hydra_queue_runner_LDADD = $(NIX_LIBS) -lpqxx -lnixrust
 | 
				
			||||||
hydra_queue_runner_CXXFLAGS = $(NIX_CFLAGS) -Wall -I ../libhydra -Wno-deprecated-declarations
 | 
					hydra_queue_runner_CXXFLAGS = $(NIX_CFLAGS) -Wall -I ../libhydra -Wno-deprecated-declarations
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,10 +82,10 @@ static void openConnection(Machine::ptr machine, Path tmpDir, int stderrFD, Chil
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void copyClosureTo(std::timed_mutex & sendMutex, ref<Store> destStore,
 | 
					static void copyClosureTo(std::timed_mutex & sendMutex, ref<Store> destStore,
 | 
				
			||||||
    FdSource & from, FdSink & to, const PathSet & paths,
 | 
					    FdSource & from, FdSink & to, const StorePathSet & paths,
 | 
				
			||||||
    bool useSubstitutes = false)
 | 
					    bool useSubstitutes = false)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    PathSet closure;
 | 
					    StorePathSet closure;
 | 
				
			||||||
    for (auto & path : paths)
 | 
					    for (auto & path : paths)
 | 
				
			||||||
        destStore->computeFSClosure(path, closure);
 | 
					        destStore->computeFSClosure(path, closure);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -94,20 +94,21 @@ static void copyClosureTo(std::timed_mutex & sendMutex, ref<Store> destStore,
 | 
				
			|||||||
       garbage-collect paths that are already there. Optionally, ask
 | 
					       garbage-collect paths that are already there. Optionally, ask
 | 
				
			||||||
       the remote host to substitute missing paths. */
 | 
					       the remote host to substitute missing paths. */
 | 
				
			||||||
    // FIXME: substitute output pollutes our build log
 | 
					    // FIXME: substitute output pollutes our build log
 | 
				
			||||||
    to << cmdQueryValidPaths << 1 << useSubstitutes << closure;
 | 
					    to << cmdQueryValidPaths << 1 << useSubstitutes;
 | 
				
			||||||
 | 
					    writeStorePaths(*destStore, to, closure);
 | 
				
			||||||
    to.flush();
 | 
					    to.flush();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Get back the set of paths that are already valid on the remote
 | 
					    /* Get back the set of paths that are already valid on the remote
 | 
				
			||||||
       host. */
 | 
					       host. */
 | 
				
			||||||
    auto present = readStorePaths<PathSet>(*destStore, from);
 | 
					    auto present = readStorePaths<StorePathSet>(*destStore, from);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (present.size() == closure.size()) return;
 | 
					    if (present.size() == closure.size()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Paths sorted = destStore->topoSortPaths(closure);
 | 
					    auto sorted = destStore->topoSortPaths(closure);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Paths missing;
 | 
					    StorePathSet missing;
 | 
				
			||||||
    for (auto i = sorted.rbegin(); i != sorted.rend(); ++i)
 | 
					    for (auto i = sorted.rbegin(); i != sorted.rend(); ++i)
 | 
				
			||||||
        if (present.find(*i) == present.end()) missing.push_back(*i);
 | 
					        if (!present.count(*i)) missing.insert(i->clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    printMsg(lvlDebug, format("sending %1% missing paths") % missing.size());
 | 
					    printMsg(lvlDebug, format("sending %1% missing paths") % missing.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -131,7 +132,7 @@ void State::buildRemote(ref<Store> destStore,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    assert(BuildResult::TimedOut == 8);
 | 
					    assert(BuildResult::TimedOut == 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    string base = baseNameOf(step->drvPath);
 | 
					    string base(step->drvPath.to_string());
 | 
				
			||||||
    result.logFile = logDir + "/" + string(base, 0, 2) + "/" + string(base, 2);
 | 
					    result.logFile = logDir + "/" + string(base, 0, 2) + "/" + string(base, 2);
 | 
				
			||||||
    AutoDelete autoDelete(result.logFile, false);
 | 
					    AutoDelete autoDelete(result.logFile, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -217,22 +218,22 @@ void State::buildRemote(ref<Store> destStore,
 | 
				
			|||||||
           outputs of the input derivations. */
 | 
					           outputs of the input derivations. */
 | 
				
			||||||
        updateStep(ssSendingInputs);
 | 
					        updateStep(ssSendingInputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        PathSet inputs;
 | 
					        StorePathSet inputs;
 | 
				
			||||||
        BasicDerivation basicDrv(step->drv);
 | 
					        BasicDerivation basicDrv(*step->drv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (sendDerivation)
 | 
					        if (sendDerivation)
 | 
				
			||||||
            inputs.insert(step->drvPath);
 | 
					            inputs.insert(step->drvPath.clone());
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            for (auto & p : step->drv.inputSrcs)
 | 
					            for (auto & p : step->drv->inputSrcs)
 | 
				
			||||||
                inputs.insert(p);
 | 
					                inputs.insert(p.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (auto & input : step->drv.inputDrvs) {
 | 
					        for (auto & input : step->drv->inputDrvs) {
 | 
				
			||||||
            Derivation drv2 = readDerivation(input.first);
 | 
					            Derivation drv2 = readDerivation(*localStore, localStore->printStorePath(input.first));
 | 
				
			||||||
            for (auto & name : input.second) {
 | 
					            for (auto & name : input.second) {
 | 
				
			||||||
                auto i = drv2.outputs.find(name);
 | 
					                auto i = drv2.outputs.find(name);
 | 
				
			||||||
                if (i == drv2.outputs.end()) continue;
 | 
					                if (i == drv2.outputs.end()) continue;
 | 
				
			||||||
                inputs.insert(i->second.path);
 | 
					                inputs.insert(i->second.path.clone());
 | 
				
			||||||
                basicDrv.inputSrcs.insert(i->second.path);
 | 
					                basicDrv.inputSrcs.insert(i->second.path.clone());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -241,14 +242,15 @@ void State::buildRemote(ref<Store> destStore,
 | 
				
			|||||||
           this will copy the inputs to the binary cache from the local
 | 
					           this will copy the inputs to the binary cache from the local
 | 
				
			||||||
           store. */
 | 
					           store. */
 | 
				
			||||||
        if (localStore != std::shared_ptr<Store>(destStore))
 | 
					        if (localStore != std::shared_ptr<Store>(destStore))
 | 
				
			||||||
            copyClosure(ref<Store>(localStore), destStore, step->drv.inputSrcs, NoRepair, NoCheckSigs);
 | 
					            copyClosure(ref<Store>(localStore), destStore, step->drv->inputSrcs, NoRepair, NoCheckSigs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Copy the input closure. */
 | 
					        /* Copy the input closure. */
 | 
				
			||||||
        if (!machine->isLocalhost()) {
 | 
					        if (!machine->isLocalhost()) {
 | 
				
			||||||
            auto mc1 = std::make_shared<MaintainCount<counter>>(nrStepsWaiting);
 | 
					            auto mc1 = std::make_shared<MaintainCount<counter>>(nrStepsWaiting);
 | 
				
			||||||
            mc1.reset();
 | 
					            mc1.reset();
 | 
				
			||||||
            MaintainCount<counter> mc2(nrStepsCopyingTo);
 | 
					            MaintainCount<counter> mc2(nrStepsCopyingTo);
 | 
				
			||||||
            printMsg(lvlDebug, format("sending closure of ‘%1%’ to ‘%2%’") % step->drvPath % machine->sshName);
 | 
					            printMsg(lvlDebug, "sending closure of ‘%s’ to ‘%s’",
 | 
				
			||||||
 | 
					                localStore->printStorePath(step->drvPath), machine->sshName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            auto now1 = std::chrono::steady_clock::now();
 | 
					            auto now1 = std::chrono::steady_clock::now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -272,14 +274,19 @@ void State::buildRemote(ref<Store> destStore,
 | 
				
			|||||||
        logFD = -1;
 | 
					        logFD = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Do the build. */
 | 
					        /* Do the build. */
 | 
				
			||||||
        printMsg(lvlDebug, format("building ‘%1%’ on ‘%2%’") % step->drvPath % machine->sshName);
 | 
					        printMsg(lvlDebug, "building ‘%s’ on ‘%s’",
 | 
				
			||||||
 | 
					            localStore->printStorePath(step->drvPath),
 | 
				
			||||||
 | 
					            machine->sshName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        updateStep(ssBuilding);
 | 
					        updateStep(ssBuilding);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (sendDerivation)
 | 
					        if (sendDerivation) {
 | 
				
			||||||
            to << cmdBuildPaths << PathSet({step->drvPath});
 | 
					            to << cmdBuildPaths;
 | 
				
			||||||
        else
 | 
					            writeStorePaths(*localStore, to, singleton(step->drvPath));
 | 
				
			||||||
            to << cmdBuildDerivation << step->drvPath << basicDrv;
 | 
					        } else {
 | 
				
			||||||
 | 
					            to << cmdBuildDerivation << localStore->printStorePath(step->drvPath);
 | 
				
			||||||
 | 
					            writeDerivation(to, *localStore, basicDrv);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        to << maxSilentTime << buildTimeout;
 | 
					        to << maxSilentTime << buildTimeout;
 | 
				
			||||||
        if (GET_PROTOCOL_MINOR(remoteVersion) >= 2)
 | 
					        if (GET_PROTOCOL_MINOR(remoteVersion) >= 2)
 | 
				
			||||||
            to << maxLogSize;
 | 
					            to << maxLogSize;
 | 
				
			||||||
@@ -380,7 +387,8 @@ void State::buildRemote(ref<Store> destStore,
 | 
				
			|||||||
        /* If the path was substituted or already valid, then we didn't
 | 
					        /* If the path was substituted or already valid, then we didn't
 | 
				
			||||||
           get a build log. */
 | 
					           get a build log. */
 | 
				
			||||||
        if (result.isCached) {
 | 
					        if (result.isCached) {
 | 
				
			||||||
            printMsg(lvlInfo, format("outputs of ‘%1%’ substituted or already valid on ‘%2%’") % step->drvPath % machine->sshName);
 | 
					            printMsg(lvlInfo, "outputs of ‘%s’ substituted or already valid on ‘%s’",
 | 
				
			||||||
 | 
					                localStore->printStorePath(step->drvPath), machine->sshName);
 | 
				
			||||||
            unlink(result.logFile.c_str());
 | 
					            unlink(result.logFile.c_str());
 | 
				
			||||||
            result.logFile = "";
 | 
					            result.logFile = "";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -395,13 +403,12 @@ void State::buildRemote(ref<Store> destStore,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            auto now1 = std::chrono::steady_clock::now();
 | 
					            auto now1 = std::chrono::steady_clock::now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            PathSet outputs;
 | 
					            auto outputs = step->drv->outputPaths();
 | 
				
			||||||
            for (auto & output : step->drv.outputs)
 | 
					 | 
				
			||||||
                outputs.insert(output.second.path);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /* Query the size of the output paths. */
 | 
					            /* Query the size of the output paths. */
 | 
				
			||||||
            size_t totalNarSize = 0;
 | 
					            size_t totalNarSize = 0;
 | 
				
			||||||
            to << cmdQueryPathInfos << outputs;
 | 
					            to << cmdQueryPathInfos;
 | 
				
			||||||
 | 
					            writeStorePaths(*localStore, to, outputs);
 | 
				
			||||||
            to.flush();
 | 
					            to.flush();
 | 
				
			||||||
            while (true) {
 | 
					            while (true) {
 | 
				
			||||||
                if (readString(from) == "") break;
 | 
					                if (readString(from) == "") break;
 | 
				
			||||||
@@ -416,8 +423,8 @@ void State::buildRemote(ref<Store> destStore,
 | 
				
			|||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            printMsg(lvlDebug, format("copying outputs of ‘%s’ from ‘%s’ (%d bytes)")
 | 
					            printMsg(lvlDebug, "copying outputs of ‘%s’ from ‘%s’ (%d bytes)",
 | 
				
			||||||
                % step->drvPath % machine->sshName % totalNarSize);
 | 
					                localStore->printStorePath(step->drvPath), machine->sshName, totalNarSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /* Block until we have the required amount of memory
 | 
					            /* Block until we have the required amount of memory
 | 
				
			||||||
               available, which is twice the NAR size (namely the
 | 
					               available, which is twice the NAR size (namely the
 | 
				
			||||||
@@ -431,10 +438,11 @@ void State::buildRemote(ref<Store> destStore,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            auto resMs = std::chrono::duration_cast<std::chrono::milliseconds>(resStop - resStart).count();
 | 
					            auto resMs = std::chrono::duration_cast<std::chrono::milliseconds>(resStop - resStart).count();
 | 
				
			||||||
            if (resMs >= 1000)
 | 
					            if (resMs >= 1000)
 | 
				
			||||||
                printMsg(lvlError, format("warning: had to wait %d ms for %d memory tokens for %s")
 | 
					                printMsg(lvlError, "warning: had to wait %d ms for %d memory tokens for %s",
 | 
				
			||||||
                    % resMs % totalNarSize % step->drvPath);
 | 
					                    resMs, totalNarSize, localStore->printStorePath(step->drvPath));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            to << cmdExportPaths << 0 << outputs;
 | 
					            to << cmdExportPaths << 0;
 | 
				
			||||||
 | 
					            writeStorePaths(*localStore, to, outputs);
 | 
				
			||||||
            to.flush();
 | 
					            to.flush();
 | 
				
			||||||
            destStore->importPaths(from, result.accessor, NoCheckSigs);
 | 
					            destStore->importPaths(from, result.accessor, NoCheckSigs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,16 +14,14 @@ BuildOutput getBuildOutput(nix::ref<Store> store,
 | 
				
			|||||||
    BuildOutput res;
 | 
					    BuildOutput res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Compute the closure size. */
 | 
					    /* Compute the closure size. */
 | 
				
			||||||
    PathSet outputs;
 | 
					    auto outputs = drv.outputPaths();
 | 
				
			||||||
    for (auto & output : drv.outputs)
 | 
					    StorePathSet closure;
 | 
				
			||||||
        outputs.insert(output.second.path);
 | 
					 | 
				
			||||||
    PathSet closure;
 | 
					 | 
				
			||||||
    for (auto & output : outputs)
 | 
					    for (auto & output : outputs)
 | 
				
			||||||
        store->computeFSClosure(output, closure);
 | 
					        store->computeFSClosure(singleton(output), closure);
 | 
				
			||||||
    for (auto & path : closure) {
 | 
					    for (auto & path : closure) {
 | 
				
			||||||
        auto info = store->queryPathInfo(path);
 | 
					        auto info = store->queryPathInfo(path);
 | 
				
			||||||
        res.closureSize += info->narSize;
 | 
					        res.closureSize += info->narSize;
 | 
				
			||||||
        if (outputs.find(path) != outputs.end()) res.size += info->narSize;
 | 
					        if (outputs.count(path)) res.size += info->narSize;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Get build products. */
 | 
					    /* Get build products. */
 | 
				
			||||||
@@ -39,11 +37,13 @@ BuildOutput getBuildOutput(nix::ref<Store> store,
 | 
				
			|||||||
        , std::regex::extended);
 | 
					        , std::regex::extended);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (auto & output : outputs) {
 | 
					    for (auto & output : outputs) {
 | 
				
			||||||
        Path failedFile = output + "/nix-support/failed";
 | 
					        auto outputS = store->printStorePath(output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Path failedFile = outputS + "/nix-support/failed";
 | 
				
			||||||
        if (accessor->stat(failedFile).type == FSAccessor::Type::tRegular)
 | 
					        if (accessor->stat(failedFile).type == FSAccessor::Type::tRegular)
 | 
				
			||||||
            res.failed = true;
 | 
					            res.failed = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Path productsFile = output + "/nix-support/hydra-build-products";
 | 
					        Path productsFile = outputS + "/nix-support/hydra-build-products";
 | 
				
			||||||
        if (accessor->stat(productsFile).type != FSAccessor::Type::tRegular)
 | 
					        if (accessor->stat(productsFile).type != FSAccessor::Type::tRegular)
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -72,7 +72,7 @@ BuildOutput getBuildOutput(nix::ref<Store> store,
 | 
				
			|||||||
            auto st = accessor->stat(product.path);
 | 
					            auto st = accessor->stat(product.path);
 | 
				
			||||||
            if (st.type == FSAccessor::Type::tMissing) continue;
 | 
					            if (st.type == FSAccessor::Type::tMissing) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            product.name = product.path == output ? "" : baseNameOf(product.path);
 | 
					            product.name = product.path == store->printStorePath(output) ? "" : baseNameOf(product.path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (st.type == FSAccessor::Type::tRegular) {
 | 
					            if (st.type == FSAccessor::Type::tRegular) {
 | 
				
			||||||
                product.isRegular = true;
 | 
					                product.isRegular = true;
 | 
				
			||||||
@@ -91,14 +91,14 @@ BuildOutput getBuildOutput(nix::ref<Store> store,
 | 
				
			|||||||
    if (!explicitProducts) {
 | 
					    if (!explicitProducts) {
 | 
				
			||||||
        for (auto & output : drv.outputs) {
 | 
					        for (auto & output : drv.outputs) {
 | 
				
			||||||
            BuildProduct product;
 | 
					            BuildProduct product;
 | 
				
			||||||
            product.path = output.second.path;
 | 
					            product.path = store->printStorePath(output.second.path);
 | 
				
			||||||
            product.type = "nix-build";
 | 
					            product.type = "nix-build";
 | 
				
			||||||
            product.subtype = output.first == "out" ? "" : output.first;
 | 
					            product.subtype = output.first == "out" ? "" : output.first;
 | 
				
			||||||
            product.name = storePathToName(product.path);
 | 
					            product.name = output.second.path.name();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            auto st = accessor->stat(product.path);
 | 
					            auto st = accessor->stat(product.path);
 | 
				
			||||||
            if (st.type == FSAccessor::Type::tMissing)
 | 
					            if (st.type == FSAccessor::Type::tMissing)
 | 
				
			||||||
                throw Error(format("getting status of ‘%1%’") % product.path);
 | 
					                throw Error("getting status of ‘%s’", product.path);
 | 
				
			||||||
            if (st.type == FSAccessor::Type::tDirectory)
 | 
					            if (st.type == FSAccessor::Type::tDirectory)
 | 
				
			||||||
                res.products.push_back(product);
 | 
					                res.products.push_back(product);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -106,7 +106,7 @@ BuildOutput getBuildOutput(nix::ref<Store> store,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* Get the release name from $output/nix-support/hydra-release-name. */
 | 
					    /* Get the release name from $output/nix-support/hydra-release-name. */
 | 
				
			||||||
    for (auto & output : outputs) {
 | 
					    for (auto & output : outputs) {
 | 
				
			||||||
        Path p = output + "/nix-support/hydra-release-name";
 | 
					        auto p = store->printStorePath(output) + "/nix-support/hydra-release-name";
 | 
				
			||||||
        if (accessor->stat(p).type != FSAccessor::Type::tRegular) continue;
 | 
					        if (accessor->stat(p).type != FSAccessor::Type::tRegular) continue;
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            res.releaseName = trim(accessor->readFile(p));
 | 
					            res.releaseName = trim(accessor->readFile(p));
 | 
				
			||||||
@@ -116,7 +116,7 @@ BuildOutput getBuildOutput(nix::ref<Store> store,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* Get metrics. */
 | 
					    /* Get metrics. */
 | 
				
			||||||
    for (auto & output : outputs) {
 | 
					    for (auto & output : outputs) {
 | 
				
			||||||
        Path metricsFile = output + "/nix-support/hydra-metrics";
 | 
					        auto metricsFile = store->printStorePath(output) + "/nix-support/hydra-metrics";
 | 
				
			||||||
        if (accessor->stat(metricsFile).type != FSAccessor::Type::tRegular) continue;
 | 
					        if (accessor->stat(metricsFile).type != FSAccessor::Type::tRegular) continue;
 | 
				
			||||||
        for (auto & line : tokenizeString<Strings>(accessor->readFile(metricsFile), "\n")) {
 | 
					        for (auto & line : tokenizeString<Strings>(accessor->readFile(metricsFile), "\n")) {
 | 
				
			||||||
            auto fields = tokenizeString<std::vector<std::string>>(line);
 | 
					            auto fields = tokenizeString<std::vector<std::string>>(line);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,7 @@ void setThreadName(const std::string & name)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void State::builder(MachineReservation::ptr reservation)
 | 
					void State::builder(MachineReservation::ptr reservation)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    setThreadName("bld~" + baseNameOf(reservation->step->drvPath));
 | 
					    setThreadName("bld~" + std::string(reservation->step->drvPath.to_string()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    StepResult res = sRetry;
 | 
					    StepResult res = sRetry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,8 +39,10 @@ void State::builder(MachineReservation::ptr reservation)
 | 
				
			|||||||
            auto destStore = getDestStore();
 | 
					            auto destStore = getDestStore();
 | 
				
			||||||
            res = doBuildStep(destStore, reservation, activeStep);
 | 
					            res = doBuildStep(destStore, reservation, activeStep);
 | 
				
			||||||
        } catch (std::exception & e) {
 | 
					        } catch (std::exception & e) {
 | 
				
			||||||
            printMsg(lvlError, format("uncaught exception building ‘%1%’ on ‘%2%’: %3%")
 | 
					            printMsg(lvlError, "uncaught exception building ‘%s’ on ‘%s’: %s",
 | 
				
			||||||
                % reservation->step->drvPath % reservation->machine->sshName % e.what());
 | 
					                localStore->printStorePath(reservation->step->drvPath),
 | 
				
			||||||
 | 
					                reservation->machine->sshName,
 | 
				
			||||||
 | 
					                e.what());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -60,7 +62,7 @@ void State::builder(MachineReservation::ptr reservation)
 | 
				
			|||||||
            nrRetries++;
 | 
					            nrRetries++;
 | 
				
			||||||
            if (step_->tries > maxNrRetries) maxNrRetries = step_->tries; // yeah yeah, not atomic
 | 
					            if (step_->tries > maxNrRetries) maxNrRetries = step_->tries; // yeah yeah, not atomic
 | 
				
			||||||
            int delta = retryInterval * std::pow(retryBackoff, step_->tries - 1) + (rand() % 10);
 | 
					            int delta = retryInterval * std::pow(retryBackoff, step_->tries - 1) + (rand() % 10);
 | 
				
			||||||
            printMsg(lvlInfo, format("will retry ‘%1%’ after %2%s") % step->drvPath % delta);
 | 
					            printMsg(lvlInfo, "will retry ‘%s’ after %ss", localStore->printStorePath(step->drvPath), delta);
 | 
				
			||||||
            step_->after = std::chrono::system_clock::now() + std::chrono::seconds(delta);
 | 
					            step_->after = std::chrono::system_clock::now() + std::chrono::seconds(delta);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -95,7 +97,7 @@ State::StepResult State::doBuildStep(nix::ref<Store> destStore,
 | 
				
			|||||||
       cancelled (namely if there are no more Builds referring to
 | 
					       cancelled (namely if there are no more Builds referring to
 | 
				
			||||||
       it). */
 | 
					       it). */
 | 
				
			||||||
    BuildID buildId;
 | 
					    BuildID buildId;
 | 
				
			||||||
    Path buildDrvPath;
 | 
					    std::optional<StorePath> buildDrvPath;
 | 
				
			||||||
    unsigned int maxSilentTime, buildTimeout;
 | 
					    unsigned int maxSilentTime, buildTimeout;
 | 
				
			||||||
    unsigned int repeats = step->isDeterministic ? 1 : 0;
 | 
					    unsigned int repeats = step->isDeterministic ? 1 : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -116,7 +118,7 @@ State::StepResult State::doBuildStep(nix::ref<Store> destStore,
 | 
				
			|||||||
               possibility, we retry this step (putting it back in
 | 
					               possibility, we retry this step (putting it back in
 | 
				
			||||||
               the runnable queue). If there are really no strong
 | 
					               the runnable queue). If there are really no strong
 | 
				
			||||||
               pointers to the step, it will be deleted. */
 | 
					               pointers to the step, it will be deleted. */
 | 
				
			||||||
            printMsg(lvlInfo, format("maybe cancelling build step ‘%1%’") % step->drvPath);
 | 
					            printMsg(lvlInfo, "maybe cancelling build step ‘%s’", localStore->printStorePath(step->drvPath));
 | 
				
			||||||
            return sMaybeCancelled;
 | 
					            return sMaybeCancelled;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -138,15 +140,15 @@ State::StepResult State::doBuildStep(nix::ref<Store> destStore,
 | 
				
			|||||||
        if (!build) build = *dependents.begin();
 | 
					        if (!build) build = *dependents.begin();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        buildId = build->id;
 | 
					        buildId = build->id;
 | 
				
			||||||
        buildDrvPath = build->drvPath;
 | 
					        buildDrvPath = build->drvPath.clone();
 | 
				
			||||||
        maxSilentTime = build->maxSilentTime;
 | 
					        maxSilentTime = build->maxSilentTime;
 | 
				
			||||||
        buildTimeout = build->buildTimeout;
 | 
					        buildTimeout = build->buildTimeout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        printInfo("performing step ‘%s’ %d times on ‘%s’ (needed by build %d and %d others)",
 | 
					        printInfo("performing step ‘%s’ %d times on ‘%s’ (needed by build %d and %d others)",
 | 
				
			||||||
            step->drvPath, repeats + 1, machine->sshName, buildId, (dependents.size() - 1));
 | 
					            localStore->printStorePath(step->drvPath), repeats + 1, machine->sshName, buildId, (dependents.size() - 1));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool quit = buildId == buildOne && step->drvPath == buildDrvPath;
 | 
					    bool quit = buildId == buildOne && step->drvPath == *buildDrvPath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    RemoteResult result;
 | 
					    RemoteResult result;
 | 
				
			||||||
    BuildOutput res;
 | 
					    BuildOutput res;
 | 
				
			||||||
@@ -166,7 +168,7 @@ State::StepResult State::doBuildStep(nix::ref<Store> destStore,
 | 
				
			|||||||
            try {
 | 
					            try {
 | 
				
			||||||
                auto store = destStore.dynamic_pointer_cast<BinaryCacheStore>();
 | 
					                auto store = destStore.dynamic_pointer_cast<BinaryCacheStore>();
 | 
				
			||||||
                if (uploadLogsToBinaryCache && store && pathExists(result.logFile)) {
 | 
					                if (uploadLogsToBinaryCache && store && pathExists(result.logFile)) {
 | 
				
			||||||
                    store->upsertFile("log/" + baseNameOf(step->drvPath), readFile(result.logFile), "text/plain; charset=utf-8");
 | 
					                    store->upsertFile("log/" + std::string(step->drvPath.to_string()), readFile(result.logFile), "text/plain; charset=utf-8");
 | 
				
			||||||
                    unlink(result.logFile.c_str());
 | 
					                    unlink(result.logFile.c_str());
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } catch (...) {
 | 
					            } catch (...) {
 | 
				
			||||||
@@ -218,7 +220,7 @@ State::StepResult State::doBuildStep(nix::ref<Store> destStore,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (result.stepStatus == bsSuccess) {
 | 
					        if (result.stepStatus == bsSuccess) {
 | 
				
			||||||
            updateStep(ssPostProcessing);
 | 
					            updateStep(ssPostProcessing);
 | 
				
			||||||
            res = getBuildOutput(destStore, ref<FSAccessor>(result.accessor), step->drv);
 | 
					            res = getBuildOutput(destStore, ref<FSAccessor>(result.accessor), *step->drv);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        result.accessor = 0;
 | 
					        result.accessor = 0;
 | 
				
			||||||
@@ -255,8 +257,8 @@ State::StepResult State::doBuildStep(nix::ref<Store> destStore,
 | 
				
			|||||||
    /* The step had a hopefully temporary failure (e.g. network
 | 
					    /* The step had a hopefully temporary failure (e.g. network
 | 
				
			||||||
       issue). Retry a number of times. */
 | 
					       issue). Retry a number of times. */
 | 
				
			||||||
    if (result.canRetry) {
 | 
					    if (result.canRetry) {
 | 
				
			||||||
        printMsg(lvlError, format("possibly transient failure building ‘%1%’ on ‘%2%’: %3%")
 | 
					        printMsg(lvlError, "possibly transient failure building ‘%s’ on ‘%s’: %s",
 | 
				
			||||||
            % step->drvPath % machine->sshName % result.errorMsg);
 | 
					            localStore->printStorePath(step->drvPath), machine->sshName, result.errorMsg);
 | 
				
			||||||
        assert(stepNr);
 | 
					        assert(stepNr);
 | 
				
			||||||
        bool retry;
 | 
					        bool retry;
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -275,7 +277,7 @@ State::StepResult State::doBuildStep(nix::ref<Store> destStore,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        assert(stepNr);
 | 
					        assert(stepNr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (auto & path : step->drv.outputPaths())
 | 
					        for (auto & path : step->drv->outputPaths())
 | 
				
			||||||
            addRoot(path);
 | 
					            addRoot(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Register success in the database for all Build objects that
 | 
					        /* Register success in the database for all Build objects that
 | 
				
			||||||
@@ -308,7 +310,8 @@ State::StepResult State::doBuildStep(nix::ref<Store> destStore,
 | 
				
			|||||||
                   no new referrers can have been added in the
 | 
					                   no new referrers can have been added in the
 | 
				
			||||||
                   meantime or be added afterwards. */
 | 
					                   meantime or be added afterwards. */
 | 
				
			||||||
                if (direct.empty()) {
 | 
					                if (direct.empty()) {
 | 
				
			||||||
                    printMsg(lvlDebug, format("finishing build step ‘%1%’") % step->drvPath);
 | 
					                    printMsg(lvlDebug, "finishing build step ‘%s’",
 | 
				
			||||||
 | 
					                        localStore->printStorePath(step->drvPath));
 | 
				
			||||||
                    steps_->erase(step->drvPath);
 | 
					                    steps_->erase(step->drvPath);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -393,7 +396,8 @@ State::StepResult State::doBuildStep(nix::ref<Store> destStore,
 | 
				
			|||||||
                   be certain no new referrers can be added. */
 | 
					                   be certain no new referrers can be added. */
 | 
				
			||||||
                if (indirect.empty()) {
 | 
					                if (indirect.empty()) {
 | 
				
			||||||
                    for (auto & s : steps) {
 | 
					                    for (auto & s : steps) {
 | 
				
			||||||
                        printMsg(lvlDebug, format("finishing build step ‘%1%’") % s->drvPath);
 | 
					                        printMsg(lvlDebug, "finishing build step ‘%s’",
 | 
				
			||||||
 | 
					                            localStore->printStorePath(s->drvPath));
 | 
				
			||||||
                        steps_->erase(s->drvPath);
 | 
					                        steps_->erase(s->drvPath);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -437,8 +441,8 @@ State::StepResult State::doBuildStep(nix::ref<Store> destStore,
 | 
				
			|||||||
                /* Remember failed paths in the database so that they
 | 
					                /* Remember failed paths in the database so that they
 | 
				
			||||||
                   won't be built again. */
 | 
					                   won't be built again. */
 | 
				
			||||||
                if (result.stepStatus != bsCachedFailure && result.canCache)
 | 
					                if (result.stepStatus != bsCachedFailure && result.canCache)
 | 
				
			||||||
                    for (auto & path : step->drv.outputPaths())
 | 
					                    for (auto & path : step->drv->outputPaths())
 | 
				
			||||||
                        txn.parameterized("insert into FailedPaths values ($1)")(path).exec();
 | 
					                        txn.parameterized("insert into FailedPaths values ($1)")(localStore->printStorePath(path)).exec();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                txn.commit();
 | 
					                txn.commit();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -478,8 +482,8 @@ State::StepResult State::doBuildStep(nix::ref<Store> destStore,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void State::addRoot(const Path & storePath)
 | 
					void State::addRoot(const StorePath & storePath)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    auto root = rootsDir + "/" + baseNameOf(storePath);
 | 
					    auto root = rootsDir + "/" + std::string(storePath.to_string());
 | 
				
			||||||
    if (!pathExists(root)) writeFile(root, "");
 | 
					    if (!pathExists(root)) writeFile(root, "");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ using namespace nix;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void State::makeRunnable(Step::ptr step)
 | 
					void State::makeRunnable(Step::ptr step)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    printMsg(lvlChatty, format("step ‘%1%’ is now runnable") % step->drvPath);
 | 
					    printMsg(lvlChatty, "step ‘%s’ is now runnable", localStore->printStorePath(step->drvPath));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        auto step_(step->state.lock());
 | 
					        auto step_(step->state.lock());
 | 
				
			||||||
@@ -248,7 +248,7 @@ system_time State::doDispatch()
 | 
				
			|||||||
                /* Can this machine do this step? */
 | 
					                /* Can this machine do this step? */
 | 
				
			||||||
                if (!mi.machine->supportsStep(step)) {
 | 
					                if (!mi.machine->supportsStep(step)) {
 | 
				
			||||||
                    debug("machine '%s' does not support step '%s' (system type '%s')",
 | 
					                    debug("machine '%s' does not support step '%s' (system type '%s')",
 | 
				
			||||||
                        mi.machine->sshName, step->drvPath, step->drv.platform);
 | 
					                        mi.machine->sshName, localStore->printStorePath(step->drvPath), step->drv->platform);
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,9 +38,9 @@ static uint64_t getMemSize()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
std::string getEnvOrDie(const std::string & key)
 | 
					std::string getEnvOrDie(const std::string & key)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char * value = getenv(key.c_str());
 | 
					    auto value = getEnv(key);
 | 
				
			||||||
    if (!value) throw Error("environment variable '%s' is not set", key);
 | 
					    if (!value) throw Error("environment variable '%s' is not set", key);
 | 
				
			||||||
    return value;
 | 
					    return *value;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -160,7 +160,7 @@ void State::monitorMachinesFile()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    string defaultMachinesFile = "/etc/nix/machines";
 | 
					    string defaultMachinesFile = "/etc/nix/machines";
 | 
				
			||||||
    auto machinesFiles = tokenizeString<std::vector<Path>>(
 | 
					    auto machinesFiles = tokenizeString<std::vector<Path>>(
 | 
				
			||||||
        getEnv("NIX_REMOTE_SYSTEMS", pathExists(defaultMachinesFile) ? defaultMachinesFile : ""), ":");
 | 
					        getEnv("NIX_REMOTE_SYSTEMS").value_or(pathExists(defaultMachinesFile) ? defaultMachinesFile : ""), ":");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (machinesFiles.empty()) {
 | 
					    if (machinesFiles.empty()) {
 | 
				
			||||||
        parseMachines("localhost " +
 | 
					        parseMachines("localhost " +
 | 
				
			||||||
@@ -252,10 +252,10 @@ unsigned int State::createBuildStep(pqxx::work & txn, time_t startTime, BuildID
 | 
				
			|||||||
        (buildId)
 | 
					        (buildId)
 | 
				
			||||||
        (stepNr)
 | 
					        (stepNr)
 | 
				
			||||||
        (0) // == build
 | 
					        (0) // == build
 | 
				
			||||||
        (step->drvPath)
 | 
					        (localStore->printStorePath(step->drvPath))
 | 
				
			||||||
        (status == bsBusy ? 1 : 0)
 | 
					        (status == bsBusy ? 1 : 0)
 | 
				
			||||||
        (startTime, startTime != 0)
 | 
					        (startTime, startTime != 0)
 | 
				
			||||||
        (step->drv.platform)
 | 
					        (step->drv->platform)
 | 
				
			||||||
        ((int) status, status != bsBusy)
 | 
					        ((int) status, status != bsBusy)
 | 
				
			||||||
        (propagatedFrom, propagatedFrom != 0)
 | 
					        (propagatedFrom, propagatedFrom != 0)
 | 
				
			||||||
        (errorMsg, errorMsg != "")
 | 
					        (errorMsg, errorMsg != "")
 | 
				
			||||||
@@ -264,10 +264,10 @@ unsigned int State::createBuildStep(pqxx::work & txn, time_t startTime, BuildID
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (r.affected_rows() == 0) goto restart;
 | 
					    if (r.affected_rows() == 0) goto restart;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (auto & output : step->drv.outputs)
 | 
					    for (auto & output : step->drv->outputs)
 | 
				
			||||||
        txn.parameterized
 | 
					        txn.parameterized
 | 
				
			||||||
            ("insert into BuildStepOutputs (build, stepnr, name, path) values ($1, $2, $3, $4)")
 | 
					            ("insert into BuildStepOutputs (build, stepnr, name, path) values ($1, $2, $3, $4)")
 | 
				
			||||||
            (buildId)(stepNr)(output.first)(output.second.path).exec();
 | 
					            (buildId)(stepNr)(output.first)(localStore->printStorePath(output.second.path)).exec();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (status == bsBusy)
 | 
					    if (status == bsBusy)
 | 
				
			||||||
        txn.exec(fmt("notify step_started, '%d\t%d'", buildId, stepNr));
 | 
					        txn.exec(fmt("notify step_started, '%d\t%d'", buildId, stepNr));
 | 
				
			||||||
@@ -310,7 +310,7 @@ void State::finishBuildStep(pqxx::work & txn, const RemoteResult & result,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int State::createSubstitutionStep(pqxx::work & txn, time_t startTime, time_t stopTime,
 | 
					int State::createSubstitutionStep(pqxx::work & txn, time_t startTime, time_t stopTime,
 | 
				
			||||||
    Build::ptr build, const Path & drvPath, const string & outputName, const Path & storePath)
 | 
					    Build::ptr build, const StorePath & drvPath, const string & outputName, const StorePath & storePath)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 restart:
 | 
					 restart:
 | 
				
			||||||
    auto stepNr = allocBuildStep(txn, build->id);
 | 
					    auto stepNr = allocBuildStep(txn, build->id);
 | 
				
			||||||
@@ -320,7 +320,7 @@ int State::createSubstitutionStep(pqxx::work & txn, time_t startTime, time_t sto
 | 
				
			|||||||
        (build->id)
 | 
					        (build->id)
 | 
				
			||||||
        (stepNr)
 | 
					        (stepNr)
 | 
				
			||||||
        (1) // == substitution
 | 
					        (1) // == substitution
 | 
				
			||||||
        (drvPath)
 | 
					        (localStore->printStorePath(drvPath))
 | 
				
			||||||
        (0)
 | 
					        (0)
 | 
				
			||||||
        (0)
 | 
					        (0)
 | 
				
			||||||
        (startTime)
 | 
					        (startTime)
 | 
				
			||||||
@@ -330,7 +330,10 @@ int State::createSubstitutionStep(pqxx::work & txn, time_t startTime, time_t sto
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    txn.parameterized
 | 
					    txn.parameterized
 | 
				
			||||||
        ("insert into BuildStepOutputs (build, stepnr, name, path) values ($1, $2, $3, $4)")
 | 
					        ("insert into BuildStepOutputs (build, stepnr, name, path) values ($1, $2, $3, $4)")
 | 
				
			||||||
        (build->id)(stepNr)(outputName)(storePath).exec();
 | 
					        (build->id)
 | 
				
			||||||
 | 
					        (stepNr)
 | 
				
			||||||
 | 
					        (outputName)
 | 
				
			||||||
 | 
					        (localStore->printStorePath(storePath)).exec();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return stepNr;
 | 
					    return stepNr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -450,8 +453,8 @@ void State::markSucceededBuild(pqxx::work & txn, Build::ptr build,
 | 
				
			|||||||
bool State::checkCachedFailure(Step::ptr step, Connection & conn)
 | 
					bool State::checkCachedFailure(Step::ptr step, Connection & conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    pqxx::work txn(conn);
 | 
					    pqxx::work txn(conn);
 | 
				
			||||||
    for (auto & path : step->drv.outputPaths())
 | 
					    for (auto & path : step->drv->outputPaths())
 | 
				
			||||||
        if (!txn.parameterized("select 1 from FailedPaths where path = $1")(path).exec().empty())
 | 
					        if (!txn.parameterized("select 1 from FailedPaths where path = $1")(localStore->printStorePath(path)).exec().empty())
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -763,7 +766,7 @@ void State::run(BuildID buildOne)
 | 
				
			|||||||
    Store::Params localParams;
 | 
					    Store::Params localParams;
 | 
				
			||||||
    localParams["max-connections"] = "16";
 | 
					    localParams["max-connections"] = "16";
 | 
				
			||||||
    localParams["max-connection-age"] = "600";
 | 
					    localParams["max-connection-age"] = "600";
 | 
				
			||||||
    localStore = openStore(getEnv("NIX_REMOTE"), localParams);
 | 
					    localStore = openStore(getEnv("NIX_REMOTE").value_or(""), localParams);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto storeUri = config->getStrOption("store_uri");
 | 
					    auto storeUri = config->getStrOption("store_uri");
 | 
				
			||||||
    _destStore = storeUri == "" ? localStore : openStore(storeUri);
 | 
					    _destStore = storeUri == "" ? localStore : openStore(storeUri);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -83,7 +83,7 @@ bool State::getQueuedBuilds(Connection & conn,
 | 
				
			|||||||
       them yet (since we don't want a long-running transaction). */
 | 
					       them yet (since we don't want a long-running transaction). */
 | 
				
			||||||
    std::vector<BuildID> newIDs;
 | 
					    std::vector<BuildID> newIDs;
 | 
				
			||||||
    std::map<BuildID, Build::ptr> newBuildsByID;
 | 
					    std::map<BuildID, Build::ptr> newBuildsByID;
 | 
				
			||||||
    std::multimap<Path, BuildID> newBuildsByPath;
 | 
					    std::multimap<StorePath, BuildID> newBuildsByPath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unsigned int newLastBuildId = lastBuildId;
 | 
					    unsigned int newLastBuildId = lastBuildId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -104,7 +104,7 @@ bool State::getQueuedBuilds(Connection & conn,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            auto build = std::make_shared<Build>();
 | 
					            auto build = std::make_shared<Build>();
 | 
				
			||||||
            build->id = id;
 | 
					            build->id = id;
 | 
				
			||||||
            build->drvPath = row["drvPath"].as<string>();
 | 
					            build->drvPath = localStore->parseStorePath(row["drvPath"].as<string>());
 | 
				
			||||||
            build->projectName = row["project"].as<string>();
 | 
					            build->projectName = row["project"].as<string>();
 | 
				
			||||||
            build->jobsetName = row["jobset"].as<string>();
 | 
					            build->jobsetName = row["jobset"].as<string>();
 | 
				
			||||||
            build->jobName = row["job"].as<string>();
 | 
					            build->jobName = row["job"].as<string>();
 | 
				
			||||||
@@ -117,14 +117,14 @@ bool State::getQueuedBuilds(Connection & conn,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            newIDs.push_back(id);
 | 
					            newIDs.push_back(id);
 | 
				
			||||||
            newBuildsByID[id] = build;
 | 
					            newBuildsByID[id] = build;
 | 
				
			||||||
            newBuildsByPath.emplace(std::make_pair(build->drvPath, id));
 | 
					            newBuildsByPath.emplace(std::make_pair(build->drvPath.clone(), id));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::set<Step::ptr> newRunnable;
 | 
					    std::set<Step::ptr> newRunnable;
 | 
				
			||||||
    unsigned int nrAdded;
 | 
					    unsigned int nrAdded;
 | 
				
			||||||
    std::function<void(Build::ptr)> createBuild;
 | 
					    std::function<void(Build::ptr)> createBuild;
 | 
				
			||||||
    std::set<Path> finishedDrvs;
 | 
					    std::set<StorePath> finishedDrvs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    createBuild = [&](Build::ptr build) {
 | 
					    createBuild = [&](Build::ptr build) {
 | 
				
			||||||
        printMsg(lvlTalkative, format("loading build %1% (%2%)") % build->id % build->fullJobName());
 | 
					        printMsg(lvlTalkative, format("loading build %1% (%2%)") % build->id % build->fullJobName());
 | 
				
			||||||
@@ -160,7 +160,8 @@ bool State::getQueuedBuilds(Connection & conn,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            /* Some step previously failed, so mark the build as
 | 
					            /* Some step previously failed, so mark the build as
 | 
				
			||||||
               failed right away. */
 | 
					               failed right away. */
 | 
				
			||||||
            printMsg(lvlError, format("marking build %d as cached failure due to ‘%s’") % build->id % ex.step->drvPath);
 | 
					            printMsg(lvlError, "marking build %d as cached failure due to ‘%s’",
 | 
				
			||||||
 | 
					                build->id, localStore->printStorePath(ex.step->drvPath));
 | 
				
			||||||
            if (!build->finishedInDB) {
 | 
					            if (!build->finishedInDB) {
 | 
				
			||||||
                auto mc = startDbUpdate();
 | 
					                auto mc = startDbUpdate();
 | 
				
			||||||
                pqxx::work txn(conn);
 | 
					                pqxx::work txn(conn);
 | 
				
			||||||
@@ -171,14 +172,14 @@ bool State::getQueuedBuilds(Connection & conn,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                auto res = txn.parameterized
 | 
					                auto res = txn.parameterized
 | 
				
			||||||
                    ("select max(build) from BuildSteps where drvPath = $1 and startTime != 0 and stopTime != 0 and status = 1")
 | 
					                    ("select max(build) from BuildSteps where drvPath = $1 and startTime != 0 and stopTime != 0 and status = 1")
 | 
				
			||||||
                    (ex.step->drvPath).exec();
 | 
					                    (localStore->printStorePath(ex.step->drvPath)).exec();
 | 
				
			||||||
                if (!res[0][0].is_null()) propagatedFrom = res[0][0].as<BuildID>();
 | 
					                if (!res[0][0].is_null()) propagatedFrom = res[0][0].as<BuildID>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (!propagatedFrom) {
 | 
					                if (!propagatedFrom) {
 | 
				
			||||||
                    for (auto & output : ex.step->drv.outputs) {
 | 
					                    for (auto & output : ex.step->drv->outputs) {
 | 
				
			||||||
                        auto res = txn.parameterized
 | 
					                        auto res = txn.parameterized
 | 
				
			||||||
                            ("select max(s.build) from BuildSteps s join BuildStepOutputs o on s.build = o.build where path = $1 and startTime != 0 and stopTime != 0 and status = 1")
 | 
					                            ("select max(s.build) from BuildSteps s join BuildStepOutputs o on s.build = o.build where path = $1 and startTime != 0 and stopTime != 0 and status = 1")
 | 
				
			||||||
                            (output.second.path).exec();
 | 
					                            (localStore->printStorePath(output.second.path)).exec();
 | 
				
			||||||
                        if (!res[0][0].is_null()) {
 | 
					                        if (!res[0][0].is_null()) {
 | 
				
			||||||
                            propagatedFrom = res[0][0].as<BuildID>();
 | 
					                            propagatedFrom = res[0][0].as<BuildID>();
 | 
				
			||||||
                            break;
 | 
					                            break;
 | 
				
			||||||
@@ -217,7 +218,7 @@ bool State::getQueuedBuilds(Connection & conn,
 | 
				
			|||||||
        /* If we didn't get a step, it means the step's outputs are
 | 
					        /* If we didn't get a step, it means the step's outputs are
 | 
				
			||||||
           all valid. So we mark this as a finished, cached build. */
 | 
					           all valid. So we mark this as a finished, cached build. */
 | 
				
			||||||
        if (!step) {
 | 
					        if (!step) {
 | 
				
			||||||
            Derivation drv = readDerivation(build->drvPath);
 | 
					            Derivation drv = readDerivation(*localStore, localStore->printStorePath(build->drvPath));
 | 
				
			||||||
            BuildOutput res = getBuildOutputCached(conn, destStore, drv);
 | 
					            BuildOutput res = getBuildOutputCached(conn, destStore, drv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (auto & path : drv.outputPaths())
 | 
					            for (auto & path : drv.outputPaths())
 | 
				
			||||||
@@ -227,7 +228,7 @@ bool State::getQueuedBuilds(Connection & conn,
 | 
				
			|||||||
            auto mc = startDbUpdate();
 | 
					            auto mc = startDbUpdate();
 | 
				
			||||||
            pqxx::work txn(conn);
 | 
					            pqxx::work txn(conn);
 | 
				
			||||||
            time_t now = time(0);
 | 
					            time_t now = time(0);
 | 
				
			||||||
            printMsg(lvlInfo, format("marking build %1% as succeeded (cached)") % build->id);
 | 
					            printMsg(lvlInfo, "marking build %1% as succeeded (cached)", build->id);
 | 
				
			||||||
            markSucceededBuild(txn, build, res, true, now, now);
 | 
					            markSucceededBuild(txn, build, res, true, now, now);
 | 
				
			||||||
            notifyBuildFinished(txn, build->id, {});
 | 
					            notifyBuildFinished(txn, build->id, {});
 | 
				
			||||||
            txn.commit();
 | 
					            txn.commit();
 | 
				
			||||||
@@ -250,8 +251,8 @@ bool State::getQueuedBuilds(Connection & conn,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        build->propagatePriorities();
 | 
					        build->propagatePriorities();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        printMsg(lvlChatty, format("added build %1% (top-level step %2%, %3% new steps)")
 | 
					        printMsg(lvlChatty, "added build %1% (top-level step %2%, %3% new steps)",
 | 
				
			||||||
            % build->id % step->drvPath % newSteps.size());
 | 
					            build->id, localStore->printStorePath(step->drvPath), newSteps.size());
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Now instantiate build steps for each new build. The builder
 | 
					    /* Now instantiate build steps for each new build. The builder
 | 
				
			||||||
@@ -271,7 +272,7 @@ bool State::getQueuedBuilds(Connection & conn,
 | 
				
			|||||||
        try {
 | 
					        try {
 | 
				
			||||||
            createBuild(build);
 | 
					            createBuild(build);
 | 
				
			||||||
        } catch (Error & e) {
 | 
					        } catch (Error & e) {
 | 
				
			||||||
            e.addPrefix(format("while loading build %1%: ") % build->id);
 | 
					            e.addPrefix(fmt("while loading build %1%: ", build->id));
 | 
				
			||||||
            throw;
 | 
					            throw;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -358,10 +359,12 @@ void State::processQueueChange(Connection & conn)
 | 
				
			|||||||
                activeStepState->cancelled = true;
 | 
					                activeStepState->cancelled = true;
 | 
				
			||||||
                if (activeStepState->pid != -1) {
 | 
					                if (activeStepState->pid != -1) {
 | 
				
			||||||
                    printInfo("killing builder process %d of build step ‘%s’",
 | 
					                    printInfo("killing builder process %d of build step ‘%s’",
 | 
				
			||||||
                        activeStepState->pid, activeStep->step->drvPath);
 | 
					                        activeStepState->pid,
 | 
				
			||||||
 | 
					                        localStore->printStorePath(activeStep->step->drvPath));
 | 
				
			||||||
                    if (kill(activeStepState->pid, SIGINT) == -1)
 | 
					                    if (kill(activeStepState->pid, SIGINT) == -1)
 | 
				
			||||||
                        printError("error killing build step ‘%s’: %s",
 | 
					                        printError("error killing build step ‘%s’: %s",
 | 
				
			||||||
                            activeStep->step->drvPath, strerror(errno));
 | 
					                            localStore->printStorePath(activeStep->step->drvPath),
 | 
				
			||||||
 | 
					                            strerror(errno));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -370,8 +373,8 @@ void State::processQueueChange(Connection & conn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Step::ptr State::createStep(ref<Store> destStore,
 | 
					Step::ptr State::createStep(ref<Store> destStore,
 | 
				
			||||||
    Connection & conn, Build::ptr build, const Path & drvPath,
 | 
					    Connection & conn, Build::ptr build, const StorePath & drvPath,
 | 
				
			||||||
    Build::ptr referringBuild, Step::ptr referringStep, std::set<Path> & finishedDrvs,
 | 
					    Build::ptr referringBuild, Step::ptr referringStep, std::set<StorePath> & finishedDrvs,
 | 
				
			||||||
    std::set<Step::ptr> & newSteps, std::set<Step::ptr> & newRunnable)
 | 
					    std::set<Step::ptr> & newSteps, std::set<Step::ptr> & newRunnable)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (finishedDrvs.find(drvPath) != finishedDrvs.end()) return 0;
 | 
					    if (finishedDrvs.find(drvPath) != finishedDrvs.end()) return 0;
 | 
				
			||||||
@@ -400,7 +403,7 @@ Step::ptr State::createStep(ref<Store> destStore,
 | 
				
			|||||||
        /* If it doesn't exist, create it. */
 | 
					        /* If it doesn't exist, create it. */
 | 
				
			||||||
        if (!step) {
 | 
					        if (!step) {
 | 
				
			||||||
            step = std::make_shared<Step>();
 | 
					            step = std::make_shared<Step>();
 | 
				
			||||||
            step->drvPath = drvPath;
 | 
					            step->drvPath = drvPath.clone();
 | 
				
			||||||
            isNew = true;
 | 
					            isNew = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -414,28 +417,28 @@ Step::ptr State::createStep(ref<Store> destStore,
 | 
				
			|||||||
        if (referringStep)
 | 
					        if (referringStep)
 | 
				
			||||||
            step_->rdeps.push_back(referringStep);
 | 
					            step_->rdeps.push_back(referringStep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        (*steps_)[drvPath] = step;
 | 
					        steps_->insert_or_assign(drvPath.clone(), step);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!isNew) return step;
 | 
					    if (!isNew) return step;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    printMsg(lvlDebug, format("considering derivation ‘%1%’") % drvPath);
 | 
					    printMsg(lvlDebug, "considering derivation ‘%1%’", localStore->printStorePath(drvPath));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Initialize the step. Note that the step may be visible in
 | 
					    /* Initialize the step. Note that the step may be visible in
 | 
				
			||||||
       ‘steps’ before this point, but that doesn't matter because
 | 
					       ‘steps’ before this point, but that doesn't matter because
 | 
				
			||||||
       it's not runnable yet, and other threads won't make it
 | 
					       it's not runnable yet, and other threads won't make it
 | 
				
			||||||
       runnable while step->created == false. */
 | 
					       runnable while step->created == false. */
 | 
				
			||||||
    step->drv = readDerivation(drvPath);
 | 
					    step->drv = std::make_unique<Derivation>(readDerivation(*localStore, localStore->printStorePath(drvPath)));
 | 
				
			||||||
    step->parsedDrv = std::make_unique<ParsedDerivation>(drvPath, step->drv);
 | 
					    step->parsedDrv = std::make_unique<ParsedDerivation>(drvPath.clone(), *step->drv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    step->preferLocalBuild = step->parsedDrv->willBuildLocally();
 | 
					    step->preferLocalBuild = step->parsedDrv->willBuildLocally();
 | 
				
			||||||
    step->isDeterministic = get(step->drv.env, "isDetermistic", "0") == "1";
 | 
					    step->isDeterministic = get(step->drv->env, "isDetermistic").value_or("0") == "1";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    step->systemType = step->drv.platform;
 | 
					    step->systemType = step->drv->platform;
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        auto i = step->drv.env.find("requiredSystemFeatures");
 | 
					        auto i = step->drv->env.find("requiredSystemFeatures");
 | 
				
			||||||
        StringSet features;
 | 
					        StringSet features;
 | 
				
			||||||
        if (i != step->drv.env.end())
 | 
					        if (i != step->drv->env.end())
 | 
				
			||||||
            features = step->requiredSystemFeatures = tokenizeString<std::set<std::string>>(i->second);
 | 
					            features = step->requiredSystemFeatures = tokenizeString<std::set<std::string>>(i->second);
 | 
				
			||||||
        if (step->preferLocalBuild)
 | 
					        if (step->preferLocalBuild)
 | 
				
			||||||
            features.insert("local");
 | 
					            features.insert("local");
 | 
				
			||||||
@@ -451,12 +454,13 @@ Step::ptr State::createStep(ref<Store> destStore,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* Are all outputs valid? */
 | 
					    /* Are all outputs valid? */
 | 
				
			||||||
    bool valid = true;
 | 
					    bool valid = true;
 | 
				
			||||||
    PathSet outputs = step->drv.outputPaths();
 | 
					    auto outputs = step->drv->outputPaths();
 | 
				
			||||||
    DerivationOutputs missing;
 | 
					    DerivationOutputs missing;
 | 
				
			||||||
    for (auto & i : step->drv.outputs)
 | 
					    for (auto & i : step->drv->outputs)
 | 
				
			||||||
        if (!destStore->isValidPath(i.second.path)) {
 | 
					        if (!destStore->isValidPath(i.second.path)) {
 | 
				
			||||||
            valid = false;
 | 
					            valid = false;
 | 
				
			||||||
            missing[i.first] = i.second;
 | 
					            missing.insert_or_assign(i.first,
 | 
				
			||||||
 | 
					                DerivationOutput(i.second.path.clone(), std::string(i.second.hashAlgo), std::string(i.second.hash)));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Try to copy the missing paths from the local store or from
 | 
					    /* Try to copy the missing paths from the local store or from
 | 
				
			||||||
@@ -469,7 +473,7 @@ Step::ptr State::createStep(ref<Store> destStore,
 | 
				
			|||||||
                avail++;
 | 
					                avail++;
 | 
				
			||||||
            else if (useSubstitutes) {
 | 
					            else if (useSubstitutes) {
 | 
				
			||||||
                SubstitutablePathInfos infos;
 | 
					                SubstitutablePathInfos infos;
 | 
				
			||||||
                localStore->querySubstitutablePathInfos({i.second.path}, infos);
 | 
					                localStore->querySubstitutablePathInfos(singleton(i.second.path), infos);
 | 
				
			||||||
                if (infos.size() == 1)
 | 
					                if (infos.size() == 1)
 | 
				
			||||||
                    avail++;
 | 
					                    avail++;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -482,14 +486,18 @@ Step::ptr State::createStep(ref<Store> destStore,
 | 
				
			|||||||
                    time_t startTime = time(0);
 | 
					                    time_t startTime = time(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (localStore->isValidPath(i.second.path))
 | 
					                    if (localStore->isValidPath(i.second.path))
 | 
				
			||||||
                        printInfo("copying output ‘%1%’ of ‘%2%’ from local store", i.second.path, drvPath);
 | 
					                        printInfo("copying output ‘%1%’ of ‘%2%’ from local store",
 | 
				
			||||||
 | 
					                            localStore->printStorePath(i.second.path),
 | 
				
			||||||
 | 
					                            localStore->printStorePath(drvPath));
 | 
				
			||||||
                    else {
 | 
					                    else {
 | 
				
			||||||
                        printInfo("substituting output ‘%1%’ of ‘%2%’", i.second.path, drvPath);
 | 
					                        printInfo("substituting output ‘%1%’ of ‘%2%’",
 | 
				
			||||||
 | 
					                            localStore->printStorePath(i.second.path),
 | 
				
			||||||
 | 
					                            localStore->printStorePath(drvPath));
 | 
				
			||||||
                        localStore->ensurePath(i.second.path);
 | 
					                        localStore->ensurePath(i.second.path);
 | 
				
			||||||
                        // FIXME: should copy directly from substituter to destStore.
 | 
					                        // FIXME: should copy directly from substituter to destStore.
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    copyClosure(ref<Store>(localStore), destStore, {i.second.path});
 | 
					                    copyClosure(ref<Store>(localStore), destStore, singleton(i.second.path));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    time_t stopTime = time(0);
 | 
					                    time_t stopTime = time(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -501,7 +509,10 @@ Step::ptr State::createStep(ref<Store> destStore,
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                } catch (Error & e) {
 | 
					                } catch (Error & e) {
 | 
				
			||||||
                    printError("while copying/substituting output ‘%s’ of ‘%s’: %s", i.second.path, drvPath, e.what());
 | 
					                    printError("while copying/substituting output ‘%s’ of ‘%s’: %s",
 | 
				
			||||||
 | 
					                        localStore->printStorePath(i.second.path),
 | 
				
			||||||
 | 
					                        localStore->printStorePath(drvPath),
 | 
				
			||||||
 | 
					                        e.what());
 | 
				
			||||||
                    valid = false;
 | 
					                    valid = false;
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -511,15 +522,15 @@ Step::ptr State::createStep(ref<Store> destStore,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // FIXME: check whether all outputs are in the binary cache.
 | 
					    // FIXME: check whether all outputs are in the binary cache.
 | 
				
			||||||
    if (valid) {
 | 
					    if (valid) {
 | 
				
			||||||
        finishedDrvs.insert(drvPath);
 | 
					        finishedDrvs.insert(drvPath.clone());
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* No, we need to build. */
 | 
					    /* No, we need to build. */
 | 
				
			||||||
    printMsg(lvlDebug, format("creating build step ‘%1%’") % drvPath);
 | 
					    printMsg(lvlDebug, "creating build step ‘%1%’", localStore->printStorePath(drvPath));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Create steps for the dependencies. */
 | 
					    /* Create steps for the dependencies. */
 | 
				
			||||||
    for (auto & i : step->drv.inputDrvs) {
 | 
					    for (auto & i : step->drv->inputDrvs) {
 | 
				
			||||||
        auto dep = createStep(destStore, conn, build, i.first, 0, step, finishedDrvs, newSteps, newRunnable);
 | 
					        auto dep = createStep(destStore, conn, build, i.first, 0, step, finishedDrvs, newSteps, newRunnable);
 | 
				
			||||||
        if (dep) {
 | 
					        if (dep) {
 | 
				
			||||||
            auto step_(step->state.lock());
 | 
					            auto step_(step->state.lock());
 | 
				
			||||||
@@ -607,7 +618,7 @@ BuildOutput State::getBuildOutputCached(Connection & conn, nix::ref<nix::Store>
 | 
				
			|||||||
            ("select id, buildStatus, releaseName, closureSize, size from Builds b "
 | 
					            ("select id, buildStatus, releaseName, closureSize, size from Builds b "
 | 
				
			||||||
             "join BuildOutputs o on b.id = o.build "
 | 
					             "join BuildOutputs o on b.id = o.build "
 | 
				
			||||||
             "where finished = 1 and (buildStatus = 0 or buildStatus = 6) and path = $1")
 | 
					             "where finished = 1 and (buildStatus = 0 or buildStatus = 6) and path = $1")
 | 
				
			||||||
            (output.second.path).exec();
 | 
					            (localStore->printStorePath(output.second.path)).exec();
 | 
				
			||||||
        if (r.empty()) continue;
 | 
					        if (r.empty()) continue;
 | 
				
			||||||
        BuildID id = r[0][0].as<BuildID>();
 | 
					        BuildID id = r[0][0].as<BuildID>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -123,8 +123,8 @@ struct Build
 | 
				
			|||||||
    typedef std::weak_ptr<Build> wptr;
 | 
					    typedef std::weak_ptr<Build> wptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    BuildID id;
 | 
					    BuildID id;
 | 
				
			||||||
    nix::Path drvPath;
 | 
					    nix::StorePath drvPath;
 | 
				
			||||||
    std::map<std::string, nix::Path> outputs;
 | 
					    std::map<std::string, nix::StorePath> outputs;
 | 
				
			||||||
    std::string projectName, jobsetName, jobName;
 | 
					    std::string projectName, jobsetName, jobName;
 | 
				
			||||||
    time_t timestamp;
 | 
					    time_t timestamp;
 | 
				
			||||||
    unsigned int maxSilentTime, buildTimeout;
 | 
					    unsigned int maxSilentTime, buildTimeout;
 | 
				
			||||||
@@ -150,8 +150,8 @@ struct Step
 | 
				
			|||||||
    typedef std::shared_ptr<Step> ptr;
 | 
					    typedef std::shared_ptr<Step> ptr;
 | 
				
			||||||
    typedef std::weak_ptr<Step> wptr;
 | 
					    typedef std::weak_ptr<Step> wptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nix::Path drvPath;
 | 
					    nix::StorePath drvPath;
 | 
				
			||||||
    nix::Derivation drv;
 | 
					    std::unique_ptr<nix::Derivation> drv;
 | 
				
			||||||
    std::unique_ptr<nix::ParsedDerivation> parsedDrv;
 | 
					    std::unique_ptr<nix::ParsedDerivation> parsedDrv;
 | 
				
			||||||
    std::set<std::string> requiredSystemFeatures;
 | 
					    std::set<std::string> requiredSystemFeatures;
 | 
				
			||||||
    bool preferLocalBuild;
 | 
					    bool preferLocalBuild;
 | 
				
			||||||
@@ -252,7 +252,7 @@ struct Machine
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        /* Check that this machine is of the type required by the
 | 
					        /* Check that this machine is of the type required by the
 | 
				
			||||||
           step. */
 | 
					           step. */
 | 
				
			||||||
        if (!systemTypes.count(step->drv.platform == "builtin" ? nix::settings.thisSystem : step->drv.platform))
 | 
					        if (!systemTypes.count(step->drv->platform == "builtin" ? nix::settings.thisSystem : step->drv->platform))
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Check that the step requires all mandatory features of this
 | 
					        /* Check that the step requires all mandatory features of this
 | 
				
			||||||
@@ -313,7 +313,7 @@ private:
 | 
				
			|||||||
       queued builds). Note that these are weak pointers. Steps are
 | 
					       queued builds). Note that these are weak pointers. Steps are
 | 
				
			||||||
       kept alive by being reachable from Builds or by being in
 | 
					       kept alive by being reachable from Builds or by being in
 | 
				
			||||||
       progress. */
 | 
					       progress. */
 | 
				
			||||||
    typedef std::map<nix::Path, Step::wptr> Steps;
 | 
					    typedef std::map<nix::StorePath, Step::wptr> Steps;
 | 
				
			||||||
    nix::Sync<Steps> steps;
 | 
					    nix::Sync<Steps> steps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Build steps that have no unbuilt dependencies. */
 | 
					    /* Build steps that have no unbuilt dependencies. */
 | 
				
			||||||
@@ -454,7 +454,7 @@ private:
 | 
				
			|||||||
        const std::string & machine);
 | 
					        const std::string & machine);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int createSubstitutionStep(pqxx::work & txn, time_t startTime, time_t stopTime,
 | 
					    int createSubstitutionStep(pqxx::work & txn, time_t startTime, time_t stopTime,
 | 
				
			||||||
        Build::ptr build, const nix::Path & drvPath, const std::string & outputName, const nix::Path & storePath);
 | 
					        Build::ptr build, const nix::StorePath & drvPath, const std::string & outputName, const nix::StorePath & storePath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void updateBuild(pqxx::work & txn, Build::ptr build, BuildStatus status);
 | 
					    void updateBuild(pqxx::work & txn, Build::ptr build, BuildStatus status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -473,8 +473,8 @@ private:
 | 
				
			|||||||
        const nix::Derivation & drv);
 | 
					        const nix::Derivation & drv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Step::ptr createStep(nix::ref<nix::Store> store,
 | 
					    Step::ptr createStep(nix::ref<nix::Store> store,
 | 
				
			||||||
        Connection & conn, Build::ptr build, const nix::Path & drvPath,
 | 
					        Connection & conn, Build::ptr build, const nix::StorePath & drvPath,
 | 
				
			||||||
        Build::ptr referringBuild, Step::ptr referringStep, std::set<nix::Path> & finishedDrvs,
 | 
					        Build::ptr referringBuild, Step::ptr referringStep, std::set<nix::StorePath> & finishedDrvs,
 | 
				
			||||||
        std::set<Step::ptr> & newSteps, std::set<Step::ptr> & newRunnable);
 | 
					        std::set<Step::ptr> & newSteps, std::set<Step::ptr> & newRunnable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Jobset::ptr createJobset(pqxx::work & txn,
 | 
					    Jobset::ptr createJobset(pqxx::work & txn,
 | 
				
			||||||
@@ -523,7 +523,7 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void dumpStatus(Connection & conn, bool log);
 | 
					    void dumpStatus(Connection & conn, bool log);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void addRoot(const nix::Path & storePath);
 | 
					    void addRoot(const nix::StorePath & storePath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace nix {
 | 
					namespace nix {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MakeError(NoTokens, Error)
 | 
					MakeError(NoTokens, Error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This class hands out tokens. There are only ‘maxTokens’ tokens
 | 
					/* This class hands out tokens. There are only ‘maxTokens’ tokens
 | 
				
			||||||
   available. Calling get(N) will return a Token object, representing
 | 
					   available. Calling get(N) will return a Token object, representing
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ struct Connection : pqxx::connection
 | 
				
			|||||||
    std::string getFlags()
 | 
					    std::string getFlags()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        using namespace nix;
 | 
					        using namespace nix;
 | 
				
			||||||
        auto s = getEnv("HYDRA_DBI", "dbi:Pg:dbname=hydra;");
 | 
					        auto s = getEnv("HYDRA_DBI").value_or("dbi:Pg:dbname=hydra;");
 | 
				
			||||||
        std::string prefix = "dbi:Pg:";
 | 
					        std::string prefix = "dbi:Pg:";
 | 
				
			||||||
        if (std::string(s, 0, prefix.size()) != prefix)
 | 
					        if (std::string(s, 0, prefix.size()) != prefix)
 | 
				
			||||||
            throw Error("$HYDRA_DBI does not denote a PostgreSQL database");
 | 
					            throw Error("$HYDRA_DBI does not denote a PostgreSQL database");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,9 +14,9 @@ struct Config
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        /* Read hydra.conf. */
 | 
					        /* Read hydra.conf. */
 | 
				
			||||||
        auto hydraConfigFile = getEnv("HYDRA_CONFIG");
 | 
					        auto hydraConfigFile = getEnv("HYDRA_CONFIG");
 | 
				
			||||||
        if (pathExists(hydraConfigFile)) {
 | 
					        if (hydraConfigFile && pathExists(*hydraConfigFile)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (auto line : tokenizeString<Strings>(readFile(hydraConfigFile), "\n")) {
 | 
					            for (auto line : tokenizeString<Strings>(readFile(*hydraConfigFile), "\n")) {
 | 
				
			||||||
                line = trim(string(line, 0, line.find('#')));
 | 
					                line = trim(string(line, 0, line.find('#')));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                auto eq = line.find('=');
 | 
					                auto eq = line.find('=');
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user