aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/build.cc7
-rw-r--r--src/libstore/builtins.hh1
-rw-r--r--src/libstore/builtins/buildenv.cc120
-rw-r--r--src/libstore/builtins/buildenv.hh21
-rw-r--r--src/libstore/download.cc20
-rw-r--r--src/libstore/download.hh3
-rw-r--r--src/libstore/globals.hh3
-rw-r--r--src/libstore/http-binary-cache-store.cc5
-rw-r--r--src/libstore/local-store.cc9
-rw-r--r--src/libstore/nar-info-disk-cache.cc7
-rw-r--r--src/libstore/nar-info-disk-cache.hh2
-rw-r--r--src/libstore/parsed-derivations.cc6
-rw-r--r--src/libstore/parsed-derivations.hh10
-rw-r--r--src/libstore/profiles.cc18
-rw-r--r--src/libstore/profiles.hh4
-rw-r--r--src/libstore/sqlite.cc25
-rw-r--r--src/libstore/sqlite.hh10
-rw-r--r--src/libstore/store-api.cc9
-rw-r--r--src/libstore/store-api.hh1
19 files changed, 176 insertions, 105 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index c82f60748..bf259e0b6 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -6,6 +6,7 @@
#include "archive.hh"
#include "affinity.hh"
#include "builtins.hh"
+#include "builtins/buildenv.hh"
#include "download.hh"
#include "finally.hh"
#include "compression.hh"
@@ -1898,7 +1899,7 @@ void DerivationGoal::startBuilder()
concatStringsSep(", ", parsedDrv->getRequiredSystemFeatures()),
drvPath,
settings.thisSystem,
- concatStringsSep(", ", settings.systemFeatures));
+ concatStringsSep<StringSet>(", ", settings.systemFeatures));
if (drv->isBuiltin())
preloadNSS();
@@ -2521,7 +2522,7 @@ static std::regex shVarName("[A-Za-z_][A-Za-z0-9_]*");
void DerivationGoal::writeStructuredAttrs()
{
- auto & structuredAttrs = parsedDrv->getStructuredAttrs();
+ auto structuredAttrs = parsedDrv->getStructuredAttrs();
if (!structuredAttrs) return;
auto json = *structuredAttrs;
@@ -3283,7 +3284,7 @@ void DerivationGoal::registerOutputs()
worker.hashMismatch = true;
delayedException = std::make_exception_ptr(
BuildError("hash mismatch in fixed-output derivation '%s':\n wanted: %s\n got: %s",
- dest, h.to_string(), h2.to_string()));
+ dest, h.to_string(SRI), h2.to_string(SRI)));
Path actualDest = worker.store.toRealPath(dest);
diff --git a/src/libstore/builtins.hh b/src/libstore/builtins.hh
index 0d2da873e..f9b5f7900 100644
--- a/src/libstore/builtins.hh
+++ b/src/libstore/builtins.hh
@@ -6,6 +6,5 @@ namespace nix {
// TODO: make pluggable.
void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData);
-void builtinBuildenv(const BasicDerivation & drv);
}
diff --git a/src/libstore/builtins/buildenv.cc b/src/libstore/builtins/buildenv.cc
index 096593886..1b802d908 100644
--- a/src/libstore/builtins/buildenv.cc
+++ b/src/libstore/builtins/buildenv.cc
@@ -1,4 +1,4 @@
-#include "builtins.hh"
+#include "buildenv.hh"
#include <sys/stat.h>
#include <sys/types.h>
@@ -7,16 +7,14 @@
namespace nix {
-typedef std::map<Path,int> Priorities;
-
-// FIXME: change into local variables.
-
-static Priorities priorities;
-
-static unsigned long symlinks;
+struct State
+{
+ std::map<Path, int> priorities;
+ unsigned long symlinks = 0;
+};
/* 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;
@@ -67,7 +65,7 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
auto res = lstat(dstFile.c_str(), &dstSt);
if (res == 0) {
if (S_ISDIR(dstSt.st_mode)) {
- createLinks(srcFile, dstFile, priority);
+ createLinks(state, srcFile, dstFile, priority);
continue;
} else if (S_ISLNK(dstSt.st_mode)) {
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);
if (mkdir(dstFile.c_str(), 0755) == -1)
throw SysError(format("creating directory '%1%'"));
- createLinks(target, dstFile, priorities[dstFile]);
- createLinks(srcFile, dstFile, priority);
+ createLinks(state, target, dstFile, state.priorities[dstFile]);
+ createLinks(state, srcFile, dstFile, priority);
continue;
}
} 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);
if (res == 0) {
if (S_ISLNK(dstSt.st_mode)) {
- auto prevPriority = priorities[dstFile];
+ auto prevPriority = state.priorities[dstFile];
if (prevPriority == priority)
throw Error(
"packages '%1%' and '%2%' have the same priority %3%; "
@@ -109,41 +107,57 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
}
createSymlink(srcFile, dstFile);
- priorities[dstFile] = priority;
- symlinks++;
+ state.priorities[dstFile] = priority;
+ state.symlinks++;
}
}
-typedef std::set<Path> FileProp;
+void buildProfile(const Path & out, Packages && pkgs)
+{
+ State state;
-static FileProp done;
-static FileProp postponed = FileProp{};
+ std::set<Path> done, postponed;
-static Path out;
+ auto addPkg = [&](const Path & pkgDir, int priority) {
+ if (!done.insert(pkgDir).second) return;
+ createLinks(state, pkgDir, out, priority);
-static void addPkg(const Path & pkgDir, int priority)
-{
- if (!done.insert(pkgDir).second) return;
- createLinks(pkgDir, out, priority);
+ try {
+ for (const auto & p : tokenizeString<std::vector<string>>(
+ readFile(pkgDir + "/nix-support/propagated-user-env-packages"), " \n"))
+ if (!done.count(p))
+ postponed.insert(p);
+ } catch (SysError & e) {
+ if (e.errNo != ENOENT && e.errNo != ENOTDIR) throw;
+ }
+ };
- try {
- for (const auto & p : tokenizeString<std::vector<string>>(
- readFile(pkgDir + "/nix-support/propagated-user-env-packages"), " \n"))
- if (!done.count(p))
- postponed.insert(p);
- } catch (SysError & e) {
- if (e.errNo != ENOENT && e.errNo != ENOTDIR) throw;
- }
-}
+ /* Symlink to the packages that have been installed explicitly by the
+ * user. Process in priority order to reduce unnecessary
+ * symlink/unlink steps.
+ */
+ std::sort(pkgs.begin(), pkgs.end(), [](const Package & a, const Package & b) {
+ return a.priority < b.priority || (a.priority == b.priority && a.path < b.path);
+ });
+ for (const auto & pkg : pkgs)
+ if (pkg.active)
+ addPkg(pkg.path, pkg.priority);
-struct Package {
- Path path;
- bool active;
- int priority;
- Package(Path path, bool active, int priority) : path{path}, active{active}, priority{priority} {}
-};
+ /* Symlink to the packages that have been "propagated" by packages
+ * installed by the user (i.e., package X declares that it wants Y
+ * installed as well). We do these later because they have a lower
+ * priority in case of collisions.
+ */
+ auto priorityCounter = 1000;
+ while (!postponed.empty()) {
+ std::set<Path> pkgDirs;
+ postponed.swap(pkgDirs);
+ for (const auto & pkgDir : pkgDirs)
+ addPkg(pkgDir, priorityCounter++);
+ }
-typedef std::vector<Package> Packages;
+ debug("created %d symlinks in user environment", state.symlinks);
+}
void builtinBuildenv(const BasicDerivation & drv)
{
@@ -153,7 +167,7 @@ void builtinBuildenv(const BasicDerivation & drv)
return i->second;
};
- out = getAttr("out");
+ Path out = getAttr("out");
createDirs(out);
/* Convert the stuff we get from the environment back into a
@@ -171,31 +185,7 @@ void builtinBuildenv(const BasicDerivation & drv)
}
}
- /* Symlink to the packages that have been installed explicitly by the
- * user. Process in priority order to reduce unnecessary
- * symlink/unlink steps.
- */
- std::sort(pkgs.begin(), pkgs.end(), [](const Package & a, const Package & b) {
- return a.priority < b.priority || (a.priority == b.priority && a.path < b.path);
- });
- for (const auto & pkg : pkgs)
- if (pkg.active)
- addPkg(pkg.path, pkg.priority);
-
- /* Symlink to the packages that have been "propagated" by packages
- * installed by the user (i.e., package X declares that it wants Y
- * installed as well). We do these later because they have a lower
- * priority in case of collisions.
- */
- auto priorityCounter = 1000;
- while (!postponed.empty()) {
- auto pkgDirs = postponed;
- postponed = FileProp{};
- for (const auto & pkgDir : pkgDirs)
- addPkg(pkgDir, priorityCounter++);
- }
-
- printError("created %d symlinks in user environment", symlinks);
+ buildProfile(out, std::move(pkgs));
createSymlink(getAttr("manifest"), out + "/manifest.nix");
}
diff --git a/src/libstore/builtins/buildenv.hh b/src/libstore/builtins/buildenv.hh
new file mode 100644
index 000000000..0a37459b0
--- /dev/null
+++ b/src/libstore/builtins/buildenv.hh
@@ -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);
+
+}
diff --git a/src/libstore/download.cc b/src/libstore/download.cc
index 8fe278d02..d49d63912 100644
--- a/src/libstore/download.cc
+++ b/src/libstore/download.cc
@@ -816,6 +816,7 @@ CachedDownloadResult Downloader::downloadCached(
CachedDownloadResult result;
result.storePath = expectedStorePath;
result.path = store->toRealPath(expectedStorePath);
+ assert(!request.getLastModified); // FIXME
return result;
}
}
@@ -900,16 +901,26 @@ CachedDownloadResult Downloader::downloadCached(
store->addTempRoot(unpackedStorePath);
if (!store->isValidPath(unpackedStorePath))
unpackedStorePath = "";
+ else
+ result.lastModified = lstat(unpackedLink).st_mtime;
}
if (unpackedStorePath.empty()) {
printInfo(format("unpacking '%1%'...") % url);
Path tmpDir = createTempDir();
AutoDelete autoDelete(tmpDir, true);
// FIXME: this requires GNU tar for decompression.
- runProgram("tar", true, {"xf", store->toRealPath(storePath), "-C", tmpDir, "--strip-components", "1"});
- unpackedStorePath = store->addToStore(name, tmpDir, true, htSHA256, defaultPathFilter, NoRepair);
+ runProgram("tar", true, {"xf", store->toRealPath(storePath), "-C", tmpDir});
+ auto members = readDirectory(tmpDir);
+ if (members.size() != 1)
+ throw nix::Error("tarball '%s' contains an unexpected number of top-level files", url);
+ auto topDir = tmpDir + "/" + members.begin()->name;
+ result.lastModified = lstat(topDir).st_mtime;
+ unpackedStorePath = store->addToStore(name, topDir, true, htSHA256, defaultPathFilter, NoRepair);
}
- replaceSymlink(unpackedStorePath, unpackedLink);
+ // Store the last-modified date of the tarball in the symlink
+ // mtime. This saves us from having to store it somewhere
+ // else.
+ replaceSymlink(unpackedStorePath, unpackedLink, result.lastModified);
storePath = unpackedStorePath;
}
@@ -922,6 +933,9 @@ CachedDownloadResult Downloader::downloadCached(
url, request.expectedHash.to_string(), gotHash.to_string());
}
+ if (request.gcRoot)
+ store->addIndirectRoot(fileLink);
+
result.storePath = storePath;
result.path = store->toRealPath(storePath);
return result;
diff --git a/src/libstore/download.hh b/src/libstore/download.hh
index 5a131c704..487036833 100644
--- a/src/libstore/download.hh
+++ b/src/libstore/download.hh
@@ -72,6 +72,8 @@ struct CachedDownloadRequest
std::string name;
Hash expectedHash;
unsigned int ttl;
+ bool gcRoot = false;
+ bool getLastModified = false;
CachedDownloadRequest(const std::string & uri);
CachedDownloadRequest() = delete;
@@ -85,6 +87,7 @@ struct CachedDownloadResult
Path path;
std::optional<std::string> etag;
std::string effectiveUri;
+ std::optional<time_t> lastModified;
};
class Store;
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 1221e4db7..0b1a8dac5 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -354,6 +354,9 @@ public:
Setting<Paths> pluginFiles{this, {}, "plugin-files",
"Plugins to dynamically load at nix initialization time."};
+ Setting<std::string> githubAccessToken{this, "", "github-acces-token",
+ "GitHub access token to get access to GitHub data through the GitHub API for github:<..> flakes."};
+
Setting<Strings> experimentalFeatures{this, {}, "experimental-features",
"Experimental Nix features to enable."};
diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc
index 779f89e68..c8a00a949 100644
--- a/src/libstore/http-binary-cache-store.cc
+++ b/src/libstore/http-binary-cache-store.cc
@@ -160,10 +160,11 @@ static RegisterStoreImplementation regStore([](
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{
+ static bool forceHttp = getEnv("_NIX_FORCE_HTTP") == "1";
if (std::string(uri, 0, 7) != "http://" &&
std::string(uri, 0, 8) != "https://" &&
- (getEnv("_NIX_FORCE_HTTP_BINARY_CACHE_STORE") != "1" || std::string(uri, 0, 7) != "file://")
- ) return 0;
+ (!forceHttp || std::string(uri, 0, 7) != "file://"))
+ return 0;
auto store = std::make_shared<HttpBinaryCacheStore>(params, uri);
store->init();
return store;
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index b5b0f1ba7..46e8138be 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -297,9 +297,7 @@ void LocalStore::openDB(State & state, bool create)
/* Open the Nix database. */
string dbPath = dbDir + "/db.sqlite";
auto & db(state.db);
- if (sqlite3_open_v2(dbPath.c_str(), &db.db,
- SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), 0) != SQLITE_OK)
- throw Error(format("cannot open Nix database '%1%'") % dbPath);
+ state.db = SQLite(dbPath, create);
#ifdef __CYGWIN__
/* The cygwin version of sqlite3 has a patch which calls
@@ -311,11 +309,6 @@ void LocalStore::openDB(State & state, bool create)
SetDllDirectoryW(L"");
#endif
- if (sqlite3_busy_timeout(db, 60 * 60 * 1000) != SQLITE_OK)
- throwSQLiteError(db, "setting timeout");
-
- db.exec("pragma foreign_keys = 1");
-
/* !!! check whether sqlite has been built with foreign key
support */
diff --git a/src/libstore/nar-info-disk-cache.cc b/src/libstore/nar-info-disk-cache.cc
index 5bf982195..37c4c72e0 100644
--- a/src/libstore/nar-info-disk-cache.cc
+++ b/src/libstore/nar-info-disk-cache.cc
@@ -78,12 +78,7 @@ public:
state->db = SQLite(dbPath);
- if (sqlite3_busy_timeout(state->db, 60 * 60 * 1000) != SQLITE_OK)
- throwSQLiteError(state->db, "setting timeout");
-
- // We can always reproduce the cache.
- state->db.exec("pragma synchronous = off");
- state->db.exec("pragma main.journal_mode = truncate");
+ state->db.isCache();
state->db.exec(schema);
diff --git a/src/libstore/nar-info-disk-cache.hh b/src/libstore/nar-info-disk-cache.hh
index 11e6c55ca..fb34f8c93 100644
--- a/src/libstore/nar-info-disk-cache.hh
+++ b/src/libstore/nar-info-disk-cache.hh
@@ -10,6 +10,8 @@ class NarInfoDiskCache
public:
typedef enum { oValid, oInvalid, oUnknown } Outcome;
+ virtual ~NarInfoDiskCache() { }
+
virtual void createCache(const std::string & uri, const Path & storeDir,
bool wantMassQuery, int priority) = 0;
diff --git a/src/libstore/parsed-derivations.cc b/src/libstore/parsed-derivations.cc
index 87be8a24e..5553dd863 100644
--- a/src/libstore/parsed-derivations.cc
+++ b/src/libstore/parsed-derivations.cc
@@ -1,5 +1,7 @@
#include "parsed-derivations.hh"
+#include <nlohmann/json.hpp>
+
namespace nix {
ParsedDerivation::ParsedDerivation(const Path & drvPath, BasicDerivation & drv)
@@ -9,13 +11,15 @@ ParsedDerivation::ParsedDerivation(const Path & drvPath, BasicDerivation & drv)
auto jsonAttr = drv.env.find("__json");
if (jsonAttr != drv.env.end()) {
try {
- structuredAttrs = nlohmann::json::parse(jsonAttr->second);
+ structuredAttrs = std::make_unique<nlohmann::json>(nlohmann::json::parse(jsonAttr->second));
} catch (std::exception & e) {
throw Error("cannot process __json attribute of '%s': %s", drvPath, e.what());
}
}
}
+ParsedDerivation::~ParsedDerivation() { }
+
std::optional<std::string> ParsedDerivation::getStringAttr(const std::string & name) const
{
if (structuredAttrs) {
diff --git a/src/libstore/parsed-derivations.hh b/src/libstore/parsed-derivations.hh
index 9bde4b4dc..6e67e1665 100644
--- a/src/libstore/parsed-derivations.hh
+++ b/src/libstore/parsed-derivations.hh
@@ -1,6 +1,6 @@
#include "derivations.hh"
-#include <nlohmann/json.hpp>
+#include <nlohmann/json_fwd.hpp>
namespace nix {
@@ -8,15 +8,17 @@ class ParsedDerivation
{
Path drvPath;
BasicDerivation & drv;
- std::optional<nlohmann::json> structuredAttrs;
+ std::unique_ptr<nlohmann::json> structuredAttrs;
public:
ParsedDerivation(const Path & drvPath, BasicDerivation & drv);
- const std::optional<nlohmann::json> & getStructuredAttrs() const
+ ~ParsedDerivation();
+
+ const nlohmann::json * getStructuredAttrs() const
{
- return structuredAttrs;
+ return structuredAttrs.get();
}
std::optional<std::string> getStringAttr(const std::string & name) const;
diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc
index 4c6af567a..29f6f6c17 100644
--- a/src/libstore/profiles.cc
+++ b/src/libstore/profiles.cc
@@ -256,4 +256,22 @@ string optimisticLockProfile(const Path & profile)
}
+Path getDefaultProfile()
+{
+ Path profileLink = getHome() + "/.nix-profile";
+ try {
+ if (!pathExists(profileLink)) {
+ replaceSymlink(
+ getuid() == 0
+ ? settings.nixStateDir + "/profiles/default"
+ : fmt("%s/profiles/per-user/%s/profile", settings.nixStateDir, getUserName()),
+ profileLink);
+ }
+ return absPath(readLink(profileLink), dirOf(profileLink));
+ } catch (Error &) {
+ return profileLink;
+ }
+}
+
+
}
diff --git a/src/libstore/profiles.hh b/src/libstore/profiles.hh
index 5fa1533de..78645d8b6 100644
--- a/src/libstore/profiles.hh
+++ b/src/libstore/profiles.hh
@@ -64,4 +64,8 @@ void lockProfile(PathLocks & lock, const Path & profile);
rebuilt. */
string optimisticLockProfile(const Path & profile);
+/* Resolve ~/.nix-profile. If ~/.nix-profile doesn't exist yet, create
+ it. */
+Path getDefaultProfile();
+
}
diff --git a/src/libstore/sqlite.cc b/src/libstore/sqlite.cc
index a061d64f3..eb1daafc5 100644
--- a/src/libstore/sqlite.cc
+++ b/src/libstore/sqlite.cc
@@ -25,11 +25,16 @@ namespace nix {
throw SQLiteError("%s: %s (in '%s')", fs.s, sqlite3_errstr(exterr), path);
}
-SQLite::SQLite(const Path & path)
+SQLite::SQLite(const Path & path, bool create)
{
if (sqlite3_open_v2(path.c_str(), &db,
- SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0) != SQLITE_OK)
+ SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), 0) != SQLITE_OK)
throw Error(format("cannot open SQLite database '%s'") % path);
+
+ if (sqlite3_busy_timeout(db, 60 * 60 * 1000) != SQLITE_OK)
+ throwSQLiteError(db, "setting timeout");
+
+ exec("pragma foreign_keys = 1");
}
SQLite::~SQLite()
@@ -42,6 +47,12 @@ SQLite::~SQLite()
}
}
+void SQLite::isCache()
+{
+ exec("pragma synchronous = off");
+ exec("pragma main.journal_mode = truncate");
+}
+
void SQLite::exec(const std::string & stmt)
{
retrySQLite<void>([&]() {
@@ -94,6 +105,16 @@ SQLiteStmt::Use & SQLiteStmt::Use::operator () (const std::string & value, bool
return *this;
}
+SQLiteStmt::Use & SQLiteStmt::Use::operator () (const unsigned char * data, size_t len, bool notNull)
+{
+ if (notNull) {
+ if (sqlite3_bind_blob(stmt, curArg++, data, len, SQLITE_TRANSIENT) != SQLITE_OK)
+ throwSQLiteError(stmt.db, "binding argument");
+ } else
+ bind();
+ return *this;
+}
+
SQLiteStmt::Use & SQLiteStmt::Use::operator () (int64_t value, bool notNull)
{
if (notNull) {
diff --git a/src/libstore/sqlite.hh b/src/libstore/sqlite.hh
index 115679b84..0f46f6a07 100644
--- a/src/libstore/sqlite.hh
+++ b/src/libstore/sqlite.hh
@@ -5,8 +5,8 @@
#include "types.hh"
-class sqlite3;
-class sqlite3_stmt;
+struct sqlite3;
+struct sqlite3_stmt;
namespace nix {
@@ -15,13 +15,16 @@ struct SQLite
{
sqlite3 * db = 0;
SQLite() { }
- SQLite(const Path & path);
+ SQLite(const Path & path, bool create = true);
SQLite(const SQLite & from) = delete;
SQLite& operator = (const SQLite & from) = delete;
SQLite& operator = (SQLite && from) { db = from.db; from.db = 0; return *this; }
~SQLite();
operator sqlite3 * () { return db; }
+ /* Disable synchronous mode, set truncate journal mode. */
+ void isCache();
+
void exec(const std::string & stmt);
};
@@ -52,6 +55,7 @@ struct SQLiteStmt
/* Bind the next parameter. */
Use & operator () (const std::string & value, bool notNull = true);
+ Use & operator () (const unsigned char * data, size_t len, bool notNull = true);
Use & operator () (int64_t value, bool notNull = true);
Use & bind(); // null
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 54430d3ba..ea91bf20e 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -55,7 +55,7 @@ Path Store::followLinksToStore(const Path & _path) const
path = absPath(target, dirOf(path));
}
if (!isInStore(path))
- throw Error(format("path '%1%' is not in the Nix store") % path);
+ throw NotInStore("path '%1%' is not in the Nix store", path);
return path;
}
@@ -747,12 +747,7 @@ ValidPathInfo decodeValidPathInfo(std::istream & str, bool hashGiven)
string showPaths(const PathSet & paths)
{
- string s;
- for (auto & i : paths) {
- if (s.size() != 0) s += ", ";
- s += "'" + i + "'";
- }
- return s;
+ return concatStringsSep(", ", quoteStrings(paths));
}
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index e9e6e0dd2..814ec8d29 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -26,6 +26,7 @@ MakeError(InvalidPath, Error)
MakeError(Unsupported, Error)
MakeError(SubstituteGone, Error)
MakeError(SubstituterDisabled, Error)
+MakeError(NotInStore, Error)
struct BasicDerivation;