aboutsummaryrefslogtreecommitdiff
path: root/src/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/abstract-setting-to-json.hh15
-rw-r--r--src/libutil/archive.cc11
-rw-r--r--src/libutil/args.cc6
-rw-r--r--src/libutil/args.hh2
-rw-r--r--src/libutil/callback.hh46
-rw-r--r--src/libutil/config.cc44
-rw-r--r--src/libutil/config.hh8
-rw-r--r--src/libutil/error.cc26
-rw-r--r--src/libutil/error.hh4
-rw-r--r--src/libutil/fmt.hh31
-rw-r--r--src/libutil/logging.cc2
-rw-r--r--src/libutil/serialise.cc55
-rw-r--r--src/libutil/serialise.hh102
-rw-r--r--src/libutil/split.hh2
-rw-r--r--src/libutil/tests/config.cc2
-rw-r--r--src/libutil/topo-sort.hh2
-rw-r--r--src/libutil/types.hh2
-rw-r--r--src/libutil/url-parts.hh44
-rw-r--r--src/libutil/url.cc1
-rw-r--r--src/libutil/url.hh38
-rw-r--r--src/libutil/util.cc61
-rw-r--r--src/libutil/util.hh44
22 files changed, 386 insertions, 162 deletions
diff --git a/src/libutil/abstract-setting-to-json.hh b/src/libutil/abstract-setting-to-json.hh
new file mode 100644
index 000000000..b3fbc84f7
--- /dev/null
+++ b/src/libutil/abstract-setting-to-json.hh
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <nlohmann/json.hpp>
+#include "config.hh"
+
+namespace nix {
+template<typename T>
+std::map<std::string, nlohmann::json> BaseSetting<T>::toJSONObject()
+{
+ auto obj = AbstractSetting::toJSONObject();
+ obj.emplace("value", value);
+ obj.emplace("defaultValue", defaultValue);
+ return obj;
+}
+}
diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc
index 14399dea3..f1479329f 100644
--- a/src/libutil/archive.cc
+++ b/src/libutil/archive.cc
@@ -27,11 +27,13 @@ struct ArchiveSettings : Config
#endif
"use-case-hack",
"Whether to enable a Darwin-specific hack for dealing with file name collisions."};
+ Setting<bool> preallocateContents{this, true, "preallocate-contents",
+ "Whether to preallocate files when writing objects with known size."};
};
static ArchiveSettings archiveSettings;
-static GlobalConfig::Register r1(&archiveSettings);
+static GlobalConfig::Register rArchiveSettings(&archiveSettings);
const std::string narVersionMagic1 = "nix-archive-1";
@@ -66,9 +68,7 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter)
{
checkInterrupt();
- struct stat st;
- if (lstat(path.c_str(), &st))
- throw SysError("getting attributes of path '%1%'", path);
+ auto st = lstat(path);
sink << "(";
@@ -325,6 +325,9 @@ struct RestoreSink : ParseSink
void preallocateContents(uint64_t len)
{
+ if (!archiveSettings.preallocateContents)
+ return;
+
#if HAVE_POSIX_FALLOCATE
if (len) {
errno = posix_fallocate(fd.get(), 0, len);
diff --git a/src/libutil/args.cc b/src/libutil/args.cc
index 147602415..2760b830b 100644
--- a/src/libutil/args.cc
+++ b/src/libutil/args.cc
@@ -277,7 +277,7 @@ Args::Flag Args::Flag::mkHashTypeOptFlag(std::string && longName, std::optional<
};
}
-static void completePath(std::string_view prefix, bool onlyDirs)
+static void _completePath(std::string_view prefix, bool onlyDirs)
{
pathCompletions = true;
glob_t globbuf;
@@ -300,12 +300,12 @@ static void completePath(std::string_view prefix, bool onlyDirs)
void completePath(size_t, std::string_view prefix)
{
- completePath(prefix, false);
+ _completePath(prefix, false);
}
void completeDir(size_t, std::string_view prefix)
{
- completePath(prefix, true);
+ _completePath(prefix, true);
}
Strings argvToStrings(int argc, char * * argv)
diff --git a/src/libutil/args.hh b/src/libutil/args.hh
index 3c1f87f7e..f41242e17 100644
--- a/src/libutil/args.hh
+++ b/src/libutil/args.hh
@@ -192,7 +192,7 @@ public:
{
expectArgs({
.label = label,
- .optional = true,
+ .optional = optional,
.handler = {dest}
});
}
diff --git a/src/libutil/callback.hh b/src/libutil/callback.hh
new file mode 100644
index 000000000..ef31794be
--- /dev/null
+++ b/src/libutil/callback.hh
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <future>
+#include <functional>
+
+namespace nix {
+
+/* A callback is a wrapper around a lambda that accepts a valid of
+ type T or an exception. (We abuse std::future<T> to pass the value or
+ exception.) */
+template<typename T>
+class Callback
+{
+ std::function<void(std::future<T>)> fun;
+ std::atomic_flag done = ATOMIC_FLAG_INIT;
+
+public:
+
+ Callback(std::function<void(std::future<T>)> fun) : fun(fun) { }
+
+ Callback(Callback && callback) : fun(std::move(callback.fun))
+ {
+ auto prev = callback.done.test_and_set();
+ if (prev) done.test_and_set();
+ }
+
+ void operator()(T && t) noexcept
+ {
+ auto prev = done.test_and_set();
+ assert(!prev);
+ std::promise<T> promise;
+ promise.set_value(std::move(t));
+ fun(promise.get_future());
+ }
+
+ void rethrow(const std::exception_ptr & exc = std::current_exception()) noexcept
+ {
+ auto prev = done.test_and_set();
+ assert(!prev);
+ std::promise<T> promise;
+ promise.set_exception(exc);
+ fun(promise.get_future());
+ }
+};
+
+}
diff --git a/src/libutil/config.cc b/src/libutil/config.cc
index 3cf720bce..521733025 100644
--- a/src/libutil/config.cc
+++ b/src/libutil/config.cc
@@ -1,5 +1,6 @@
#include "config.hh"
#include "args.hh"
+#include "abstract-setting-to-json.hh"
#include <nlohmann/json.hpp>
@@ -137,11 +138,7 @@ nlohmann::json Config::toJSON()
auto res = nlohmann::json::object();
for (auto & s : _settings)
if (!s.second.isAlias) {
- auto obj = nlohmann::json::object();
- obj.emplace("description", s.second.setting->description);
- obj.emplace("aliases", s.second.setting->aliases);
- obj.emplace("value", s.second.setting->toJSON());
- res.emplace(s.first, obj);
+ res.emplace(s.first, s.second.setting->toJSON());
}
return res;
}
@@ -168,17 +165,19 @@ void AbstractSetting::setDefault(const std::string & str)
nlohmann::json AbstractSetting::toJSON()
{
- return to_string();
+ return nlohmann::json(toJSONObject());
}
-void AbstractSetting::convertToArg(Args & args, const std::string & category)
+std::map<std::string, nlohmann::json> AbstractSetting::toJSONObject()
{
+ std::map<std::string, nlohmann::json> obj;
+ obj.emplace("description", description);
+ obj.emplace("aliases", aliases);
+ return obj;
}
-template<typename T>
-nlohmann::json BaseSetting<T>::toJSON()
+void AbstractSetting::convertToArg(Args & args, const std::string & category)
{
- return value;
}
template<typename T>
@@ -259,11 +258,6 @@ template<> std::string BaseSetting<Strings>::to_string() const
return concatStringsSep(" ", value);
}
-template<> nlohmann::json BaseSetting<Strings>::toJSON()
-{
- return value;
-}
-
template<> void BaseSetting<StringSet>::set(const std::string & str)
{
value = tokenizeString<StringSet>(str);
@@ -274,9 +268,24 @@ template<> std::string BaseSetting<StringSet>::to_string() const
return concatStringsSep(" ", value);
}
-template<> nlohmann::json BaseSetting<StringSet>::toJSON()
+template<> void BaseSetting<StringMap>::set(const std::string & str)
{
- return value;
+ auto kvpairs = tokenizeString<Strings>(str);
+ for (auto & s : kvpairs)
+ {
+ auto eq = s.find_first_of('=');
+ if (std::string::npos != eq)
+ value.emplace(std::string(s, 0, eq), std::string(s, eq + 1));
+ // else ignored
+ }
+}
+
+template<> std::string BaseSetting<StringMap>::to_string() const
+{
+ Strings kvstrs;
+ std::transform(value.begin(), value.end(), back_inserter(kvstrs),
+ [&](auto kvpair){ return kvpair.first + "=" + kvpair.second; });
+ return concatStringsSep(" ", kvstrs);
}
template class BaseSetting<int>;
@@ -289,6 +298,7 @@ template class BaseSetting<bool>;
template class BaseSetting<std::string>;
template class BaseSetting<Strings>;
template class BaseSetting<StringSet>;
+template class BaseSetting<StringMap>;
void PathSetting::set(const std::string & str)
{
diff --git a/src/libutil/config.hh b/src/libutil/config.hh
index 2b4265806..1f5f4e7b9 100644
--- a/src/libutil/config.hh
+++ b/src/libutil/config.hh
@@ -206,7 +206,9 @@ protected:
virtual std::string to_string() const = 0;
- virtual nlohmann::json toJSON();
+ nlohmann::json toJSON();
+
+ virtual std::map<std::string, nlohmann::json> toJSONObject();
virtual void convertToArg(Args & args, const std::string & category);
@@ -220,6 +222,7 @@ class BaseSetting : public AbstractSetting
protected:
T value;
+ const T defaultValue;
public:
@@ -229,6 +232,7 @@ public:
const std::set<std::string> & aliases = {})
: AbstractSetting(name, description, aliases)
, value(def)
+ , defaultValue(def)
{ }
operator const T &() const { return value; }
@@ -251,7 +255,7 @@ public:
void convertToArg(Args & args, const std::string & category) override;
- nlohmann::json toJSON() override;
+ std::map<std::string, nlohmann::json> toJSONObject() override;
};
template<typename T>
diff --git a/src/libutil/error.cc b/src/libutil/error.cc
index fd6f69b7f..803a72953 100644
--- a/src/libutil/error.cc
+++ b/src/libutil/error.cc
@@ -11,13 +11,13 @@ const std::string nativeSystem = SYSTEM;
BaseError & BaseError::addTrace(std::optional<ErrPos> e, hintformat hint)
{
- err.traces.push_front(Trace { .pos = e, .hint = hint});
+ err.traces.push_front(Trace { .pos = e, .hint = hint });
return *this;
}
// c++ std::exception descendants must have a 'const char* what()' function.
// This stringifies the error and caches it for use by what(), or similarly by msg().
-const string& BaseError::calcWhat() const
+const string & BaseError::calcWhat() const
{
if (what_.has_value())
return *what_;
@@ -34,12 +34,12 @@ const string& BaseError::calcWhat() const
std::optional<string> ErrorInfo::programName = std::nullopt;
-std::ostream& operator<<(std::ostream &os, const hintformat &hf)
+std::ostream & operator<<(std::ostream & os, const hintformat & hf)
{
return os << hf.str();
}
-string showErrPos(const ErrPos &errPos)
+string showErrPos(const ErrPos & errPos)
{
if (errPos.line > 0) {
if (errPos.column > 0) {
@@ -53,7 +53,7 @@ string showErrPos(const ErrPos &errPos)
}
}
-std::optional<LinesOfCode> getCodeLines(const ErrPos &errPos)
+std::optional<LinesOfCode> getCodeLines(const ErrPos & errPos)
{
if (errPos.line <= 0)
return std::nullopt;
@@ -92,13 +92,13 @@ std::optional<LinesOfCode> getCodeLines(const ErrPos &errPos)
return loc;
}
}
- catch (EndOfFile &eof) {
+ catch (EndOfFile & eof) {
if (loc.errLineOfCode.has_value())
return loc;
else
return std::nullopt;
}
- catch (std::exception &e) {
+ catch (std::exception & e) {
printError("error reading nix file: %s\n%s", errPos.file, e.what());
return std::nullopt;
}
@@ -137,10 +137,10 @@ std::optional<LinesOfCode> getCodeLines(const ErrPos &errPos)
}
// print lines of code to the ostream, indicating the error column.
-void printCodeLines(std::ostream &out,
- const string &prefix,
- const ErrPos &errPos,
- const LinesOfCode &loc)
+void printCodeLines(std::ostream & out,
+ const string & prefix,
+ const ErrPos & errPos,
+ const LinesOfCode & loc)
{
// previous line of code.
if (loc.prevLineOfCode.has_value()) {
@@ -186,7 +186,7 @@ void printCodeLines(std::ostream &out,
}
}
-void printAtPos(const string &prefix, const ErrPos &pos, std::ostream &out)
+void printAtPos(const string & prefix, const ErrPos & pos, std::ostream & out)
{
if (pos)
{
@@ -212,7 +212,7 @@ void printAtPos(const string &prefix, const ErrPos &pos, std::ostream &out)
}
}
-std::ostream& showErrorInfo(std::ostream &out, const ErrorInfo &einfo, bool showTrace)
+std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace)
{
auto errwidth = std::max<size_t>(getWindowSize().second, 20);
string prefix = "";
diff --git a/src/libutil/error.hh b/src/libutil/error.hh
index f3babcbde..d1b6d82bb 100644
--- a/src/libutil/error.hh
+++ b/src/libutil/error.hh
@@ -107,7 +107,7 @@ struct Trace {
struct ErrorInfo {
Verbosity level;
string name;
- string description;
+ string description; // FIXME: remove? it seems to be barely used
std::optional<hintformat> hint;
std::optional<ErrPos> errPos;
std::list<Trace> traces;
@@ -169,7 +169,7 @@ public:
#endif
const string & msg() const { return calcWhat(); }
- const ErrorInfo & info() { calcWhat(); return err; }
+ const ErrorInfo & info() const { calcWhat(); return err; }
template<typename... Args>
BaseError & addTrace(std::optional<ErrPos> e, const string &fs, const Args & ... args)
diff --git a/src/libutil/fmt.hh b/src/libutil/fmt.hh
index a39de041f..85c0e9429 100644
--- a/src/libutil/fmt.hh
+++ b/src/libutil/fmt.hh
@@ -1,7 +1,6 @@
#pragma once
#include <boost/format.hpp>
-#include <boost/algorithm/string/replace.hpp>
#include <string>
#include "ansicolor.hh"
@@ -77,11 +76,11 @@ template <class T>
struct yellowtxt
{
yellowtxt(const T &s) : value(s) {}
- const T &value;
+ const T & value;
};
template <class T>
-std::ostream& operator<<(std::ostream &out, const yellowtxt<T> &y)
+std::ostream & operator<<(std::ostream & out, const yellowtxt<T> & y)
{
return out << ANSI_YELLOW << y.value << ANSI_NORMAL;
}
@@ -89,12 +88,12 @@ std::ostream& operator<<(std::ostream &out, const yellowtxt<T> &y)
template <class T>
struct normaltxt
{
- normaltxt(const T &s) : value(s) {}
- const T &value;
+ normaltxt(const T & s) : value(s) {}
+ const T & value;
};
template <class T>
-std::ostream& operator<<(std::ostream &out, const normaltxt<T> &y)
+std::ostream & operator<<(std::ostream & out, const normaltxt<T> & y)
{
return out << ANSI_NORMAL << y.value;
}
@@ -102,26 +101,30 @@ std::ostream& operator<<(std::ostream &out, const normaltxt<T> &y)
class hintformat
{
public:
- hintformat(const string &format) :fmt(format)
+ hintformat(const string & format) : fmt(format)
{
- fmt.exceptions(boost::io::all_error_bits ^
+ fmt.exceptions(boost::io::all_error_bits ^
boost::io::too_many_args_bit ^
boost::io::too_few_args_bit);
}
- hintformat(const hintformat &hf)
- : fmt(hf.fmt)
- {}
+ hintformat(const hintformat & hf)
+ : fmt(hf.fmt)
+ { }
+
+ hintformat(format && fmt)
+ : fmt(std::move(fmt))
+ { }
template<class T>
- hintformat& operator%(const T &value)
+ hintformat & operator%(const T & value)
{
fmt % yellowtxt(value);
return *this;
}
template<class T>
- hintformat& operator%(const normaltxt<T> &value)
+ hintformat & operator%(const normaltxt<T> & value)
{
fmt % value.value;
return *this;
@@ -136,7 +139,7 @@ private:
format fmt;
};
-std::ostream& operator<<(std::ostream &os, const hintformat &hf);
+std::ostream & operator<<(std::ostream & os, const hintformat & hf);
template<typename... Args>
inline hintformat hintfmt(const std::string & fs, const Args & ... args)
diff --git a/src/libutil/logging.cc b/src/libutil/logging.cc
index cbbf64395..8a6752e22 100644
--- a/src/libutil/logging.cc
+++ b/src/libutil/logging.cc
@@ -10,7 +10,7 @@ namespace nix {
LoggerSettings loggerSettings;
-static GlobalConfig::Register r1(&loggerSettings);
+static GlobalConfig::Register rLoggerSettings(&loggerSettings);
static thread_local ActivityId curActivity = 0;
diff --git a/src/libutil/serialise.cc b/src/libutil/serialise.cc
index 00c945113..5c9f6f901 100644
--- a/src/libutil/serialise.cc
+++ b/src/libutil/serialise.cc
@@ -93,7 +93,7 @@ void Source::operator () (unsigned char * data, size_t len)
}
-std::string Source::drain()
+void Source::drainInto(Sink & sink)
{
std::string s;
std::vector<unsigned char> buf(8192);
@@ -101,12 +101,19 @@ std::string Source::drain()
size_t n;
try {
n = read(buf.data(), buf.size());
- s.append((char *) buf.data(), n);
+ sink(buf.data(), n);
} catch (EndOfFile &) {
break;
}
}
- return s;
+}
+
+
+std::string Source::drain()
+{
+ StringSink s;
+ drainInto(s);
+ return *s.s;
}
@@ -259,6 +266,24 @@ Sink & operator << (Sink & sink, const StringSet & s)
return sink;
}
+Sink & operator << (Sink & sink, const Error & ex)
+{
+ auto info = ex.info();
+ sink
+ << "Error"
+ << info.level
+ << info.name
+ << info.description
+ << (info.hint ? info.hint->str() : "")
+ << 0 // FIXME: info.errPos
+ << info.traces.size();
+ for (auto & trace : info.traces) {
+ sink << 0; // FIXME: trace.pos
+ sink << trace.hint.str();
+ }
+ return sink;
+}
+
void readPadding(size_t len, Source & source)
{
@@ -312,6 +337,30 @@ template Paths readStrings(Source & source);
template PathSet readStrings(Source & source);
+Error readError(Source & source)
+{
+ auto type = readString(source);
+ assert(type == "Error");
+ ErrorInfo info;
+ info.level = (Verbosity) readInt(source);
+ info.name = readString(source);
+ info.description = readString(source);
+ auto hint = readString(source);
+ if (hint != "") info.hint = hintformat(std::move(format("%s") % hint));
+ auto havePos = readNum<size_t>(source);
+ assert(havePos == 0);
+ auto nrTraces = readNum<size_t>(source);
+ for (size_t i = 0; i < nrTraces; ++i) {
+ havePos = readNum<size_t>(source);
+ assert(havePos == 0);
+ info.traces.push_back(Trace {
+ .hint = hintformat(std::move(format("%s") % readString(source)))
+ });
+ }
+ return Error(std::move(info));
+}
+
+
void StringSink::operator () (const unsigned char * data, size_t len)
{
static bool warned = false;
diff --git a/src/libutil/serialise.hh b/src/libutil/serialise.hh
index a6f1c42e9..d7fe0b81e 100644
--- a/src/libutil/serialise.hh
+++ b/src/libutil/serialise.hh
@@ -22,6 +22,12 @@ struct Sink
}
};
+/* Just throws away data. */
+struct NullSink : Sink
+{
+ void operator () (const unsigned char * data, size_t len) override
+ { }
+};
/* A buffered abstract sink. Warning: a BufferedSink should not be
used from multiple threads concurrently. */
@@ -63,6 +69,8 @@ struct Source
virtual bool good() { return true; }
+ void drainInto(Sink & sink);
+
std::string drain();
};
@@ -313,6 +321,7 @@ inline Sink & operator << (Sink & sink, uint64_t n)
Sink & operator << (Sink & sink, const string & s);
Sink & operator << (Sink & sink, const Strings & s);
Sink & operator << (Sink & sink, const StringSet & s);
+Sink & operator << (Sink & in, const Error & ex);
MakeError(SerialisationError, Error);
@@ -334,7 +343,7 @@ T readNum(Source & source)
((uint64_t) buf[6] << 48) |
((uint64_t) buf[7] << 56);
- if (n > std::numeric_limits<T>::max())
+ if (n > (uint64_t)std::numeric_limits<T>::max())
throw SerialisationError("serialised integer %d is too large for type '%s'", n, typeid(T).name());
return (T) n;
@@ -374,6 +383,8 @@ Source & operator >> (Source & in, bool & b)
return in;
}
+Error readError(Source & source);
+
/* An adapter that converts a std::basic_istream into a source. */
struct StreamToSourceAdapter : Source
@@ -398,4 +409,93 @@ struct StreamToSourceAdapter : Source
};
+/* A source that reads a distinct format of concatenated chunks back into its
+ logical form, in order to guarantee a known state to the original stream,
+ even in the event of errors.
+
+ Use with FramedSink, which also allows the logical stream to be terminated
+ in the event of an exception.
+*/
+struct FramedSource : Source
+{
+ Source & from;
+ bool eof = false;
+ std::vector<unsigned char> pending;
+ size_t pos = 0;
+
+ FramedSource(Source & from) : from(from)
+ { }
+
+ ~FramedSource()
+ {
+ if (!eof) {
+ while (true) {
+ auto n = readInt(from);
+ if (!n) break;
+ std::vector<unsigned char> data(n);
+ from(data.data(), n);
+ }
+ }
+ }
+
+ size_t read(unsigned char * data, size_t len) override
+ {
+ if (eof) throw EndOfFile("reached end of FramedSource");
+
+ if (pos >= pending.size()) {
+ size_t len = readInt(from);
+ if (!len) {
+ eof = true;
+ return 0;
+ }
+ pending = std::vector<unsigned char>(len);
+ pos = 0;
+ from(pending.data(), len);
+ }
+
+ auto n = std::min(len, pending.size() - pos);
+ memcpy(data, pending.data() + pos, n);
+ pos += n;
+ return n;
+ }
+};
+
+/* Write as chunks in the format expected by FramedSource.
+
+ The exception_ptr reference can be used to terminate the stream when you
+ detect that an error has occurred on the remote end.
+*/
+struct FramedSink : nix::BufferedSink
+{
+ BufferedSink & to;
+ std::exception_ptr & ex;
+
+ FramedSink(BufferedSink & to, std::exception_ptr & ex) : to(to), ex(ex)
+ { }
+
+ ~FramedSink()
+ {
+ try {
+ to << 0;
+ to.flush();
+ } catch (...) {
+ ignoreException();
+ }
+ }
+
+ void write(const unsigned char * data, size_t len) override
+ {
+ /* Don't send more data if the remote has
+ encountered an error. */
+ if (ex) {
+ auto ex2 = ex;
+ ex = nullptr;
+ std::rethrow_exception(ex2);
+ }
+ to << len;
+ to(data, len);
+ };
+};
+
+
}
diff --git a/src/libutil/split.hh b/src/libutil/split.hh
index d19d7d8ed..87a23b13e 100644
--- a/src/libutil/split.hh
+++ b/src/libutil/split.hh
@@ -9,7 +9,7 @@ namespace nix {
// If `separator` is found, we return the portion of the string before the
// separator, and modify the string argument to contain only the part after the
-// separator. Otherwise, wer return `std::nullopt`, and we leave the argument
+// separator. Otherwise, we return `std::nullopt`, and we leave the argument
// string alone.
static inline std::optional<std::string_view> splitPrefixTo(std::string_view & string, char separator) {
auto sepInstance = string.find(separator);
diff --git a/src/libutil/tests/config.cc b/src/libutil/tests/config.cc
index c5abefe11..c7777a21f 100644
--- a/src/libutil/tests/config.cc
+++ b/src/libutil/tests/config.cc
@@ -161,7 +161,7 @@ namespace nix {
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
setting.assign("value");
- ASSERT_EQ(config.toJSON().dump(), R"#({"name-of-the-setting":{"aliases":[],"description":"description\n","value":"value"}})#");
+ ASSERT_EQ(config.toJSON().dump(), R"#({"name-of-the-setting":{"aliases":[],"defaultValue":"","description":"description\n","value":"value"}})#");
}
TEST(Config, setSettingAlias) {
diff --git a/src/libutil/topo-sort.hh b/src/libutil/topo-sort.hh
index 7a68ff169..7418be5e0 100644
--- a/src/libutil/topo-sort.hh
+++ b/src/libutil/topo-sort.hh
@@ -1,3 +1,5 @@
+#pragma once
+
#include "error.hh"
namespace nix {
diff --git a/src/libutil/types.hh b/src/libutil/types.hh
index 2170e4c93..6c4c5ab74 100644
--- a/src/libutil/types.hh
+++ b/src/libutil/types.hh
@@ -25,6 +25,8 @@ typedef string Path;
typedef list<Path> Paths;
typedef set<Path> PathSet;
+typedef vector<std::pair<string, string>> Headers;
+
/* Helper class to run code at startup. */
template<typename T>
struct OnStartup
diff --git a/src/libutil/url-parts.hh b/src/libutil/url-parts.hh
new file mode 100644
index 000000000..68be15cb0
--- /dev/null
+++ b/src/libutil/url-parts.hh
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <string>
+#include <regex>
+
+namespace nix {
+
+// URI stuff.
+const static std::string pctEncoded = "(?:%[0-9a-fA-F][0-9a-fA-F])";
+const static std::string schemeRegex = "(?:[a-z][a-z0-9+.-]*)";
+const static std::string ipv6AddressRegex = "(?:\\[[0-9a-fA-F:]+\\])";
+const static std::string unreservedRegex = "(?:[a-zA-Z0-9-._~])";
+const static std::string subdelimsRegex = "(?:[!$&'\"()*+,;=])";
+const static std::string hostnameRegex = "(?:(?:" + unreservedRegex + "|" + pctEncoded + "|" + subdelimsRegex + ")*)";
+const static std::string hostRegex = "(?:" + ipv6AddressRegex + "|" + hostnameRegex + ")";
+const static std::string userRegex = "(?:(?:" + unreservedRegex + "|" + pctEncoded + "|" + subdelimsRegex + "|:)*)";
+const static std::string authorityRegex = "(?:" + userRegex + "@)?" + hostRegex + "(?::[0-9]+)?";
+const static std::string pcharRegex = "(?:" + unreservedRegex + "|" + pctEncoded + "|" + subdelimsRegex + "|[:@])";
+const static std::string queryRegex = "(?:" + pcharRegex + "|[/? \"])*";
+const static std::string segmentRegex = "(?:" + pcharRegex + "+)";
+const static std::string absPathRegex = "(?:(?:/" + segmentRegex + ")*/?)";
+const static std::string pathRegex = "(?:" + segmentRegex + "(?:/" + segmentRegex + ")*/?)";
+
+// A Git ref (i.e. branch or tag name).
+const static std::string refRegexS = "[a-zA-Z0-9][a-zA-Z0-9_.-]*"; // FIXME: check
+extern std::regex refRegex;
+
+// Instead of defining what a good Git Ref is, we define what a bad Git Ref is
+// This is because of the definition of a ref in refs.c in https://github.com/git/git
+// See tests/fetchGitRefs.sh for the full definition
+const static std::string badGitRefRegexS = "//|^[./]|/\\.|\\.\\.|[[:cntrl:][:space:]:?^~\[]|\\\\|\\*|\\.lock$|\\.lock/|@\\{|[/.]$|^@$|^$";
+extern std::regex badGitRefRegex;
+
+// A Git revision (a SHA-1 commit hash).
+const static std::string revRegexS = "[0-9a-fA-F]{40}";
+extern std::regex revRegex;
+
+// A ref or revision, or a ref followed by a revision.
+const static std::string refAndOrRevRegex = "(?:(" + revRegexS + ")|(?:(" + refRegexS + ")(?:/(" + revRegexS + "))?))";
+
+const static std::string flakeIdRegexS = "[a-zA-Z][a-zA-Z0-9_-]*";
+extern std::regex flakeIdRegex;
+
+}
diff --git a/src/libutil/url.cc b/src/libutil/url.cc
index 88c09eef9..c1bab866c 100644
--- a/src/libutil/url.cc
+++ b/src/libutil/url.cc
@@ -1,4 +1,5 @@
#include "url.hh"
+#include "url-parts.hh"
#include "util.hh"
namespace nix {
diff --git a/src/libutil/url.hh b/src/libutil/url.hh
index 2ef88ef2a..6e77142e3 100644
--- a/src/libutil/url.hh
+++ b/src/libutil/url.hh
@@ -2,8 +2,6 @@
#include "error.hh"
-#include <regex>
-
namespace nix {
struct ParsedURL
@@ -29,40 +27,4 @@ std::map<std::string, std::string> decodeQuery(const std::string & query);
ParsedURL parseURL(const std::string & url);
-// URI stuff.
-const static std::string pctEncoded = "(?:%[0-9a-fA-F][0-9a-fA-F])";
-const static std::string schemeRegex = "(?:[a-z+]+)";
-const static std::string ipv6AddressRegex = "(?:\\[[0-9a-fA-F:]+\\])";
-const static std::string unreservedRegex = "(?:[a-zA-Z0-9-._~])";
-const static std::string subdelimsRegex = "(?:[!$&'\"()*+,;=])";
-const static std::string hostnameRegex = "(?:(?:" + unreservedRegex + "|" + pctEncoded + "|" + subdelimsRegex + ")*)";
-const static std::string hostRegex = "(?:" + ipv6AddressRegex + "|" + hostnameRegex + ")";
-const static std::string userRegex = "(?:(?:" + unreservedRegex + "|" + pctEncoded + "|" + subdelimsRegex + "|:)*)";
-const static std::string authorityRegex = "(?:" + userRegex + "@)?" + hostRegex + "(?::[0-9]+)?";
-const static std::string pcharRegex = "(?:" + unreservedRegex + "|" + pctEncoded + "|" + subdelimsRegex + "|[:@])";
-const static std::string queryRegex = "(?:" + pcharRegex + "|[/? \"])*";
-const static std::string segmentRegex = "(?:" + pcharRegex + "+)";
-const static std::string absPathRegex = "(?:(?:/" + segmentRegex + ")*/?)";
-const static std::string pathRegex = "(?:" + segmentRegex + "(?:/" + segmentRegex + ")*/?)";
-
-// A Git ref (i.e. branch or tag name).
-const static std::string refRegexS = "[a-zA-Z0-9][a-zA-Z0-9_.-]*"; // FIXME: check
-extern std::regex refRegex;
-
-// Instead of defining what a good Git Ref is, we define what a bad Git Ref is
-// This is because of the definition of a ref in refs.c in https://github.com/git/git
-// See tests/fetchGitRefs.sh for the full definition
-const static std::string badGitRefRegexS = "//|^[./]|/\\.|\\.\\.|[[:cntrl:][:space:]:?^~\[]|\\\\|\\*|\\.lock$|\\.lock/|@\\{|[/.]$|^@$|^$";
-extern std::regex badGitRefRegex;
-
-// A Git revision (a SHA-1 commit hash).
-const static std::string revRegexS = "[0-9a-fA-F]{40}";
-extern std::regex revRegex;
-
-// A ref or revision, or a ref followed by a revision.
-const static std::string refAndOrRevRegex = "(?:(" + revRegexS + ")|(?:(" + refRegexS + ")(?:/(" + revRegexS + "))?))";
-
-const static std::string flakeIdRegexS = "[a-zA-Z][a-zA-Z0-9_-]*";
-extern std::regex flakeIdRegex;
-
}
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 16cfa654f..9804e9a51 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -325,7 +325,12 @@ void writeFile(const Path & path, const string & s, mode_t mode)
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
if (!fd)
throw SysError("opening file '%1%'", path);
- writeFull(fd.get(), s);
+ try {
+ writeFull(fd.get(), s);
+ } catch (Error & e) {
+ e.addTrace({}, "writing file '%1%'", path);
+ throw;
+ }
}
@@ -337,11 +342,16 @@ void writeFile(const Path & path, Source & source, mode_t mode)
std::vector<unsigned char> buf(64 * 1024);
- while (true) {
- try {
- auto n = source.read(buf.data(), buf.size());
- writeFull(fd.get(), (unsigned char *) buf.data(), n);
- } catch (EndOfFile &) { break; }
+ try {
+ while (true) {
+ try {
+ auto n = source.read(buf.data(), buf.size());
+ writeFull(fd.get(), (unsigned char *) buf.data(), n);
+ } catch (EndOfFile &) { break; }
+ }
+ } catch (Error & e) {
+ e.addTrace({}, "writing file '%1%'", path);
+ throw;
}
}
@@ -511,22 +521,24 @@ std::string getUserName()
}
-static Path getHome2()
+Path getHome()
{
- auto homeDir = getEnv("HOME");
- if (!homeDir) {
- std::vector<char> buf(16384);
- struct passwd pwbuf;
- struct passwd * pw;
- if (getpwuid_r(geteuid(), &pwbuf, buf.data(), buf.size(), &pw) != 0
- || !pw || !pw->pw_dir || !pw->pw_dir[0])
- throw Error("cannot determine user's home directory");
- homeDir = pw->pw_dir;
- }
- return *homeDir;
-};
-
-Path getHome() { return getHome2(); }
+ static Path homeDir = []()
+ {
+ auto homeDir = getEnv("HOME");
+ if (!homeDir) {
+ std::vector<char> buf(16384);
+ struct passwd pwbuf;
+ struct passwd * pw;
+ if (getpwuid_r(geteuid(), &pwbuf, buf.data(), buf.size(), &pw) != 0
+ || !pw || !pw->pw_dir || !pw->pw_dir[0])
+ throw Error("cannot determine user's home directory");
+ homeDir = pw->pw_dir;
+ }
+ return *homeDir;
+ }();
+ return homeDir;
+}
Path getCacheDir()
@@ -1641,4 +1653,11 @@ AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode)
return fdSocket;
}
+
+string showBytes(uint64_t bytes)
+{
+ return fmt("%.2f MiB", bytes / (1024.0 * 1024.0));
+}
+
+
}
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 082e26375..129d59a97 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -12,13 +12,9 @@
#include <signal.h>
#include <functional>
-#include <limits>
-#include <cstdio>
#include <map>
#include <sstream>
#include <optional>
-#include <future>
-#include <iterator>
#ifndef HAVE_STRUCT_DIRENT_D_TYPE
#define DT_UNKNOWN 0
@@ -480,43 +476,8 @@ std::optional<typename T::mapped_type> get(const T & map, const typename T::key_
}
-/* A callback is a wrapper around a lambda that accepts a valid of
- type T or an exception. (We abuse std::future<T> to pass the value or
- exception.) */
template<typename T>
-class Callback
-{
- std::function<void(std::future<T>)> fun;
- std::atomic_flag done = ATOMIC_FLAG_INIT;
-
-public:
-
- Callback(std::function<void(std::future<T>)> fun) : fun(fun) { }
-
- Callback(Callback && callback) : fun(std::move(callback.fun))
- {
- auto prev = callback.done.test_and_set();
- if (prev) done.test_and_set();
- }
-
- void operator()(T && t) noexcept
- {
- auto prev = done.test_and_set();
- assert(!prev);
- std::promise<T> promise;
- promise.set_value(std::move(t));
- fun(promise.get_future());
- }
-
- void rethrow(const std::exception_ptr & exc = std::current_exception()) noexcept
- {
- auto prev = done.test_and_set();
- assert(!prev);
- std::promise<T> promise;
- promise.set_exception(exc);
- fun(promise.get_future());
- }
-};
+class Callback;
/* Start a thread that handles various signals. Also block those signals
@@ -612,4 +573,7 @@ template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
+std::string showBytes(uint64_t bytes);
+
+
}