buildenv: Eliminate global variables, other cleanup

(cherry picked from commit b82f75464d)
This commit is contained in:
Eelco Dolstra 2019-10-21 17:17:15 +02:00
parent 76e7d958ed
commit f9611c7ae4
4 changed files with 81 additions and 70 deletions

View file

@ -6,6 +6,7 @@
#include "archive.hh" #include "archive.hh"
#include "affinity.hh" #include "affinity.hh"
#include "builtins.hh" #include "builtins.hh"
#include "builtins/buildenv.hh"
#include "download.hh" #include "download.hh"
#include "finally.hh" #include "finally.hh"
#include "compression.hh" #include "compression.hh"

View file

@ -6,7 +6,6 @@ namespace nix {
// TODO: make pluggable. // TODO: make pluggable.
void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData); void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData);
void builtinBuildenv(const BasicDerivation & drv);
void builtinUnpackChannel(const BasicDerivation & drv); void builtinUnpackChannel(const BasicDerivation & drv);
} }

View file

@ -1,4 +1,4 @@
#include "builtins.hh" #include "buildenv.hh"
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
@ -7,16 +7,14 @@
namespace nix { namespace nix {
typedef std::map<Path,int> Priorities; struct State
{
// FIXME: change into local variables. std::map<Path, int> priorities;
unsigned long symlinks = 0;
static Priorities priorities; };
static unsigned long symlinks;
/* For each activated package, create symlinks */ /* For each activated package, create symlinks */
static void createLinks(const Path & srcDir, const Path & dstDir, int priority) static void createLinks(State & state, const Path & srcDir, const Path & dstDir, int priority)
{ {
DirEntries srcFiles; DirEntries srcFiles;
@ -67,7 +65,7 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
auto res = lstat(dstFile.c_str(), &dstSt); auto res = lstat(dstFile.c_str(), &dstSt);
if (res == 0) { if (res == 0) {
if (S_ISDIR(dstSt.st_mode)) { if (S_ISDIR(dstSt.st_mode)) {
createLinks(srcFile, dstFile, priority); createLinks(state, srcFile, dstFile, priority);
continue; continue;
} else if (S_ISLNK(dstSt.st_mode)) { } else if (S_ISLNK(dstSt.st_mode)) {
auto target = canonPath(dstFile, true); auto target = canonPath(dstFile, true);
@ -77,8 +75,8 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
throw SysError(format("unlinking '%1%'") % dstFile); throw SysError(format("unlinking '%1%'") % dstFile);
if (mkdir(dstFile.c_str(), 0755) == -1) if (mkdir(dstFile.c_str(), 0755) == -1)
throw SysError(format("creating directory '%1%'")); throw SysError(format("creating directory '%1%'"));
createLinks(target, dstFile, priorities[dstFile]); createLinks(state, target, dstFile, state.priorities[dstFile]);
createLinks(srcFile, dstFile, priority); createLinks(state, srcFile, dstFile, priority);
continue; continue;
} }
} else if (errno != ENOENT) } else if (errno != ENOENT)
@ -90,7 +88,7 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
auto res = lstat(dstFile.c_str(), &dstSt); auto res = lstat(dstFile.c_str(), &dstSt);
if (res == 0) { if (res == 0) {
if (S_ISLNK(dstSt.st_mode)) { if (S_ISLNK(dstSt.st_mode)) {
auto prevPriority = priorities[dstFile]; auto prevPriority = state.priorities[dstFile];
if (prevPriority == priority) if (prevPriority == priority)
throw Error( throw Error(
"packages '%1%' and '%2%' have the same priority %3%; " "packages '%1%' and '%2%' have the same priority %3%; "
@ -109,22 +107,20 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
} }
createSymlink(srcFile, dstFile); createSymlink(srcFile, dstFile);
priorities[dstFile] = priority; state.priorities[dstFile] = priority;
symlinks++; state.symlinks++;
} }
} }
typedef std::set<Path> FileProp; void buildProfile(const Path & out, Packages && pkgs)
static FileProp done;
static FileProp postponed = FileProp{};
static Path out;
static void addPkg(const Path & pkgDir, int priority)
{ {
State state;
std::set<Path> done, postponed;
auto addPkg = [&](const Path & pkgDir, int priority) {
if (!done.insert(pkgDir).second) return; if (!done.insert(pkgDir).second) return;
createLinks(pkgDir, out, priority); createLinks(state, pkgDir, out, priority);
try { try {
for (const auto & p : tokenizeString<std::vector<string>>( for (const auto & p : tokenizeString<std::vector<string>>(
@ -134,43 +130,8 @@ static void addPkg(const Path & pkgDir, int priority)
} catch (SysError & e) { } catch (SysError & e) {
if (e.errNo != ENOENT && e.errNo != ENOTDIR) throw; if (e.errNo != ENOENT && e.errNo != ENOTDIR) throw;
} }
}
struct Package {
Path path;
bool active;
int priority;
Package(Path path, bool active, int priority) : path{path}, active{active}, priority{priority} {}
};
typedef std::vector<Package> Packages;
void builtinBuildenv(const BasicDerivation & drv)
{
auto getAttr = [&](const string & name) {
auto i = drv.env.find(name);
if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
return i->second;
}; };
out = getAttr("out");
createDirs(out);
/* Convert the stuff we get from the environment back into a
* coherent data type. */
Packages pkgs;
auto derivations = tokenizeString<Strings>(getAttr("derivations"));
while (!derivations.empty()) {
/* !!! We're trusting the caller to structure derivations env var correctly */
auto active = derivations.front(); derivations.pop_front();
auto priority = stoi(derivations.front()); derivations.pop_front();
auto outputs = stoi(derivations.front()); derivations.pop_front();
for (auto n = 0; n < outputs; n++) {
auto path = derivations.front(); derivations.pop_front();
pkgs.emplace_back(path, active != "false", priority);
}
}
/* Symlink to the packages that have been installed explicitly by the /* Symlink to the packages that have been installed explicitly by the
* user. Process in priority order to reduce unnecessary * user. Process in priority order to reduce unnecessary
* symlink/unlink steps. * symlink/unlink steps.
@ -189,13 +150,42 @@ void builtinBuildenv(const BasicDerivation & drv)
*/ */
auto priorityCounter = 1000; auto priorityCounter = 1000;
while (!postponed.empty()) { while (!postponed.empty()) {
auto pkgDirs = postponed; std::set<Path> pkgDirs;
postponed = FileProp{}; postponed.swap(pkgDirs);
for (const auto & pkgDir : pkgDirs) for (const auto & pkgDir : pkgDirs)
addPkg(pkgDir, priorityCounter++); addPkg(pkgDir, priorityCounter++);
} }
printError("created %d symlinks in user environment", symlinks); printError("created %d symlinks in user environment", state.symlinks);
}
void builtinBuildenv(const BasicDerivation & drv)
{
auto getAttr = [&](const string & name) {
auto i = drv.env.find(name);
if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
return i->second;
};
Path out = getAttr("out");
createDirs(out);
/* Convert the stuff we get from the environment back into a
* coherent data type. */
Packages pkgs;
auto derivations = tokenizeString<Strings>(getAttr("derivations"));
while (!derivations.empty()) {
/* !!! We're trusting the caller to structure derivations env var correctly */
auto active = derivations.front(); derivations.pop_front();
auto priority = stoi(derivations.front()); derivations.pop_front();
auto outputs = stoi(derivations.front()); derivations.pop_front();
for (auto n = 0; n < outputs; n++) {
auto path = derivations.front(); derivations.pop_front();
pkgs.emplace_back(path, active != "false", priority);
}
}
buildProfile(out, std::move(pkgs));
createSymlink(getAttr("manifest"), out + "/manifest.nix"); createSymlink(getAttr("manifest"), out + "/manifest.nix");
} }

View file

@ -0,0 +1,21 @@
#pragma once
#include "derivations.hh"
#include "store-api.hh"
namespace nix {
struct Package {
Path path;
bool active;
int priority;
Package(Path path, bool active, int priority) : path{path}, active{active}, priority{priority} {}
};
typedef std::vector<Package> Packages;
void buildProfile(const Path & out, Packages && pkgs);
void builtinBuildenv(const BasicDerivation & drv);
}