Merge remote-tracking branch 'origin/master' into flakes

This commit is contained in:
Eelco Dolstra 2020-04-29 13:32:27 +02:00
commit 5ada0831cf
3 changed files with 79 additions and 32 deletions

View file

@ -269,16 +269,13 @@ bool isLink(const Path & path)
} }
DirEntries readDirectory(const Path & path) DirEntries readDirectory(DIR *dir, const Path & path)
{ {
DirEntries entries; DirEntries entries;
entries.reserve(64); entries.reserve(64);
AutoCloseDir dir(opendir(path.c_str()));
if (!dir) throw SysError(format("opening directory '%1%'") % path);
struct dirent * dirent; struct dirent * dirent;
while (errno = 0, dirent = readdir(dir.get())) { /* sic */ while (errno = 0, dirent = readdir(dir)) { /* sic */
checkInterrupt(); checkInterrupt();
string name = dirent->d_name; string name = dirent->d_name;
if (name == "." || name == "..") continue; if (name == "." || name == "..") continue;
@ -295,6 +292,14 @@ DirEntries readDirectory(const Path & path)
return entries; return entries;
} }
DirEntries readDirectory(const Path & path)
{
AutoCloseDir dir(opendir(path.c_str()));
if (!dir) throw SysError(format("opening directory '%1%'") % path);
return readDirectory(dir.get(), path);
}
unsigned char getFileType(const Path & path) unsigned char getFileType(const Path & path)
{ {
@ -389,12 +394,14 @@ void writeLine(int fd, string s)
} }
static void _deletePath(const Path & path, unsigned long long & bytesFreed) static void _deletePath(int parentfd, const Path & path, unsigned long long & bytesFreed)
{ {
checkInterrupt(); checkInterrupt();
string name(baseNameOf(path));
struct stat st; struct stat st;
if (lstat(path.c_str(), &st) == -1) { if (fstatat(parentfd, name.c_str(), &st, AT_SYMLINK_NOFOLLOW) == -1) {
if (errno == ENOENT) return; if (errno == ENOENT) return;
throw SysError(format("getting status of '%1%'") % path); throw SysError(format("getting status of '%1%'") % path);
} }
@ -406,20 +413,45 @@ static void _deletePath(const Path & path, unsigned long long & bytesFreed)
/* Make the directory accessible. */ /* Make the directory accessible. */
const auto PERM_MASK = S_IRUSR | S_IWUSR | S_IXUSR; const auto PERM_MASK = S_IRUSR | S_IWUSR | S_IXUSR;
if ((st.st_mode & PERM_MASK) != PERM_MASK) { if ((st.st_mode & PERM_MASK) != PERM_MASK) {
if (chmod(path.c_str(), st.st_mode | PERM_MASK) == -1) if (fchmodat(parentfd, name.c_str(), st.st_mode | PERM_MASK, 0) == -1)
throw SysError(format("chmod '%1%'") % path); throw SysError(format("chmod '%1%'") % path);
} }
for (auto & i : readDirectory(path)) int fd = openat(parentfd, path.c_str(), O_RDONLY);
_deletePath(path + "/" + i.name, bytesFreed); if (!fd)
throw SysError(format("opening directory '%1%'") % path);
AutoCloseDir dir(fdopendir(fd));
if (!dir)
throw SysError(format("opening directory '%1%'") % path);
for (auto & i : readDirectory(dir.get(), path))
_deletePath(dirfd(dir.get()), path + "/" + i.name, bytesFreed);
} }
if (remove(path.c_str()) == -1) { int flags = S_ISDIR(st.st_mode) ? AT_REMOVEDIR : 0;
if (unlinkat(parentfd, name.c_str(), flags) == -1) {
if (errno == ENOENT) return; if (errno == ENOENT) return;
throw SysError(format("cannot unlink '%1%'") % path); throw SysError(format("cannot unlink '%1%'") % path);
} }
} }
static void _deletePath(const Path & path, unsigned long long & bytesFreed)
{
Path dir = dirOf(path);
if (dir == "")
dir = "/";
AutoCloseFD dirfd(open(dir.c_str(), O_RDONLY));
if (!dirfd) {
// This really shouldn't fail silently, but it's left this way
// for backwards compatibility.
if (errno == ENOENT) return;
throw SysError(format("opening directory '%1%'") % path);
}
_deletePath(dirfd.get(), path, bytesFreed);
}
void deletePath(const Path & path) void deletePath(const Path & path)
{ {

View file

@ -718,28 +718,39 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
while (true) { while (true) {
string lockToken = optimisticLockProfile(profile); string lockToken = optimisticLockProfile(profile);
DrvInfos installedElems = queryInstalled(*globals.state, profile); DrvInfos workingElems = queryInstalled(*globals.state, profile);
DrvInfos newElems;
for (auto & i : installedElems) { for (auto & selector : selectors) {
DrvName drvName(i.queryName()); DrvInfos::iterator split = workingElems.begin();
bool found = false; if (isPath(selector)) {
for (auto & j : selectors) StorePath selectorStorePath = globals.state->store->followLinksToStorePath(selector);
/* !!! the repeated calls to followLinksToStorePath() split = std::partition(
are expensive, should pre-compute them. */ workingElems.begin(), workingElems.end(),
if ((isPath(j) && globals.state->store->parseStorePath(i.queryOutPath()) == globals.state->store->followLinksToStorePath(j)) [&selectorStorePath, globals](auto &elem) {
|| DrvName(j).matches(drvName)) return selectorStorePath != globals.state->store->parseStorePath(elem.queryOutPath());
{ }
printInfo("uninstalling '%s'", i.queryName()); );
found = true; } else {
break; DrvName selectorName(selector);
} split = std::partition(
if (!found) newElems.push_back(i); workingElems.begin(), workingElems.end(),
[&selectorName](auto &elem){
DrvName elemName(elem.queryName());
return !selectorName.matches(elemName);
}
);
}
if (split == workingElems.end())
warn("selector '%s' matched no installed derivations", selector);
for (auto removedElem = split; removedElem != workingElems.end(); removedElem++) {
printInfo("uninstalling '%s'", removedElem->queryName());
}
workingElems.erase(split, workingElems.end());
} }
if (globals.dryRun) return; if (globals.dryRun) return;
if (createUserEnv(*globals.state, newElems, if (createUserEnv(*globals.state, workingElems,
profile, settings.envKeepDerivations, lockToken)) break; profile, settings.envKeepDerivations, lockToken)) break;
} }
} }

View file

@ -205,13 +205,15 @@ struct Common : InstallableCommand, MixProfile
} }
} }
BuildEnvironment getBuildEnvironment(ref<Store> store) std::pair<BuildEnvironment, std::string> getBuildEnvironment(ref<Store> store)
{ {
auto shellOutPath = getShellOutPath(store); auto shellOutPath = getShellOutPath(store);
auto strPath = store->printStorePath(shellOutPath);
updateProfile(shellOutPath); updateProfile(shellOutPath);
return readEnvironment(store->printStorePath(shellOutPath)); return {readEnvironment(strPath), strPath};
} }
}; };
@ -262,7 +264,7 @@ struct CmdDevShell : Common, MixEnvironment
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
auto buildEnvironment = getBuildEnvironment(store); auto [buildEnvironment, gcroot] = getBuildEnvironment(store);
auto [rcFileFd, rcFilePath] = createTempFile("nix-shell"); auto [rcFileFd, rcFilePath] = createTempFile("nix-shell");
@ -285,6 +287,8 @@ struct CmdDevShell : Common, MixEnvironment
auto shell = getEnv("SHELL").value_or("bash"); auto shell = getEnv("SHELL").value_or("bash");
setEnviron(); setEnviron();
// prevent garbage collection until shell exits
setenv("NIX_GCROOT", gcroot.data(), 1);
auto args = Strings{std::string(baseNameOf(shell)), "--rcfile", rcFilePath}; auto args = Strings{std::string(baseNameOf(shell)), "--rcfile", rcFilePath};
@ -316,7 +320,7 @@ struct CmdPrintDevEnv : Common
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
auto buildEnvironment = getBuildEnvironment(store); auto buildEnvironment = getBuildEnvironment(store).first;
stopProgressBar(); stopProgressBar();