1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-16 07:22:43 +01:00

Apply clang-format universally.

* It is tough to contribute to a project that doesn't use a formatter,
* It is extra hard to contribute to a project which has configured the formatter, but ignores it for some files
* Code formatting makes it harder to hide obscure / weird bugs by accident or on purpose,

Let's rip the bandaid off?

Note that PRs currently in flight should be able to be merged relatively easily by applying `clang-format` to their tip prior to merge.

Co-authored-by: Graham Christensen <graham@grahamc.com>
This commit is contained in:
Sergei Zimmerman 2025-07-18 22:36:31 +03:00
parent 7b97377ac3
commit a5264aa46e
No known key found for this signature in database
565 changed files with 23490 additions and 23405 deletions

View file

@ -16,12 +16,13 @@ namespace nix {
struct ArchiveSettings : Config
{
Setting<bool> useCaseHack{this,
#ifdef __APPLE__
true,
#else
false,
#endif
Setting<bool> useCaseHack{
this,
#ifdef __APPLE__
true,
#else
false,
#endif
"use-case-hack",
"Whether to enable a macOS-specific hack for dealing with file name case collisions."};
};
@ -32,18 +33,12 @@ static GlobalConfig::Register rArchiveSettings(&archiveSettings);
PathFilter defaultPathFilter = [](const Path &) { return true; };
void SourceAccessor::dumpPath(
const CanonPath & path,
Sink & sink,
PathFilter & filter)
void SourceAccessor::dumpPath(const CanonPath & path, Sink & sink, PathFilter & filter)
{
auto dumpContents = [&](const CanonPath & path)
{
auto dumpContents = [&](const CanonPath & path) {
sink << "contents";
std::optional<uint64_t> size;
readFile(path, sink, [&](uint64_t _size)
{
readFile(path, sink, [&](uint64_t _size) {
size = _size;
sink << _size;
});
@ -82,9 +77,8 @@ void SourceAccessor::dumpPath(
name.erase(pos);
}
if (!unhacked.emplace(name, i.first).second)
throw Error("file name collision between '%s' and '%s'",
(path / unhacked[name]),
(path / i.first));
throw Error(
"file name collision between '%s' and '%s'", (path / unhacked[name]), (path / i.first));
} else
unhacked.emplace(i.first, i.first);
@ -99,7 +93,8 @@ void SourceAccessor::dumpPath(
else if (st.type == tSymlink)
sink << "type" << "symlink" << "target" << readLink(path);
else throw Error("file '%s' has an unsupported type", path);
else
throw Error("file '%s' has an unsupported type", path);
sink << ")";
};
@ -108,7 +103,6 @@ void SourceAccessor::dumpPath(
dump(path);
}
time_t dumpPathAndGetMtime(const Path & path, Sink & sink, PathFilter & filter)
{
auto path2 = PosixSourceAccessor::createAtRoot(path);
@ -121,20 +115,17 @@ void dumpPath(const Path & path, Sink & sink, PathFilter & filter)
dumpPathAndGetMtime(path, sink, filter);
}
void dumpString(std::string_view s, Sink & sink)
{
sink << narVersionMagic1 << "(" << "type" << "regular" << "contents" << s << ")";
}
template<typename... Args>
static SerialisationError badArchive(std::string_view s, const Args & ... args)
static SerialisationError badArchive(std::string_view s, const Args &... args)
{
return SerialisationError("bad archive: " + s, args...);
}
static void parseContents(CreateRegularFileSink & sink, Source & source)
{
uint64_t size = readLongLong(source);
@ -147,7 +138,8 @@ static void parseContents(CreateRegularFileSink & sink, Source & source)
while (left) {
checkInterrupt();
auto n = buf.size();
if ((uint64_t)n > left) n = left;
if ((uint64_t) n > left)
n = left;
source(buf.data(), n);
sink({buf.data(), n});
left -= n;
@ -156,16 +148,14 @@ static void parseContents(CreateRegularFileSink & sink, Source & source)
readPadding(size, source);
}
struct CaseInsensitiveCompare
{
bool operator() (const std::string & a, const std::string & b) const
bool operator()(const std::string & a, const std::string & b) const
{
return strcasecmp(a.c_str(), b.c_str()) < 0;
}
};
static void parse(FileSystemObjectSink & sink, Source & source, const CanonPath & path)
{
auto getString = [&]() {
@ -191,7 +181,8 @@ static void parse(FileSystemObjectSink & sink, Source & source, const CanonPath
if (tag == "executable") {
auto s2 = getString();
if (s2 != "") throw badArchive("executable marker has non-empty value");
if (s2 != "")
throw badArchive("executable marker has non-empty value");
crf.isExecutable();
tag = getString();
}
@ -213,7 +204,8 @@ static void parse(FileSystemObjectSink & sink, Source & source, const CanonPath
while (1) {
auto tag = getString();
if (tag == ")") break;
if (tag == ")")
break;
if (tag != "entry")
throw badArchive("expected tag 'entry' or ')', got '%s'", tag);
@ -223,7 +215,8 @@ static void parse(FileSystemObjectSink & sink, Source & source, const CanonPath
expectTag("name");
auto name = getString();
if (name.empty() || name == "." || name == ".." || name.find('/') != std::string::npos || name.find((char) 0) != std::string::npos)
if (name.empty() || name == "." || name == ".." || name.find('/') != std::string::npos
|| name.find((char) 0) != std::string::npos)
throw badArchive("NAR contains invalid file name '%1%'", name);
if (name <= prevName)
throw badArchive("NAR directory is not sorted");
@ -236,7 +229,10 @@ static void parse(FileSystemObjectSink & sink, Source & source, const CanonPath
name += std::to_string(++i->second);
auto j = names.find(name);
if (j != names.end())
throw badArchive("NAR contains file name '%s' that collides with case-hacked file name '%s'", prevName, j->first);
throw badArchive(
"NAR contains file name '%s' that collides with case-hacked file name '%s'",
prevName,
j->first);
} else
names[name] = 0;
}
@ -258,10 +254,10 @@ static void parse(FileSystemObjectSink & sink, Source & source, const CanonPath
expectTag(")");
}
else throw badArchive("unknown file type '%s'", type);
else
throw badArchive("unknown file type '%s'", type);
}
void parseDump(FileSystemObjectSink & sink, Source & source)
{
std::string version;
@ -276,7 +272,6 @@ void parseDump(FileSystemObjectSink & sink, Source & source)
parse(sink, source, CanonPath::root);
}
void restorePath(const std::filesystem::path & path, Source & source, bool startFsync)
{
RestoreSink sink{startFsync};
@ -284,7 +279,6 @@ void restorePath(const std::filesystem::path & path, Source & source, bool start
parseDump(sink, source);
}
void copyNAR(Source & source, Sink & sink)
{
// FIXME: if 'source' is the output of dumpPath() followed by EOF,
@ -292,10 +286,9 @@ void copyNAR(Source & source, Sink & sink)
NullFileSystemObjectSink parseSink; /* just parse the NAR */
TeeSource wrapper { source, sink };
TeeSource wrapper{source, sink};
parseDump(parseSink, wrapper);
}
}
} // namespace nix

View file

@ -10,7 +10,7 @@
#include <string>
#include <regex>
#ifndef _WIN32
# include <glob.h>
# include <glob.h>
#endif
namespace nix {
@ -24,14 +24,16 @@ void Args::addFlag(Flag && flag_)
longFlags[flag->longName] = flag;
for (auto & alias : flag->aliases)
longFlags[alias] = flag;
if (flag->shortName) shortFlags[flag->shortName] = flag;
if (flag->shortName)
shortFlags[flag->shortName] = flag;
}
void Args::removeFlag(const std::string & longName)
{
auto flag = longFlags.find(longName);
assert(flag != longFlags.end());
if (flag->second->shortName) shortFlags.erase(flag->second->shortName);
if (flag->second->shortName)
shortFlags.erase(flag->second->shortName);
longFlags.erase(flag);
}
@ -51,10 +53,7 @@ void Completions::add(std::string completion, std::string description)
if (needs_ellipsis)
description.append(" [...]");
}
completions.insert(Completion {
.completion = completion,
.description = description
});
completions.insert(Completion{.completion = completion, .description = description});
}
auto Completion::operator<=>(const Completion & other) const noexcept = default;
@ -74,7 +73,8 @@ RootArgs & Args::getRoot()
std::optional<std::string> RootArgs::needsCompletion(std::string_view s)
{
if (!completions) return {};
if (!completions)
return {};
auto i = s.find(completionMarker);
if (i != std::string::npos)
return std::string(s.begin(), i);
@ -86,7 +86,8 @@ std::optional<std::string> RootArgs::needsCompletion(std::string_view s)
*
* Except we can't recursively reference the Parser typedef, so we have to write a class.
*/
struct Parser {
struct Parser
{
std::string_view remaining;
/**
@ -94,12 +95,14 @@ struct Parser {
*/
virtual void operator()(std::shared_ptr<Parser> & state, Strings & r) = 0;
Parser(std::string_view s) : remaining(s) {};
Parser(std::string_view s)
: remaining(s) {};
virtual ~Parser() { };
virtual ~Parser() {};
};
struct ParseQuoted : public Parser {
struct ParseQuoted : public Parser
{
/**
* @brief Accumulated string
*
@ -107,13 +110,14 @@ struct ParseQuoted : public Parser {
*/
std::string acc;
ParseQuoted(std::string_view s) : Parser(s) {};
ParseQuoted(std::string_view s)
: Parser(s) {};
virtual void operator()(std::shared_ptr<Parser> & state, Strings & r) override;
};
struct ParseUnquoted : public Parser {
struct ParseUnquoted : public Parser
{
/**
* @brief Accumulated string
*
@ -122,9 +126,11 @@ struct ParseUnquoted : public Parser {
*/
std::string acc;
ParseUnquoted(std::string_view s) : Parser(s) {};
ParseUnquoted(std::string_view s)
: Parser(s) {};
virtual void operator()(std::shared_ptr<Parser> & state, Strings & r) override {
virtual void operator()(std::shared_ptr<Parser> & state, Strings & r) override
{
if (remaining.empty()) {
if (!acc.empty())
r.push_back(acc);
@ -132,111 +138,116 @@ struct ParseUnquoted : public Parser {
return;
}
switch (remaining[0]) {
case ' ': case '\t': case '\n': case '\r':
if (!acc.empty())
r.push_back(acc);
state = std::make_shared<ParseUnquoted>(ParseUnquoted(remaining.substr(1)));
case ' ':
case '\t':
case '\n':
case '\r':
if (!acc.empty())
r.push_back(acc);
state = std::make_shared<ParseUnquoted>(ParseUnquoted(remaining.substr(1)));
return;
case '`':
if (remaining.size() > 1 && remaining[1] == '`') {
state = std::make_shared<ParseQuoted>(ParseQuoted(remaining.substr(2)));
return;
case '`':
if (remaining.size() > 1 && remaining[1] == '`') {
state = std::make_shared<ParseQuoted>(ParseQuoted(remaining.substr(2)));
return;
}
else
throw Error("single backtick is not a supported syntax in the nix shebang.");
} else
throw Error("single backtick is not a supported syntax in the nix shebang.");
// reserved characters
// meaning to be determined, or may be reserved indefinitely so that
// #!nix syntax looks unambiguous
case '$':
case '*':
case '~':
case '<':
case '>':
case '|':
case ';':
case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
case '\'':
case '"':
case '\\':
throw Error("unsupported unquoted character in nix shebang: " + std::string(1, remaining[0]) + ". Use double backticks to escape?");
// reserved characters
// meaning to be determined, or may be reserved indefinitely so that
// #!nix syntax looks unambiguous
case '$':
case '*':
case '~':
case '<':
case '>':
case '|':
case ';':
case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
case '\'':
case '"':
case '\\':
throw Error(
"unsupported unquoted character in nix shebang: " + std::string(1, remaining[0])
+ ". Use double backticks to escape?");
case '#':
if (acc.empty()) {
throw Error ("unquoted nix shebang argument cannot start with #. Use double backticks to escape?");
} else {
acc += remaining[0];
remaining = remaining.substr(1);
return;
}
default:
case '#':
if (acc.empty()) {
throw Error("unquoted nix shebang argument cannot start with #. Use double backticks to escape?");
} else {
acc += remaining[0];
remaining = remaining.substr(1);
return;
}
default:
acc += remaining[0];
remaining = remaining.substr(1);
return;
}
assert(false);
}
};
void ParseQuoted::operator()(std::shared_ptr<Parser> &state, Strings & r) {
void ParseQuoted::operator()(std::shared_ptr<Parser> & state, Strings & r)
{
if (remaining.empty()) {
throw Error("unterminated quoted string in nix shebang");
}
switch (remaining[0]) {
case ' ':
if ((remaining.size() == 3 && remaining[1] == '`' && remaining[2] == '`')
|| (remaining.size() > 3 && remaining[1] == '`' && remaining[2] == '`' && remaining[3] != '`')) {
// exactly two backticks mark the end of a quoted string, but a preceding space is ignored if present.
state = std::make_shared<ParseUnquoted>(ParseUnquoted(remaining.substr(3)));
r.push_back(acc);
return;
}
else {
// just a normal space
acc += remaining[0];
remaining = remaining.substr(1);
return;
}
case '`':
// exactly two backticks mark the end of a quoted string
if ((remaining.size() == 2 && remaining[1] == '`')
|| (remaining.size() > 2 && remaining[1] == '`' && remaining[2] != '`')) {
state = std::make_shared<ParseUnquoted>(ParseUnquoted(remaining.substr(2)));
r.push_back(acc);
return;
}
// a sequence of at least 3 backticks is one escape-backtick which is ignored, followed by any number of backticks, which are verbatim
else if (remaining.size() >= 3 && remaining[1] == '`' && remaining[2] == '`') {
// ignore "escape" backtick
remaining = remaining.substr(1);
// add the rest
while (remaining.size() > 0 && remaining[0] == '`') {
acc += '`';
remaining = remaining.substr(1);
}
return;
}
else {
acc += remaining[0];
remaining = remaining.substr(1);
return;
}
default:
case ' ':
if ((remaining.size() == 3 && remaining[1] == '`' && remaining[2] == '`')
|| (remaining.size() > 3 && remaining[1] == '`' && remaining[2] == '`' && remaining[3] != '`')) {
// exactly two backticks mark the end of a quoted string, but a preceding space is ignored if present.
state = std::make_shared<ParseUnquoted>(ParseUnquoted(remaining.substr(3)));
r.push_back(acc);
return;
} else {
// just a normal space
acc += remaining[0];
remaining = remaining.substr(1);
return;
}
case '`':
// exactly two backticks mark the end of a quoted string
if ((remaining.size() == 2 && remaining[1] == '`')
|| (remaining.size() > 2 && remaining[1] == '`' && remaining[2] != '`')) {
state = std::make_shared<ParseUnquoted>(ParseUnquoted(remaining.substr(2)));
r.push_back(acc);
return;
}
// a sequence of at least 3 backticks is one escape-backtick which is ignored, followed by any number of
// backticks, which are verbatim
else if (remaining.size() >= 3 && remaining[1] == '`' && remaining[2] == '`') {
// ignore "escape" backtick
remaining = remaining.substr(1);
// add the rest
while (remaining.size() > 0 && remaining[0] == '`') {
acc += '`';
remaining = remaining.substr(1);
}
return;
} else {
acc += remaining[0];
remaining = remaining.substr(1);
return;
}
default:
acc += remaining[0];
remaining = remaining.substr(1);
return;
}
assert(false);
}
Strings parseShebangContent(std::string_view s) {
Strings parseShebangContent(std::string_view s)
{
Strings result;
std::shared_ptr<Parser> parserState(std::make_shared<ParseUnquoted>(ParseUnquoted(s)));
@ -268,22 +279,22 @@ void RootArgs::parseCmdline(const Strings & _cmdline, bool allowShebang)
// if we have at least one argument, it's the name of an
// executable file, and it starts with "#!".
Strings savedArgs;
if (allowShebang){
if (allowShebang) {
auto script = *cmdline.begin();
try {
std::ifstream stream(script);
char shebang[3]={0,0,0};
stream.get(shebang,3);
if (strncmp(shebang,"#!",2) == 0){
for (auto pos = std::next(cmdline.begin()); pos != cmdline.end();pos++)
char shebang[3] = {0, 0, 0};
stream.get(shebang, 3);
if (strncmp(shebang, "#!", 2) == 0) {
for (auto pos = std::next(cmdline.begin()); pos != cmdline.end(); pos++)
savedArgs.push_back(*pos);
cmdline.clear();
std::string line;
std::getline(stream,line);
std::getline(stream, line);
static const std::string commentChars("#/\\%@*-(");
std::string shebangContent;
while (std::getline(stream,line) && !line.empty() && commentChars.find(line[0]) != std::string::npos){
while (std::getline(stream, line) && !line.empty() && commentChars.find(line[0]) != std::string::npos) {
line = chomp(line);
std::smatch match;
@ -297,12 +308,13 @@ void RootArgs::parseCmdline(const Strings & _cmdline, bool allowShebang)
}
cmdline.push_back(script);
commandBaseDir = dirOf(script);
for (auto pos = savedArgs.begin(); pos != savedArgs.end();pos++)
for (auto pos = savedArgs.begin(); pos != savedArgs.end(); pos++)
cmdline.push_back(*pos);
}
} catch (SystemError &) { }
} catch (SystemError &) {
}
}
for (auto pos = cmdline.begin(); pos != cmdline.end(); ) {
for (auto pos = cmdline.begin(); pos != cmdline.end();) {
auto arg = *pos;
@ -310,7 +322,8 @@ void RootArgs::parseCmdline(const Strings & _cmdline, bool allowShebang)
`-j3` -> `-j 3`). */
if (!dashDash && arg.length() > 2 && arg[0] == '-' && arg[1] != '-' && isalpha(arg[1])) {
*pos = (std::string) "-" + arg[1];
auto next = pos; ++next;
auto next = pos;
++next;
for (unsigned int j = 2; j < arg.length(); j++)
if (isalpha(arg[j]))
cmdline.insert(next, (std::string) "-" + arg[j]);
@ -324,12 +337,10 @@ void RootArgs::parseCmdline(const Strings & _cmdline, bool allowShebang)
if (!dashDash && arg == "--") {
dashDash = true;
++pos;
}
else if (!dashDash && std::string(arg, 0, 1) == "-") {
} else if (!dashDash && std::string(arg, 0, 1) == "-") {
if (!processFlag(pos, cmdline.end()))
throw UsageError("unrecognised flag '%1%'", arg);
}
else {
} else {
pos = rewriteArgs(cmdline, pos);
pendingArgs.push_back(*pos++);
if (processArgs(pendingArgs, false))
@ -377,12 +388,12 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
std::vector<std::string> args;
bool anyCompleted = false;
for (size_t n = 0 ; n < flag.handler.arity; ++n) {
for (size_t n = 0; n < flag.handler.arity; ++n) {
if (pos == end) {
if (flag.handler.arity == ArityAny || anyCompleted) break;
if (flag.handler.arity == ArityAny || anyCompleted)
break;
throw UsageError(
"flag '%s' requires %d argument(s), but only %d were given",
name, flag.handler.arity, n);
"flag '%s' requires %d argument(s), but only %d were given", name, flag.handler.arity, n);
}
if (auto prefix = rootArgs.needsCompletion(*pos)) {
anyCompleted = true;
@ -404,9 +415,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
if (std::string(*pos, 0, 2) == "--") {
if (auto prefix = rootArgs.needsCompletion(*pos)) {
for (auto & [name, flag] : longFlags) {
if (!hiddenCategories.count(flag->category)
&& hasPrefix(name, std::string(*prefix, 2)))
{
if (!hiddenCategories.count(flag->category) && hasPrefix(name, std::string(*prefix, 2))) {
if (auto & f = flag->experimentalFeature)
rootArgs.flagExperimentalFeatures.insert(*f);
rootArgs.completions->add("--" + name, flag->description);
@ -415,14 +424,16 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
return false;
}
auto i = longFlags.find(std::string(*pos, 2));
if (i == longFlags.end()) return false;
if (i == longFlags.end())
return false;
return process("--" + i->first, *i->second);
}
if (std::string(*pos, 0, 1) == "-" && pos->size() == 2) {
auto c = (*pos)[1];
auto i = shortFlags.find(c);
if (i == shortFlags.end()) return false;
if (i == shortFlags.end())
return false;
return process(std::string("-") + c, *i->second);
}
@ -452,12 +463,11 @@ bool Args::processArgs(const Strings & args, bool finish)
bool res = false;
if ((exp.handler.arity == ArityAny && finish) ||
(exp.handler.arity != ArityAny && args.size() == exp.handler.arity))
{
if ((exp.handler.arity == ArityAny && finish)
|| (exp.handler.arity != ArityAny && args.size() == exp.handler.arity)) {
std::vector<std::string> ss;
bool anyCompleted = false;
for (const auto &[n, s] : enumerate(args)) {
for (const auto & [n, s] : enumerate(args)) {
if (auto prefix = rootArgs.needsCompletion(s)) {
anyCompleted = true;
ss.push_back(*prefix);
@ -479,11 +489,7 @@ bool Args::processArgs(const Strings & args, bool finish)
except that it will only adjust the next and prev pointers of the list
elements, meaning the actual contents don't move in memory. This is
critical to prevent invalidating internal pointers! */
processedArgs.splice(
processedArgs.end(),
expectedArgs,
expectedArgs.begin(),
++expectedArgs.begin());
processedArgs.splice(processedArgs.end(), expectedArgs, expectedArgs.begin(), ++expectedArgs.begin());
res = true;
}
@ -501,7 +507,8 @@ nlohmann::json Args::toJSON()
for (auto & [name, flag] : longFlags) {
auto j = nlohmann::json::object();
j["hiddenCategory"] = hiddenCategories.count(flag->category) > 0;
if (flag->aliases.count(name)) continue;
if (flag->aliases.count(name))
continue;
if (flag->shortName)
j["shortName"] = std::string(1, flag->shortName);
if (flag->description != "")
@ -531,32 +538,34 @@ nlohmann::json Args::toJSON()
res["flags"] = std::move(flags);
res["args"] = std::move(args);
auto s = doc();
if (s != "") res.emplace("doc", stripIndentation(s));
if (s != "")
res.emplace("doc", stripIndentation(s));
return res;
}
static void _completePath(AddCompletions & completions, std::string_view prefix, bool onlyDirs)
{
completions.setType(Completions::Type::Filenames);
#ifndef _WIN32 // TODO implement globbing completions on Windows
#ifndef _WIN32 // TODO implement globbing completions on Windows
glob_t globbuf;
int flags = GLOB_NOESCAPE;
#ifdef GLOB_ONLYDIR
# ifdef GLOB_ONLYDIR
if (onlyDirs)
flags |= GLOB_ONLYDIR;
#endif
# endif
// using expandTilde here instead of GLOB_TILDE(_CHECK) so that ~<Tab> expands to /home/user/
if (glob((expandTilde(prefix) + "*").c_str(), flags, nullptr, &globbuf) == 0) {
for (size_t i = 0; i < globbuf.gl_pathc; ++i) {
if (onlyDirs) {
auto st = stat(globbuf.gl_pathv[i]);
if (!S_ISDIR(st.st_mode)) continue;
if (!S_ISDIR(st.st_mode))
continue;
}
completions.add(globbuf.gl_pathv[i]);
}
}
globfree(&globbuf);
#endif
#endif
}
void Args::completePath(AddCompletions & completions, size_t, std::string_view prefix)
@ -569,53 +578,56 @@ void Args::completeDir(AddCompletions & completions, size_t, std::string_view pr
_completePath(completions, prefix, true);
}
Strings argvToStrings(int argc, char * * argv)
Strings argvToStrings(int argc, char ** argv)
{
Strings args;
argc--; argv++;
while (argc--) args.push_back(*argv++);
argc--;
argv++;
while (argc--)
args.push_back(*argv++);
return args;
}
std::optional<ExperimentalFeature> Command::experimentalFeature ()
std::optional<ExperimentalFeature> Command::experimentalFeature()
{
return { Xp::NixCommand };
return {Xp::NixCommand};
}
MultiCommand::MultiCommand(std::string_view commandName, const Commands & commands_)
: commands(commands_)
, commandName(commandName)
{
expectArgs({
.label = "subcommand",
.optional = true,
.handler = {[=,this](std::string s) {
assert(!command);
auto i = commands.find(s);
if (i == commands.end()) {
std::set<std::string> commandNames;
for (auto & [name, _] : commands)
commandNames.insert(name);
auto suggestions = Suggestions::bestMatches(commandNames, s);
throw UsageError(suggestions, "'%s' is not a recognised command", s);
}
command = {s, i->second()};
command->second->parent = this;
}},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
for (auto & [name, command] : commands)
if (hasPrefix(name, prefix))
completions.add(name);
}}
});
expectArgs(
{.label = "subcommand",
.optional = true,
.handler = {[=, this](std::string s) {
assert(!command);
auto i = commands.find(s);
if (i == commands.end()) {
std::set<std::string> commandNames;
for (auto & [name, _] : commands)
commandNames.insert(name);
auto suggestions = Suggestions::bestMatches(commandNames, s);
throw UsageError(suggestions, "'%s' is not a recognised command", s);
}
command = {s, i->second()};
command->second->parent = this;
}},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
for (auto & [name, command] : commands)
if (hasPrefix(name, prefix))
completions.add(name);
}}});
categories[Command::catDefault] = "Available commands";
}
bool MultiCommand::processFlag(Strings::iterator & pos, Strings::iterator end)
{
if (Args::processFlag(pos, end)) return true;
if (command && command->second->processFlag(pos, end)) return true;
if (Args::processFlag(pos, end))
return true;
if (command && command->second->processFlag(pos, end))
return true;
return false;
}
@ -647,4 +659,4 @@ nlohmann::json MultiCommand::toJSON()
return res;
}
}
} // namespace nix

View file

@ -9,19 +9,18 @@ CanonPath CanonPath::root = CanonPath("/");
static std::string absPathPure(std::string_view path)
{
return canonPathInner<UnixPathTrait>(path, [](auto &, auto &){});
return canonPathInner<UnixPathTrait>(path, [](auto &, auto &) {});
}
CanonPath::CanonPath(std::string_view raw)
: path(absPathPure(concatStrings("/", raw)))
{ }
{
}
CanonPath::CanonPath(std::string_view raw, const CanonPath & root)
: path(absPathPure(
raw.size() > 0 && raw[0] == '/'
? raw
: concatStrings(root.abs(), "/", raw)))
{ }
: path(absPathPure(raw.size() > 0 && raw[0] == '/' ? raw : concatStrings(root.abs(), "/", raw)))
{
}
CanonPath::CanonPath(const std::vector<std::string> & elems)
: path("/")
@ -32,7 +31,8 @@ CanonPath::CanonPath(const std::vector<std::string> & elems)
std::optional<CanonPath> CanonPath::parent() const
{
if (isRoot()) return std::nullopt;
if (isRoot())
return std::nullopt;
return CanonPath(unchecked_t(), path.substr(0, std::max((size_t) 1, path.rfind('/'))));
}
@ -45,30 +45,31 @@ void CanonPath::pop()
bool CanonPath::isWithin(const CanonPath & parent) const
{
return !(
path.size() < parent.path.size()
|| path.substr(0, parent.path.size()) != parent.path
|| (parent.path.size() > 1 && path.size() > parent.path.size()
&& path[parent.path.size()] != '/'));
path.size() < parent.path.size() || path.substr(0, parent.path.size()) != parent.path
|| (parent.path.size() > 1 && path.size() > parent.path.size() && path[parent.path.size()] != '/'));
}
CanonPath CanonPath::removePrefix(const CanonPath & prefix) const
{
assert(isWithin(prefix));
if (prefix.isRoot()) return *this;
if (path.size() == prefix.path.size()) return root;
if (prefix.isRoot())
return *this;
if (path.size() == prefix.path.size())
return root;
return CanonPath(unchecked_t(), path.substr(prefix.path.size()));
}
void CanonPath::extend(const CanonPath & x)
{
if (x.isRoot()) return;
if (x.isRoot())
return;
if (isRoot())
path += x.rel();
else
path += x.abs();
}
CanonPath CanonPath::operator / (const CanonPath & x) const
CanonPath CanonPath::operator/(const CanonPath & x) const
{
auto res = *this;
res.extend(x);
@ -79,11 +80,12 @@ void CanonPath::push(std::string_view c)
{
assert(c.find('/') == c.npos);
assert(c != "." && c != "..");
if (!isRoot()) path += '/';
if (!isRoot())
path += '/';
path += c;
}
CanonPath CanonPath::operator / (std::string_view c) const
CanonPath CanonPath::operator/(std::string_view c) const
{
auto res = *this;
res.push(c);
@ -111,7 +113,7 @@ bool CanonPath::isAllowed(const std::set<CanonPath> & allowed) const
return false;
}
std::ostream & operator << (std::ostream & stream, const CanonPath & path)
std::ostream & operator<<(std::ostream & stream, const CanonPath & path)
{
stream << path.abs();
return stream;
@ -122,7 +124,8 @@ std::string CanonPath::makeRelative(const CanonPath & path) const
auto p1 = begin();
auto p2 = path.begin();
for (; p1 != end() && p2 != path.end() && *p1 == *p2; ++p1, ++p2) ;
for (; p1 != end() && p2 != path.end() && *p1 == *p2; ++p1, ++p2)
;
if (p1 == end() && p2 == path.end())
return ".";
@ -132,15 +135,17 @@ std::string CanonPath::makeRelative(const CanonPath & path) const
std::string res;
while (p1 != end()) {
++p1;
if (!res.empty()) res += '/';
if (!res.empty())
res += '/';
res += "..";
}
if (p2 != path.end()) {
if (!res.empty()) res += '/';
if (!res.empty())
res += '/';
res += p2.remaining;
}
return res;
}
}
}
} // namespace nix

View file

@ -39,12 +39,15 @@ struct ArchiveDecompressionSource : Source
std::unique_ptr<TarArchive> archive = 0;
Source & src;
std::optional<std::string> compressionMethod;
ArchiveDecompressionSource(Source & src, std::optional<std::string> compressionMethod = std::nullopt)
: src(src)
, compressionMethod(std::move(compressionMethod))
{
}
~ArchiveDecompressionSource() override {}
size_t read(char * data, size_t len) override
{
struct archive_entry * ae;
@ -139,16 +142,19 @@ private:
struct NoneSink : CompressionSink
{
Sink & nextSink;
NoneSink(Sink & nextSink, int level = COMPRESSION_LEVEL_DEFAULT)
: nextSink(nextSink)
{
if (level != COMPRESSION_LEVEL_DEFAULT)
warn("requested compression level '%d' not supported by compression method 'none'", level);
}
void finish() override
{
flush();
}
void writeUnbuffered(std::string_view data) override
{
nextSink(data);
@ -307,4 +313,4 @@ std::string compress(const std::string & method, std::string_view in, const bool
return std::move(ssink.s);
}
}
} // namespace nix

View file

@ -3,14 +3,15 @@
#include "util-config-private.hh"
#if HAVE_LIBCPUID
#include <libcpuid/libcpuid.h>
# include <libcpuid/libcpuid.h>
#endif
namespace nix {
#if HAVE_LIBCPUID
StringSet computeLevels() {
StringSet computeLevels()
{
StringSet levels;
if (!cpuid_present())
@ -25,45 +26,31 @@ StringSet computeLevels() {
if (cpu_identify(&raw, &data) < 0)
return levels;
if (!(data.flags[CPU_FEATURE_CMOV] &&
data.flags[CPU_FEATURE_CX8] &&
data.flags[CPU_FEATURE_FPU] &&
data.flags[CPU_FEATURE_FXSR] &&
data.flags[CPU_FEATURE_MMX] &&
data.flags[CPU_FEATURE_SSE] &&
data.flags[CPU_FEATURE_SSE2]))
if (!(data.flags[CPU_FEATURE_CMOV] && data.flags[CPU_FEATURE_CX8] && data.flags[CPU_FEATURE_FPU]
&& data.flags[CPU_FEATURE_FXSR] && data.flags[CPU_FEATURE_MMX] && data.flags[CPU_FEATURE_SSE]
&& data.flags[CPU_FEATURE_SSE2]))
return levels;
levels.insert("x86_64-v1");
if (!(data.flags[CPU_FEATURE_CX16] &&
data.flags[CPU_FEATURE_LAHF_LM] &&
data.flags[CPU_FEATURE_POPCNT] &&
// SSE3
data.flags[CPU_FEATURE_PNI] &&
data.flags[CPU_FEATURE_SSSE3] &&
data.flags[CPU_FEATURE_SSE4_1] &&
data.flags[CPU_FEATURE_SSE4_2]))
if (!(data.flags[CPU_FEATURE_CX16] && data.flags[CPU_FEATURE_LAHF_LM] && data.flags[CPU_FEATURE_POPCNT] &&
// SSE3
data.flags[CPU_FEATURE_PNI] && data.flags[CPU_FEATURE_SSSE3] && data.flags[CPU_FEATURE_SSE4_1]
&& data.flags[CPU_FEATURE_SSE4_2]))
return levels;
levels.insert("x86_64-v2");
if (!(data.flags[CPU_FEATURE_AVX] &&
data.flags[CPU_FEATURE_AVX2] &&
data.flags[CPU_FEATURE_F16C] &&
data.flags[CPU_FEATURE_FMA3] &&
// LZCNT
data.flags[CPU_FEATURE_ABM] &&
data.flags[CPU_FEATURE_MOVBE]))
if (!(data.flags[CPU_FEATURE_AVX] && data.flags[CPU_FEATURE_AVX2] && data.flags[CPU_FEATURE_F16C]
&& data.flags[CPU_FEATURE_FMA3] &&
// LZCNT
data.flags[CPU_FEATURE_ABM] && data.flags[CPU_FEATURE_MOVBE]))
return levels;
levels.insert("x86_64-v3");
if (!(data.flags[CPU_FEATURE_AVX512F] &&
data.flags[CPU_FEATURE_AVX512BW] &&
data.flags[CPU_FEATURE_AVX512CD] &&
data.flags[CPU_FEATURE_AVX512DQ] &&
data.flags[CPU_FEATURE_AVX512VL]))
if (!(data.flags[CPU_FEATURE_AVX512F] && data.flags[CPU_FEATURE_AVX512BW] && data.flags[CPU_FEATURE_AVX512CD]
&& data.flags[CPU_FEATURE_AVX512DQ] && data.flags[CPU_FEATURE_AVX512VL]))
return levels;
levels.insert("x86_64-v4");
@ -73,10 +60,11 @@ StringSet computeLevels() {
#else
StringSet computeLevels() {
StringSet computeLevels()
{
return StringSet{};
}
#endif // HAVE_LIBCPUID
}
} // namespace nix

View file

@ -66,4 +66,4 @@ ExperimentalFeatureSettings experimentalFeatureSettings;
static GlobalConfig::Register rSettings(&experimentalFeatureSettings);
}
} // namespace nix

View file

@ -16,7 +16,8 @@ namespace nix {
Config::Config(StringMap initials)
: AbstractConfig(std::move(initials))
{ }
{
}
bool Config::set(const std::string & name, const std::string & value)
{
@ -54,8 +55,7 @@ void Config::addSetting(AbstractSetting * setting)
for (auto & alias : setting->aliases) {
if (auto i = unknownSettings.find(alias); i != unknownSettings.end()) {
if (set)
warn("setting '%s' is set, but it's an alias of '%s' which is also set",
alias, setting->name);
warn("setting '%s' is set, but it's an alias of '%s' which is also set", alias, setting->name);
else {
setting->set(std::move(i->second));
setting->overridden = true;
@ -68,7 +68,8 @@ void Config::addSetting(AbstractSetting * setting)
AbstractConfig::AbstractConfig(StringMap initials)
: unknownSettings(std::move(initials))
{ }
{
}
void AbstractConfig::warnUnknownSettings()
{
@ -87,21 +88,24 @@ void AbstractConfig::reapplyUnknownSettings()
void Config::getSettings(std::map<std::string, SettingInfo> & res, bool overriddenOnly)
{
for (const auto & opt : _settings)
if (!opt.second.isAlias
&& (!overriddenOnly || opt.second.setting->overridden)
if (!opt.second.isAlias && (!overriddenOnly || opt.second.setting->overridden)
&& experimentalFeatureSettings.isEnabled(opt.second.setting->experimentalFeature))
res.emplace(opt.first, SettingInfo{opt.second.setting->to_string(), opt.second.setting->description});
}
/**
* Parse configuration in `contents`, and also the configuration files included from there, with their location specified relative to `path`.
* Parse configuration in `contents`, and also the configuration files included from there, with their location
* specified relative to `path`.
*
* `contents` and `path` represent the file that is being parsed.
* The result is only an intermediate list of key-value pairs of strings.
* More parsing according to the settings-specific semantics is being done by `loadConfFile` in `libstore/globals.cc`.
*/
static void parseConfigFiles(const std::string & contents, const std::string & path, std::vector<std::pair<std::string, std::string>> & parsedContents) {
*/
static void parseConfigFiles(
const std::string & contents,
const std::string & path,
std::vector<std::pair<std::string, std::string>> & parsedContents)
{
unsigned int pos = 0;
while (pos < contents.size()) {
@ -114,7 +118,8 @@ static void parseConfigFiles(const std::string & contents, const std::string & p
line = std::string(line, 0, hash);
auto tokens = tokenizeString<std::vector<std::string>>(line);
if (tokens.empty()) continue;
if (tokens.empty())
continue;
if (tokens.size() < 2)
throw UsageError("syntax error in configuration line '%1%' in '%2%'", line, path);
@ -160,7 +165,8 @@ static void parseConfigFiles(const std::string & contents, const std::string & p
};
}
void AbstractConfig::applyConfig(const std::string & contents, const std::string & path) {
void AbstractConfig::applyConfig(const std::string & contents, const std::string & path)
{
std::vector<std::pair<std::string, std::string>> parsedContents;
parseConfigFiles(contents, path, parsedContents);
@ -176,8 +182,7 @@ void AbstractConfig::applyConfig(const std::string & contents, const std::string
// but at the time of writing it's not worth building that for just one thing
for (const auto & [name, value] : parsedContents) {
if (name != "experimental-features" && name != "extra-experimental-features") {
if ((name == "nix-path" || name == "extra-nix-path")
&& getEnv("NIX_PATH").has_value()) {
if ((name == "nix-path" || name == "extra-nix-path") && getEnv("NIX_PATH").has_value()) {
continue;
}
set(name, value);
@ -253,37 +258,42 @@ std::map<std::string, nlohmann::json> AbstractSetting::toJSONObject() const
return obj;
}
void AbstractSetting::convertToArg(Args & args, const std::string & category)
void AbstractSetting::convertToArg(Args & args, const std::string & category) {}
bool AbstractSetting::isOverridden() const
{
return overridden;
}
bool AbstractSetting::isOverridden() const { return overridden; }
template<> std::string BaseSetting<std::string>::parse(const std::string & str) const
template<>
std::string BaseSetting<std::string>::parse(const std::string & str) const
{
return str;
}
template<> std::string BaseSetting<std::string>::to_string() const
template<>
std::string BaseSetting<std::string>::to_string() const
{
return value;
}
template<> std::optional<std::string> BaseSetting<std::optional<std::string>>::parse(const std::string & str) const
template<>
std::optional<std::string> BaseSetting<std::optional<std::string>>::parse(const std::string & str) const
{
if (str == "")
return std::nullopt;
else
return { str };
return {str};
}
template<> std::string BaseSetting<std::optional<std::string>>::to_string() const
template<>
std::string BaseSetting<std::optional<std::string>>::to_string() const
{
return value ? *value : "";
}
template<> bool BaseSetting<bool>::parse(const std::string & str) const
template<>
bool BaseSetting<bool>::parse(const std::string & str) const
{
if (str == "true" || str == "yes" || str == "1")
return true;
@ -293,12 +303,14 @@ template<> bool BaseSetting<bool>::parse(const std::string & str) const
throw UsageError("Boolean setting '%s' has invalid value '%s'", name, str);
}
template<> std::string BaseSetting<bool>::to_string() const
template<>
std::string BaseSetting<bool>::to_string() const
{
return value ? "true" : "false";
}
template<> void BaseSetting<bool>::convertToArg(Args & args, const std::string & category)
template<>
void BaseSetting<bool>::convertToArg(Args & args, const std::string & category)
{
args.addFlag({
.longName = name,
@ -318,40 +330,48 @@ template<> void BaseSetting<bool>::convertToArg(Args & args, const std::string &
});
}
template<> Strings BaseSetting<Strings>::parse(const std::string & str) const
template<>
Strings BaseSetting<Strings>::parse(const std::string & str) const
{
return tokenizeString<Strings>(str);
}
template<> void BaseSetting<Strings>::appendOrSet(Strings newValue, bool append)
template<>
void BaseSetting<Strings>::appendOrSet(Strings newValue, bool append)
{
if (!append) value.clear();
value.insert(value.end(), std::make_move_iterator(newValue.begin()),
std::make_move_iterator(newValue.end()));
if (!append)
value.clear();
value.insert(value.end(), std::make_move_iterator(newValue.begin()), std::make_move_iterator(newValue.end()));
}
template<> std::string BaseSetting<Strings>::to_string() const
template<>
std::string BaseSetting<Strings>::to_string() const
{
return concatStringsSep(" ", value);
}
template<> StringSet BaseSetting<StringSet>::parse(const std::string & str) const
template<>
StringSet BaseSetting<StringSet>::parse(const std::string & str) const
{
return tokenizeString<StringSet>(str);
}
template<> void BaseSetting<StringSet>::appendOrSet(StringSet newValue, bool append)
template<>
void BaseSetting<StringSet>::appendOrSet(StringSet newValue, bool append)
{
if (!append) value.clear();
if (!append)
value.clear();
value.insert(std::make_move_iterator(newValue.begin()), std::make_move_iterator(newValue.end()));
}
template<> std::string BaseSetting<StringSet>::to_string() const
template<>
std::string BaseSetting<StringSet>::to_string() const
{
return concatStringsSep(" ", value);
}
template<> std::set<ExperimentalFeature> BaseSetting<std::set<ExperimentalFeature>>::parse(const std::string & str) const
template<>
std::set<ExperimentalFeature> BaseSetting<std::set<ExperimentalFeature>>::parse(const std::string & str) const
{
std::set<ExperimentalFeature> res;
for (auto & s : tokenizeString<StringSet>(str)) {
@ -365,13 +385,16 @@ template<> std::set<ExperimentalFeature> BaseSetting<std::set<ExperimentalFeatur
return res;
}
template<> void BaseSetting<std::set<ExperimentalFeature>>::appendOrSet(std::set<ExperimentalFeature> newValue, bool append)
template<>
void BaseSetting<std::set<ExperimentalFeature>>::appendOrSet(std::set<ExperimentalFeature> newValue, bool append)
{
if (!append) value.clear();
if (!append)
value.clear();
value.insert(std::make_move_iterator(newValue.begin()), std::make_move_iterator(newValue.end()));
}
template<> std::string BaseSetting<std::set<ExperimentalFeature>>::to_string() const
template<>
std::string BaseSetting<std::set<ExperimentalFeature>>::to_string() const
{
StringSet stringifiedXpFeatures;
for (const auto & feature : value)
@ -379,7 +402,8 @@ template<> std::string BaseSetting<std::set<ExperimentalFeature>>::to_string() c
return concatStringsSep(" ", stringifiedXpFeatures);
}
template<> StringMap BaseSetting<StringMap>::parse(const std::string & str) const
template<>
StringMap BaseSetting<StringMap>::parse(const std::string & str) const
{
StringMap res;
for (const auto & s : tokenizeString<Strings>(str)) {
@ -390,17 +414,23 @@ template<> StringMap BaseSetting<StringMap>::parse(const std::string & str) cons
return res;
}
template<> void BaseSetting<StringMap>::appendOrSet(StringMap newValue, bool append)
template<>
void BaseSetting<StringMap>::appendOrSet(StringMap newValue, bool append)
{
if (!append) value.clear();
if (!append)
value.clear();
value.insert(std::make_move_iterator(newValue.begin()), std::make_move_iterator(newValue.end()));
}
template<> std::string BaseSetting<StringMap>::to_string() const
template<>
std::string BaseSetting<StringMap>::to_string() const
{
return std::transform_reduce(value.cbegin(), value.cend(), std::string{},
[](const auto & l, const auto &r) { return l + " " + r; },
[](const auto & kvpair){ return kvpair.first + "=" + kvpair.second; });
return std::transform_reduce(
value.cbegin(),
value.cend(),
std::string{},
[](const auto & l, const auto & r) { return l + " " + r; },
[](const auto & kvpair) { return kvpair.first + "=" + kvpair.second; });
}
template class BaseSetting<int>;
@ -424,7 +454,8 @@ static Path parsePath(const AbstractSetting & s, const std::string & str)
return canonPath(str);
}
PathSetting::PathSetting(Config * options,
PathSetting::PathSetting(
Config * options,
const Path & def,
const std::string & name,
const std::string & description,
@ -439,8 +470,8 @@ Path PathSetting::parse(const std::string & str) const
return parsePath(*this, str);
}
OptionalPathSetting::OptionalPathSetting(Config * options,
OptionalPathSetting::OptionalPathSetting(
Config * options,
const std::optional<Path> & def,
const std::string & name,
const std::string & description,
@ -450,7 +481,6 @@ OptionalPathSetting::OptionalPathSetting(Config * options,
options->addSetting(this);
}
std::optional<Path> OptionalPathSetting::parse(const std::string & str) const
{
if (str == "")
@ -459,7 +489,7 @@ std::optional<Path> OptionalPathSetting::parse(const std::string & str) const
return parsePath(*this, str);
}
void OptionalPathSetting::operator =(const std::optional<Path> & v)
void OptionalPathSetting::operator=(const std::optional<Path> & v)
{
this->assign(v);
}
@ -483,7 +513,8 @@ bool ExperimentalFeatureSettings::isEnabled(const std::optional<ExperimentalFeat
void ExperimentalFeatureSettings::require(const std::optional<ExperimentalFeature> & feature) const
{
if (feature) require(*feature);
if (feature)
require(*feature);
}
}
} // namespace nix

View file

@ -10,23 +10,24 @@
#include <math.h>
#ifdef __APPLE__
# include <mach-o/dyld.h>
# include <mach-o/dyld.h>
#endif
#ifdef __linux__
# include <mutex>
# include "nix/util/cgroup.hh"
# include "nix/util/namespaces.hh"
# include <mutex>
# include "nix/util/cgroup.hh"
# include "nix/util/namespaces.hh"
#endif
namespace nix {
unsigned int getMaxCPU()
{
#ifdef __linux__
#ifdef __linux__
try {
auto cgroupFS = getCgroupFS();
if (!cgroupFS) return 0;
if (!cgroupFS)
return 0;
auto cpuFile = *cgroupFS + "/" + getCurrentCgroup() + "/cpu.max";
@ -40,17 +41,17 @@ unsigned int getMaxCPU()
auto quota = cpuMaxParts[0];
auto period = cpuMaxParts[1];
if (quota != "max")
return std::ceil(std::stoi(quota) / std::stof(period));
} catch (Error &) { ignoreExceptionInDestructor(lvlDebug); }
#endif
return std::ceil(std::stoi(quota) / std::stof(period));
} catch (Error &) {
ignoreExceptionInDestructor(lvlDebug);
}
#endif
return 0;
}
//////////////////////////////////////////////////////////////////////
#ifndef _WIN32
size_t savedStackSize = 0;
@ -68,9 +69,8 @@ void setStackSize(size_t stackSize)
savedStackSize,
stackSize,
limit.rlim_max,
std::strerror(errno)
).str()
);
std::strerror(errno))
.str());
}
}
}
@ -78,16 +78,16 @@ void setStackSize(size_t stackSize)
void restoreProcessContext(bool restoreMounts)
{
#ifndef _WIN32
#ifndef _WIN32
unix::restoreSignals();
#endif
#endif
if (restoreMounts) {
#ifdef __linux__
#ifdef __linux__
restoreMountNamespace();
#endif
#endif
}
#ifndef _WIN32
#ifndef _WIN32
if (savedStackSize) {
struct rlimit limit;
if (getrlimit(RLIMIT_STACK, &limit) == 0) {
@ -95,31 +95,28 @@ void restoreProcessContext(bool restoreMounts)
setrlimit(RLIMIT_STACK, &limit);
}
}
#endif
#endif
}
//////////////////////////////////////////////////////////////////////
std::optional<Path> getSelfExe()
{
static auto cached = []() -> std::optional<Path>
{
#if defined(__linux__) || defined(__GNU__)
static auto cached = []() -> std::optional<Path> {
#if defined(__linux__) || defined(__GNU__)
return readLink("/proc/self/exe");
#elif defined(__APPLE__)
#elif defined(__APPLE__)
char buf[1024];
uint32_t size = sizeof(buf);
if (_NSGetExecutablePath(buf, &size) == 0)
return buf;
else
return std::nullopt;
#else
#else
return std::nullopt;
#endif
#endif
}();
return cached;
}
}
} // namespace nix

View file

@ -2,11 +2,8 @@
namespace nix {
std::ostream & pluralize(
std::ostream & output,
unsigned int count,
const std::string_view single,
const std::string_view plural)
std::ostream &
pluralize(std::ostream & output, unsigned int count, const std::string_view single, const std::string_view plural)
{
if (count == 1)
output << "1 " << single;
@ -15,4 +12,4 @@ std::ostream & pluralize(
return output;
}
}
} // namespace nix

View file

@ -48,4 +48,4 @@ void replaceEnv(const std::map<std::string, std::string> & newEnv)
setEnv(newEnvVar.first.c_str(), newEnvVar.second.c_str());
}
}
} // namespace nix

View file

@ -15,13 +15,14 @@ namespace nix {
void BaseError::addTrace(std::shared_ptr<Pos> && e, HintFmt hint, TracePrint print)
{
err.traces.push_front(Trace { .pos = std::move(e), .hint = hint, .print = print });
err.traces.push_front(Trace{.pos = std::move(e), .hint = hint, .print = print});
}
void throwExceptionSelfCheck()
{
// This is meant to be caught in initLibUtil()
throw Error("C++ exception handling is broken. This would appear to be a problem with the way Nix was compiled and/or linked and/or loaded.");
throw Error(
"C++ exception handling is broken. This would appear to be a problem with the way Nix was compiled and/or linked and/or loaded.");
}
// c++ std::exception descendants must have a 'const char* what()' function.
@ -40,7 +41,7 @@ const std::string & BaseError::calcWhat() const
std::optional<std::string> ErrorInfo::programName = std::nullopt;
std::ostream & operator <<(std::ostream & os, const HintFmt & hf)
std::ostream & operator<<(std::ostream & os, const HintFmt & hf)
{
return os << hf.str();
}
@ -48,7 +49,7 @@ std::ostream & operator <<(std::ostream & os, const HintFmt & hf)
/**
* An arbitrarily defined value comparison for the purpose of using traces in the key of a sorted container.
*/
inline std::strong_ordering operator<=>(const Trace& lhs, const Trace& rhs)
inline std::strong_ordering operator<=>(const Trace & lhs, const Trace & rhs)
{
// `std::shared_ptr` does not have value semantics for its comparison
// functions, so we need to check for nulls and compare the dereferenced
@ -66,27 +67,16 @@ inline std::strong_ordering operator<=>(const Trace& lhs, const Trace& rhs)
}
// print lines of code to the ostream, indicating the error column.
void printCodeLines(std::ostream & out,
const std::string & prefix,
const Pos & errPos,
const LinesOfCode & loc)
void printCodeLines(std::ostream & out, const std::string & prefix, const Pos & errPos, const LinesOfCode & loc)
{
// previous line of code.
if (loc.prevLineOfCode.has_value()) {
out << std::endl
<< fmt("%1% %|2$5d|| %3%",
prefix,
(errPos.line - 1),
*loc.prevLineOfCode);
out << std::endl << fmt("%1% %|2$5d|| %3%", prefix, (errPos.line - 1), *loc.prevLineOfCode);
}
if (loc.errLineOfCode.has_value()) {
// line of code containing the error.
out << std::endl
<< fmt("%1% %|2$5d|| %3%",
prefix,
(errPos.line),
*loc.errLineOfCode);
out << std::endl << fmt("%1% %|2$5d|| %3%", prefix, (errPos.line), *loc.errLineOfCode);
// error arrows for the column range.
if (errPos.column > 0) {
int start = errPos.column;
@ -97,21 +87,13 @@ void printCodeLines(std::ostream & out,
std::string arrows("^");
out << std::endl
<< fmt("%1% |%2%" ANSI_RED "%3%" ANSI_NORMAL,
prefix,
spaces,
arrows);
out << std::endl << fmt("%1% |%2%" ANSI_RED "%3%" ANSI_NORMAL, prefix, spaces, arrows);
}
}
// next line of code.
if (loc.nextLineOfCode.has_value()) {
out << std::endl
<< fmt("%1% %|2$5d|| %3%",
prefix,
(errPos.line + 1),
*loc.nextLineOfCode);
out << std::endl << fmt("%1% %|2$5d|| %3%", prefix, (errPos.line + 1), *loc.nextLineOfCode);
}
}
@ -122,10 +104,12 @@ static std::string indent(std::string_view indentFirst, std::string_view indentR
while (!s.empty()) {
auto end = s.find('\n');
if (!first) res += "\n";
if (!first)
res += "\n";
res += chomp(std::string(first ? indentFirst : indentRest) + std::string(s.substr(0, end)));
first = false;
if (end == s.npos) break;
if (end == s.npos)
break;
s = s.substr(end + 1);
}
@ -146,7 +130,8 @@ static bool printUnknownLocations = getEnv("_NIX_EVAL_SHOW_UNKNOWN_LOCATIONS").h
*
* @return true if a position was printed.
*/
static bool printPosMaybe(std::ostream & oss, std::string_view indent, const std::shared_ptr<Pos> & pos) {
static bool printPosMaybe(std::ostream & oss, std::string_view indent, const std::shared_ptr<Pos> & pos)
{
bool hasPos = pos && *pos;
if (hasPos) {
oss << indent << ANSI_BLUE << "at " ANSI_WARNING << *pos << ANSI_NORMAL << ":";
@ -161,11 +146,7 @@ static bool printPosMaybe(std::ostream & oss, std::string_view indent, const std
return hasPos;
}
static void printTrace(
std::ostream & output,
const std::string_view & indent,
size_t & count,
const Trace & trace)
static void printTrace(std::ostream & output, const std::string_view & indent, size_t & count, const Trace & trace)
{
output << "\n" << "" << trace.hint.str() << "\n";
@ -188,7 +169,8 @@ void printSkippedTracesMaybe(
printTrace(output, indent, count, trace);
}
} else {
output << "\n" << ANSI_WARNING "(" << skippedTraces.size() << " duplicate frames omitted)" ANSI_NORMAL << "\n";
output << "\n"
<< ANSI_WARNING "(" << skippedTraces.size() << " duplicate frames omitted)" ANSI_NORMAL << "\n";
// Clear the set of "seen" traces after printing a chunk of
// `duplicate frames omitted`.
//
@ -228,43 +210,43 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
{
std::string prefix;
switch (einfo.level) {
case Verbosity::lvlError: {
prefix = ANSI_RED "error";
break;
}
case Verbosity::lvlNotice: {
prefix = ANSI_RED "note";
break;
}
case Verbosity::lvlWarn: {
if (einfo.isFromExpr)
prefix = ANSI_WARNING "evaluation warning";
else
prefix = ANSI_WARNING "warning";
break;
}
case Verbosity::lvlInfo: {
prefix = ANSI_GREEN "info";
break;
}
case Verbosity::lvlTalkative: {
prefix = ANSI_GREEN "talk";
break;
}
case Verbosity::lvlChatty: {
prefix = ANSI_GREEN "chat";
break;
}
case Verbosity::lvlVomit: {
prefix = ANSI_GREEN "vomit";
break;
}
case Verbosity::lvlDebug: {
prefix = ANSI_WARNING "debug";
break;
}
default:
assert(false);
case Verbosity::lvlError: {
prefix = ANSI_RED "error";
break;
}
case Verbosity::lvlNotice: {
prefix = ANSI_RED "note";
break;
}
case Verbosity::lvlWarn: {
if (einfo.isFromExpr)
prefix = ANSI_WARNING "evaluation warning";
else
prefix = ANSI_WARNING "warning";
break;
}
case Verbosity::lvlInfo: {
prefix = ANSI_GREEN "info";
break;
}
case Verbosity::lvlTalkative: {
prefix = ANSI_GREEN "talk";
break;
}
case Verbosity::lvlChatty: {
prefix = ANSI_GREEN "chat";
break;
}
case Verbosity::lvlVomit: {
prefix = ANSI_GREEN "vomit";
break;
}
case Verbosity::lvlDebug: {
prefix = ANSI_WARNING "debug";
break;
}
default:
assert(false);
}
// FIXME: show the program name as part of the trace?
@ -383,7 +365,8 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
bool truncate = false;
for (const auto & trace : einfo.traces) {
if (trace.hint.str().empty()) continue;
if (trace.hint.str().empty())
continue;
if (!showTrace && count > 3) {
truncate = true;
@ -406,11 +389,13 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
}
}
printSkippedTracesMaybe(oss, ellipsisIndent, count, skippedTraces, tracesSeen);
if (truncate) {
oss << "\n" << ANSI_WARNING "(stack trace truncated; use '--show-trace' to show the full, detailed trace)" ANSI_NORMAL << "\n";
oss << "\n"
<< ANSI_WARNING
"(stack trace truncated; use '--show-trace' to show the full, detailed trace)" ANSI_NORMAL
<< "\n";
}
oss << "\n" << prefix;
@ -422,9 +407,7 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
auto suggestions = einfo.suggestions.trim();
if (!suggestions.suggestions.empty()) {
oss << "Did you mean " <<
suggestions.trim() <<
"?" << std::endl;
oss << "Did you mean " << suggestions.trim() << "?" << std::endl;
}
out << indent(prefix, std::string(filterANSIEscapes(prefix, true).size(), ' '), chomp(oss.str()));
@ -440,7 +423,8 @@ static void writeErr(std::string_view buf)
while (!buf.empty()) {
auto n = write(STDERR_FILENO, buf.data(), buf.size());
if (n < 0) {
if (errno == EINTR) continue;
if (errno == EINTR)
continue;
abort();
}
buf = buf.substr(n);
@ -449,7 +433,7 @@ static void writeErr(std::string_view buf)
void panic(std::string_view msg)
{
writeErr("\n\n" ANSI_RED "terminating due to unexpected unrecoverable internal error: " ANSI_NORMAL );
writeErr("\n\n" ANSI_RED "terminating due to unexpected unrecoverable internal error: " ANSI_NORMAL);
writeErr(msg);
writeErr("\n");
abort();
@ -464,4 +448,4 @@ void panic(const char * file, int line, const char * func)
panic(std::string_view(buf, std::min(static_cast<int>(sizeof(buf)), n)));
}
}
} // namespace nix

View file

@ -4,4 +4,4 @@ namespace nix {
Exit::~Exit() {}
}
} // namespace nix

View file

@ -317,7 +317,7 @@ constexpr std::array<ExperimentalFeatureDetails, numXpFeatures> xpFeatureDetails
static_assert(
[]() constexpr {
for (auto [index, feature] : enumerate(xpFeatureDetails))
if (index != (size_t)feature.tag)
if (index != (size_t) feature.tag)
return false;
return true;
}(),
@ -342,8 +342,8 @@ const std::optional<ExperimentalFeature> parseExperimentalFeature(const std::str
std::string_view showExperimentalFeature(const ExperimentalFeature tag)
{
assert((size_t)tag < xpFeatureDetails.size());
return xpFeatureDetails[(size_t)tag].name;
assert((size_t) tag < xpFeatureDetails.size());
return xpFeatureDetails[(size_t) tag].name;
}
nlohmann::json documentExperimentalFeatures()
@ -352,7 +352,8 @@ nlohmann::json documentExperimentalFeatures()
for (auto & xpFeature : xpFeatureDetails) {
std::stringstream docOss;
docOss << stripIndentation(xpFeature.description);
docOss << fmt("\nRefer to [%1% tracking issue](%2%) for feature tracking.", xpFeature.name, xpFeature.trackingUrl);
docOss << fmt(
"\nRefer to [%1% tracking issue](%2%) for feature tracking.", xpFeature.name, xpFeature.trackingUrl);
res[std::string{xpFeature.name}] = trim(docOss.str());
}
return (nlohmann::json) res;
@ -368,11 +369,14 @@ std::set<ExperimentalFeature> parseFeatures(const std::set<std::string> & rawFea
}
MissingExperimentalFeature::MissingExperimentalFeature(ExperimentalFeature feature)
: Error("experimental Nix feature '%1%' is disabled; add '--extra-experimental-features %1%' to enable it", showExperimentalFeature(feature))
: Error(
"experimental Nix feature '%1%' is disabled; add '--extra-experimental-features %1%' to enable it",
showExperimentalFeature(feature))
, missingFeature(feature)
{}
{
}
std::ostream & operator <<(std::ostream & str, const ExperimentalFeature & feature)
std::ostream & operator<<(std::ostream & str, const ExperimentalFeature & feature)
{
return str << showExperimentalFeature(feature);
}
@ -393,4 +397,4 @@ void from_json(const nlohmann::json & j, ExperimentalFeature & feature)
throw Error("Unknown experimental feature '%s' in JSON input", input);
}
}
} // namespace nix

View file

@ -25,7 +25,6 @@ FileSerialisationMethod parseFileSerialisationMethod(std::string_view input)
throw UsageError("Unknown file serialiation method '%s', expect `flat` or `nar`", input);
}
FileIngestionMethod parseFileIngestionMethod(std::string_view input)
{
if (input == "git") {
@ -39,7 +38,6 @@ FileIngestionMethod parseFileIngestionMethod(std::string_view input)
}
}
std::string_view renderFileSerialisationMethod(FileSerialisationMethod method)
{
switch (method) {
@ -52,14 +50,12 @@ std::string_view renderFileSerialisationMethod(FileSerialisationMethod method)
}
}
std::string_view renderFileIngestionMethod(FileIngestionMethod method)
{
switch (method) {
case FileIngestionMethod::Flat:
case FileIngestionMethod::NixArchive:
return renderFileSerialisationMethod(
static_cast<FileSerialisationMethod>(method));
return renderFileSerialisationMethod(static_cast<FileSerialisationMethod>(method));
case FileIngestionMethod::Git:
return "git";
default:
@ -67,12 +63,7 @@ std::string_view renderFileIngestionMethod(FileIngestionMethod method)
}
}
void dumpPath(
const SourcePath & path,
Sink & sink,
FileSerialisationMethod method,
PathFilter & filter)
void dumpPath(const SourcePath & path, Sink & sink, FileSerialisationMethod method, PathFilter & filter)
{
switch (method) {
case FileSerialisationMethod::Flat:
@ -84,12 +75,7 @@ void dumpPath(
}
}
void restorePath(
const Path & path,
Source & source,
FileSerialisationMethod method,
bool startFsync)
void restorePath(const Path & path, Source & source, FileSerialisationMethod method, bool startFsync)
{
switch (method) {
case FileSerialisationMethod::Flat:
@ -101,22 +87,15 @@ void restorePath(
}
}
HashResult hashPath(
const SourcePath & path,
FileSerialisationMethod method, HashAlgorithm ha,
PathFilter & filter)
HashResult hashPath(const SourcePath & path, FileSerialisationMethod method, HashAlgorithm ha, PathFilter & filter)
{
HashSink sink { ha };
HashSink sink{ha};
dumpPath(path, sink, method, filter);
return sink.finish();
}
std::pair<Hash, std::optional<uint64_t>> hashPath(
const SourcePath & path,
FileIngestionMethod method, HashAlgorithm ht,
PathFilter & filter)
std::pair<Hash, std::optional<uint64_t>>
hashPath(const SourcePath & path, FileIngestionMethod method, HashAlgorithm ht, PathFilter & filter)
{
switch (method) {
case FileIngestionMethod::Flat:
@ -130,4 +109,4 @@ std::pair<Hash, std::optional<uint64_t>> hashPath(
assert(false);
}
}
} // namespace nix

View file

@ -4,9 +4,9 @@
#include <fcntl.h>
#include <unistd.h>
#ifdef _WIN32
# include <winnt.h>
# include <fileapi.h>
# include "nix/util/windows-error.hh"
# include <winnt.h>
# include <fileapi.h>
# include "nix/util/windows-error.hh"
#endif
namespace nix {
@ -17,7 +17,6 @@ void writeLine(Descriptor fd, std::string s)
writeFull(fd, s);
}
std::string drainFD(Descriptor fd, bool block, const size_t reserveSize)
{
// the parser needs two extra bytes to append terminating characters, other users will
@ -33,24 +32,27 @@ std::string drainFD(Descriptor fd, bool block, const size_t reserveSize)
return std::move(sink.s);
}
//////////////////////////////////////////////////////////////////////
AutoCloseFD::AutoCloseFD()
: fd{INVALID_DESCRIPTOR}
{
}
AutoCloseFD::AutoCloseFD() : fd{INVALID_DESCRIPTOR} {}
AutoCloseFD::AutoCloseFD(Descriptor fd) : fd{fd} {}
AutoCloseFD::AutoCloseFD(Descriptor fd)
: fd{fd}
{
}
// NOTE: This can be noexcept since we are just copying a value and resetting
// the file descriptor in the rhs.
AutoCloseFD::AutoCloseFD(AutoCloseFD && that) noexcept : fd{that.fd}
AutoCloseFD::AutoCloseFD(AutoCloseFD && that) noexcept
: fd{that.fd}
{
that.fd = INVALID_DESCRIPTOR;
}
AutoCloseFD & AutoCloseFD::operator =(AutoCloseFD && that)
AutoCloseFD & AutoCloseFD::operator=(AutoCloseFD && that)
{
close();
fd = that.fd;
@ -58,7 +60,6 @@ AutoCloseFD & AutoCloseFD::operator =(AutoCloseFD && that)
return *this;
}
AutoCloseFD::~AutoCloseFD()
{
try {
@ -68,23 +69,21 @@ AutoCloseFD::~AutoCloseFD()
}
}
Descriptor AutoCloseFD::get() const
{
return fd;
}
void AutoCloseFD::close()
{
if (fd != INVALID_DESCRIPTOR) {
if(
if (
#ifdef _WIN32
::CloseHandle(fd)
::CloseHandle(fd)
#else
::close(fd)
::close(fd)
#endif
== -1)
== -1)
/* This should never happen. */
throw NativeSysError("closing file descriptor %1%", fd);
fd = INVALID_DESCRIPTOR;
@ -109,25 +108,21 @@ void AutoCloseFD::fsync() const
}
}
void AutoCloseFD::startFsync() const
{
#ifdef __linux__
if (fd != -1) {
/* Ignore failure, since fsync must be run later anyway. This is just a performance optimization. */
::sync_file_range(fd, 0, 0, SYNC_FILE_RANGE_WRITE);
}
if (fd != -1) {
/* Ignore failure, since fsync must be run later anyway. This is just a performance optimization. */
::sync_file_range(fd, 0, 0, SYNC_FILE_RANGE_WRITE);
}
#endif
}
AutoCloseFD::operator bool() const
{
return fd != INVALID_DESCRIPTOR;
}
Descriptor AutoCloseFD::release()
{
Descriptor oldFD = fd;
@ -135,14 +130,12 @@ Descriptor AutoCloseFD::release()
return oldFD;
}
//////////////////////////////////////////////////////////////////////
void Pipe::close()
{
readSide.close();
writeSide.close();
}
}
} // namespace nix

View file

@ -22,7 +22,7 @@
#include <unistd.h>
#ifdef _WIN32
# include <io.h>
# include <io.h>
#endif
#include "nix/util/strings-inline.hh"
@ -32,29 +32,32 @@
namespace nix {
namespace fs {
using namespace std::filesystem;
using namespace std::filesystem;
bool symlink_exists(const std::filesystem::path & path) {
try {
return std::filesystem::exists(std::filesystem::symlink_status(path));
} catch (const std::filesystem::filesystem_error & e) {
throw SysError("cannot check existence of %1%", path);
}
}
bool symlink_exists(const std::filesystem::path & path)
{
try {
return std::filesystem::exists(std::filesystem::symlink_status(path));
} catch (const std::filesystem::filesystem_error & e) {
throw SysError("cannot check existence of %1%", path);
}
}
} // namespace fs
DirectoryIterator::DirectoryIterator(const std::filesystem::path& p) {
DirectoryIterator::DirectoryIterator(const std::filesystem::path & p)
{
try {
// **Attempt to create the underlying directory_iterator**
it_ = std::filesystem::directory_iterator(p);
} catch (const std::filesystem::filesystem_error& e) {
} catch (const std::filesystem::filesystem_error & e) {
// **Catch filesystem_error and throw SysError**
// Adapt the error message as needed for SysError
throw SysError("cannot read directory %s", p);
}
}
DirectoryIterator& DirectoryIterator::operator++() {
DirectoryIterator & DirectoryIterator::operator++()
{
// **Attempt to increment the underlying iterator**
std::error_code ec;
it_.increment(ec);
@ -73,10 +76,9 @@ DirectoryIterator& DirectoryIterator::operator++() {
bool isAbsolute(PathView path)
{
return fs::path { path }.is_absolute();
return fs::path{path}.is_absolute();
}
Path absPath(PathView path, std::optional<PathView> dir, bool resolveSymlinks)
{
std::string scratch;
@ -91,7 +93,7 @@ Path absPath(PathView path, std::optional<PathView> dir, bool resolveSymlinks)
#ifdef __GNU__
/* GNU (aka. GNU/Hurd) doesn't have any limitation on path
lengths and doesn't define `PATH_MAX'. */
char *buf = getcwd(NULL, 0);
char * buf = getcwd(NULL, 0);
if (buf == NULL)
#else
char buf[PATH_MAX];
@ -122,7 +124,7 @@ Path canonPath(PathView path, bool resolveSymlinks)
throw Error("not an absolute path: '%1%'", path);
// For Windows
auto rootName = fs::path { path }.root_name();
auto rootName = fs::path{path}.root_name();
/* This just exists because we cannot set the target of `remaining`
(the callback parameter) directly to a newly-constructed string,
@ -134,9 +136,7 @@ Path canonPath(PathView path, bool resolveSymlinks)
unsigned int followCount = 0, maxFollow = 1024;
auto ret = canonPathInner<OsPathTrait<char>>(
path,
[&followCount, &temp, maxFollow, resolveSymlinks]
(std::string & result, std::string_view & remaining) {
path, [&followCount, &temp, maxFollow, resolveSymlinks](std::string & result, std::string_view & remaining) {
if (resolveSymlinks && fs::is_symlink(result)) {
if (++followCount >= maxFollow)
throw Error("infinite symlink recursion in path '%1%'", remaining);
@ -160,7 +160,6 @@ Path canonPath(PathView path, bool resolveSymlinks)
return ret;
}
Path dirOf(const PathView path)
{
Path::size_type pos = OsPathTrait<char>::rfindPathSep(path);
@ -169,7 +168,6 @@ Path dirOf(const PathView path)
return fs::path{path}.parent_path().string();
}
std::string_view baseNameOf(std::string_view path)
{
if (path.empty())
@ -188,22 +186,17 @@ std::string_view baseNameOf(std::string_view path)
return path.substr(pos, last - pos + 1);
}
bool isInDir(std::string_view path, std::string_view dir)
{
return path.substr(0, 1) == "/"
&& path.substr(0, dir.size()) == dir
&& path.size() >= dir.size() + 2
&& path[dir.size()] == '/';
return path.substr(0, 1) == "/" && path.substr(0, dir.size()) == dir && path.size() >= dir.size() + 2
&& path[dir.size()] == '/';
}
bool isDirOrInDir(std::string_view path, std::string_view dir)
{
return path == dir || isInDir(path, dir);
}
struct stat stat(const Path & path)
{
struct stat st;
@ -213,9 +206,9 @@ struct stat stat(const Path & path)
}
#ifdef _WIN32
# define STAT stat
# define STAT stat
#else
# define STAT lstat
# define STAT lstat
#endif
struct stat lstat(const Path & path)
@ -226,12 +219,10 @@ struct stat lstat(const Path & path)
return st;
}
std::optional<struct stat> maybeLstat(const Path & path)
{
std::optional<struct stat> st{std::in_place};
if (STAT(path.c_str(), &*st))
{
if (STAT(path.c_str(), &*st)) {
if (errno == ENOENT || errno == ENOTDIR)
st.reset();
else
@ -240,7 +231,6 @@ std::optional<struct stat> maybeLstat(const Path & path)
return st;
}
bool pathExists(const Path & path)
{
return maybeLstat(path).has_value();
@ -252,27 +242,28 @@ bool pathAccessible(const std::filesystem::path & path)
return pathExists(path.string());
} catch (SysError & e) {
// swallow EPERM
if (e.errNo == EPERM) return false;
if (e.errNo == EPERM)
return false;
throw;
}
}
Path readLink(const Path & path)
{
checkInterrupt();
return fs::read_symlink(path).string();
}
std::string readFile(const Path & path)
{
AutoCloseFD fd = toDescriptor(open(path.c_str(), O_RDONLY
AutoCloseFD fd = toDescriptor(open(
path.c_str(),
O_RDONLY
// TODO
#ifndef _WIN32
| O_CLOEXEC
| O_CLOEXEC
#endif
));
));
if (!fd)
throw SysError("opening file '%1%'", path);
return readFile(fd.get());
@ -280,32 +271,35 @@ std::string readFile(const Path & path)
std::string readFile(const std::filesystem::path & path)
{
return readFile(os_string_to_string(PathViewNG { path }));
return readFile(os_string_to_string(PathViewNG{path}));
}
void readFile(const Path & path, Sink & sink)
{
AutoCloseFD fd = toDescriptor(open(path.c_str(), O_RDONLY
AutoCloseFD fd = toDescriptor(open(
path.c_str(),
O_RDONLY
// TODO
#ifndef _WIN32
| O_CLOEXEC
| O_CLOEXEC
#endif
));
));
if (!fd)
throw SysError("opening file '%s'", path);
drainFD(fd.get(), sink);
}
void writeFile(const Path & path, std::string_view s, mode_t mode, FsSync sync)
{
AutoCloseFD fd = toDescriptor(open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT
AutoCloseFD fd = toDescriptor(open(
path.c_str(),
O_WRONLY | O_TRUNC | O_CREAT
// TODO
#ifndef _WIN32
| O_CLOEXEC
| O_CLOEXEC
#endif
, mode));
,
mode));
if (!fd)
throw SysError("opening file '%1%'", path);
@ -332,12 +326,15 @@ void writeFile(AutoCloseFD & fd, const Path & origPath, std::string_view s, mode
void writeFile(const Path & path, Source & source, mode_t mode, FsSync sync)
{
AutoCloseFD fd = toDescriptor(open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT
AutoCloseFD fd = toDescriptor(open(
path.c_str(),
O_WRONLY | O_TRUNC | O_CREAT
// TODO
#ifndef _WIN32
| O_CLOEXEC
| O_CLOEXEC
#endif
, mode));
,
mode));
if (!fd)
throw SysError("opening file '%1%'", path);
@ -348,7 +345,9 @@ void writeFile(const Path & path, Source & source, mode_t mode, FsSync sync)
try {
auto n = source.read(buf.data(), buf.size());
writeFull(fd.get(), {buf.data(), n});
} catch (EndOfFile &) { break; }
} catch (EndOfFile &) {
break;
}
}
} catch (Error & e) {
e.addTrace({}, "writing file '%1%'", path);
@ -370,7 +369,6 @@ void syncParent(const Path & path)
fd.fsync();
}
void recursiveSync(const Path & path)
{
/* If it's a file or symlink, just fsync and return. */
@ -415,7 +413,6 @@ void recursiveSync(const Path & path)
}
}
static void _deletePath(Descriptor parentfd, const fs::path & path, uint64_t & bytesFreed)
{
#ifndef _WIN32
@ -425,9 +422,9 @@ static void _deletePath(Descriptor parentfd, const fs::path & path, uint64_t & b
assert(name != "." && name != ".." && !name.empty());
struct stat st;
if (fstatat(parentfd, name.c_str(), &st,
AT_SYMLINK_NOFOLLOW) == -1) {
if (errno == ENOENT) return;
if (fstatat(parentfd, name.c_str(), &st, AT_SYMLINK_NOFOLLOW) == -1) {
if (errno == ENOENT)
return;
throw SysError("getting status of %1%", path);
}
@ -435,23 +432,23 @@ static void _deletePath(Descriptor parentfd, const fs::path & path, uint64_t & b
/* We are about to delete a file. Will it likely free space? */
switch (st.st_nlink) {
/* Yes: last link. */
case 1:
bytesFreed += st.st_size;
break;
/* Maybe: yes, if 'auto-optimise-store' or manual optimisation
was performed. Instead of checking for real let's assume
it's an optimised file and space will be freed.
/* Yes: last link. */
case 1:
bytesFreed += st.st_size;
break;
/* Maybe: yes, if 'auto-optimise-store' or manual optimisation
was performed. Instead of checking for real let's assume
it's an optimised file and space will be freed.
In worst case we will double count on freed space for files
with exactly two hardlinks for unoptimised packages.
*/
case 2:
bytesFreed += st.st_size;
break;
/* No: 3+ links. */
default:
break;
In worst case we will double count on freed space for files
with exactly two hardlinks for unoptimised packages.
*/
case 2:
bytesFreed += st.st_size;
break;
/* No: 3+ links. */
default:
break;
}
}
@ -474,15 +471,18 @@ static void _deletePath(Descriptor parentfd, const fs::path & path, uint64_t & b
while (errno = 0, dirent = readdir(dir.get())) { /* sic */
checkInterrupt();
std::string childName = dirent->d_name;
if (childName == "." || childName == "..") continue;
if (childName == "." || childName == "..")
continue;
_deletePath(dirfd(dir.get()), path / childName, bytesFreed);
}
if (errno) throw SysError("reading directory %1%", path);
if (errno)
throw SysError("reading directory %1%", path);
}
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("cannot unlink %1%", path);
}
#else
@ -498,14 +498,14 @@ static void _deletePath(const fs::path & path, uint64_t & bytesFreed)
AutoCloseFD dirfd = toDescriptor(open(path.parent_path().string().c_str(), O_RDONLY));
if (!dirfd) {
if (errno == ENOENT) return;
if (errno == ENOENT)
return;
throw SysError("opening directory %s", path.parent_path());
}
_deletePath(dirfd.get(), path, bytesFreed);
}
void deletePath(const fs::path & path)
{
uint64_t dummy;
@ -514,11 +514,14 @@ void deletePath(const fs::path & path)
void createDir(const Path & path, mode_t mode)
{
if (mkdir(path.c_str()
if (mkdir(
path.c_str()
#ifndef _WIN32
, mode
,
mode
#endif
) == -1)
)
== -1)
throw SysError("creating directory '%1%'", path);
}
@ -531,20 +534,22 @@ void createDirs(const fs::path & path)
}
}
void deletePath(const fs::path & path, uint64_t & bytesFreed)
{
//Activity act(*logger, lvlDebug, "recursively deleting path '%1%'", path);
// Activity act(*logger, lvlDebug, "recursively deleting path '%1%'", path);
bytesFreed = 0;
_deletePath(path, bytesFreed);
}
//////////////////////////////////////////////////////////////////////
AutoDelete::AutoDelete() : del{false} {}
AutoDelete::AutoDelete()
: del{false}
{
}
AutoDelete::AutoDelete(const std::filesystem::path & p, bool recursive) : _path(p)
AutoDelete::AutoDelete(const std::filesystem::path & p, bool recursive)
: _path(p)
{
del = true;
this->recursive = recursive;
@ -570,7 +575,8 @@ void AutoDelete::cancel()
del = false;
}
void AutoDelete::reset(const fs::path & p, bool recursive) {
void AutoDelete::reset(const fs::path & p, bool recursive)
{
_path = p;
this->recursive = recursive;
del = true;
@ -580,12 +586,12 @@ void AutoDelete::reset(const fs::path & p, bool recursive) {
//////////////////////////////////////////////////////////////////////
std::string defaultTempDir() {
std::string defaultTempDir()
{
return getEnvNonEmpty("TMPDIR").value_or("/tmp");
}
static Path tempName(Path tmpRoot, const Path & prefix, bool includePid,
std::atomic<unsigned int> & counter)
static Path tempName(Path tmpRoot, const Path & prefix, bool includePid, std::atomic<unsigned int> & counter)
{
tmpRoot = canonPath(tmpRoot.empty() ? defaultTempDir() : tmpRoot, true);
if (includePid)
@ -594,8 +600,7 @@ static Path tempName(Path tmpRoot, const Path & prefix, bool includePid,
return fmt("%1%/%2%-%3%", tmpRoot, prefix, counter++);
}
Path createTempDir(const Path & tmpRoot, const Path & prefix,
bool includePid, bool useGlobalCounter, mode_t mode)
Path createTempDir(const Path & tmpRoot, const Path & prefix, bool includePid, bool useGlobalCounter, mode_t mode)
{
static std::atomic<unsigned int> globalCounter = 0;
std::atomic<unsigned int> localCounter = 0;
@ -604,11 +609,14 @@ Path createTempDir(const Path & tmpRoot, const Path & prefix,
while (1) {
checkInterrupt();
Path tmpDir = tempName(tmpRoot, prefix, includePid, counter);
if (mkdir(tmpDir.c_str()
if (mkdir(
tmpDir.c_str()
#ifndef _WIN32 // TODO abstract mkdir perms for Windows
, mode
,
mode
#endif
) == 0) {
)
== 0) {
#ifdef __FreeBSD__
/* Explicitly set the group of the directory. This is to
work around around problems caused by BSD's group
@ -628,7 +636,6 @@ Path createTempDir(const Path & tmpRoot, const Path & prefix,
}
}
std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix)
{
Path tmpl(defaultTempDir() + "/" + prefix + ".XXXXXX");
@ -661,18 +668,19 @@ void replaceSymlink(const fs::path & target, const fs::path & link)
try {
fs::create_symlink(target, tmp);
} catch (fs::filesystem_error & e) {
if (e.code() == std::errc::file_exists) continue;
if (e.code() == std::errc::file_exists)
continue;
throw SysError("creating symlink '%1%' -> '%2%'", tmp, target);
}
try {
fs::rename(tmp, link);
} catch (fs::filesystem_error & e) {
if (e.code() == std::errc::file_exists) continue;
if (e.code() == std::errc::file_exists)
continue;
throw SysError("renaming '%1%' to '%2%'", tmp, link);
}
break;
}
}
@ -691,7 +699,6 @@ void copyFile(const fs::path & from, const fs::path & to, bool andDelete)
fs::permissions(from, fs::perms::owner_write, fs::perm_options::add | fs::perm_options::nofollow);
}
if (fs::is_symlink(fromStatus) || fs::is_regular_file(fromStatus)) {
fs::copy(from, to, fs::copy_options::copy_symlinks | fs::copy_options::overwrite_existing);
} else if (fs::is_directory(fromStatus)) {
@ -720,9 +727,7 @@ void moveFile(const Path & oldName, const Path & newName)
auto newPath = fs::path(newName);
// For the move to be as atomic as possible, copy to a temporary
// directory
fs::path temp = createTempDir(
os_string_to_string(PathViewNG { newPath.parent_path() }),
"rename-tmp");
fs::path temp = createTempDir(os_string_to_string(PathViewNG{newPath.parent_path()}), "rename-tmp");
Finally removeTemp = [&]() { fs::remove(temp); };
auto tempCopyTarget = temp / "copy-target";
if (e.code().value() == EXDEV) {
@ -730,31 +735,34 @@ void moveFile(const Path & oldName, const Path & newName)
warn("cant rename %s as %s, copying instead", oldName, newName);
copyFile(oldPath, tempCopyTarget, true);
std::filesystem::rename(
os_string_to_string(PathViewNG { tempCopyTarget }),
os_string_to_string(PathViewNG { newPath }));
os_string_to_string(PathViewNG{tempCopyTarget}), os_string_to_string(PathViewNG{newPath}));
}
}
}
//////////////////////////////////////////////////////////////////////
bool isExecutableFileAmbient(const fs::path & exe) {
bool isExecutableFileAmbient(const fs::path & exe)
{
// Check file type, because directory being executable means
// something completely different.
// `is_regular_file` follows symlinks before checking.
return std::filesystem::is_regular_file(exe)
&& access(exe.string().c_str(),
&& access(
exe.string().c_str(),
#ifdef WIN32
0 // TODO do better
0 // TODO do better
#else
X_OK
X_OK
#endif
) == 0;
)
== 0;
}
std::filesystem::path makeParentCanonical(const std::filesystem::path & rawPath)
{
std::filesystem::path path(absPath(rawPath));;
std::filesystem::path path(absPath(rawPath));
;
try {
auto parent = path.parent_path();
if (parent == path) {

View file

@ -5,47 +5,38 @@
#include "nix/util/fs-sink.hh"
#ifdef _WIN32
# include <fileapi.h>
# include "nix/util/file-path.hh"
# include "nix/util/windows-error.hh"
# include <fileapi.h>
# include "nix/util/file-path.hh"
# include "nix/util/windows-error.hh"
#endif
#include "util-config-private.hh"
namespace nix {
void copyRecursive(
SourceAccessor & accessor, const CanonPath & from,
FileSystemObjectSink & sink, const CanonPath & to)
void copyRecursive(SourceAccessor & accessor, const CanonPath & from, FileSystemObjectSink & sink, const CanonPath & to)
{
auto stat = accessor.lstat(from);
switch (stat.type) {
case SourceAccessor::tSymlink:
{
case SourceAccessor::tSymlink: {
sink.createSymlink(to, accessor.readLink(from));
break;
}
case SourceAccessor::tRegular:
{
case SourceAccessor::tRegular: {
sink.createRegularFile(to, [&](CreateRegularFileSink & crf) {
if (stat.isExecutable)
crf.isExecutable();
accessor.readFile(from, crf, [&](uint64_t size) {
crf.preallocateContents(size);
});
accessor.readFile(from, crf, [&](uint64_t size) { crf.preallocateContents(size); });
});
break;
}
case SourceAccessor::tDirectory:
{
case SourceAccessor::tDirectory: {
sink.createDirectory(to);
for (auto & [name, _] : accessor.readDirectory(from)) {
copyRecursive(
accessor, from / name,
sink, to / name);
copyRecursive(accessor, from / name, sink, to / name);
break;
}
break;
@ -61,11 +52,10 @@ void copyRecursive(
}
}
struct RestoreSinkSettings : Config
{
Setting<bool> preallocateContents{this, false, "preallocate-contents",
"Whether to preallocate files when writing objects with known size."};
Setting<bool> preallocateContents{
this, false, "preallocate-contents", "Whether to preallocate files when writing objects with known size."};
};
static RestoreSinkSettings restoreSinkSettings;
@ -87,7 +77,8 @@ void RestoreSink::createDirectory(const CanonPath & path)
throw Error("path '%s' already exists", p.string());
};
struct RestoreRegularFile : CreateRegularFileSink {
struct RestoreRegularFile : CreateRegularFileSink
{
AutoCloseFD fd;
bool startFsync = false;
@ -101,7 +92,7 @@ struct RestoreRegularFile : CreateRegularFileSink {
fd.startFsync();
}
void operator () (std::string_view data) override;
void operator()(std::string_view data) override;
void isExecutable() override;
void preallocateContents(uint64_t size) override;
};
@ -114,12 +105,20 @@ void RestoreSink::createRegularFile(const CanonPath & path, std::function<void(C
crf.startFsync = startFsync;
crf.fd =
#ifdef _WIN32
CreateFileW(p.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL)
CreateFileW(
p.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL)
#else
open(p.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, 0666)
#endif
;
if (!crf.fd) throw NativeSysError("creating file '%1%'", p);
if (!crf.fd)
throw NativeSysError("creating file '%1%'", p);
func(crf);
}
@ -154,7 +153,7 @@ void RestoreRegularFile::preallocateContents(uint64_t len)
#endif
}
void RestoreRegularFile::operator () (std::string_view data)
void RestoreRegularFile::operator()(std::string_view data)
{
writeFull(fd.get(), data);
}
@ -165,32 +164,42 @@ void RestoreSink::createSymlink(const CanonPath & path, const std::string & targ
nix::createSymlink(target, p.string());
}
void RegularFileSink::createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)> func)
{
struct CRF : CreateRegularFileSink {
struct CRF : CreateRegularFileSink
{
RegularFileSink & back;
CRF(RegularFileSink & back) : back(back) {}
void operator () (std::string_view data) override
CRF(RegularFileSink & back)
: back(back)
{
}
void operator()(std::string_view data) override
{
back.sink(data);
}
void isExecutable() override {}
} crf { *this };
} crf{*this};
func(crf);
}
void NullFileSystemObjectSink::createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)> func)
void NullFileSystemObjectSink::createRegularFile(
const CanonPath & path, std::function<void(CreateRegularFileSink &)> func)
{
struct : CreateRegularFileSink {
void operator () (std::string_view data) override {}
struct : CreateRegularFileSink
{
void operator()(std::string_view data) override {}
void isExecutable() override {}
} crf;
// Even though `NullFileSystemObjectSink` doesn't do anything, it's important
// that we call the function, to e.g. advance the parser using this
// sink.
func(crf);
}
}
} // namespace nix

View file

@ -17,32 +17,31 @@ namespace nix::git {
using namespace nix;
using namespace std::string_literals;
std::optional<Mode> decodeMode(RawMode m) {
std::optional<Mode> decodeMode(RawMode m)
{
switch (m) {
case (RawMode) Mode::Directory:
case (RawMode) Mode::Executable:
case (RawMode) Mode::Regular:
case (RawMode) Mode::Symlink:
return (Mode) m;
default:
return std::nullopt;
case (RawMode) Mode::Directory:
case (RawMode) Mode::Executable:
case (RawMode) Mode::Regular:
case (RawMode) Mode::Symlink:
return (Mode) m;
default:
return std::nullopt;
}
}
static std::string getStringUntil(Source & source, char byte)
{
std::string s;
char n[1] = { 0 };
source(std::string_view { n, 1 });
char n[1] = {0};
source(std::string_view{n, 1});
while (*n != byte) {
s += *n;
source(std::string_view { n, 1 });
source(std::string_view{n, 1});
}
return s;
}
static std::string getString(Source & source, int n)
{
std::string v;
@ -75,7 +74,7 @@ void parseBlob(
while (left) {
checkInterrupt();
buf.resize(std::min((unsigned long long)buf.capacity(), left));
buf.resize(std::min((unsigned long long) buf.capacity(), left));
source(buf);
crf(buf);
left -= buf.size();
@ -93,16 +92,13 @@ void parseBlob(
doRegularFile(true);
break;
case BlobMode::Symlink:
{
case BlobMode::Symlink: {
std::string target;
target.resize(size, '0');
target.reserve(size);
for (size_t n = 0; n < target.size();) {
checkInterrupt();
n += source.read(
const_cast<char *>(target.c_str()) + n,
target.size() - n);
n += source.read(const_cast<char *>(target.c_str()) + n, target.size() - n);
}
sink.createSymlink(sinkPath, target);
@ -147,16 +143,16 @@ void parseTree(
Hash hash(HashAlgorithm::SHA1);
std::copy(hashs.begin(), hashs.end(), hash.hash);
hook(CanonPath{name}, TreeEntry {
.mode = mode,
.hash = hash,
});
hook(
CanonPath{name},
TreeEntry{
.mode = mode,
.hash = hash,
});
}
}
ObjectType parseObjectType(
Source & source,
const ExperimentalFeatureSettings & xpSettings)
ObjectType parseObjectType(Source & source, const ExperimentalFeatureSettings & xpSettings)
{
xpSettings.require(Xp::GitHashing);
@ -166,7 +162,8 @@ ObjectType parseObjectType(
return ObjectType::Blob;
} else if (type == "tree ") {
return ObjectType::Tree;
} else throw Error("input doesn't look like a Git object");
} else
throw Error("input doesn't look like a Git object");
}
void parse(
@ -193,23 +190,26 @@ void parse(
};
}
std::optional<Mode> convertMode(SourceAccessor::Type type)
{
switch (type) {
case SourceAccessor::tSymlink: return Mode::Symlink;
case SourceAccessor::tRegular: return Mode::Regular;
case SourceAccessor::tDirectory: return Mode::Directory;
case SourceAccessor::tSymlink:
return Mode::Symlink;
case SourceAccessor::tRegular:
return Mode::Regular;
case SourceAccessor::tDirectory:
return Mode::Directory;
case SourceAccessor::tChar:
case SourceAccessor::tBlock:
case SourceAccessor::tSocket:
case SourceAccessor::tFifo: return std::nullopt;
case SourceAccessor::tFifo:
return std::nullopt;
case SourceAccessor::tUnknown:
default: unreachable();
default:
unreachable();
}
}
void restore(FileSystemObjectSink & sink, Source & source, std::function<RestoreHook> hook)
{
parse(sink, CanonPath::root, source, BlobMode::Regular, [&](CanonPath name, TreeEntry entry) {
@ -217,35 +217,30 @@ void restore(FileSystemObjectSink & sink, Source & source, std::function<Restore
auto stat = accessor->lstat(from);
auto gotOpt = convertMode(stat.type);
if (!gotOpt)
throw Error("file '%s' (git hash %s) has an unsupported type",
throw Error(
"file '%s' (git hash %s) has an unsupported type",
from,
entry.hash.to_string(HashFormat::Base16, false));
auto & got = *gotOpt;
if (got != entry.mode)
throw Error("git mode of file '%s' (git hash %s) is %o but expected %o",
throw Error(
"git mode of file '%s' (git hash %s) is %o but expected %o",
from,
entry.hash.to_string(HashFormat::Base16, false),
(RawMode) got,
(RawMode) entry.mode);
copyRecursive(
*accessor, from,
sink, name);
copyRecursive(*accessor, from, sink, name);
});
}
void dumpBlobPrefix(
uint64_t size, Sink & sink,
const ExperimentalFeatureSettings & xpSettings)
void dumpBlobPrefix(uint64_t size, Sink & sink, const ExperimentalFeatureSettings & xpSettings)
{
xpSettings.require(Xp::GitHashing);
auto s = fmt("blob %d\0"s, std::to_string(size));
sink(s);
}
void dumpTree(const Tree & entries, Sink & sink,
const ExperimentalFeatureSettings & xpSettings)
void dumpTree(const Tree & entries, Sink & sink, const ExperimentalFeatureSettings & xpSettings)
{
xpSettings.require(Xp::GitHashing);
@ -270,7 +265,6 @@ void dumpTree(const Tree & entries, Sink & sink,
sink(v1);
}
Mode dump(
const SourcePath & path,
Sink & sink,
@ -281,22 +275,17 @@ Mode dump(
auto st = path.lstat();
switch (st.type) {
case SourceAccessor::tRegular:
{
path.readFile(sink, [&](uint64_t size) {
dumpBlobPrefix(size, sink, xpSettings);
});
return st.isExecutable
? Mode::Executable
: Mode::Regular;
case SourceAccessor::tRegular: {
path.readFile(sink, [&](uint64_t size) { dumpBlobPrefix(size, sink, xpSettings); });
return st.isExecutable ? Mode::Executable : Mode::Regular;
}
case SourceAccessor::tDirectory:
{
case SourceAccessor::tDirectory: {
Tree entries;
for (auto & [name, _] : path.readDirectory()) {
auto child = path / name;
if (!filter(child.path.abs())) continue;
if (!filter(child.path.abs()))
continue;
auto entry = hook(child);
@ -310,8 +299,7 @@ Mode dump(
return Mode::Directory;
}
case SourceAccessor::tSymlink:
{
case SourceAccessor::tSymlink: {
auto target = path.readLink();
dumpBlobPrefix(target.size(), sink, xpSettings);
sink(target);
@ -328,11 +316,7 @@ Mode dump(
}
}
TreeEntry dumpHash(
HashAlgorithm ha,
const SourcePath & path,
PathFilter & filter)
TreeEntry dumpHash(HashAlgorithm ha, const SourcePath & path, PathFilter & filter)
{
std::function<DumpHook> hook;
hook = [&](const SourcePath & path) -> TreeEntry {
@ -348,7 +332,6 @@ TreeEntry dumpHash(
return hook(path);
}
std::optional<LsRemoteRefLine> parseLsRemoteLine(std::string_view line)
{
const static std::regex line_regex("^(ref: *)?([^\\s]+)(?:\\t+(.*))?$");
@ -356,13 +339,10 @@ std::optional<LsRemoteRefLine> parseLsRemoteLine(std::string_view line)
if (!std::regex_match(line.cbegin(), line.cend(), match, line_regex))
return std::nullopt;
return LsRemoteRefLine {
.kind = match[1].length() == 0
? LsRemoteRefLine::Kind::Object
: LsRemoteRefLine::Kind::Symbolic,
return LsRemoteRefLine{
.kind = match[1].length() == 0 ? LsRemoteRefLine::Kind::Object : LsRemoteRefLine::Kind::Symbolic,
.target = match[2],
.reference = match[3].length() == 0 ? std::nullopt : std::optional<std::string>{ match[3] }
};
.reference = match[3].length() == 0 ? std::nullopt : std::optional<std::string>{match[3]}};
}
}
} // namespace nix::git

View file

@ -20,23 +20,29 @@
namespace nix {
static size_t regularHashSize(HashAlgorithm type) {
static size_t regularHashSize(HashAlgorithm type)
{
switch (type) {
case HashAlgorithm::BLAKE3: return blake3HashSize;
case HashAlgorithm::MD5: return md5HashSize;
case HashAlgorithm::SHA1: return sha1HashSize;
case HashAlgorithm::SHA256: return sha256HashSize;
case HashAlgorithm::SHA512: return sha512HashSize;
case HashAlgorithm::BLAKE3:
return blake3HashSize;
case HashAlgorithm::MD5:
return md5HashSize;
case HashAlgorithm::SHA1:
return sha1HashSize;
case HashAlgorithm::SHA256:
return sha256HashSize;
case HashAlgorithm::SHA512:
return sha512HashSize;
}
unreachable();
}
const std::set<std::string> hashAlgorithms = {"blake3", "md5", "sha1", "sha256", "sha512"};
const std::set<std::string> hashAlgorithms = {"blake3", "md5", "sha1", "sha256", "sha512" };
const std::set<std::string> hashFormats = {"base64", "nix32", "base16", "sri"};
const std::set<std::string> hashFormats = {"base64", "nix32", "base16", "sri" };
Hash::Hash(HashAlgorithm algo, const ExperimentalFeatureSettings & xpSettings) : algo(algo)
Hash::Hash(HashAlgorithm algo, const ExperimentalFeatureSettings & xpSettings)
: algo(algo)
{
if (algo == HashAlgorithm::BLAKE3) {
xpSettings.require(Xp::BLAKE3Hashes);
@ -46,30 +52,31 @@ Hash::Hash(HashAlgorithm algo, const ExperimentalFeatureSettings & xpSettings) :
memset(hash, 0, maxHashSize);
}
bool Hash::operator == (const Hash & h2) const noexcept
bool Hash::operator==(const Hash & h2) const noexcept
{
if (hashSize != h2.hashSize) return false;
if (hashSize != h2.hashSize)
return false;
for (unsigned int i = 0; i < hashSize; i++)
if (hash[i] != h2.hash[i]) return false;
if (hash[i] != h2.hash[i])
return false;
return true;
}
std::strong_ordering Hash::operator <=> (const Hash & h) const noexcept
std::strong_ordering Hash::operator<=>(const Hash & h) const noexcept
{
if (auto cmp = hashSize <=> h.hashSize; cmp != 0) return cmp;
if (auto cmp = hashSize <=> h.hashSize; cmp != 0)
return cmp;
for (unsigned int i = 0; i < hashSize; i++) {
if (auto cmp = hash[i] <=> h.hash[i]; cmp != 0) return cmp;
if (auto cmp = hash[i] <=> h.hash[i]; cmp != 0)
return cmp;
}
if (auto cmp = algo <=> h.algo; cmp != 0) return cmp;
if (auto cmp = algo <=> h.algo; cmp != 0)
return cmp;
return std::strong_ordering::equivalent;
}
const std::string base16Chars = "0123456789abcdef";
static std::string printHash16(const Hash & hash)
{
std::string buf;
@ -81,11 +88,9 @@ static std::string printHash16(const Hash & hash)
return buf;
}
// omitted: E O U T
const std::string nix32Chars = "0123456789abcdfghijklmnpqrsvwxyz";
static std::string printHash32(const Hash & hash)
{
assert(hash.hashSize);
@ -99,23 +104,19 @@ static std::string printHash32(const Hash & hash)
unsigned int b = n * 5;
unsigned int i = b / 8;
unsigned int j = b % 8;
unsigned char c =
(hash.hash[i] >> j)
| (i >= hash.hashSize - 1 ? 0 : hash.hash[i + 1] << (8 - j));
unsigned char c = (hash.hash[i] >> j) | (i >= hash.hashSize - 1 ? 0 : hash.hash[i + 1] << (8 - j));
s.push_back(nix32Chars[c & 0x1f]);
}
return s;
}
std::string printHash16or32(const Hash & hash)
{
assert(static_cast<char>(hash.algo));
return hash.to_string(hash.algo == HashAlgorithm::MD5 ? HashFormat::Base16 : HashFormat::Nix32, false);
}
std::string Hash::to_string(HashFormat hashFormat, bool includeAlgo) const
{
std::string s;
@ -215,16 +216,17 @@ Hash::Hash(std::string_view rest, HashAlgorithm algo, bool isSRI)
if (!isSRI && rest.size() == base16Len()) {
auto parseHexDigit = [&](char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
throw BadHash("invalid base-16 hash '%s'", rest);
};
for (unsigned int i = 0; i < hashSize; i++) {
hash[i] =
parseHexDigit(rest[i * 2]) << 4
| parseHexDigit(rest[i * 2 + 1]);
hash[i] = parseHexDigit(rest[i * 2]) << 4 | parseHexDigit(rest[i * 2 + 1]);
}
}
@ -234,7 +236,8 @@ Hash::Hash(std::string_view rest, HashAlgorithm algo, bool isSRI)
char c = rest[rest.size() - n - 1];
unsigned char digit;
for (digit = 0; digit < nix32Chars.size(); ++digit) /* !!! slow */
if (nix32Chars[digit] == c) break;
if (nix32Chars[digit] == c)
break;
if (digit >= 32)
throw BadHash("invalid base-32 hash '%s'", rest);
unsigned int b = n * 5;
@ -287,7 +290,6 @@ Hash newHashAllowEmpty(std::string_view hashStr, std::optional<HashAlgorithm> ha
return Hash::parseAny(hashStr, ha);
}
union Ctx
{
blake3_hasher blake3;
@ -297,39 +299,49 @@ union Ctx
SHA512_CTX sha512;
};
static void start(HashAlgorithm ha, Ctx & ctx)
{
if (ha == HashAlgorithm::BLAKE3) blake3_hasher_init(&ctx.blake3);
else if (ha == HashAlgorithm::MD5) MD5_Init(&ctx.md5);
else if (ha == HashAlgorithm::SHA1) SHA1_Init(&ctx.sha1);
else if (ha == HashAlgorithm::SHA256) SHA256_Init(&ctx.sha256);
else if (ha == HashAlgorithm::SHA512) SHA512_Init(&ctx.sha512);
if (ha == HashAlgorithm::BLAKE3)
blake3_hasher_init(&ctx.blake3);
else if (ha == HashAlgorithm::MD5)
MD5_Init(&ctx.md5);
else if (ha == HashAlgorithm::SHA1)
SHA1_Init(&ctx.sha1);
else if (ha == HashAlgorithm::SHA256)
SHA256_Init(&ctx.sha256);
else if (ha == HashAlgorithm::SHA512)
SHA512_Init(&ctx.sha512);
}
static void update(HashAlgorithm ha, Ctx & ctx,
std::string_view data)
static void update(HashAlgorithm ha, Ctx & ctx, std::string_view data)
{
if (ha == HashAlgorithm::BLAKE3) blake3_hasher_update(&ctx.blake3, data.data(), data.size());
else if (ha == HashAlgorithm::MD5) MD5_Update(&ctx.md5, data.data(), data.size());
else if (ha == HashAlgorithm::SHA1) SHA1_Update(&ctx.sha1, data.data(), data.size());
else if (ha == HashAlgorithm::SHA256) SHA256_Update(&ctx.sha256, data.data(), data.size());
else if (ha == HashAlgorithm::SHA512) SHA512_Update(&ctx.sha512, data.data(), data.size());
if (ha == HashAlgorithm::BLAKE3)
blake3_hasher_update(&ctx.blake3, data.data(), data.size());
else if (ha == HashAlgorithm::MD5)
MD5_Update(&ctx.md5, data.data(), data.size());
else if (ha == HashAlgorithm::SHA1)
SHA1_Update(&ctx.sha1, data.data(), data.size());
else if (ha == HashAlgorithm::SHA256)
SHA256_Update(&ctx.sha256, data.data(), data.size());
else if (ha == HashAlgorithm::SHA512)
SHA512_Update(&ctx.sha512, data.data(), data.size());
}
static void finish(HashAlgorithm ha, Ctx & ctx, unsigned char * hash)
{
if (ha == HashAlgorithm::BLAKE3) blake3_hasher_finalize(&ctx.blake3, hash, BLAKE3_OUT_LEN);
else if (ha == HashAlgorithm::MD5) MD5_Final(hash, &ctx.md5);
else if (ha == HashAlgorithm::SHA1) SHA1_Final(hash, &ctx.sha1);
else if (ha == HashAlgorithm::SHA256) SHA256_Final(hash, &ctx.sha256);
else if (ha == HashAlgorithm::SHA512) SHA512_Final(hash, &ctx.sha512);
if (ha == HashAlgorithm::BLAKE3)
blake3_hasher_finalize(&ctx.blake3, hash, BLAKE3_OUT_LEN);
else if (ha == HashAlgorithm::MD5)
MD5_Final(hash, &ctx.md5);
else if (ha == HashAlgorithm::SHA1)
SHA1_Final(hash, &ctx.sha1);
else if (ha == HashAlgorithm::SHA256)
SHA256_Final(hash, &ctx.sha256);
else if (ha == HashAlgorithm::SHA512)
SHA512_Final(hash, &ctx.sha512);
}
Hash hashString(
HashAlgorithm ha, std::string_view s, const ExperimentalFeatureSettings & xpSettings)
Hash hashString(HashAlgorithm ha, std::string_view s, const ExperimentalFeatureSettings & xpSettings)
{
Ctx ctx;
Hash hash(ha, xpSettings);
@ -346,8 +358,8 @@ Hash hashFile(HashAlgorithm ha, const Path & path)
return sink.finish().first;
}
HashSink::HashSink(HashAlgorithm ha) : ha(ha)
HashSink::HashSink(HashAlgorithm ha)
: ha(ha)
{
ctx = new Ctx;
bytes = 0;
@ -383,7 +395,6 @@ HashResult HashSink::currentHash()
return HashResult(hash, bytes);
}
Hash compressHash(const Hash & hash, unsigned int newSize)
{
Hash h(hash.algo);
@ -393,17 +404,20 @@ Hash compressHash(const Hash & hash, unsigned int newSize)
return h;
}
std::optional<HashFormat> parseHashFormatOpt(std::string_view hashFormatName)
{
if (hashFormatName == "base16") return HashFormat::Base16;
if (hashFormatName == "nix32") return HashFormat::Nix32;
if (hashFormatName == "base16")
return HashFormat::Base16;
if (hashFormatName == "nix32")
return HashFormat::Nix32;
if (hashFormatName == "base32") {
warn(R"("base32" is a deprecated alias for hash format "nix32".)");
return HashFormat::Nix32;
}
if (hashFormatName == "base64") return HashFormat::Base64;
if (hashFormatName == "sri") return HashFormat::SRI;
if (hashFormatName == "base64")
return HashFormat::Base64;
if (hashFormatName == "sri")
return HashFormat::SRI;
return std::nullopt;
}
@ -435,11 +449,16 @@ std::string_view printHashFormat(HashFormat HashFormat)
std::optional<HashAlgorithm> parseHashAlgoOpt(std::string_view s)
{
if (s == "blake3") return HashAlgorithm::BLAKE3;
if (s == "md5") return HashAlgorithm::MD5;
if (s == "sha1") return HashAlgorithm::SHA1;
if (s == "sha256") return HashAlgorithm::SHA256;
if (s == "sha512") return HashAlgorithm::SHA512;
if (s == "blake3")
return HashAlgorithm::BLAKE3;
if (s == "md5")
return HashAlgorithm::MD5;
if (s == "sha1")
return HashAlgorithm::SHA1;
if (s == "sha256")
return HashAlgorithm::SHA256;
if (s == "sha512")
return HashAlgorithm::SHA512;
return std::nullopt;
}
@ -455,11 +474,16 @@ HashAlgorithm parseHashAlgo(std::string_view s)
std::string_view printHashAlgo(HashAlgorithm ha)
{
switch (ha) {
case HashAlgorithm::BLAKE3: return "blake3";
case HashAlgorithm::MD5: return "md5";
case HashAlgorithm::SHA1: return "sha1";
case HashAlgorithm::SHA256: return "sha256";
case HashAlgorithm::SHA512: return "sha512";
case HashAlgorithm::BLAKE3:
return "blake3";
case HashAlgorithm::MD5:
return "md5";
case HashAlgorithm::SHA1:
return "sha1";
case HashAlgorithm::SHA256:
return "sha256";
case HashAlgorithm::SHA512:
return "sha512";
default:
// illegal hash type enum value internally, as opposed to external input
// which should be validated with nice error message.
@ -467,4 +491,4 @@ std::string_view printHashAlgo(HashAlgorithm ha)
}
}
}
} // namespace nix

View file

@ -2,19 +2,15 @@
namespace nix {
std::string hiliteMatches(
std::string_view s,
std::vector<std::smatch> matches,
std::string_view prefix,
std::string_view postfix)
std::string
hiliteMatches(std::string_view s, std::vector<std::smatch> matches, std::string_view prefix, std::string_view postfix)
{
// Avoid extra work on zero matches
if (matches.size() == 0)
return std::string(s);
std::sort(matches.begin(), matches.end(), [](const auto & a, const auto & b) {
return a.position() < b.position();
});
std::sort(
matches.begin(), matches.end(), [](const auto & a, const auto & b) { return a.position() < b.position(); });
std::string out;
ssize_t last_end = 0;
@ -41,4 +37,4 @@ std::string hiliteMatches(
return out;
}
}
} // namespace nix

View file

@ -15,4 +15,4 @@ std::map<std::string, nlohmann::json> BaseSetting<T>::toJSONObject() const
obj.emplace("documentDefault", documentDefault);
return obj;
}
}
} // namespace nix

View file

@ -1,4 +1,5 @@
#pragma once
/**
* @file
*
@ -18,4 +19,4 @@ namespace nix {
#define ANSI_MAGENTA "\e[35;1m"
#define ANSI_CYAN "\e[36;1m"
}
} // namespace nix

View file

@ -5,10 +5,8 @@
#include "nix/util/serialise.hh"
#include "nix/util/fs-sink.hh"
namespace nix {
/**
* dumpPath creates a Nix archive of the specified path.
*
@ -57,14 +55,12 @@ namespace nix {
* `+` denotes string concatenation.
* ```
*/
void dumpPath(const Path & path, Sink & sink,
PathFilter & filter = defaultPathFilter);
void dumpPath(const Path & path, Sink & sink, PathFilter & filter = defaultPathFilter);
/**
* Same as dumpPath(), but returns the last modified date of the path.
*/
time_t dumpPathAndGetMtime(const Path & path, Sink & sink,
PathFilter & filter = defaultPathFilter);
time_t dumpPathAndGetMtime(const Path & path, Sink & sink, PathFilter & filter = defaultPathFilter);
/**
* Dump an archive with a single file with these contents.
@ -82,10 +78,8 @@ void restorePath(const std::filesystem::path & path, Source & source, bool start
*/
void copyNAR(Source & source, Sink & sink);
inline constexpr std::string_view narVersionMagic1 = "nix-archive-1";
inline constexpr std::string_view caseHackSuffix = "~nix~case~hack~";
}
} // namespace nix

View file

@ -31,18 +31,28 @@ public:
/**
* Return a short one-line description of the command.
*/
virtual std::string description() { return ""; }
*/
virtual std::string description()
{
return "";
}
virtual bool forceImpureByDefault() { return false; }
virtual bool forceImpureByDefault()
{
return false;
}
/**
* Return documentation about this command, in Markdown format.
*/
virtual std::string doc() { return ""; }
virtual std::string doc()
{
return "";
}
/**
* @brief Get the [base directory](https://nixos.org/manual/nix/unstable/glossary#gloss-base-directory) for the command.
* @brief Get the [base directory](https://nixos.org/manual/nix/unstable/glossary#gloss-base-directory) for the
* command.
*
* @return Generally the working directory, but in case of a shebang
* interpreter, returns the directory of the script.
@ -78,73 +88,79 @@ protected:
Handler(std::function<void(std::vector<std::string>)> && fun)
: fun(std::move(fun))
, arity(ArityAny)
{ }
{
}
Handler(std::function<void()> && handler)
: fun([handler{std::move(handler)}](std::vector<std::string>) { handler(); })
, arity(0)
{ }
{
}
Handler(std::function<void(std::string)> && handler)
: fun([handler{std::move(handler)}](std::vector<std::string> ss) {
handler(std::move(ss[0]));
})
: fun([handler{std::move(handler)}](std::vector<std::string> ss) { handler(std::move(ss[0])); })
, arity(1)
{ }
{
}
Handler(std::function<void(std::string, std::string)> && handler)
: fun([handler{std::move(handler)}](std::vector<std::string> ss) {
handler(std::move(ss[0]), std::move(ss[1]));
})
})
, arity(2)
{ }
{
}
Handler(std::vector<std::string> * dest)
: fun([dest](std::vector<std::string> ss) { *dest = ss; })
, arity(ArityAny)
{ }
{
}
Handler(std::string * dest)
: fun([dest](std::vector<std::string> ss) { *dest = ss[0]; })
, arity(1)
{ }
{
}
Handler(std::optional<std::string> * dest)
: fun([dest](std::vector<std::string> ss) { *dest = ss[0]; })
, arity(1)
{ }
{
}
Handler(std::filesystem::path * dest)
: fun([dest](std::vector<std::string> ss) { *dest = ss[0]; })
, arity(1)
{ }
{
}
Handler(std::optional<std::filesystem::path> * dest)
: fun([dest](std::vector<std::string> ss) { *dest = ss[0]; })
, arity(1)
{ }
{
}
template<class T>
Handler(T * dest, const T & val)
: fun([dest, val](std::vector<std::string> ss) { *dest = val; })
, arity(0)
{ }
{
}
template<class I>
Handler(I * dest)
: fun([dest](std::vector<std::string> ss) {
*dest = string2IntWithUnitPrefix<I>(ss[0]);
})
: fun([dest](std::vector<std::string> ss) { *dest = string2IntWithUnitPrefix<I>(ss[0]); })
, arity(1)
{ }
{
}
template<class I>
Handler(std::optional<I> * dest)
: fun([dest](std::vector<std::string> ss) {
*dest = string2IntWithUnitPrefix<I>(ss[0]);
})
: fun([dest](std::vector<std::string> ss) { *dest = string2IntWithUnitPrefix<I>(ss[0]); })
, arity(1)
{ }
{
}
};
/**
@ -248,8 +264,8 @@ protected:
* This list is used to extend the lifetime of the argument forms.
* If this is not done, some closures that reference the command
* itself will segfault.
*/
std::list<ExpectedArg> processedArgs;
*/
std::list<ExpectedArg> processedArgs;
/**
* Process some positional arugments
@ -261,7 +277,9 @@ protected:
virtual bool processArgs(const Strings & args, bool finish);
virtual Strings::iterator rewriteArgs(Strings & args, Strings::iterator pos)
{ return pos; }
{
return pos;
}
std::set<std::string> hiddenCategories;
@ -287,11 +305,7 @@ public:
*/
void expectArg(const std::string & label, std::string * dest, bool optional = false)
{
expectArgs({
.label = label,
.optional = optional,
.handler = {dest}
});
expectArgs({.label = label, .optional = optional, .handler = {dest}});
}
/**
@ -299,11 +313,7 @@ public:
*/
void expectArg(const std::string & label, std::filesystem::path * dest, bool optional = false)
{
expectArgs({
.label = label,
.optional = optional,
.handler = {dest}
});
expectArgs({.label = label, .optional = optional, .handler = {dest}});
}
/**
@ -311,10 +321,7 @@ public:
*/
void expectArgs(const std::string & label, std::vector<std::string> * dest)
{
expectArgs({
.label = label,
.handler = {dest}
});
expectArgs({.label = label, .handler = {dest}});
}
static CompleterFun completePath;
@ -364,7 +371,10 @@ struct Command : virtual public Args
virtual std::optional<ExperimentalFeature> experimentalFeature();
virtual Category category() { return catDefault; }
virtual Category category()
{
return catDefault;
}
};
using Commands = std::map<std::string, std::function<ref<Command>()>>;
@ -397,9 +407,10 @@ protected:
std::string commandName = "";
};
Strings argvToStrings(int argc, char * * argv);
Strings argvToStrings(int argc, char ** argv);
struct Completion {
struct Completion
{
std::string completion;
std::string description;
@ -443,4 +454,4 @@ public:
Strings parseShebangContent(std::string_view s);
}
} // namespace nix

View file

@ -57,7 +57,8 @@ protected:
/**
* A pointer to the completion and its two arguments; a thunk;
*/
struct DeferredCompletion {
struct DeferredCompletion
{
const CompleterClosure & completer;
size_t n;
std::string prefix;
@ -82,4 +83,4 @@ private:
std::optional<std::string> needsCompletion(std::string_view s);
};
}
} // namespace nix

View file

@ -20,14 +20,18 @@ class Callback
public:
Callback(std::function<void(std::future<T>)> fun) : fun(fun) { }
Callback(std::function<void(std::future<T>)> fun)
: fun(fun)
{
}
// NOTE: std::function is noexcept move-constructible since C++20.
Callback(Callback && callback) noexcept(std::is_nothrow_move_constructible_v<decltype(fun)>)
: fun(std::move(callback.fun))
{
auto prev = callback.done.test_and_set();
if (prev) done.test_and_set();
if (prev)
done.test_and_set();
}
void operator()(T && t) noexcept
@ -49,4 +53,4 @@ public:
}
};
}
} // namespace nix

View file

@ -51,13 +51,16 @@ public:
explicit CanonPath(const char * raw)
: CanonPath(std::string_view(raw))
{ }
{
}
struct unchecked_t { };
struct unchecked_t
{};
CanonPath(unchecked_t _, std::string path)
: path(std::move(path))
{ }
{
}
/**
* Construct a canon path from a vector of elements.
@ -74,13 +77,19 @@ public:
CanonPath(std::string_view raw, const CanonPath & root);
bool isRoot() const
{ return path.size() <= 1; }
{
return path.size() <= 1;
}
explicit operator std::string_view() const
{ return path; }
{
return path;
}
const std::string & abs() const
{ return path; }
{
return path;
}
/**
* Like abs(), but return an empty string if this path is
@ -93,10 +102,14 @@ public:
}
const char * c_str() const
{ return path.c_str(); }
{
return path.c_str();
}
std::string_view rel() const
{ return ((std::string_view) path).substr(1); }
{
return ((std::string_view) path).substr(1);
}
const char * rel_c_str() const
{
@ -113,18 +126,25 @@ public:
Iterator(std::string_view remaining)
: remaining(remaining)
, slash(remaining.find('/'))
{ }
{
}
bool operator != (const Iterator & x) const
{ return remaining.data() != x.remaining.data(); }
bool operator!=(const Iterator & x) const
{
return remaining.data() != x.remaining.data();
}
bool operator == (const Iterator & x) const
{ return !(*this != x); }
bool operator==(const Iterator & x) const
{
return !(*this != x);
}
const std::string_view operator * () const
{ return remaining.substr(0, slash); }
const std::string_view operator*() const
{
return remaining.substr(0, slash);
}
void operator ++ ()
void operator++()
{
if (slash == remaining.npos)
remaining = remaining.substr(remaining.size());
@ -135,8 +155,15 @@ public:
}
};
Iterator begin() const { return Iterator(rel()); }
Iterator end() const { return Iterator(rel().substr(path.size() - 1)); }
Iterator begin() const
{
return Iterator(rel());
}
Iterator end() const
{
return Iterator(rel().substr(path.size() - 1));
}
std::optional<CanonPath> parent() const;
@ -147,21 +174,27 @@ public:
std::optional<std::string_view> dirOf() const
{
if (isRoot()) return std::nullopt;
if (isRoot())
return std::nullopt;
return ((std::string_view) path).substr(0, path.rfind('/'));
}
std::optional<std::string_view> baseName() const
{
if (isRoot()) return std::nullopt;
if (isRoot())
return std::nullopt;
return ((std::string_view) path).substr(path.rfind('/') + 1);
}
bool operator == (const CanonPath & x) const
{ return path == x.path; }
bool operator==(const CanonPath & x) const
{
return path == x.path;
}
bool operator != (const CanonPath & x) const
{ return path != x.path; }
bool operator!=(const CanonPath & x) const
{
return path != x.path;
}
/**
* Compare paths lexicographically except that path separators
@ -169,16 +202,19 @@ public:
* a directory is always followed directly by its children. For
* instance, 'foo' < 'foo/bar' < 'foo!'.
*/
auto operator <=> (const CanonPath & x) const
auto operator<=>(const CanonPath & x) const
{
auto i = path.begin();
auto j = x.path.begin();
for ( ; i != path.end() && j != x.path.end(); ++i, ++j) {
for (; i != path.end() && j != x.path.end(); ++i, ++j) {
auto c_i = *i;
if (c_i == '/') c_i = 0;
if (c_i == '/')
c_i = 0;
auto c_j = *j;
if (c_j == '/') c_j = 0;
if (auto cmp = c_i <=> c_j; cmp != 0) return cmp;
if (c_j == '/')
c_j = 0;
if (auto cmp = c_i <=> c_j; cmp != 0)
return cmp;
}
return (i != path.end()) <=> (j != x.path.end());
}
@ -199,14 +235,14 @@ public:
/**
* Concatenate two paths.
*/
CanonPath operator / (const CanonPath & x) const;
CanonPath operator/(const CanonPath & x) const;
/**
* Add a path component to this one. It must not contain any slashes.
*/
void push(std::string_view c);
CanonPath operator / (std::string_view c) const;
CanonPath operator/(std::string_view c) const;
/**
* Check whether access to this path is allowed, which is the case
@ -225,14 +261,14 @@ public:
friend class std::hash<CanonPath>;
};
std::ostream & operator << (std::ostream & stream, const CanonPath & path);
std::ostream & operator<<(std::ostream & stream, const CanonPath & path);
}
} // namespace nix
template<>
struct std::hash<nix::CanonPath>
{
std::size_t operator ()(const nix::CanonPath & s) const noexcept
std::size_t operator()(const nix::CanonPath & s) const noexcept
{
return std::hash<std::string>{}(s.path);
}

View file

@ -32,15 +32,18 @@ struct Checked
T value;
Checked() = default;
explicit Checked(T const value)
: value{value}
{
}
Checked(Checked<T> const & other) = default;
Checked(Checked<T> && other) = default;
Checked<T> & operator=(Checked<T> const & other) = default;
std::strong_ordering operator<=>(Checked<T> const & other) const = default;
std::strong_ordering operator<=>(T const & other) const
{
return value <=> other;
@ -68,6 +71,7 @@ struct Checked
, overflowed_{overflowed ? OverflowKind::Overflow : OverflowKind::NoOverflow}
{
}
Result(T value, OverflowKind overflowed)
: value{value}
, overflowed_{overflowed}
@ -116,6 +120,7 @@ struct Checked
{
return (*this) + other.value;
}
Result operator+(T const other) const
{
T result;
@ -127,6 +132,7 @@ struct Checked
{
return (*this) - other.value;
}
Result operator-(T const other) const
{
T result;
@ -138,6 +144,7 @@ struct Checked
{
return (*this) * other.value;
}
Result operator*(T const other) const
{
T result;
@ -149,6 +156,7 @@ struct Checked
{
return (*this) / other.value;
}
/**
* Performs a checked division.
*
@ -181,4 +189,4 @@ std::ostream & operator<<(std::ostream & ios, Checked<T> v)
return ios;
}
}
} // namespace nix::checked

View file

@ -20,7 +20,8 @@ namespace nix {
* references to its elements.
*/
template<typename T, size_t ChunkSize>
class ChunkedVector {
class ChunkedVector
{
private:
uint32_t size_ = 0;
std::vector<std::vector<T>> chunks;
@ -45,12 +46,15 @@ public:
addChunk();
}
uint32_t size() const { return size_; }
uint32_t size() const
{
return size_;
}
std::pair<T &, uint32_t> add(T value)
{
const auto idx = size_++;
auto & chunk = [&] () -> auto & {
auto & chunk = [&]() -> auto & {
if (auto & back = chunks.back(); back.size() < ChunkSize)
return back;
return addChunk();
@ -72,4 +76,4 @@ public:
fn(e);
}
};
}
} // namespace nix

View file

@ -13,11 +13,7 @@ template<typename T>
using GetEdgesAsync = std::function<void(const T &, std::function<void(std::promise<set<T>> &)>)>;
template<typename T>
void computeClosure(
const set<T> startElts,
set<T> & res,
GetEdgesAsync<T> getEdgesAsync
)
void computeClosure(const set<T> startElts, set<T> & res, GetEdgesAsync<T> getEdgesAsync)
{
struct State
{
@ -35,8 +31,10 @@ void computeClosure(
enqueue = [&](const T & current) -> void {
{
auto state(state_.lock());
if (state->exc) return;
if (!state->res.insert(current).second) return;
if (state->exc)
return;
if (!state->res.insert(current).second)
return;
state->pending++;
}
@ -48,13 +46,16 @@ void computeClosure(
{
auto state(state_.lock());
assert(state->pending);
if (!--state->pending) done.notify_one();
if (!--state->pending)
done.notify_one();
}
} catch (...) {
auto state(state_.lock());
if (!state->exc) state->exc = std::current_exception();
if (!state->exc)
state->exc = std::current_exception();
assert(state->pending);
if (!--state->pending) done.notify_one();
if (!--state->pending)
done.notify_one();
};
});
};
@ -64,9 +65,11 @@ void computeClosure(
{
auto state(state_.lock());
while (state->pending) state.wait(done);
if (state->exc) std::rethrow_exception(state->exc);
while (state->pending)
state.wait(done);
if (state->exc)
std::rethrow_exception(state->exc);
}
}
}
} // namespace nix

View file

@ -1,13 +1,14 @@
#pragma once
///@file
#define GENERATE_ONE_CMP(PRE, RET, QUAL, COMPARATOR, MY_TYPE, ...) \
PRE RET QUAL operator COMPARATOR(const MY_TYPE & other) const noexcept { \
__VA_OPT__(const MY_TYPE * me = this;) \
auto fields1 = std::tie( __VA_ARGS__ ); \
__VA_OPT__(me = &other;) \
auto fields2 = std::tie( __VA_ARGS__ ); \
return fields1 COMPARATOR fields2; \
#define GENERATE_ONE_CMP(PRE, RET, QUAL, COMPARATOR, MY_TYPE, ...) \
PRE RET QUAL operator COMPARATOR(const MY_TYPE & other) const noexcept \
{ \
__VA_OPT__(const MY_TYPE * me = this;) \
auto fields1 = std::tie(__VA_ARGS__); \
__VA_OPT__(me = &other;) \
auto fields2 = std::tie(__VA_ARGS__); \
return fields1 COMPARATOR fields2; \
}
#define GENERATE_EQUAL(prefix, qualification, my_type, args...) \
GENERATE_ONE_CMP(prefix, bool, qualification, ==, my_type, args)
@ -36,8 +37,8 @@
* ```
*/
#define GENERATE_CMP(args...) \
GENERATE_EQUAL(,,args) \
GENERATE_SPACESHIP(,auto,,args)
GENERATE_EQUAL(, , args) \
GENERATE_SPACESHIP(, auto, , args)
/**
* @param prefix This is for something before each declaration like
@ -46,5 +47,5 @@
* @param my_type the type are defining operators for.
*/
#define GENERATE_CMP_EXT(prefix, ret, my_type, args...) \
GENERATE_EQUAL(prefix, my_type ::, my_type, args) \
GENERATE_EQUAL(prefix, my_type ::, my_type, args) \
GENERATE_SPACESHIP(prefix, ret, my_type ::, my_type, args)

View file

@ -29,4 +29,4 @@ MakeError(UnknownCompressionMethod, Error);
MakeError(CompressionError, Error);
}
} // namespace nix

View file

@ -30,4 +30,4 @@ struct GlobalConfig : public AbstractConfig
extern GlobalConfig globalConfig;
}
} // namespace nix

View file

@ -17,19 +17,26 @@
namespace nix {
template<> struct BaseSetting<Strings>::trait
template<>
struct BaseSetting<Strings>::trait
{
static constexpr bool appendable = true;
};
template<> struct BaseSetting<StringSet>::trait
template<>
struct BaseSetting<StringSet>::trait
{
static constexpr bool appendable = true;
};
template<> struct BaseSetting<StringMap>::trait
template<>
struct BaseSetting<StringMap>::trait
{
static constexpr bool appendable = true;
};
template<> struct BaseSetting<std::set<ExperimentalFeature>>::trait
template<>
struct BaseSetting<std::set<ExperimentalFeature>>::trait
{
static constexpr bool appendable = true;
};
@ -46,17 +53,19 @@ bool BaseSetting<T>::isAppendable()
return trait::appendable;
}
template<> void BaseSetting<Strings>::appendOrSet(Strings newValue, bool append);
template<> void BaseSetting<StringSet>::appendOrSet(StringSet newValue, bool append);
template<> void BaseSetting<StringMap>::appendOrSet(StringMap newValue, bool append);
template<> void BaseSetting<std::set<ExperimentalFeature>>::appendOrSet(std::set<ExperimentalFeature> newValue, bool append);
template<>
void BaseSetting<Strings>::appendOrSet(Strings newValue, bool append);
template<>
void BaseSetting<StringSet>::appendOrSet(StringSet newValue, bool append);
template<>
void BaseSetting<StringMap>::appendOrSet(StringMap newValue, bool append);
template<>
void BaseSetting<std::set<ExperimentalFeature>>::appendOrSet(std::set<ExperimentalFeature> newValue, bool append);
template<typename T>
void BaseSetting<T>::appendOrSet(T newValue, bool append)
{
static_assert(
!trait::appendable,
"using default `appendOrSet` implementation with an appendable type");
static_assert(!trait::appendable, "using default `appendOrSet` implementation with an appendable type");
assert(!append);
value = std::move(newValue);
@ -69,13 +78,15 @@ void BaseSetting<T>::set(const std::string & str, bool append)
appendOrSet(parse(str), append);
else {
assert(experimentalFeature);
warn("Ignoring setting '%s' because experimental feature '%s' is not enabled",
warn(
"Ignoring setting '%s' because experimental feature '%s' is not enabled",
name,
showExperimentalFeature(*experimentalFeature));
}
}
template<> void BaseSetting<bool>::convertToArg(Args & args, const std::string & category);
template<>
void BaseSetting<bool>::convertToArg(Args & args, const std::string & category);
template<typename T>
void BaseSetting<T>::convertToArg(Args & args, const std::string & category)
@ -86,7 +97,10 @@ void BaseSetting<T>::convertToArg(Args & args, const std::string & category)
.description = fmt("Set the `%s` setting.", name),
.category = category,
.labels = {"value"},
.handler = {[this](std::string s) { overridden = true; set(s); }},
.handler = {[this](std::string s) {
overridden = true;
set(s);
}},
.experimentalFeature = experimentalFeature,
});
@ -97,14 +111,19 @@ void BaseSetting<T>::convertToArg(Args & args, const std::string & category)
.description = fmt("Append to the `%s` setting.", name),
.category = category,
.labels = {"value"},
.handler = {[this](std::string s) { overridden = true; set(s, true); }},
.handler = {[this](std::string s) {
overridden = true;
set(s, true);
}},
.experimentalFeature = experimentalFeature,
});
}
#define DECLARE_CONFIG_SERIALISER(TY) \
template<> TY BaseSetting< TY >::parse(const std::string & str) const; \
template<> std::string BaseSetting< TY >::to_string() const;
#define DECLARE_CONFIG_SERIALISER(TY) \
template<> \
TY BaseSetting<TY>::parse(const std::string & str) const; \
template<> \
std::string BaseSetting<TY>::to_string() const;
DECLARE_CONFIG_SERIALISER(std::string)
DECLARE_CONFIG_SERIALISER(std::optional<std::string>)
@ -134,4 +153,4 @@ std::string BaseSetting<T>::to_string() const
return std::to_string(value);
}
}
} // namespace nix

View file

@ -247,7 +247,8 @@ protected:
public:
BaseSetting(const T & def,
BaseSetting(
const T & def,
const bool documentDefault,
const std::string & name,
const std::string & description,
@ -257,21 +258,58 @@ public:
, value(def)
, defaultValue(def)
, documentDefault(documentDefault)
{ }
{
}
operator const T &() const
{
return value;
}
operator T &()
{
return value;
}
const T & get() const
{
return value;
}
T & get()
{
return value;
}
operator const T &() const { return value; }
operator T &() { return value; }
const T & get() const { return value; }
T & get() { return value; }
template<typename U>
bool operator ==(const U & v2) const { return value == v2; }
bool operator==(const U & v2) const
{
return value == v2;
}
template<typename U>
bool operator !=(const U & v2) const { return value != v2; }
bool operator!=(const U & v2) const
{
return value != v2;
}
template<typename U>
void operator =(const U & v) { assign(v); }
virtual void assign(const T & v) { value = v; }
void operator=(const U & v)
{
assign(v);
}
virtual void assign(const T & v)
{
value = v;
}
template<typename U>
void setDefault(const U & v) { if (!overridden) value = v; }
void setDefault(const U & v)
{
if (!overridden)
value = v;
}
/**
* Require any experimental feature the setting depends on
@ -307,19 +345,23 @@ public:
};
template<typename T>
std::ostream & operator <<(std::ostream & str, const BaseSetting<T> & opt)
std::ostream & operator<<(std::ostream & str, const BaseSetting<T> & opt)
{
return str << static_cast<const T &>(opt);
}
template<typename T>
bool operator ==(const T & v1, const BaseSetting<T> & v2) { return v1 == static_cast<const T &>(v2); }
bool operator==(const T & v1, const BaseSetting<T> & v2)
{
return v1 == static_cast<const T &>(v2);
}
template<typename T>
class Setting : public BaseSetting<T>
{
public:
Setting(Config * options,
Setting(
Config * options,
const T & def,
const std::string & name,
const std::string & description,
@ -331,7 +373,10 @@ public:
options->addSetting(this);
}
void operator =(const T & v) { this->assign(v); }
void operator=(const T & v)
{
this->assign(v);
}
};
/**
@ -345,7 +390,8 @@ class PathSetting : public BaseSetting<Path>
{
public:
PathSetting(Config * options,
PathSetting(
Config * options,
const Path & def,
const std::string & name,
const std::string & description,
@ -353,9 +399,15 @@ public:
Path parse(const std::string & str) const override;
Path operator +(const char * p) const { return value + p; }
Path operator+(const char * p) const
{
return value + p;
}
void operator =(const Path & v) { this->assign(v); }
void operator=(const Path & v)
{
this->assign(v);
}
};
/**
@ -367,7 +419,8 @@ class OptionalPathSetting : public BaseSetting<std::optional<Path>>
{
public:
OptionalPathSetting(Config * options,
OptionalPathSetting(
Config * options,
const std::optional<Path> & def,
const std::string & name,
const std::string & description,
@ -375,14 +428,16 @@ public:
std::optional<Path> parse(const std::string & str) const override;
void operator =(const std::optional<Path> & v);
void operator=(const std::optional<Path> & v);
};
struct ExperimentalFeatureSettings : Config {
struct ExperimentalFeatureSettings : Config
{
Setting<std::set<ExperimentalFeature>> experimentalFeatures{
this, {}, "experimental-features",
this,
{},
"experimental-features",
R"(
Experimental features that are enabled.
@ -426,4 +481,4 @@ struct ExperimentalFeatureSettings : Config {
// FIXME: don't use a global variable.
extern ExperimentalFeatureSettings experimentalFeatureSettings;
}
} // namespace nix

View file

@ -4,7 +4,7 @@
#include <optional>
#ifndef _WIN32
# include <sys/resource.h>
# include <sys/resource.h>
#endif
#include "nix/util/types.hh"
@ -38,4 +38,4 @@ void restoreProcessContext(bool restoreMounts = true);
*/
std::optional<Path> getSelfExe();
}
} // namespace nix

View file

@ -9,10 +9,7 @@ namespace nix {
*
* If `count == 1`, prints `1 {single}` to `output`, otherwise prints `{count} {plural}`.
*/
std::ostream & pluralize(
std::ostream & output,
unsigned int count,
const std::string_view single,
const std::string_view plural);
std::ostream &
pluralize(std::ostream & output, unsigned int count, const std::string_view single, const std::string_view plural);
}
} // namespace nix

View file

@ -66,4 +66,4 @@ void clearEnv();
*/
void replaceEnv(const std::map<std::string, std::string> & newEnv);
}
} // namespace nix

View file

@ -29,22 +29,13 @@
namespace nix {
typedef enum {
lvlError = 0,
lvlWarn,
lvlNotice,
lvlInfo,
lvlTalkative,
lvlChatty,
lvlDebug,
lvlVomit
} Verbosity;
typedef enum { lvlError = 0, lvlWarn, lvlNotice, lvlInfo, lvlTalkative, lvlChatty, lvlDebug, lvlVomit } Verbosity;
/**
* The lines of code surrounding an error.
*/
struct LinesOfCode {
struct LinesOfCode
{
std::optional<std::string> prevLineOfCode;
std::optional<std::string> errLineOfCode;
std::optional<std::string> nextLineOfCode;
@ -60,10 +51,7 @@ struct LinesOfCode {
4feb7d9f71? */
struct Pos;
void printCodeLines(std::ostream & out,
const std::string & prefix,
const Pos & errPos,
const LinesOfCode & loc);
void printCodeLines(std::ostream & out, const std::string & prefix, const Pos & errPos, const LinesOfCode & loc);
/**
* When a stack frame is printed.
@ -77,15 +65,17 @@ enum struct TracePrint {
Always,
};
struct Trace {
struct Trace
{
std::shared_ptr<Pos> pos;
HintFmt hint;
TracePrint print = TracePrint::Default;
};
inline std::strong_ordering operator<=>(const Trace& lhs, const Trace& rhs);
inline std::strong_ordering operator<=>(const Trace & lhs, const Trace & rhs);
struct ErrorInfo {
struct ErrorInfo
{
Verbosity level;
HintFmt msg;
std::shared_ptr<Pos> pos;
@ -128,51 +118,71 @@ protected:
public:
BaseError(const BaseError &) = default;
BaseError& operator=(const BaseError &) = default;
BaseError& operator=(BaseError &&) = default;
BaseError & operator=(const BaseError &) = default;
BaseError & operator=(BaseError &&) = default;
template<typename... Args>
BaseError(unsigned int status, const Args & ... args)
: err { .level = lvlError, .msg = HintFmt(args...), .status = status }
{ }
BaseError(unsigned int status, const Args &... args)
: err{.level = lvlError, .msg = HintFmt(args...), .status = status}
{
}
template<typename... Args>
explicit BaseError(const std::string & fs, const Args & ... args)
: err { .level = lvlError, .msg = HintFmt(fs, args...) }
{ }
explicit BaseError(const std::string & fs, const Args &... args)
: err{.level = lvlError, .msg = HintFmt(fs, args...)}
{
}
template<typename... Args>
BaseError(const Suggestions & sug, const Args & ... args)
: err { .level = lvlError, .msg = HintFmt(args...), .suggestions = sug }
{ }
BaseError(const Suggestions & sug, const Args &... args)
: err{.level = lvlError, .msg = HintFmt(args...), .suggestions = sug}
{
}
BaseError(HintFmt hint)
: err { .level = lvlError, .msg = hint }
{ }
: err{.level = lvlError, .msg = hint}
{
}
BaseError(ErrorInfo && e)
: err(std::move(e))
{ }
{
}
BaseError(const ErrorInfo & e)
: err(e)
{ }
{
}
/** The error message without "error: " prefixed to it. */
std::string message() {
std::string message()
{
return err.msg.str();
}
const char * what() const noexcept override { return calcWhat().c_str(); }
const std::string & msg() const { return calcWhat(); }
const ErrorInfo & info() const { calcWhat(); return err; }
const char * what() const noexcept override
{
return calcWhat().c_str();
}
const std::string & msg() const
{
return calcWhat();
}
const ErrorInfo & info() const
{
calcWhat();
return err;
}
void withExitStatus(unsigned int status)
{
err.status = status;
}
void atPos(std::shared_ptr<Pos> pos) {
void atPos(std::shared_ptr<Pos> pos)
{
err.pos = pos;
}
@ -182,23 +192,29 @@ public:
}
template<typename... Args>
void addTrace(std::shared_ptr<Pos> && e, std::string_view fs, const Args & ... args)
void addTrace(std::shared_ptr<Pos> && e, std::string_view fs, const Args &... args)
{
addTrace(std::move(e), HintFmt(std::string(fs), args...));
}
void addTrace(std::shared_ptr<Pos> && e, HintFmt hint, TracePrint print = TracePrint::Default);
bool hasTrace() const { return !err.traces.empty(); }
bool hasTrace() const
{
return !err.traces.empty();
}
const ErrorInfo & info() { return err; };
const ErrorInfo & info()
{
return err;
};
};
#define MakeError(newClass, superClass) \
class newClass : public superClass \
{ \
public: \
using superClass::superClass; \
class newClass : public superClass \
{ \
public: \
using superClass::superClass; \
}
MakeError(Error, BaseError);
@ -236,8 +252,9 @@ public:
* will be used to try to add additional information to the message.
*/
template<typename... Args>
SysError(int errNo, const Args & ... args)
: SystemError(""), errNo(errNo)
SysError(int errNo, const Args &... args)
: SystemError("")
, errNo(errNo)
{
auto hf = HintFmt(args...);
err.msg = HintFmt("%1%: %2%", Uncolored(hf.str()), strerror(errNo));
@ -250,15 +267,15 @@ public:
* calling this constructor!
*/
template<typename... Args>
SysError(const Args & ... args)
: SysError(errno, args ...)
SysError(const Args &... args)
: SysError(errno, args...)
{
}
};
#ifdef _WIN32
namespace windows {
class WinError;
class WinError;
}
#endif
@ -301,4 +318,4 @@ void panic(const char * file, int line, const char * func);
*/
#define unreachable() (::nix::panic(__FILE__, __LINE__, __func__))
}
} // namespace nix

View file

@ -12,4 +12,4 @@ namespace nix {
*/
int execvpe(const OsChar * file0, const OsChar * const argv[], const OsChar * const envp[]);
}
} // namespace nix

View file

@ -11,9 +11,18 @@ class Exit : public std::exception
{
public:
int status;
Exit() : status(0) { }
explicit Exit(int status) : status(status) { }
Exit()
: status(0)
{
}
explicit Exit(int status)
: status(status)
{
}
virtual ~Exit();
};
}
} // namespace nix

View file

@ -15,8 +15,7 @@ namespace nix {
* their string representation and documentation in the corresponding
* `.cc` file as well.
*/
enum struct ExperimentalFeature
{
enum struct ExperimentalFeature {
CaDerivations,
ImpureDerivations,
Flakes,
@ -49,8 +48,7 @@ using Xp = ExperimentalFeature;
* Parse an experimental feature (enum value) from its name. Experimental
* feature flag names are hyphenated and do not contain spaces.
*/
const std::optional<ExperimentalFeature> parseExperimentalFeature(
const std::string_view & name);
const std::optional<ExperimentalFeature> parseExperimentalFeature(const std::string_view & name);
/**
* Show the name of an experimental feature. This is the opposite of
@ -68,9 +66,7 @@ nlohmann::json documentExperimentalFeatures();
/**
* Shorthand for `str << showExperimentalFeature(feature)`.
*/
std::ostream & operator<<(
std::ostream & str,
const ExperimentalFeature & feature);
std::ostream & operator<<(std::ostream & str, const ExperimentalFeature & feature);
/**
* Parse a set of strings to the corresponding set of experimental
@ -100,4 +96,4 @@ public:
void to_json(nlohmann::json &, const ExperimentalFeature &);
void from_json(const nlohmann::json &, ExperimentalFeature &);
}
} // namespace nix

View file

@ -57,22 +57,14 @@ std::string_view renderFileSerialisationMethod(FileSerialisationMethod method);
* Dump a serialization of the given file system object.
*/
void dumpPath(
const SourcePath & path,
Sink & sink,
FileSerialisationMethod method,
PathFilter & filter = defaultPathFilter);
const SourcePath & path, Sink & sink, FileSerialisationMethod method, PathFilter & filter = defaultPathFilter);
/**
* Restore a serialisation of the given file system object.
*
* \todo use an arbitrary `FileSystemObjectSink`.
*/
void restorePath(
const Path & path,
Source & source,
FileSerialisationMethod method,
bool startFsync = false);
void restorePath(const Path & path, Source & source, FileSerialisationMethod method, bool startFsync = false);
/**
* Compute the hash of the given file system object according to the
@ -85,9 +77,7 @@ void restorePath(
* ```
*/
HashResult hashPath(
const SourcePath & path,
FileSerialisationMethod method, HashAlgorithm ha,
PathFilter & filter = defaultPathFilter);
const SourcePath & path, FileSerialisationMethod method, HashAlgorithm ha, PathFilter & filter = defaultPathFilter);
/**
* An enumeration of the ways we can ingest file system
@ -153,8 +143,6 @@ std::string_view renderFileIngestionMethod(FileIngestionMethod method);
* useful defined for a merkle format.
*/
std::pair<Hash, std::optional<uint64_t>> hashPath(
const SourcePath & path,
FileIngestionMethod method, HashAlgorithm ha,
PathFilter & filter = defaultPathFilter);
const SourcePath & path, FileIngestionMethod method, HashAlgorithm ha, PathFilter & filter = defaultPathFilter);
}
} // namespace nix

View file

@ -5,8 +5,8 @@
#include "nix/util/error.hh"
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif
namespace nix {
@ -93,18 +93,19 @@ void writeLine(Descriptor fd, std::string s);
/**
* Read a file descriptor until EOF occurs.
*/
std::string drainFD(Descriptor fd, bool block = true, const size_t reserveSize=0);
std::string drainFD(Descriptor fd, bool block = true, const size_t reserveSize = 0);
/**
* The Windows version is always blocking.
*/
void drainFD(
Descriptor fd
, Sink & sink
Descriptor fd,
Sink & sink
#ifndef _WIN32
, bool block = true
,
bool block = true
#endif
);
);
/**
* Get [Standard Input](https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin))
@ -155,10 +156,10 @@ public:
AutoCloseFD();
AutoCloseFD(Descriptor fd);
AutoCloseFD(const AutoCloseFD & fd) = delete;
AutoCloseFD(AutoCloseFD&& fd) noexcept;
AutoCloseFD(AutoCloseFD && fd) noexcept;
~AutoCloseFD();
AutoCloseFD& operator =(const AutoCloseFD & fd) = delete;
AutoCloseFD& operator =(AutoCloseFD&& fd);
AutoCloseFD & operator=(const AutoCloseFD & fd) = delete;
AutoCloseFD & operator=(AutoCloseFD && fd);
Descriptor get() const;
explicit operator bool() const;
Descriptor release();
@ -213,4 +214,4 @@ std::wstring handleToFileName(Descriptor handle);
MakeError(EndOfFile, Error);
}
} // namespace nix

View file

@ -42,7 +42,6 @@ struct UnixPathTrait
}
};
/**
* Windows-style path primitives.
*
@ -75,22 +74,17 @@ struct WindowsPathTrait
{
size_t p1 = path.find('/', from);
size_t p2 = path.find(preferredSep, from);
return p1 == String::npos ? p2 :
p2 == String::npos ? p1 :
std::min(p1, p2);
return p1 == String::npos ? p2 : p2 == String::npos ? p1 : std::min(p1, p2);
}
static size_t rfindPathSep(StringView path, size_t from = String::npos)
{
size_t p1 = path.rfind('/', from);
size_t p2 = path.rfind(preferredSep, from);
return p1 == String::npos ? p2 :
p2 == String::npos ? p1 :
std::max(p1, p2);
return p1 == String::npos ? p2 : p2 == String::npos ? p1 : std::max(p1, p2);
}
};
template<typename CharT>
using OsPathTrait =
#ifdef _WIN32
@ -100,7 +94,6 @@ using OsPathTrait =
#endif
;
/**
* Core pure path canonicalization algorithm.
*
@ -116,9 +109,7 @@ using OsPathTrait =
* "result" points to a symlink.
*/
template<class PathDict>
typename PathDict::String canonPathInner(
typename PathDict::StringView remaining,
auto && hookComponent)
typename PathDict::String canonPathInner(typename PathDict::StringView remaining, auto && hookComponent)
{
assert(remaining != "");
@ -131,7 +122,8 @@ typename PathDict::String canonPathInner(
while (!remaining.empty() && PathDict::isPathSep(remaining[0]))
remaining.remove_prefix(1);
if (remaining.empty()) break;
if (remaining.empty())
break;
auto nextComp = ({
auto nextPathSep = PathDict::findPathSep(remaining);
@ -143,9 +135,9 @@ typename PathDict::String canonPathInner(
remaining.remove_prefix(1);
/* If `..', delete the last component. */
else if (nextComp == "..")
{
if (!result.empty()) result.erase(PathDict::rfindPathSep(result));
else if (nextComp == "..") {
if (!result.empty())
result.erase(PathDict::rfindPathSep(result));
remaining.remove_prefix(2);
}
@ -165,9 +157,9 @@ typename PathDict::String canonPathInner(
}
if (result.empty())
result = typename PathDict::String { PathDict::preferredSep };
result = typename PathDict::String{PathDict::preferredSep};
return result;
}
}
} // namespace nix

View file

@ -30,18 +30,27 @@ struct PathViewNG : OsStringView
PathViewNG(const std::filesystem::path & path)
: OsStringView{path.native()}
{ }
{
}
PathViewNG(const OsString & path)
: OsStringView{path}
{ }
{
}
const string_view & native() const { return *this; }
string_view & native() { return *this; }
const string_view & native() const
{
return *this;
}
string_view & native()
{
return *this;
}
};
std::optional<std::filesystem::path> maybePath(PathView path);
std::filesystem::path pathNG(PathView path);
}
} // namespace nix

View file

@ -16,7 +16,7 @@
#include <dirent.h>
#include <unistd.h>
#ifdef _WIN32
# include <windef.h>
# include <windef.h>
#endif
#include <signal.h>
@ -34,7 +34,7 @@
* @todo get rid of this, and stop using `stat` when we want `lstat` too.
*/
#ifndef S_ISLNK
# define S_ISLNK(m) false
# define S_ISLNK(m) false
#endif
namespace nix {
@ -54,19 +54,14 @@ bool isAbsolute(PathView path);
*
* In the process of being deprecated for `std::filesystem::absolute`.
*/
Path absPath(PathView path,
std::optional<PathView> dir = {},
bool resolveSymlinks = false);
Path absPath(PathView path, std::optional<PathView> dir = {}, bool resolveSymlinks = false);
inline Path absPath(const Path & path,
std::optional<PathView> dir = {},
bool resolveSymlinks = false)
inline Path absPath(const Path & path, std::optional<PathView> dir = {}, bool resolveSymlinks = false)
{
return absPath(PathView{path}, dir, resolveSymlinks);
}
std::filesystem::path absPath(const std::filesystem::path & path,
bool resolveSymlinks = false);
std::filesystem::path absPath(const std::filesystem::path & path, bool resolveSymlinks = false);
/**
* Canonicalise a path by removing all `.` or `..` components and
@ -200,19 +195,22 @@ enum struct FsSync { Yes, No };
*/
void writeFile(const Path & path, std::string_view s, mode_t mode = 0666, FsSync sync = FsSync::No);
static inline void writeFile(const std::filesystem::path & path, std::string_view s, mode_t mode = 0666, FsSync sync = FsSync::No)
static inline void
writeFile(const std::filesystem::path & path, std::string_view s, mode_t mode = 0666, FsSync sync = FsSync::No)
{
return writeFile(path.string(), s, mode, sync);
}
void writeFile(const Path & path, Source & source, mode_t mode = 0666, FsSync sync = FsSync::No);
static inline void writeFile(const std::filesystem::path & path, Source & source, mode_t mode = 0666, FsSync sync = FsSync::No)
static inline void
writeFile(const std::filesystem::path & path, Source & source, mode_t mode = 0666, FsSync sync = FsSync::No)
{
return writeFile(path.string(), source, mode, sync);
}
void writeFile(AutoCloseFD & fd, const Path & origPath, std::string_view s, mode_t mode = 0666, FsSync sync = FsSync::No);
void writeFile(
AutoCloseFD & fd, const Path & origPath, std::string_view s, mode_t mode = 0666, FsSync sync = FsSync::No);
/**
* Flush a path's parent directory to disk.
@ -319,29 +317,46 @@ public:
void reset(const std::filesystem::path & p, bool recursive = true);
const std::filesystem::path & path() const { return _path; }
PathViewNG view() const { return _path; }
const std::filesystem::path & path() const
{
return _path;
}
operator const std::filesystem::path & () const { return _path; }
operator PathViewNG () const { return _path; }
PathViewNG view() const
{
return _path;
}
operator const std::filesystem::path &() const
{
return _path;
}
operator PathViewNG() const
{
return _path;
}
};
struct DIRDeleter
{
void operator()(DIR * dir) const {
void operator()(DIR * dir) const
{
closedir(dir);
}
};
typedef std::unique_ptr<DIR, DIRDeleter> AutoCloseDir;
/**
* Create a temporary directory.
*/
Path createTempDir(const Path & tmpRoot = "", const Path & prefix = "nix",
bool includePid = true, bool useGlobalCounter = true, mode_t mode = 0755);
Path createTempDir(
const Path & tmpRoot = "",
const Path & prefix = "nix",
bool includePid = true,
bool useGlobalCounter = true,
mode_t mode = 0755);
/**
* Create a temporary file, returning a file handle and its path.
@ -383,63 +398,75 @@ extern PathFilter defaultPathFilter;
bool chmodIfNeeded(const std::filesystem::path & path, mode_t mode, mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO);
/**
* @brief A directory iterator that can be used to iterate over the
* contents of a directory. It is similar to std::filesystem::directory_iterator
* but throws NixError on failure instead of std::filesystem::filesystem_error.
*/
class DirectoryIterator {
* @brief A directory iterator that can be used to iterate over the
* contents of a directory. It is similar to std::filesystem::directory_iterator
* but throws NixError on failure instead of std::filesystem::filesystem_error.
*/
class DirectoryIterator
{
public:
// --- Iterator Traits ---
using iterator_category = std::input_iterator_tag;
using value_type = std::filesystem::directory_entry;
using difference_type = std::ptrdiff_t;
using pointer = const std::filesystem::directory_entry*;
using reference = const std::filesystem::directory_entry&;
using value_type = std::filesystem::directory_entry;
using difference_type = std::ptrdiff_t;
using pointer = const std::filesystem::directory_entry *;
using reference = const std::filesystem::directory_entry &;
// Default constructor (represents end iterator)
DirectoryIterator() noexcept = default;
// Constructor taking a path
explicit DirectoryIterator(const std::filesystem::path& p);
explicit DirectoryIterator(const std::filesystem::path & p);
reference operator*() const {
reference operator*() const
{
// Accessing the value itself doesn't typically throw filesystem_error
// after successful construction/increment, but underlying operations might.
// If directory_entry methods called via -> could throw, add try-catch there.
return *it_;
}
pointer operator->() const {
pointer operator->() const
{
return &(*it_);
}
DirectoryIterator& operator++();
DirectoryIterator & operator++();
// Postfix increment operator
DirectoryIterator operator++(int) {
DirectoryIterator operator++(int)
{
DirectoryIterator temp = *this;
++(*this); // Uses the prefix increment's try-catch logic
return temp;
}
// Equality comparison
friend bool operator==(const DirectoryIterator& a, const DirectoryIterator& b) noexcept {
friend bool operator==(const DirectoryIterator & a, const DirectoryIterator & b) noexcept
{
return a.it_ == b.it_;
}
// Inequality comparison
friend bool operator!=(const DirectoryIterator& a, const DirectoryIterator& b) noexcept {
friend bool operator!=(const DirectoryIterator & a, const DirectoryIterator & b) noexcept
{
return !(a == b);
}
// Allow direct use in range-based for loops if iterating over an instance
DirectoryIterator begin() const { return *this; }
DirectoryIterator end() const { return DirectoryIterator{}; }
DirectoryIterator begin() const
{
return *this;
}
DirectoryIterator end() const
{
return DirectoryIterator{};
}
private:
std::filesystem::directory_iterator it_;
};
}
} // namespace nix

View file

@ -16,10 +16,15 @@ private:
bool movedFrom = false;
public:
Finally(Fn fun) : fun(std::move(fun)) { }
Finally(Fn fun)
: fun(std::move(fun))
{
}
// Copying Finallys is definitely not a good idea and will cause them to be
// called twice.
Finally(Finally &other) = delete;
Finally(Finally & other) = delete;
// NOTE: Move constructor can be nothrow if the callable type is itself nothrow
// move-constructible.
Finally(Finally && other) noexcept(std::is_nothrow_move_constructible_v<Fn>)
@ -27,6 +32,7 @@ public:
{
other.movedFrom = true;
}
~Finally() noexcept(false)
{
try {

View file

@ -5,7 +5,6 @@
#include <string>
#include "nix/util/ansicolor.hh"
namespace nix {
/**
@ -22,10 +21,11 @@ namespace nix {
*/
template<class F>
inline void formatHelper(F & f)
{ }
{
}
template<class F, typename T, typename... Args>
inline void formatHelper(F & f, const T & x, const Args & ... args)
inline void formatHelper(F & f, const T & x, const Args &... args)
{
// Interpolate one argument and then recurse.
formatHelper(f % x, args...);
@ -36,10 +36,7 @@ inline void formatHelper(F & f, const T & x, const Args & ... args)
*/
inline void setExceptions(boost::format & fmt)
{
fmt.exceptions(
boost::io::all_error_bits ^
boost::io::too_many_args_bit ^
boost::io::too_few_args_bit);
fmt.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit ^ boost::io::too_few_args_bit);
}
/**
@ -80,7 +77,7 @@ inline std::string fmt(const char * s)
}
template<typename... Args>
inline std::string fmt(const std::string & fs, const Args & ... args)
inline std::string fmt(const std::string & fs, const Args &... args)
{
boost::format f(fs);
setExceptions(f);
@ -95,14 +92,18 @@ inline std::string fmt(const std::string & fs, const Args & ... args)
* either wrap the argument in `Uncolored` or add a specialization of
* `HintFmt::operator%`.
*/
template <class T>
template<class T>
struct Magenta
{
Magenta(const T &s) : value(s) {}
Magenta(const T & s)
: value(s)
{
}
const T & value;
};
template <class T>
template<class T>
std::ostream & operator<<(std::ostream & out, const Magenta<T> & y)
{
return out << ANSI_WARNING << y.value << ANSI_NORMAL;
@ -115,14 +116,18 @@ std::ostream & operator<<(std::ostream & out, const Magenta<T> & y)
*
* By default, arguments to `HintFmt` are printed in magenta (see `Magenta`).
*/
template <class T>
template<class T>
struct Uncolored
{
Uncolored(const T & s) : value(s) {}
Uncolored(const T & s)
: value(s)
{
}
const T & value;
};
template <class T>
template<class T>
std::ostream & operator<<(std::ostream & out, const Uncolored<T> & y)
{
return out << ANSI_NORMAL << y.value;
@ -144,9 +149,11 @@ public:
*/
HintFmt(const std::string & literal)
: HintFmt("%s", Uncolored(literal))
{ }
{
}
static HintFmt fromFormatString(const std::string & format) {
static HintFmt fromFormatString(const std::string & format)
{
return HintFmt(boost::format(format));
}
@ -154,16 +161,18 @@ public:
* Interpolate the given arguments into the format string.
*/
template<typename... Args>
HintFmt(const std::string & format, const Args & ... args)
HintFmt(const std::string & format, const Args &... args)
: HintFmt(boost::format(format), args...)
{ }
{
}
HintFmt(const HintFmt & hf)
: fmt(hf.fmt)
{ }
{
}
template<typename... Args>
HintFmt(boost::format && fmt, const Args & ... args)
HintFmt(boost::format && fmt, const Args &... args)
: fmt(std::move(fmt))
{
setExceptions(fmt);
@ -194,4 +203,4 @@ public:
std::ostream & operator<<(std::ostream & os, const HintFmt & hf);
}
} // namespace nix

View file

@ -19,10 +19,9 @@ struct CreateRegularFileSink : Sink
/**
* An optimization. By default, do nothing.
*/
virtual void preallocateContents(uint64_t size) { };
virtual void preallocateContents(uint64_t size) {};
};
struct FileSystemObjectSink
{
virtual ~FileSystemObjectSink() = default;
@ -33,9 +32,7 @@ struct FileSystemObjectSink
* This function in general is no re-entrant. Only one file can be
* written at a time.
*/
virtual void createRegularFile(
const CanonPath & path,
std::function<void(CreateRegularFileSink &)>) = 0;
virtual void createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)>) = 0;
virtual void createSymlink(const CanonPath & path, const std::string & target) = 0;
};
@ -57,19 +54,18 @@ struct ExtendedFileSystemObjectSink : virtual FileSystemObjectSink
* Recursively copy file system objects from the source into the sink.
*/
void copyRecursive(
SourceAccessor & accessor, const CanonPath & sourcePath,
FileSystemObjectSink & sink, const CanonPath & destPath);
SourceAccessor & accessor, const CanonPath & sourcePath, FileSystemObjectSink & sink, const CanonPath & destPath);
/**
* Ignore everything and do nothing
*/
struct NullFileSystemObjectSink : FileSystemObjectSink
{
void createDirectory(const CanonPath & path) override { }
void createSymlink(const CanonPath & path, const std::string & target) override { }
void createRegularFile(
const CanonPath & path,
std::function<void(CreateRegularFileSink &)>) override;
void createDirectory(const CanonPath & path) override {}
void createSymlink(const CanonPath & path, const std::string & target) override {}
void createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)>) override;
};
/**
@ -82,13 +78,12 @@ struct RestoreSink : FileSystemObjectSink
explicit RestoreSink(bool startFsync)
: startFsync{startFsync}
{ }
{
}
void createDirectory(const CanonPath & path) override;
void createRegularFile(
const CanonPath & path,
std::function<void(CreateRegularFileSink &)>) override;
void createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)>) override;
void createSymlink(const CanonPath & path, const std::string & target) override;
};
@ -103,7 +98,10 @@ struct RegularFileSink : FileSystemObjectSink
bool regular = true;
Sink & sink;
RegularFileSink(Sink & sink) : sink(sink) { }
RegularFileSink(Sink & sink)
: sink(sink)
{
}
void createDirectory(const CanonPath & path) override
{
@ -115,9 +113,7 @@ struct RegularFileSink : FileSystemObjectSink
regular = false;
}
void createRegularFile(
const CanonPath & path,
std::function<void(CreateRegularFileSink &)>) override;
void createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)>) override;
};
}
} // namespace nix

View file

@ -16,8 +16,8 @@ namespace nix::git {
enum struct ObjectType {
Blob,
Tree,
//Commit,
//Tag,
// Commit,
// Tag,
};
using RawMode = uint32_t;
@ -39,8 +39,8 @@ struct TreeEntry
Mode mode;
Hash hash;
bool operator ==(const TreeEntry &) const = default;
auto operator <=>(const TreeEntry &) const = default;
bool operator==(const TreeEntry &) const = default;
auto operator<=>(const TreeEntry &) const = default;
};
/**
@ -72,9 +72,8 @@ using SinkHook = void(const CanonPath & name, TreeEntry entry);
*
* @throws if prefix not recognized
*/
ObjectType parseObjectType(
Source & source,
const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
ObjectType
parseObjectType(Source & source, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
/**
* These 3 modes are represented by blob objects.
@ -82,21 +81,22 @@ ObjectType parseObjectType(
* Sometimes we need this information to disambiguate how a blob is
* being used to better match our own "file system object" data model.
*/
enum struct BlobMode : RawMode
{
enum struct BlobMode : RawMode {
Regular = static_cast<RawMode>(Mode::Regular),
Executable = static_cast<RawMode>(Mode::Executable),
Symlink = static_cast<RawMode>(Mode::Symlink),
};
void parseBlob(
FileSystemObjectSink & sink, const CanonPath & sinkPath,
FileSystemObjectSink & sink,
const CanonPath & sinkPath,
Source & source,
BlobMode blobMode,
const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
void parseTree(
FileSystemObjectSink & sink, const CanonPath & sinkPath,
FileSystemObjectSink & sink,
const CanonPath & sinkPath,
Source & source,
std::function<SinkHook> hook,
const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
@ -109,7 +109,8 @@ void parseTree(
* a blob, this is ignored.
*/
void parse(
FileSystemObjectSink & sink, const CanonPath & sinkPath,
FileSystemObjectSink & sink,
const CanonPath & sinkPath,
Source & source,
BlobMode rootModeIfBlob,
std::function<SinkHook> hook,
@ -139,15 +140,13 @@ void restore(FileSystemObjectSink & sink, Source & source, std::function<Restore
* @param xpSettings for testing purposes
*/
void dumpBlobPrefix(
uint64_t size, Sink & sink,
const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
uint64_t size, Sink & sink, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
/**
* Dumps a representation of a git tree to a sink
*/
void dumpTree(
const Tree & entries, Sink & sink,
const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
const Tree & entries, Sink & sink, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
/**
* Callback for processing a child with `dump`
@ -172,10 +171,7 @@ Mode dump(
*
* A smaller wrapper around `dump`.
*/
TreeEntry dumpHash(
HashAlgorithm ha,
const SourcePath & path,
PathFilter & filter = defaultPathFilter);
TreeEntry dumpHash(HashAlgorithm ha, const SourcePath & path, PathFilter & filter = defaultPathFilter);
/**
* A line from the output of `git ls-remote --symref`.
@ -196,11 +192,9 @@ TreeEntry dumpHash(
* ```
* where {target} is a commit id and {reference} is mandatory
*/
struct LsRemoteRefLine {
enum struct Kind {
Symbolic,
Object
};
struct LsRemoteRefLine
{
enum struct Kind { Symbolic, Object };
Kind kind;
std::string target;
std::optional<std::string> reference;
@ -211,4 +205,4 @@ struct LsRemoteRefLine {
*/
std::optional<LsRemoteRefLine> parseLsRemoteLine(std::string_view line);
}
} // namespace nix::git

View file

@ -8,10 +8,8 @@
namespace nix {
MakeError(BadHash, Error);
enum struct HashAlgorithm : char { MD5 = 42, SHA1, SHA256, SHA512, BLAKE3 };
const int blake3HashSize = 32;
@ -89,12 +87,12 @@ public:
/**
* Check whether two hashes are equal.
*/
bool operator == (const Hash & h2) const noexcept;
bool operator==(const Hash & h2) const noexcept;
/**
* Compare how two hashes are ordered.
*/
std::strong_ordering operator <=> (const Hash & h2) const noexcept;
std::strong_ordering operator<=>(const Hash & h2) const noexcept;
/**
* Returns the length of a base-16 representation of this hash.
@ -158,7 +156,8 @@ std::string printHash16or32(const Hash & hash);
/**
* Compute the hash of the given string.
*/
Hash hashString(HashAlgorithm ha, std::string_view s, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
Hash hashString(
HashAlgorithm ha, std::string_view s, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
/**
* Compute the hash of the given file, hashing its contents directly.
@ -210,7 +209,6 @@ std::optional<HashAlgorithm> parseHashAlgoOpt(std::string_view s);
*/
std::string_view printHashAlgo(HashAlgorithm ha);
union Ctx;
struct AbstractHashSink : virtual Sink
@ -234,5 +232,4 @@ public:
HashResult currentHash();
};
}
} // namespace nix

View file

@ -14,10 +14,7 @@ namespace nix {
* If some matches overlap, then their union will be wrapped rather
* than the individual matches.
*/
std::string hiliteMatches(
std::string_view s,
std::vector<std::smatch> matches,
std::string_view prefix,
std::string_view postfix);
std::string
hiliteMatches(std::string_view s, std::vector<std::smatch> matches, std::string_view prefix, std::string_view postfix);
}
} // namespace nix

View file

@ -4,12 +4,13 @@
#include <nlohmann/json_fwd.hpp>
// Following https://github.com/nlohmann/json#how-can-i-use-get-for-non-default-constructiblenon-copyable-types
#define JSON_IMPL(TYPE) \
namespace nlohmann { \
using namespace nix; \
template <> \
struct adl_serializer<TYPE> { \
static TYPE from_json(const json & json); \
static void to_json(json & json, TYPE t); \
}; \
#define JSON_IMPL(TYPE) \
namespace nlohmann { \
using namespace nix; \
template<> \
struct adl_serializer<TYPE> \
{ \
static TYPE from_json(const json & json); \
static void to_json(json & json, TYPE t); \
}; \
}

View file

@ -21,9 +21,7 @@ nlohmann::json * get(nlohmann::json & map, const std::string & key);
*
* Use instead of nlohmann::json::at() to avoid ugly exceptions.
*/
const nlohmann::json & valueAt(
const nlohmann::json::object_t & map,
const std::string & key);
const nlohmann::json & valueAt(const nlohmann::json::object_t & map, const std::string & key);
std::optional<nlohmann::json> optionalValueAt(const nlohmann::json::object_t & value, const std::string & key);
std::optional<nlohmann::json> nullableValueAt(const nlohmann::json::object_t & value, const std::string & key);
@ -73,36 +71,45 @@ struct json_avoids_null;
* Handle numbers in default impl
*/
template<typename T>
struct json_avoids_null : std::bool_constant<std::is_integral<T>::value> {};
struct json_avoids_null : std::bool_constant<std::is_integral<T>::value>
{};
template<>
struct json_avoids_null<std::nullptr_t> : std::false_type {};
struct json_avoids_null<std::nullptr_t> : std::false_type
{};
template<>
struct json_avoids_null<bool> : std::true_type {};
struct json_avoids_null<bool> : std::true_type
{};
template<>
struct json_avoids_null<std::string> : std::true_type {};
struct json_avoids_null<std::string> : std::true_type
{};
template<typename T>
struct json_avoids_null<std::vector<T>> : std::true_type {};
struct json_avoids_null<std::vector<T>> : std::true_type
{};
template<typename T>
struct json_avoids_null<std::list<T>> : std::true_type {};
struct json_avoids_null<std::list<T>> : std::true_type
{};
template<typename T>
struct json_avoids_null<std::set<T>> : std::true_type {};
struct json_avoids_null<std::set<T>> : std::true_type
{};
template<typename K, typename V>
struct json_avoids_null<std::map<K, V>> : std::true_type {};
struct json_avoids_null<std::map<K, V>> : std::true_type
{};
/**
* `ExperimentalFeature` is always rendered as a string.
*/
template<>
struct json_avoids_null<ExperimentalFeature> : std::true_type {};
struct json_avoids_null<ExperimentalFeature> : std::true_type
{};
}
} // namespace nix
namespace nlohmann {
@ -123,12 +130,8 @@ struct adl_serializer<std::optional<T>>
*/
static void from_json(const json & json, std::optional<T> & t)
{
static_assert(
nix::json_avoids_null<T>::value,
"null is already in use for underlying type's JSON");
t = json.is_null()
? std::nullopt
: std::make_optional(json.template get<T>());
static_assert(nix::json_avoids_null<T>::value, "null is already in use for underlying type's JSON");
t = json.is_null() ? std::nullopt : std::make_optional(json.template get<T>());
}
/**
@ -137,9 +140,7 @@ struct adl_serializer<std::optional<T>>
*/
static void to_json(json & json, const std::optional<T> & t)
{
static_assert(
nix::json_avoids_null<T>::value,
"null is already in use for underlying type's JSON");
static_assert(nix::json_avoids_null<T>::value, "null is already in use for underlying type's JSON");
if (t)
json = *t;
else
@ -147,4 +148,4 @@ struct adl_serializer<std::optional<T>>
}
};
}
} // namespace nlohmann

View file

@ -44,7 +44,9 @@ typedef uint64_t ActivityId;
struct LoggerSettings : Config
{
Setting<bool> showTrace{
this, false, "show-trace",
this,
false,
"show-trace",
R"(
Whether Nix should print out a stack trace in case of Nix
expression evaluation errors.
@ -63,23 +65,40 @@ public:
{
// FIXME: use std::variant.
enum { tInt = 0, tString = 1 } type;
uint64_t i = 0;
std::string s;
Field(const std::string & s) : type(tString), s(s) { }
Field(const char * s) : type(tString), s(s) { }
Field(const uint64_t & i) : type(tInt), i(i) { }
Field(const std::string & s)
: type(tString)
, s(s)
{
}
Field(const char * s)
: type(tString)
, s(s)
{
}
Field(const uint64_t & i)
: type(tInt)
, i(i)
{
}
};
typedef std::vector<Field> Fields;
virtual ~Logger() { }
virtual ~Logger() {}
virtual void stop() { };
virtual void stop() {};
/**
* Guard object to resume the logger when done.
*/
struct Suspension {
struct Suspension
{
Finally<std::function<void()>> _finalize;
};
@ -87,11 +106,14 @@ public:
std::optional<Suspension> suspendIf(bool cond);
virtual void pause() { };
virtual void resume() { };
virtual void pause() {};
virtual void resume() {};
// Whether the logger prints the whole build log
virtual bool isVerbose() { return false; }
virtual bool isVerbose()
{
return false;
}
virtual void log(Verbosity lvl, std::string_view s) = 0;
@ -110,26 +132,32 @@ public:
virtual void warn(const std::string & msg);
virtual void startActivity(ActivityId act, Verbosity lvl, ActivityType type,
const std::string & s, const Fields & fields, ActivityId parent) { };
virtual void startActivity(
ActivityId act,
Verbosity lvl,
ActivityType type,
const std::string & s,
const Fields & fields,
ActivityId parent) {};
virtual void stopActivity(ActivityId act) { };
virtual void stopActivity(ActivityId act) {};
virtual void result(ActivityId act, ResultType type, const Fields & fields) { };
virtual void result(ActivityId act, ResultType type, const Fields & fields) {};
virtual void writeToStdout(std::string_view s);
template<typename... Args>
inline void cout(const Args & ... args)
inline void cout(const Args &... args)
{
writeToStdout(fmt(args...));
}
virtual std::optional<char> ask(std::string_view s)
{ return {}; }
{
return {};
}
virtual void setPrintBuildLogs(bool printBuildLogs)
{ }
virtual void setPrintBuildLogs(bool printBuildLogs) {}
};
/**
@ -139,8 +167,10 @@ public:
*/
struct nop
{
template<typename... T> nop(T...)
{ }
template<typename... T>
nop(T...)
{
}
};
ActivityId getCurActivity();
@ -152,25 +182,34 @@ struct Activity
const ActivityId id;
Activity(Logger & logger, Verbosity lvl, ActivityType type, const std::string & s = "",
const Logger::Fields & fields = {}, ActivityId parent = getCurActivity());
Activity(
Logger & logger,
Verbosity lvl,
ActivityType type,
const std::string & s = "",
const Logger::Fields & fields = {},
ActivityId parent = getCurActivity());
Activity(Logger & logger, ActivityType type,
const Logger::Fields & fields = {}, ActivityId parent = getCurActivity())
: Activity(logger, lvlError, type, "", fields, parent) { };
Activity(
Logger & logger, ActivityType type, const Logger::Fields & fields = {}, ActivityId parent = getCurActivity())
: Activity(logger, lvlError, type, "", fields, parent) {};
Activity(const Activity & act) = delete;
~Activity();
void progress(uint64_t done = 0, uint64_t expected = 0, uint64_t running = 0, uint64_t failed = 0) const
{ result(resProgress, done, expected, running, failed); }
{
result(resProgress, done, expected, running, failed);
}
void setExpected(ActivityType type2, uint64_t expected) const
{ result(resSetExpected, type2, expected); }
{
result(resSetExpected, type2, expected);
}
template<typename... Args>
void result(ResultType type, const Args & ... args) const
void result(ResultType type, const Args &... args) const
{
Logger::Fields fields;
nop{(fields.emplace_back(Logger::Field(args)), 1)...};
@ -188,8 +227,17 @@ struct Activity
struct PushActivity
{
const ActivityId prevAct;
PushActivity(ActivityId act) : prevAct(getCurActivity()) { setCurActivity(act); }
~PushActivity() { setCurActivity(prevAct); }
PushActivity(ActivityId act)
: prevAct(getCurActivity())
{
setCurActivity(act);
}
~PushActivity()
{
setCurActivity(prevAct);
}
};
extern std::unique_ptr<Logger> logger;
@ -206,16 +254,20 @@ std::optional<nlohmann::json> parseJSONMessage(const std::string & msg, std::str
/**
* @param source A noun phrase describing the source of the message, e.g. "the builder".
*/
bool handleJSONLogMessage(nlohmann::json & json,
const Activity & act, std::map<ActivityId, Activity> & activities,
bool handleJSONLogMessage(
nlohmann::json & json,
const Activity & act,
std::map<ActivityId, Activity> & activities,
std::string_view source,
bool trusted);
/**
* @param source A noun phrase describing the source of the message, e.g. "the builder".
*/
bool handleJSONLogMessage(const std::string & msg,
const Activity & act, std::map<ActivityId, Activity> & activities,
bool handleJSONLogMessage(
const std::string & msg,
const Activity & act,
std::map<ActivityId, Activity> & activities,
std::string_view source,
bool trusted);
@ -230,11 +282,11 @@ extern Verbosity verbosity;
* intervention or that need more explanation. Use the 'print' macros for more
* lightweight status messages.
*/
#define logErrorInfo(level, errorInfo...) \
do { \
if ((level) <= nix::verbosity) { \
logger->logEI((level), errorInfo); \
} \
#define logErrorInfo(level, errorInfo...) \
do { \
if ((level) <= nix::verbosity) { \
logger->logEI((level), errorInfo); \
} \
} while (0)
#define logError(errorInfo...) logErrorInfo(lvlError, errorInfo)
@ -246,11 +298,11 @@ extern Verbosity verbosity;
* arguments are evaluated lazily.
*/
#define printMsgUsing(loggerParam, level, args...) \
do { \
auto __lvl = level; \
if (__lvl <= nix::verbosity) { \
loggerParam->log(__lvl, fmt(args)); \
} \
do { \
auto __lvl = level; \
if (__lvl <= nix::verbosity) { \
loggerParam->log(__lvl, fmt(args)); \
} \
} while (0)
#define printMsg(level, args...) printMsgUsing(logger, level, args)
@ -265,7 +317,7 @@ extern Verbosity verbosity;
* if verbosity >= lvlWarn, print a message with a yellow 'warning:' prefix.
*/
template<typename... Args>
inline void warn(const std::string & fs, const Args & ... args)
inline void warn(const std::string & fs, const Args &... args)
{
boost::format f(fs);
formatHelper(f, args...);
@ -280,4 +332,4 @@ inline void warn(const std::string & fs, const Args & ... args)
void writeToStderr(std::string_view s);
}
} // namespace nix

View file

@ -25,21 +25,28 @@ private:
using Data = std::map<Key, std::pair<LRUIterator, Value>>;
using LRU = std::list<typename Data::iterator>;
struct LRUIterator { typename LRU::iterator it; };
struct LRUIterator
{
typename LRU::iterator it;
};
Data data;
LRU lru;
public:
LRUCache(size_t capacity) : capacity(capacity) { }
LRUCache(size_t capacity)
: capacity(capacity)
{
}
/**
* Insert or upsert an item in the cache.
*/
void upsert(const Key & key, const Value & value)
{
if (capacity == 0) return;
if (capacity == 0)
return;
erase(key);
@ -64,7 +71,8 @@ public:
bool erase(const Key & key)
{
auto i = data.find(key);
if (i == data.end()) return false;
if (i == data.end())
return false;
lru.erase(i->second.first.it);
data.erase(i);
return true;
@ -77,7 +85,8 @@ public:
std::optional<Value> get(const Key & key)
{
auto i = data.find(key);
if (i == data.end()) return {};
if (i == data.end())
return {};
/**
* Move this item to the back of the LRU list.
@ -101,4 +110,4 @@ public:
}
};
}
} // namespace nix

View file

@ -14,33 +14,37 @@ struct MemorySourceAccessor : virtual SourceAccessor
* `MemorySourceAccessor`, this has a side benefit of nicely
* defining what a "file system object" is in Nix.
*/
struct File {
bool operator == (const File &) const noexcept;
std::strong_ordering operator <=> (const File &) const noexcept;
struct File
{
bool operator==(const File &) const noexcept;
std::strong_ordering operator<=>(const File &) const noexcept;
struct Regular {
struct Regular
{
bool executable = false;
std::string contents;
bool operator == (const Regular &) const = default;
auto operator <=> (const Regular &) const = default;
bool operator==(const Regular &) const = default;
auto operator<=>(const Regular &) const = default;
};
struct Directory {
struct Directory
{
using Name = std::string;
std::map<Name, File, std::less<>> contents;
bool operator == (const Directory &) const noexcept;
bool operator==(const Directory &) const noexcept;
// TODO libc++ 16 (used by darwin) missing `std::map::operator <=>`, can't do yet.
bool operator < (const Directory &) const noexcept;
bool operator<(const Directory &) const noexcept;
};
struct Symlink {
struct Symlink
{
std::string target;
bool operator == (const Symlink &) const = default;
auto operator <=> (const Symlink &) const = default;
bool operator==(const Symlink &) const = default;
auto operator<=>(const Symlink &) const = default;
};
using Raw = std::variant<Regular, Directory, Symlink>;
@ -51,10 +55,12 @@ struct MemorySourceAccessor : virtual SourceAccessor
Stat lstat() const;
};
File root { File::Directory {} };
File root{File::Directory{}};
bool operator == (const MemorySourceAccessor &) const noexcept = default;
bool operator < (const MemorySourceAccessor & other) const noexcept {
bool operator==(const MemorySourceAccessor &) const noexcept = default;
bool operator<(const MemorySourceAccessor & other) const noexcept
{
return root < other.root;
}
@ -80,19 +86,18 @@ struct MemorySourceAccessor : virtual SourceAccessor
SourcePath addFile(CanonPath path, std::string && contents);
};
inline bool MemorySourceAccessor::File::Directory::operator == (
inline bool MemorySourceAccessor::File::Directory::operator==(
const MemorySourceAccessor::File::Directory &) const noexcept = default;
inline bool MemorySourceAccessor::File::Directory::operator < (
const MemorySourceAccessor::File::Directory & other) const noexcept
inline bool
MemorySourceAccessor::File::Directory::operator<(const MemorySourceAccessor::File::Directory & other) const noexcept
{
return contents < other.contents;
}
inline bool MemorySourceAccessor::File::operator == (
const MemorySourceAccessor::File &) const noexcept = default;
inline std::strong_ordering MemorySourceAccessor::File::operator <=> (
const MemorySourceAccessor::File &) const noexcept = default;
inline bool MemorySourceAccessor::File::operator==(const MemorySourceAccessor::File &) const noexcept = default;
inline std::strong_ordering
MemorySourceAccessor::File::operator<=>(const MemorySourceAccessor::File &) const noexcept = default;
/**
* Write to a `MemorySourceAccessor` at the given path
@ -101,15 +106,16 @@ struct MemorySink : FileSystemObjectSink
{
MemorySourceAccessor & dst;
MemorySink(MemorySourceAccessor & dst) : dst(dst) { }
MemorySink(MemorySourceAccessor & dst)
: dst(dst)
{
}
void createDirectory(const CanonPath & path) override;
void createRegularFile(
const CanonPath & path,
std::function<void(CreateRegularFileSink &)>) override;
void createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)>) override;
void createSymlink(const CanonPath & path, const std::string & target) override;
};
}
} // namespace nix

View file

@ -79,4 +79,4 @@ struct MuxablePipePollState
std::function<void(Descriptor fd)> handleEOF);
};
}
} // namespace nix

View file

@ -49,4 +49,4 @@ OsString string_to_os_string(std::string_view s);
# define OS_STR(s) L##s
#endif
}
} // namespace nix

View file

@ -29,7 +29,7 @@ namespace nix {
* Here, the Connection object referenced by conn is automatically
* returned to the pool when conn goes out of scope.
*/
template <class R>
template<class R>
class Pool
{
public:
@ -63,7 +63,8 @@ private:
public:
Pool(size_t max = std::numeric_limits<size_t>::max(),
Pool(
size_t max = std::numeric_limits<size_t>::max(),
const Factory & factory = []() { return make_ref<R>(); },
const Validator & validator = [](ref<R> r) { return true; })
: factory(factory)
@ -106,7 +107,11 @@ public:
friend Pool;
Handle(Pool & pool, std::shared_ptr<R> r) : pool(pool), r(r) { }
Handle(Pool & pool, std::shared_ptr<R> r)
: pool(pool)
, r(r)
{
}
public:
// NOTE: Copying std::shared_ptr and calling a .reset() on it is always noexcept.
@ -123,7 +128,8 @@ public:
~Handle()
{
if (!r) return;
if (!r)
return;
{
auto state_(pool.state.lock());
if (!bad)
@ -134,10 +140,20 @@ public:
pool.wakeup.notify_one();
}
R * operator -> () { return &*r; }
R & operator * () { return *r; }
R * operator->()
{
return &*r;
}
void markBad() { bad = true; }
R & operator*()
{
return *r;
}
void markBad()
{
bad = true;
}
};
Handle get()
@ -197,4 +213,4 @@ public:
}
};
}
} // namespace nix

View file

@ -49,7 +49,7 @@ public:
inline PosIdx noPos = {};
}
} // namespace nix
namespace std {

View file

@ -97,4 +97,4 @@ public:
}
};
}
} // namespace nix

View file

@ -21,34 +21,58 @@ struct Pos
uint32_t line = 0;
uint32_t column = 0;
struct Stdin {
struct Stdin
{
ref<std::string> source;
bool operator==(const Stdin & rhs) const noexcept
{ return *source == *rhs.source; }
{
return *source == *rhs.source;
}
std::strong_ordering operator<=>(const Stdin & rhs) const noexcept
{ return *source <=> *rhs.source; }
{
return *source <=> *rhs.source;
}
};
struct String {
struct String
{
ref<std::string> source;
bool operator==(const String & rhs) const noexcept
{ return *source == *rhs.source; }
{
return *source == *rhs.source;
}
std::strong_ordering operator<=>(const String & rhs) const noexcept
{ return *source <=> *rhs.source; }
{
return *source <=> *rhs.source;
}
};
typedef std::variant<std::monostate, Stdin, String, SourcePath> Origin;
Origin origin = std::monostate();
Pos() { }
Pos() {}
Pos(uint32_t line, uint32_t column, Origin origin)
: line(line), column(column), origin(origin) { }
: line(line)
, column(column)
, origin(origin)
{
}
Pos(Pos & other) = default;
Pos(const Pos & other) = default;
Pos(Pos && other) = default;
Pos(const Pos * other);
explicit operator bool() const { return line > 0; }
explicit operator bool() const
{
return line > 0;
}
/* TODO: Why std::shared_ptr<Pos> and not std::shared_ptr<const Pos>? */
operator std::shared_ptr<Pos>() const;
@ -72,39 +96,60 @@ struct Pos
*/
std::optional<SourcePath> getSourcePath() const;
struct LinesIterator {
struct LinesIterator
{
using difference_type = size_t;
using value_type = std::string_view;
using reference = const std::string_view &;
using pointer = const std::string_view *;
using iterator_category = std::input_iterator_tag;
LinesIterator(): pastEnd(true) {}
explicit LinesIterator(std::string_view input): input(input), pastEnd(input.empty()) {
LinesIterator()
: pastEnd(true)
{
}
explicit LinesIterator(std::string_view input)
: input(input)
, pastEnd(input.empty())
{
if (!pastEnd)
bump(true);
}
LinesIterator & operator++() {
LinesIterator & operator++()
{
bump(false);
return *this;
}
LinesIterator operator++(int) {
LinesIterator operator++(int)
{
auto result = *this;
++*this;
return result;
}
reference operator*() const { return curLine; }
pointer operator->() const { return &curLine; }
reference operator*() const
{
return curLine;
}
bool operator!=(const LinesIterator & other) const {
pointer operator->() const
{
return &curLine;
}
bool operator!=(const LinesIterator & other) const
{
return !(*this == other);
}
bool operator==(const LinesIterator & other) const {
bool operator==(const LinesIterator & other) const
{
return (pastEnd && other.pastEnd)
|| (std::forward_as_tuple(input.size(), input.data())
== std::forward_as_tuple(other.input.size(), other.input.data()));
|| (std::forward_as_tuple(input.size(), input.data())
== std::forward_as_tuple(other.input.size(), other.input.data()));
}
private:
@ -117,4 +162,4 @@ struct Pos
std::ostream & operator<<(std::ostream & str, const Pos & pos);
}
} // namespace nix

View file

@ -27,10 +27,7 @@ struct PosixSourceAccessor : virtual SourceAccessor
*/
time_t mtime = 0;
void readFile(
const CanonPath & path,
Sink & sink,
std::function<void(uint64_t)> sizeCallback) override;
void readFile(const CanonPath & path, Sink & sink, std::function<void(uint64_t)> sizeCallback) override;
bool pathExists(const CanonPath & path) override;
@ -81,4 +78,4 @@ private:
std::filesystem::path makeAbsPath(const CanonPath & path);
};
}
} // namespace nix

View file

@ -37,11 +37,11 @@ public:
Pid();
#ifndef _WIN32
Pid(pid_t pid);
void operator =(pid_t pid);
void operator=(pid_t pid);
operator pid_t();
#else
Pid(AutoCloseFD pid);
void operator =(AutoCloseFD pid);
void operator=(AutoCloseFD pid);
#endif
~Pid();
int kill();
@ -55,7 +55,6 @@ public:
#endif
};
#ifndef _WIN32
/**
* Kill all processes running under the specified uid by sending them
@ -64,7 +63,6 @@ public:
void killUser(uid_t uid);
#endif
/**
* Fork a process that runs the given function, and return the child
* pid to the caller.
@ -89,9 +87,12 @@ pid_t startProcess(std::function<void()> fun, const ProcessOptions & options = P
* Run a program and return its stdout in a string (i.e., like the
* shell backtick operator).
*/
std::string runProgram(Path program, bool lookupPath = false,
std::string runProgram(
Path program,
bool lookupPath = false,
const Strings & args = Strings(),
const std::optional<std::string> & input = {}, bool isInteractive = false);
const std::optional<std::string> & input = {},
bool isInteractive = false);
struct RunOptions
{
@ -115,16 +116,17 @@ std::pair<int, std::string> runProgram(RunOptions && options);
void runProgram2(const RunOptions & options);
class ExecError : public Error
{
public:
int status;
template<typename... Args>
ExecError(int status, const Args & ... args)
: Error(args...), status(status)
{ }
ExecError(int status, const Args &... args)
: Error(args...)
, status(status)
{
}
};
/**
@ -135,4 +137,4 @@ std::string statusToString(int status);
bool statusOk(int status);
}
} // namespace nix

View file

@ -32,17 +32,17 @@ public:
throw std::invalid_argument("null pointer cast to ref");
}
T* operator ->() const
T * operator->() const
{
return &*p;
}
T& operator *() const
T & operator*() const
{
return *p;
}
operator std::shared_ptr<T> () const
operator std::shared_ptr<T>() const
{
return p;
}
@ -65,22 +65,22 @@ public:
}
template<typename T2>
operator ref<T2> () const
operator ref<T2>() const
{
return ref<T2>((std::shared_ptr<T2>) p);
}
bool operator == (const ref<T> & other) const
bool operator==(const ref<T> & other) const
{
return p == other.p;
}
bool operator != (const ref<T> & other) const
bool operator!=(const ref<T> & other) const
{
return p != other.p;
}
auto operator <=> (const ref<T> & other) const
auto operator<=>(const ref<T> & other) const
{
return p <=> other.p;
}
@ -88,17 +88,14 @@ public:
private:
template<typename T2, typename... Args>
friend ref<T2>
make_ref(Args&&... args);
friend ref<T2> make_ref(Args &&... args);
};
template<typename T, typename... Args>
inline ref<T>
make_ref(Args&&... args)
inline ref<T> make_ref(Args &&... args)
{
auto p = std::make_shared<T>(std::forward<Args>(args)...);
return ref<T>(p);
}
}
} // namespace nix

View file

@ -14,13 +14,17 @@ class RefScanSink : public Sink
public:
RefScanSink(StringSet && hashes) : hashes(hashes)
{ }
RefScanSink(StringSet && hashes)
: hashes(hashes)
{
}
StringSet & getResult()
{ return seen; }
{
return seen;
}
void operator () (std::string_view data) override;
void operator()(std::string_view data) override;
};
struct RewritingSink : Sink
@ -36,7 +40,7 @@ struct RewritingSink : Sink
RewritingSink(const std::string & from, const std::string & to, Sink & nextSink);
RewritingSink(const StringMap & rewrites, Sink & nextSink);
void operator () (std::string_view data) override;
void operator()(std::string_view data) override;
void flush();
};
@ -48,9 +52,9 @@ struct HashModuloSink : AbstractHashSink
HashModuloSink(HashAlgorithm ha, const std::string & modulus);
void operator () (std::string_view data) override;
void operator()(std::string_view data) override;
HashResult finish() override;
};
}
} // namespace nix

View file

@ -31,4 +31,4 @@ static inline std::string list(std::string_view a)
return ss.str();
}
}
} // namespace nix::regex

View file

@ -1,4 +1,5 @@
#pragma once
///@file
namespace nix {

View file

@ -8,19 +8,25 @@
#include "nix/util/util.hh"
#include "nix/util/file-descriptor.hh"
namespace boost::context { struct stack_context; }
namespace boost::context {
struct stack_context;
}
namespace nix {
/**
* Abstract destination of binary data.
*/
struct Sink
{
virtual ~Sink() { }
virtual void operator () (std::string_view data) = 0;
virtual bool good() { return true; }
virtual ~Sink() {}
virtual void operator()(std::string_view data) = 0;
virtual bool good()
{
return true;
}
};
/**
@ -28,17 +34,14 @@ struct Sink
*/
struct NullSink : Sink
{
void operator () (std::string_view data) override
{ }
void operator()(std::string_view data) override {}
};
struct FinishSink : virtual Sink
{
virtual void finish() = 0;
};
/**
* A buffered abstract sink. Warning: a BufferedSink should not be
* used from multiple threads concurrently.
@ -49,9 +52,13 @@ struct BufferedSink : virtual Sink
std::unique_ptr<char[]> buffer;
BufferedSink(size_t bufSize = 32 * 1024)
: bufSize(bufSize), bufPos(0), buffer(nullptr) { }
: bufSize(bufSize)
, bufPos(0)
, buffer(nullptr)
{
}
void operator () (std::string_view data) override;
void operator()(std::string_view data) override;
void flush();
@ -60,21 +67,20 @@ protected:
virtual void writeUnbuffered(std::string_view data) = 0;
};
/**
* Abstract source of binary data.
*/
struct Source
{
virtual ~Source() { }
virtual ~Source() {}
/**
* Store exactly len bytes in the buffer pointed to by data.
* It blocks until all the requested data is available, or throws
* an error if it is not going to be available.
*/
void operator () (char * data, size_t len);
void operator () (std::string_view data);
void operator()(char * data, size_t len);
void operator()(std::string_view data);
/**
* Store up to len in the buffer pointed to by data, and
@ -83,14 +89,16 @@ struct Source
*/
virtual size_t read(char * data, size_t len) = 0;
virtual bool good() { return true; }
virtual bool good()
{
return true;
}
void drainInto(Sink & sink);
std::string drain();
};
/**
* A buffered abstract source. Warning: a BufferedSource should not be
* used from multiple threads concurrently.
@ -101,7 +109,12 @@ struct BufferedSource : Source
std::unique_ptr<char[]> buffer;
BufferedSource(size_t bufSize = 32 * 1024)
: bufSize(bufSize), bufPosIn(0), bufPosOut(0), buffer(nullptr) { }
: bufSize(bufSize)
, bufPosIn(0)
, bufPosOut(0)
, buffer(nullptr)
{
}
size_t read(char * data, size_t len) override;
@ -117,7 +130,6 @@ protected:
virtual size_t readUnbuffered(char * data, size_t len) = 0;
};
/**
* A sink that writes data to a file descriptor.
*/
@ -126,9 +138,17 @@ struct FdSink : BufferedSink
Descriptor fd;
size_t written = 0;
FdSink() : fd(INVALID_DESCRIPTOR) { }
FdSink(Descriptor fd) : fd(fd) { }
FdSink(FdSink&&) = default;
FdSink()
: fd(INVALID_DESCRIPTOR)
{
}
FdSink(Descriptor fd)
: fd(fd)
{
}
FdSink(FdSink &&) = default;
FdSink & operator=(FdSink && s)
{
@ -149,7 +169,6 @@ private:
bool _good = true;
};
/**
* A source that reads data from a file descriptor.
*/
@ -159,8 +178,16 @@ struct FdSource : BufferedSource
size_t read = 0;
BackedStringView endOfFileError{"unexpected end-of-file"};
FdSource() : fd(INVALID_DESCRIPTOR) { }
FdSource(Descriptor fd) : fd(fd) { }
FdSource()
: fd(INVALID_DESCRIPTOR)
{
}
FdSource(Descriptor fd)
: fd(fd)
{
}
FdSource(FdSource &&) = default;
FdSource & operator=(FdSource && s) = default;
@ -179,22 +206,24 @@ private:
bool _good = true;
};
/**
* A sink that writes data to a string.
*/
struct StringSink : Sink
{
std::string s;
StringSink() { }
StringSink() {}
explicit StringSink(const size_t reservedSize)
{
s.reserve(reservedSize);
s.reserve(reservedSize);
};
StringSink(std::string && s) : s(std::move(s)) { };
void operator () (std::string_view data) override;
};
StringSink(std::string && s)
: s(std::move(s)) {};
void operator()(std::string_view data) override;
};
/**
* A source that reads data from a string.
@ -208,28 +237,41 @@ struct StringSource : Source
// from std::string -> std::string_view occurs when the string is passed
// by rvalue.
StringSource(std::string &&) = delete;
StringSource(std::string_view s) : s(s), pos(0) { }
StringSource(const std::string& str): StringSource(std::string_view(str)) {}
StringSource(std::string_view s)
: s(s)
, pos(0)
{
}
StringSource(const std::string & str)
: StringSource(std::string_view(str))
{
}
size_t read(char * data, size_t len) override;
};
/**
* A sink that writes all incoming data to two other sinks.
*/
struct TeeSink : Sink
{
Sink & sink1, & sink2;
TeeSink(Sink & sink1, Sink & sink2) : sink1(sink1), sink2(sink2) { }
virtual void operator () (std::string_view data) override
Sink &sink1, &sink2;
TeeSink(Sink & sink1, Sink & sink2)
: sink1(sink1)
, sink2(sink2)
{
}
virtual void operator()(std::string_view data) override
{
sink1(data);
sink2(data);
}
};
/**
* Adapter class of a Source that saves all data read to a sink.
*/
@ -237,8 +279,13 @@ struct TeeSource : Source
{
Source & orig;
Sink & sink;
TeeSource(Source & orig, Sink & sink)
: orig(orig), sink(sink) { }
: orig(orig)
, sink(sink)
{
}
size_t read(char * data, size_t len) override
{
size_t n = orig.read(data, len);
@ -254,8 +301,13 @@ struct SizedSource : Source
{
Source & orig;
size_t remain;
SizedSource(Source & orig, size_t size)
: orig(orig), remain(size) { }
: orig(orig)
, remain(size)
{
}
size_t read(char * data, size_t len) override
{
if (this->remain <= 0) {
@ -289,7 +341,7 @@ struct LengthSink : Sink
{
uint64_t length = 0;
void operator () (std::string_view data) override
void operator()(std::string_view data) override
{
length += data.size();
}
@ -302,8 +354,10 @@ struct LengthSource : Source
{
Source & next;
LengthSource(Source & next) : next(next)
{ }
LengthSource(Source & next)
: next(next)
{
}
uint64_t total = 0;
@ -324,15 +378,17 @@ struct LambdaSink : Sink
lambda_t lambda;
LambdaSink(const lambda_t & lambda) : lambda(lambda) { }
LambdaSink(const lambda_t & lambda)
: lambda(lambda)
{
}
void operator () (std::string_view data) override
void operator()(std::string_view data) override
{
lambda(data);
}
};
/**
* Convert a function into a source.
*/
@ -342,7 +398,10 @@ struct LambdaSource : Source
lambda_t lambda;
LambdaSource(const lambda_t & lambda) : lambda(lambda) { }
LambdaSource(const lambda_t & lambda)
: lambda(lambda)
{
}
size_t read(char * data, size_t len) override
{
@ -356,11 +415,14 @@ struct LambdaSource : Source
*/
struct ChainSource : Source
{
Source & source1, & source2;
Source &source1, &source2;
bool useSecond = false;
ChainSource(Source & s1, Source & s2)
: source1(s1), source2(s2)
{ }
: source1(s1)
, source2(s2)
{
}
size_t read(char * data, size_t len) override;
};
@ -372,16 +434,12 @@ std::unique_ptr<FinishSink> sourceToSink(std::function<void(Source &)> fun);
* Source executes the function as a coroutine.
*/
std::unique_ptr<Source> sinkToSource(
std::function<void(Sink &)> fun,
std::function<void()> eof = []() {
throw EndOfFile("coroutine has finished");
});
std::function<void(Sink &)> fun, std::function<void()> eof = []() { throw EndOfFile("coroutine has finished"); });
void writePadding(size_t len, Sink & sink);
void writeString(std::string_view s, Sink & sink);
inline Sink & operator << (Sink & sink, uint64_t n)
inline Sink & operator<<(Sink & sink, uint64_t n)
{
unsigned char buf[8];
buf[0] = n & 0xff;
@ -396,15 +454,13 @@ inline Sink & operator << (Sink & sink, uint64_t n)
return sink;
}
Sink & operator << (Sink & in, const Error & ex);
Sink & operator << (Sink & sink, std::string_view s);
Sink & operator << (Sink & sink, const Strings & s);
Sink & operator << (Sink & sink, const StringSet & s);
Sink & operator<<(Sink & in, const Error & ex);
Sink & operator<<(Sink & sink, std::string_view s);
Sink & operator<<(Sink & sink, const Strings & s);
Sink & operator<<(Sink & sink, const StringSet & s);
MakeError(SerialisationError, Error);
template<typename T>
T readNum(Source & source)
{
@ -419,35 +475,33 @@ T readNum(Source & source)
return (T) n;
}
inline unsigned int readInt(Source & source)
{
return readNum<unsigned int>(source);
}
inline uint64_t readLongLong(Source & source)
{
return readNum<uint64_t>(source);
}
void readPadding(size_t len, Source & source);
size_t readString(char * buf, size_t max, Source & source);
std::string readString(Source & source, size_t max = std::numeric_limits<size_t>::max());
template<class T> T readStrings(Source & source);
template<class T>
T readStrings(Source & source);
Source & operator >> (Source & in, std::string & s);
Source & operator>>(Source & in, std::string & s);
template<typename T>
Source & operator >> (Source & in, T & n)
Source & operator>>(Source & in, T & n)
{
n = readNum<T>(in);
return in;
}
template<typename T>
Source & operator >> (Source & in, bool & b)
Source & operator>>(Source & in, bool & b)
{
b = readNum<uint64_t>(in);
return in;
@ -455,7 +509,6 @@ Source & operator >> (Source & in, bool & b)
Error readError(Source & source);
/**
* An adapter that converts a std::basic_istream into a source.
*/
@ -465,7 +518,8 @@ struct StreamToSourceAdapter : Source
StreamToSourceAdapter(std::shared_ptr<std::basic_istream<char>> istream)
: istream(istream)
{ }
{
}
size_t read(char * data, size_t len) override
{
@ -480,7 +534,6 @@ 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,
@ -496,8 +549,10 @@ struct FramedSource : Source
std::vector<char> pending;
size_t pos = 0;
FramedSource(Source & from) : from(from)
{ }
FramedSource(Source & from)
: from(from)
{
}
~FramedSource()
{
@ -505,7 +560,8 @@ struct FramedSource : Source
if (!eof) {
while (true) {
auto n = readInt(from);
if (!n) break;
if (!n)
break;
std::vector<char> data(n);
from(data.data(), n);
}
@ -517,7 +573,8 @@ struct FramedSource : Source
size_t read(char * data, size_t len) override
{
if (eof) throw EndOfFile("reached end of FramedSource");
if (eof)
throw EndOfFile("reached end of FramedSource");
if (pos >= pending.size()) {
size_t len = readInt(from);
@ -549,8 +606,10 @@ struct FramedSink : nix::BufferedSink
std::function<void()> checkError;
FramedSink(BufferedSink & to, std::function<void()> && checkError)
: to(to), checkError(checkError)
{ }
: to(to)
, checkError(checkError)
{
}
~FramedSink()
{
@ -572,4 +631,4 @@ struct FramedSink : nix::BufferedSink
};
};
}
} // namespace nix

View file

@ -41,10 +41,9 @@ inline void checkInterrupt();
*/
MakeError(Interrupted, BaseError);
struct InterruptCallback
{
virtual ~InterruptCallback() { };
virtual ~InterruptCallback() {};
};
/**
@ -53,8 +52,7 @@ struct InterruptCallback
*
* @note Does nothing on Windows
*/
std::unique_ptr<InterruptCallback> createInterruptCallback(
std::function<void()> callback);
std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()> callback);
/**
* A RAII class that causes the current thread to receive SIGUSR1 when
@ -65,6 +63,6 @@ std::unique_ptr<InterruptCallback> createInterruptCallback(
*/
struct ReceiveInterrupts;
}
} // namespace nix
#include "nix/util/signals-impl.hh"

View file

@ -15,7 +15,8 @@ namespace nix {
* <name>:<key/signature-in-Base64>
* ```
*/
struct BorrowedCryptoValue {
struct BorrowedCryptoValue
{
std::string_view name;
std::string_view payload;
@ -45,7 +46,10 @@ protected:
Key(std::string_view s, bool sensitiveValue);
Key(std::string_view name, std::string && key)
: name(name), key(std::move(key)) { }
: name(name)
, key(std::move(key))
{
}
};
struct PublicKey;
@ -65,7 +69,9 @@ struct SecretKey : Key
private:
SecretKey(std::string_view name, std::string && key)
: Key(name, std::move(key)) { }
: Key(name, std::move(key))
{
}
};
struct PublicKey : Key
@ -89,7 +95,9 @@ struct PublicKey : Key
private:
PublicKey(std::string_view name, std::string && key)
: Key(name, std::move(key)) { }
: Key(name, std::move(key))
{
}
friend struct SecretKey;
};
@ -104,4 +112,4 @@ typedef std::map<std::string, PublicKey> PublicKeys;
*/
bool verifyDetached(std::string_view data, std::string_view sig, const PublicKeys & publicKeys);
}
} // namespace nix

View file

@ -37,7 +37,7 @@ struct Signer
virtual const PublicKey & getPublicKey() = 0;
};
using Signers = std::map<std::string, Signer*>;
using Signers = std::map<std::string, Signer *>;
/**
* Local signer
@ -58,4 +58,4 @@ private:
PublicKey publicKey;
};
}
} // namespace nix

View file

@ -46,8 +46,7 @@ struct SourceAccessor : std::enable_shared_from_this<SourceAccessor>
SourceAccessor();
virtual ~SourceAccessor()
{ }
virtual ~SourceAccessor() {}
/**
* Return the contents of a file as a string.
@ -72,24 +71,28 @@ struct SourceAccessor : std::enable_shared_from_this<SourceAccessor>
* @note subclasses of `SourceAccessor` need to implement at least
* one of the `readFile()` variants.
*/
virtual void readFile(
const CanonPath & path,
Sink & sink,
std::function<void(uint64_t)> sizeCallback = [](uint64_t size){});
virtual void
readFile(const CanonPath & path, Sink & sink, std::function<void(uint64_t)> sizeCallback = [](uint64_t size) {});
virtual bool pathExists(const CanonPath & path);
enum Type {
tRegular, tSymlink, tDirectory,
/**
Any other node types that may be encountered on the file system, such as device nodes, sockets, named pipe, and possibly even more exotic things.
tRegular,
tSymlink,
tDirectory,
/**
Any other node types that may be encountered on the file system, such as device nodes, sockets, named pipe,
and possibly even more exotic things.
Responsible for `"unknown"` from `builtins.readFileType "/dev/null"`.
Responsible for `"unknown"` from `builtins.readFileType "/dev/null"`.
Unlike `DT_UNKNOWN`, this must not be used for deferring the lookup of types.
*/
tChar, tBlock, tSocket, tFifo,
tUnknown
Unlike `DT_UNKNOWN`, this must not be used for deferring the lookup of types.
*/
tChar,
tBlock,
tSocket,
tFifo,
tUnknown
};
struct Stat
@ -133,15 +136,10 @@ struct SourceAccessor : std::enable_shared_from_this<SourceAccessor>
virtual std::string readLink(const CanonPath & path) = 0;
virtual void dumpPath(
const CanonPath & path,
Sink & sink,
PathFilter & filter = defaultPathFilter);
virtual void dumpPath(const CanonPath & path, Sink & sink, PathFilter & filter = defaultPathFilter);
Hash hashPath(
const CanonPath & path,
PathFilter & filter = defaultPathFilter,
HashAlgorithm ha = HashAlgorithm::SHA256);
Hash
hashPath(const CanonPath & path, PathFilter & filter = defaultPathFilter, HashAlgorithm ha = HashAlgorithm::SHA256);
/**
* Return a corresponding path in the root filesystem, if
@ -149,14 +147,16 @@ struct SourceAccessor : std::enable_shared_from_this<SourceAccessor>
* materialized in the root filesystem.
*/
virtual std::optional<std::filesystem::path> getPhysicalPath(const CanonPath & path)
{ return std::nullopt; }
{
return std::nullopt;
}
bool operator == (const SourceAccessor & x) const
bool operator==(const SourceAccessor & x) const
{
return number == x.number;
}
auto operator <=> (const SourceAccessor & x) const
auto operator<=>(const SourceAccessor & x) const
{
return number <=> x.number;
}
@ -172,9 +172,7 @@ struct SourceAccessor : std::enable_shared_from_this<SourceAccessor>
* @param mode might only be a temporary solution for this.
* See the discussion in https://github.com/NixOS/nix/pull/9985.
*/
CanonPath resolveSymlinks(
const CanonPath & path,
SymlinkResolution mode = SymlinkResolution::Full);
CanonPath resolveSymlinks(const CanonPath & path, SymlinkResolution mode = SymlinkResolution::Full);
/**
* A string that uniquely represents the contents of this
@ -187,7 +185,9 @@ struct SourceAccessor : std::enable_shared_from_this<SourceAccessor>
* tree, if available.
*/
virtual std::optional<time_t> getLastModified()
{ return std::nullopt; }
{
return std::nullopt;
}
};
/**
@ -222,4 +222,4 @@ ref<SourceAccessor> makeMountedSourceAccessor(std::map<CanonPath, ref<SourceAcce
*/
ref<SourceAccessor> makeUnionSourceAccessor(std::vector<ref<SourceAccessor>> && accessors);
}
} // namespace nix

View file

@ -26,7 +26,8 @@ struct SourcePath
SourcePath(ref<SourceAccessor> accessor, CanonPath path = CanonPath::root)
: accessor(std::move(accessor))
, path(std::move(path))
{ }
{
}
std::string_view baseName() const;
@ -42,15 +43,15 @@ struct SourcePath
*/
std::string readFile() const;
void readFile(
Sink & sink,
std::function<void(uint64_t)> sizeCallback = [](uint64_t size){}) const
{ return accessor->readFile(path, sink, sizeCallback); }
void readFile(Sink & sink, std::function<void(uint64_t)> sizeCallback = [](uint64_t size) {}) const
{
return accessor->readFile(path, sink, sizeCallback);
}
/**
* Return whether this `SourcePath` denotes a file (of any type)
* that exists
*/
*/
bool pathExists() const;
/**
@ -80,9 +81,7 @@ struct SourcePath
/**
* Dump this `SourcePath` to `sink` as a NAR archive.
*/
void dumpPath(
Sink & sink,
PathFilter & filter = defaultPathFilter) const;
void dumpPath(Sink & sink, PathFilter & filter = defaultPathFilter) const;
/**
* Return the location of this path in the "real" filesystem, if
@ -95,14 +94,14 @@ struct SourcePath
/**
* Append a `CanonPath` to this path.
*/
SourcePath operator / (const CanonPath & x) const;
SourcePath operator/(const CanonPath & x) const;
/**
* Append a single component `c` to this path. `c` must not
* contain a slash. A slash is implicitly added between this path
* and `c`.
*/
SourcePath operator / (std::string_view c) const;
SourcePath operator/(std::string_view c) const;
bool operator==(const SourcePath & x) const noexcept;
std::strong_ordering operator<=>(const SourcePath & x) const noexcept;
@ -110,8 +109,7 @@ struct SourcePath
/**
* Convenience wrapper around `SourceAccessor::resolveSymlinks()`.
*/
SourcePath resolveSymlinks(
SymlinkResolution mode = SymlinkResolution::Full) const
SourcePath resolveSymlinks(SymlinkResolution mode = SymlinkResolution::Full) const
{
return {accessor, accessor->resolveSymlinks(path, mode)};
}
@ -119,9 +117,9 @@ struct SourcePath
friend class std::hash<nix::SourcePath>;
};
std::ostream & operator << (std::ostream & str, const SourcePath & path);
std::ostream & operator<<(std::ostream & str, const SourcePath & path);
}
} // namespace nix
template<>
struct std::hash<nix::SourcePath>

View file

@ -14,23 +14,25 @@ namespace nix {
* 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) {
static inline std::optional<std::string_view> splitPrefixTo(std::string_view & string, char separator)
{
auto sepInstance = string.find(separator);
if (sepInstance != std::string_view::npos) {
auto prefix = string.substr(0, sepInstance);
string.remove_prefix(sepInstance+1);
string.remove_prefix(sepInstance + 1);
return prefix;
}
return std::nullopt;
}
static inline bool splitPrefix(std::string_view & string, std::string_view prefix) {
static inline bool splitPrefix(std::string_view & string, std::string_view prefix)
{
bool res = hasPrefix(string, prefix);
if (res)
string.remove_prefix(prefix.length());
return res;
}
}
} // namespace nix

View file

@ -95,4 +95,4 @@ extern template std::string dropEmptyInitThenConcatStringsSep(std::string_view,
* Arguments that need to be passed to ssh with spaces in them.
*/
std::list<std::string> shellSplitString(std::string_view s);
}
} // namespace nix

View file

@ -11,7 +11,8 @@ int levenshteinDistance(std::string_view first, std::string_view second);
/**
* A potential suggestion for the cli interface.
*/
class Suggestion {
class Suggestion
{
public:
/// The smaller the better
int distance;
@ -19,27 +20,22 @@ public:
std::string to_string() const;
bool operator ==(const Suggestion &) const = default;
auto operator <=>(const Suggestion &) const = default;
bool operator==(const Suggestion &) const = default;
auto operator<=>(const Suggestion &) const = default;
};
class Suggestions {
class Suggestions
{
public:
std::set<Suggestion> suggestions;
std::string to_string() const;
Suggestions trim(
int limit = 5,
int maxDistance = 2
) const;
Suggestions trim(int limit = 5, int maxDistance = 2) const;
static Suggestions bestMatches (
const std::set<std::string> & allMatches,
std::string_view query
);
static Suggestions bestMatches(const std::set<std::string> & allMatches, std::string_view query);
Suggestions& operator+=(const Suggestions & other);
Suggestions & operator+=(const Suggestions & other);
};
std::ostream & operator<<(std::ostream & str, const Suggestion &);
@ -49,18 +45,19 @@ std::ostream & operator<<(std::ostream & str, const Suggestions &);
* Either a value of type `T`, or some suggestions
*/
template<typename T>
class OrSuggestions {
class OrSuggestions
{
public:
using Raw = std::variant<T, Suggestions>;
Raw raw;
T* operator ->()
T * operator->()
{
return &**this;
}
T& operator *()
T & operator*()
{
return std::get<T>(raw);
}
@ -100,7 +97,6 @@ public:
else
return noSuggestions;
}
};
}
} // namespace nix

View file

@ -36,9 +36,17 @@ private:
public:
SyncBase() { }
SyncBase(const T & data) : data(data) { }
SyncBase(T && data) noexcept : data(std::move(data)) { }
SyncBase() {}
SyncBase(const T & data)
: data(data)
{
}
SyncBase(T && data) noexcept
: data(std::move(data))
{
}
template<class L>
class Lock
@ -47,11 +55,22 @@ public:
SyncBase * s;
L lk;
friend SyncBase;
Lock(SyncBase * s) : s(s), lk(s->mutex) { }
Lock(SyncBase * s)
: s(s)
, lk(s->mutex)
{
}
public:
Lock(Lock && l) : s(l.s) { unreachable(); }
Lock(Lock && l)
: s(l.s)
{
unreachable();
}
Lock(const Lock & l) = delete;
~Lock() { }
~Lock() {}
void wait(std::condition_variable & cv)
{
@ -60,25 +79,22 @@ public:
}
template<class Rep, class Period>
std::cv_status wait_for(std::condition_variable & cv,
const std::chrono::duration<Rep, Period> & duration)
std::cv_status wait_for(std::condition_variable & cv, const std::chrono::duration<Rep, Period> & duration)
{
assert(s);
return cv.wait_for(lk, duration);
}
template<class Rep, class Period, class Predicate>
bool wait_for(std::condition_variable & cv,
const std::chrono::duration<Rep, Period> & duration,
Predicate pred)
bool wait_for(std::condition_variable & cv, const std::chrono::duration<Rep, Period> & duration, Predicate pred)
{
assert(s);
return cv.wait_for(lk, duration, pred);
}
template<class Clock, class Duration>
std::cv_status wait_until(std::condition_variable & cv,
const std::chrono::time_point<Clock, Duration> & duration)
std::cv_status
wait_until(std::condition_variable & cv, const std::chrono::time_point<Clock, Duration> & duration)
{
assert(s);
return cv.wait_until(lk, duration);
@ -87,32 +103,53 @@ public:
struct WriteLock : Lock<WL>
{
T * operator -> () { return &WriteLock::s->data; }
T & operator * () { return WriteLock::s->data; }
T * operator->()
{
return &WriteLock::s->data;
}
T & operator*()
{
return WriteLock::s->data;
}
};
/**
* Acquire write (exclusive) access to the inner value.
*/
WriteLock lock() { return WriteLock(this); }
WriteLock lock()
{
return WriteLock(this);
}
struct ReadLock : Lock<RL>
{
const T * operator -> () { return &ReadLock::s->data; }
const T & operator * () { return ReadLock::s->data; }
const T * operator->()
{
return &ReadLock::s->data;
}
const T & operator*()
{
return ReadLock::s->data;
}
};
/**
* Acquire read access to the inner value. When using
* `std::shared_mutex`, this will use a shared lock.
*/
ReadLock readLock() const { return ReadLock(const_cast<SyncBase *>(this)); }
ReadLock readLock() const
{
return ReadLock(const_cast<SyncBase *>(this));
}
};
template<class T>
using Sync = SyncBase<T, std::mutex, std::unique_lock<std::mutex>, std::unique_lock<std::mutex>>;
template<class T>
using SharedSync = SyncBase<T, std::shared_mutex, std::unique_lock<std::shared_mutex>, std::shared_lock<std::shared_mutex>>;
using SharedSync =
SyncBase<T, std::shared_mutex, std::unique_lock<std::shared_mutex>, std::shared_lock<std::shared_mutex>>;
}
} // namespace nix

View file

@ -43,4 +43,4 @@ void unpackTarfile(const std::filesystem::path & tarFile, const std::filesystem:
time_t unpackTarfileToSink(TarArchive & archive, ExtendedFileSystemObjectSink & parseSink);
}
} // namespace nix

View file

@ -18,9 +18,8 @@ bool isTTY();
* included in the character count. Also, tabs are expanded to
* spaces.
*/
std::string filterANSIEscapes(std::string_view s,
bool filterAll = false,
unsigned int width = std::numeric_limits<unsigned int>::max());
std::string filterANSIEscapes(
std::string_view s, bool filterAll = false, unsigned int width = std::numeric_limits<unsigned int>::max());
/**
* Recalculate the window size, updating a global variable.
@ -37,4 +36,4 @@ void updateWindowSize();
*/
std::pair<unsigned short, unsigned short> getWindowSize();
}
} // namespace nix

View file

@ -87,7 +87,8 @@ void processGraph(
std::function<std::set<T>(const T &)> getEdges,
std::function<void(const T &)> processNode)
{
struct Graph {
struct Graph
{
std::set<T> left;
std::map<T, std::set<T>> refs, rrefs;
};
@ -101,7 +102,6 @@ void processGraph(
ThreadPool pool;
worker = [&](const T & node) {
{
auto graph(graph_.lock());
auto i = graph->refs.find(node);
@ -110,22 +110,21 @@ void processGraph(
goto doWork;
}
getRefs:
{
auto refs = getEdges(node);
refs.erase(node);
getRefs: {
auto refs = getEdges(node);
refs.erase(node);
{
auto graph(graph_.lock());
for (auto & ref : refs)
if (graph->left.count(ref)) {
graph->refs[node].insert(ref);
graph->rrefs[ref].insert(node);
}
if (graph->refs[node].empty())
goto doWork;
}
{
auto graph(graph_.lock());
for (auto & ref : refs)
if (graph->left.count(ref)) {
graph->refs[node].insert(ref);
graph->rrefs[ref].insert(node);
}
if (graph->refs[node].empty())
goto doWork;
}
}
return;
@ -167,4 +166,4 @@ void processGraph(
throw Error("graph processing incomplete (cyclic reference?)");
}
}
} // namespace nix

View file

@ -6,9 +6,10 @@
namespace nix {
template<typename T>
std::vector<T> topoSort(std::set<T> items,
std::function<std::set<T>(const T &)> getChildren,
std::function<Error(const T &, const T &)> makeCycleError)
std::vector<T> topoSort(
std::set<T> items,
std::function<std::set<T>(const T &)> getChildren,
std::function<Error(const T &, const T &)> makeCycleError)
{
std::vector<T> sorted;
std::set<T> visited, parents;
@ -16,9 +17,11 @@ std::vector<T> topoSort(std::set<T> items,
std::function<void(const T & path, const T * parent)> dfsVisit;
dfsVisit = [&](const T & path, const T * parent) {
if (parents.count(path)) throw makeCycleError(path, *parent);
if (parents.count(path))
throw makeCycleError(path, *parent);
if (!visited.insert(path).second) return;
if (!visited.insert(path).second)
return;
parents.insert(path);
std::set<T> references = getChildren(path);
@ -40,4 +43,4 @@ std::vector<T> topoSort(std::set<T> items,
return sorted;
}
}
} // namespace nix

View file

@ -1,7 +1,6 @@
#pragma once
///@file
#include <list>
#include <set>
#include <string>
@ -32,7 +31,10 @@ typedef std::vector<std::pair<std::string, std::string>> Headers;
template<typename T>
struct OnStartup
{
OnStartup(T && t) { t(); }
OnStartup(T && t)
{
t();
}
};
/**
@ -40,18 +42,18 @@ struct OnStartup
* cast to a bool in Attr.
*/
template<typename T>
struct Explicit {
struct Explicit
{
T t;
bool operator ==(const Explicit<T> & other) const = default;
bool operator==(const Explicit<T> & other) const = default;
bool operator <(const Explicit<T> & other) const
bool operator<(const Explicit<T> & other) const
{
return t < other.t;
}
};
/**
* This wants to be a little bit like rust's Cow type.
* Some parts of the evaluator benefit greatly from being able to reuse
@ -62,7 +64,8 @@ struct Explicit {
* since those can easily become ambiguous to the reader and can degrade
* into copying behaviour we want to avoid.
*/
class BackedStringView {
class BackedStringView
{
private:
std::variant<std::string, std::string_view> data;
@ -71,19 +74,38 @@ private:
* a pointer. Without this we'd need to store the view object
* even when we already own a string.
*/
class Ptr {
class Ptr
{
private:
std::string_view view;
public:
Ptr(std::string_view view): view(view) {}
const std::string_view * operator->() const { return &view; }
Ptr(std::string_view view)
: view(view)
{
}
const std::string_view * operator->() const
{
return &view;
}
};
public:
BackedStringView(std::string && s): data(std::move(s)) {}
BackedStringView(std::string_view sv): data(sv) {}
BackedStringView(std::string && s)
: data(std::move(s))
{
}
BackedStringView(std::string_view sv)
: data(sv)
{
}
template<size_t N>
BackedStringView(const char (& lit)[N]): data(std::string_view(lit)) {}
BackedStringView(const char (&lit)[N])
: data(std::string_view(lit))
{
}
BackedStringView(const BackedStringView &) = delete;
BackedStringView & operator=(const BackedStringView &) = delete;
@ -102,18 +124,18 @@ public:
std::string toOwned() &&
{
return isOwned()
? std::move(std::get<std::string>(data))
: std::string(std::get<std::string_view>(data));
return isOwned() ? std::move(std::get<std::string>(data)) : std::string(std::get<std::string_view>(data));
}
std::string_view operator*() const
{
return isOwned()
? std::get<std::string>(data)
: std::get<std::string_view>(data);
return isOwned() ? std::get<std::string>(data) : std::get<std::string_view>(data);
}
Ptr operator->() const
{
return Ptr(**this);
}
Ptr operator->() const { return Ptr(**this); }
};
}
} // namespace nix

View file

@ -80,4 +80,4 @@ void bind(Socket fd, const std::string & path);
*/
void connect(Socket fd, const std::string & path);
}
} // namespace nix

View file

@ -33,7 +33,8 @@ 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/functional/fetchGitRefs.sh for the full definition
const static std::string badGitRefRegexS = "//|^[./]|/\\.|\\.\\.|[[:cntrl:][:space:]:?^~\[]|\\\\|\\*|\\.lock$|\\.lock/|@\\{|[/.]$|^@$|^$";
const static std::string badGitRefRegexS =
"//|^[./]|/\\.|\\.\\.|[[:cntrl:][:space:]:?^~\[]|\\\\|\\*|\\.lock$|\\.lock/|@\\{|[/.]$|^@$|^$";
extern std::regex badGitRefRegex;
/// A Git revision (a SHA-1 commit hash).
@ -43,4 +44,4 @@ extern std::regex revRegex;
/// A ref or revision, or a ref followed by a revision.
const static std::string refAndOrRevRegex = "(?:(" + revRegexS + ")|(?:(" + refRegexS + ")(?:/(" + revRegexS + "))?))";
}
} // namespace nix

View file

@ -15,7 +15,7 @@ struct ParsedURL
std::string to_string() const;
bool operator ==(const ParsedURL & other) const noexcept;
bool operator==(const ParsedURL & other) const noexcept;
/**
* Remove `.` and `..` path elements.
@ -23,12 +23,12 @@ struct ParsedURL
ParsedURL canonicalise();
};
std::ostream & operator << (std::ostream & os, const ParsedURL & url);
std::ostream & operator<<(std::ostream & os, const ParsedURL & url);
MakeError(BadURL, Error);
std::string percentDecode(std::string_view in);
std::string percentEncode(std::string_view s, std::string_view keep="");
std::string percentEncode(std::string_view s, std::string_view keep = "");
std::map<std::string, std::string> decodeQuery(const std::string & query);
@ -44,7 +44,8 @@ ParsedURL parseURL(const std::string & url);
* For example git uses `git+https` to designate remotes using a Git
* protocol over http.
*/
struct ParsedUrlScheme {
struct ParsedUrlScheme
{
std::optional<std::string_view> application;
std::string_view transport;
};
@ -65,4 +66,4 @@ std::string fixGitURL(const std::string & url);
*/
bool isValidSchemeName(std::string_view scheme);
}
} // namespace nix

View file

@ -4,7 +4,7 @@
#include "nix/util/types.hh"
#ifndef _WIN32
# include <sys/types.h>
# include <sys/types.h>
#endif
namespace nix {
@ -59,7 +59,6 @@ Path createNixStateDir();
*/
std::string expandTilde(std::string_view path);
/**
* Is the current user UID 0 on Unix?
*
@ -67,4 +66,4 @@ std::string expandTilde(std::string_view path);
*/
bool isRootUser();
}
} // namespace nix

View file

@ -5,7 +5,6 @@
#include "nix/util/error.hh"
#include "nix/util/logging.hh"
#include <functional>
#include <map>
#include <sstream>
@ -24,10 +23,8 @@ void initLibUtil();
*/
std::vector<char *> stringsToCharPtrs(const Strings & ss);
MakeError(FormatError, Error);
template<class... Parts>
auto concatStrings(Parts &&... parts)
-> std::enable_if_t<(... && std::is_convertible_v<Parts, std::string_view>), std::string>
@ -36,11 +33,11 @@ auto concatStrings(Parts &&... parts)
return concatStringsSep({}, views);
}
/**
* Add quotes around a collection of strings.
*/
template<class C> Strings quoteStrings(const C & c)
template<class C>
Strings quoteStrings(const C & c)
{
Strings res;
for (auto & s : c)
@ -55,25 +52,18 @@ template<class C> Strings quoteStrings(const C & c)
*/
std::string chomp(std::string_view s);
/**
* Remove whitespace from the start and end of a string.
*/
std::string trim(std::string_view s, std::string_view whitespace = " \n\r\t");
/**
* Replace all occurrences of a string inside another string.
*/
std::string replaceStrings(
std::string s,
std::string_view from,
std::string_view to);
std::string replaceStrings(std::string s, std::string_view from, std::string_view to);
std::string rewriteStrings(std::string s, const StringMap & rewrites);
/**
* Parse a string into an integer.
*/
@ -91,11 +81,16 @@ N string2IntWithUnitPrefix(std::string_view s)
if (!s.empty()) {
char u = std::toupper(*s.rbegin());
if (std::isalpha(u)) {
if (u == 'K') multiplier = 1ULL << 10;
else if (u == 'M') multiplier = 1ULL << 20;
else if (u == 'G') multiplier = 1ULL << 30;
else if (u == 'T') multiplier = 1ULL << 40;
else throw UsageError("invalid unit specifier '%1%'", u);
if (u == 'K')
multiplier = 1ULL << 10;
else if (u == 'M')
multiplier = 1ULL << 20;
else if (u == 'G')
multiplier = 1ULL << 30;
else if (u == 'T')
multiplier = 1ULL << 40;
else
throw UsageError("invalid unit specifier '%1%'", u);
s.remove_suffix(1);
}
}
@ -117,7 +112,6 @@ std::string renderSize(uint64_t value, bool align = false);
template<class N>
std::optional<N> string2Float(const std::string_view s);
/**
* Convert a little-endian integer to host order.
*/
@ -131,31 +125,26 @@ T readLittleEndian(unsigned char * p)
return x;
}
/**
* @return true iff `s` starts with `prefix`.
*/
bool hasPrefix(std::string_view s, std::string_view prefix);
/**
* @return true iff `s` ends in `suffix`.
*/
bool hasSuffix(std::string_view s, std::string_view suffix);
/**
* Convert a string to lower case.
*/
std::string toLower(std::string s);
/**
* Escape a string as a shell word.
*/
std::string shellEscape(const std::string_view s);
/**
* Exception handling in destructors: print an error message, then
* ignore the exception.
@ -177,8 +166,6 @@ void ignoreExceptionInDestructor(Verbosity lvl = lvlError);
*/
void ignoreExceptionExceptInterrupt(Verbosity lvl = lvlError);
/**
* Tree formatting.
*/
@ -187,7 +174,6 @@ constexpr char treeLast[] = "└───";
constexpr char treeLine[] = "";
constexpr char treeNull[] = " ";
/**
* Encode arbitrary bytes as Base64.
*/
@ -198,7 +184,6 @@ std::string base64Encode(std::string_view s);
*/
std::string base64Decode(std::string_view s);
/**
* Remove common leading whitespace from the lines in the string
* 's'. For example, if every line is indented by at least 3 spaces,
@ -206,7 +191,6 @@ std::string base64Decode(std::string_view s);
*/
std::string stripIndentation(std::string_view s);
/**
* Get the prefix of 's' up to and excluding the next line break (LF
* optionally preceded by CR), and the remainder following the line
@ -214,66 +198,67 @@ std::string stripIndentation(std::string_view s);
*/
std::pair<std::string_view, std::string_view> getLine(std::string_view s);
/**
* Get a value for the specified key from an associate container.
*/
template <class T>
template<class T>
const typename T::mapped_type * get(const T & map, const typename T::key_type & key)
{
auto i = map.find(key);
if (i == map.end()) return nullptr;
if (i == map.end())
return nullptr;
return &i->second;
}
template <class T>
template<class T>
typename T::mapped_type * get(T & map, const typename T::key_type & key)
{
auto i = map.find(key);
if (i == map.end()) return nullptr;
if (i == map.end())
return nullptr;
return &i->second;
}
/**
* Get a value for the specified key from an associate container, or a default value if the key isn't present.
*/
template <class T>
const typename T::mapped_type & getOr(T & map,
const typename T::key_type & key,
const typename T::mapped_type & defaultValue)
template<class T>
const typename T::mapped_type &
getOr(T & map, const typename T::key_type & key, const typename T::mapped_type & defaultValue)
{
auto i = map.find(key);
if (i == map.end()) return defaultValue;
if (i == map.end())
return defaultValue;
return i->second;
}
/**
* Remove and return the first item from a container.
*/
template <class T>
template<class T>
std::optional<typename T::value_type> remove_begin(T & c)
{
auto i = c.begin();
if (i == c.end()) return {};
if (i == c.end())
return {};
auto v = std::move(*i);
c.erase(i);
return v;
}
/**
* Remove and return the first item from a container.
*/
template <class T>
template<class T>
std::optional<typename T::value_type> pop(T & c)
{
if (c.empty()) return {};
if (c.empty())
return {};
auto v = std::move(c.front());
c.pop();
return v;
}
/**
* Append items to a container. TODO: remove this once we can use
* C++23's `append_range()`.
@ -284,11 +269,9 @@ void append(C & c, std::initializer_list<T> l)
c.insert(c.end(), l.begin(), l.end());
}
template<typename T>
class Callback;
/**
* A RAII helper that increments a counter on construction and
* decrements it on destruction.
@ -298,56 +281,89 @@ struct MaintainCount
{
T & counter;
long delta;
MaintainCount(T & counter, long delta = 1) : counter(counter), delta(delta) { counter += delta; }
~MaintainCount() { counter -= delta; }
};
MaintainCount(T & counter, long delta = 1)
: counter(counter)
, delta(delta)
{
counter += delta;
}
~MaintainCount()
{
counter -= delta;
}
};
/**
* A Rust/Python-like enumerate() iterator adapter.
*
* Borrowed from http://reedbeta.com/blog/python-like-enumerate-in-cpp17.
*/
template <typename T,
typename TIter = decltype(std::begin(std::declval<T>())),
typename = decltype(std::end(std::declval<T>()))>
template<
typename T,
typename TIter = decltype(std::begin(std::declval<T>())),
typename = decltype(std::end(std::declval<T>()))>
constexpr auto enumerate(T && iterable)
{
struct iterator
{
size_t i;
TIter iter;
constexpr bool operator != (const iterator & other) const { return iter != other.iter; }
constexpr void operator ++ () { ++i; ++iter; }
constexpr auto operator * () const { return std::tie(i, *iter); }
constexpr bool operator!=(const iterator & other) const
{
return iter != other.iter;
}
constexpr void operator++()
{
++i;
++iter;
}
constexpr auto operator*() const
{
return std::tie(i, *iter);
}
};
struct iterable_wrapper
{
T iterable;
constexpr auto begin() { return iterator{ 0, std::begin(iterable) }; }
constexpr auto end() { return iterator{ 0, std::end(iterable) }; }
constexpr auto begin()
{
return iterator{0, std::begin(iterable)};
}
constexpr auto end()
{
return iterator{0, std::end(iterable)};
}
};
return iterable_wrapper{ std::forward<T>(iterable) };
return iterable_wrapper{std::forward<T>(iterable)};
}
/**
* C++17 std::visit boilerplate
*/
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
template<class... Ts>
struct overloaded : Ts...
{
using Ts::operator()...;
};
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
std::string showBytes(uint64_t bytes);
/**
* Provide an addition operator between strings and string_views
* inexplicably omitted from the standard library.
*/
inline std::string operator + (const std::string & s1, std::string_view s2)
inline std::string operator+(const std::string & s1, std::string_view s2)
{
std::string s;
s.reserve(s1.size() + s2.size());
@ -356,13 +372,13 @@ inline std::string operator + (const std::string & s1, std::string_view s2)
return s;
}
inline std::string operator + (std::string && s, std::string_view s2)
inline std::string operator+(std::string && s, std::string_view s2)
{
s.append(s2);
return std::move(s);
}
inline std::string operator + (std::string_view s1, const char * s2)
inline std::string operator+(std::string_view s1, const char * s2)
{
auto s2Size = strlen(s2);
std::string s;
@ -372,4 +388,4 @@ inline std::string operator + (std::string_view s1, const char * s2)
return s;
}
}
} // namespace nix

View file

@ -8,13 +8,13 @@
* Force the default versions of all constructors (copy, move, copy
* assignment).
*/
#define FORCE_DEFAULT_CONSTRUCTORS(CLASS_NAME) \
CLASS_NAME(const CLASS_NAME &) = default; \
CLASS_NAME(CLASS_NAME &) = default; \
CLASS_NAME(CLASS_NAME &&) = default; \
\
CLASS_NAME & operator =(const CLASS_NAME &) = default; \
CLASS_NAME & operator =(CLASS_NAME &) = default;
#define FORCE_DEFAULT_CONSTRUCTORS(CLASS_NAME) \
CLASS_NAME(const CLASS_NAME &) = default; \
CLASS_NAME(CLASS_NAME &) = default; \
CLASS_NAME(CLASS_NAME &&) = default; \
\
CLASS_NAME & operator=(const CLASS_NAME &) = default; \
CLASS_NAME & operator=(CLASS_NAME &) = default;
/**
* Make a wrapper constructor. All args are forwarded to the
@ -22,9 +22,10 @@
*
* The moral equivalent of `using Raw::Raw;`
*/
#define MAKE_WRAPPER_CONSTRUCTOR(CLASS_NAME) \
FORCE_DEFAULT_CONSTRUCTORS(CLASS_NAME) \
\
CLASS_NAME(auto &&... arg) \
#define MAKE_WRAPPER_CONSTRUCTOR(CLASS_NAME) \
FORCE_DEFAULT_CONSTRUCTORS(CLASS_NAME) \
\
CLASS_NAME(auto &&... arg) \
: raw(std::forward<decltype(arg)>(arg)...) \
{ }
{ \
}

View file

@ -6,13 +6,10 @@
#include <list>
#include <map>
namespace nix {
typedef std::map<std::string, std::string> XMLAttrs;
class XMLWriter
{
private:
@ -31,12 +28,10 @@ public:
void close();
void openElement(std::string_view name,
const XMLAttrs & attrs = XMLAttrs());
void openElement(std::string_view name, const XMLAttrs & attrs = XMLAttrs());
void closeElement();
void writeEmptyElement(std::string_view name,
const XMLAttrs & attrs = XMLAttrs());
void writeEmptyElement(std::string_view name, const XMLAttrs & attrs = XMLAttrs());
private:
void writeAttrs(const XMLAttrs & attrs);
@ -44,23 +39,21 @@ private:
void indent_(size_t depth);
};
class XMLOpenElement
{
private:
XMLWriter & writer;
public:
XMLOpenElement(XMLWriter & writer, std::string_view name,
const XMLAttrs & attrs = XMLAttrs())
XMLOpenElement(XMLWriter & writer, std::string_view name, const XMLAttrs & attrs = XMLAttrs())
: writer(writer)
{
writer.openElement(name, attrs);
}
~XMLOpenElement()
{
writer.closeElement();
}
};
}
} // namespace nix

View file

@ -10,20 +10,20 @@ namespace nix {
const nlohmann::json * get(const nlohmann::json & map, const std::string & key)
{
auto i = map.find(key);
if (i == map.end()) return nullptr;
if (i == map.end())
return nullptr;
return &*i;
}
nlohmann::json * get(nlohmann::json & map, const std::string & key)
{
auto i = map.find(key);
if (i == map.end()) return nullptr;
if (i == map.end())
return nullptr;
return &*i;
}
const nlohmann::json & valueAt(
const nlohmann::json::object_t & map,
const std::string & key)
const nlohmann::json & valueAt(const nlohmann::json::object_t & map, const std::string & key)
{
if (!map.contains(key))
throw Error("Expected JSON object to contain key '%s' but it doesn't: %s", key, nlohmann::json(map).dump());
@ -36,7 +36,7 @@ std::optional<nlohmann::json> optionalValueAt(const nlohmann::json::object_t & m
if (!map.contains(key))
return std::nullopt;
return std::optional { map.at(key) };
return std::optional{map.at(key)};
}
std::optional<nlohmann::json> nullableValueAt(const nlohmann::json::object_t & map, const std::string & key)
@ -46,7 +46,7 @@ std::optional<nlohmann::json> nullableValueAt(const nlohmann::json::object_t & m
if (value.is_null())
return std::nullopt;
return std::optional { std::move(value) };
return std::optional{std::move(value)};
}
const nlohmann::json * getNullable(const nlohmann::json & value)
@ -63,16 +63,14 @@ const nlohmann::json * getNullable(const nlohmann::json & value)
* functions. It is too cumbersome and easy to forget to expect regular
* JSON code to use it directly.
*/
static const nlohmann::json & ensureType(
const nlohmann::json & value,
nlohmann::json::value_type expectedType
)
static const nlohmann::json & ensureType(const nlohmann::json & value, nlohmann::json::value_type expectedType)
{
if (value.type() != expectedType)
throw Error(
"Expected JSON value to be of type '%s' but it is of type '%s': %s",
nlohmann::json(expectedType).type_name(),
value.type_name(), value.dump());
value.type_name(),
value.dump());
return value;
}
@ -102,8 +100,7 @@ const nlohmann::json::number_unsigned_t & getUnsigned(const nlohmann::json & val
typeName = value.is_number_float() ? "floating point number" : "signed integral number";
}
throw Error(
"Expected JSON value to be an unsigned integral number but it is of type '%s': %s",
typeName, value.dump());
"Expected JSON value to be an unsigned integral number but it is of type '%s': %s", typeName, value.dump());
}
const nlohmann::json::boolean_t & getBoolean(const nlohmann::json & value)
@ -146,4 +143,4 @@ StringSet getStringSet(const nlohmann::json & value)
return stringSet;
}
}
} // namespace nix

View file

@ -19,7 +19,8 @@ std::optional<Path> getCgroupFS()
{
static auto res = [&]() -> std::optional<Path> {
auto fp = fopen("/proc/mounts", "r");
if (!fp) return std::nullopt;
if (!fp)
return std::nullopt;
Finally delFP = [&]() { fclose(fp); };
while (auto ent = getmntent(fp))
if (std::string_view(ent->mnt_type) == "cgroup2")
@ -50,7 +51,8 @@ std::map<std::string, std::string> getCgroups(const Path & cgroupFile)
static CgroupStats destroyCgroup(const std::filesystem::path & cgroup, bool returnStats)
{
if (!pathExists(cgroup)) return {};
if (!pathExists(cgroup))
return {};
auto procsFile = cgroup / "cgroup.procs";
@ -67,7 +69,8 @@ static CgroupStats destroyCgroup(const std::filesystem::path & cgroup, bool retu
this cgroup. */
for (auto & entry : DirectoryIterator{cgroup}) {
checkInterrupt();
if (entry.symlink_status().type() != std::filesystem::file_type::directory) continue;
if (entry.symlink_status().type() != std::filesystem::file_type::directory)
continue;
destroyCgroup(cgroup / entry.path().filename(), false);
}
@ -78,7 +81,8 @@ static CgroupStats destroyCgroup(const std::filesystem::path & cgroup, bool retu
while (true) {
auto pids = tokenizeString<std::vector<std::string>>(readFile(procsFile));
if (pids.empty()) break;
if (pids.empty())
break;
if (round > 20)
throw Error("cannot kill cgroup '%s'", cgroup);
@ -93,8 +97,7 @@ static CgroupStats destroyCgroup(const std::filesystem::path & cgroup, bool retu
try {
auto cmdline = readFile(fmt("/proc/%d/cmdline", pid));
using namespace std::string_literals;
warn("killing stray builder process %d (%s)...",
pid, trim(replaceStrings(cmdline, "\0"s, " ")));
warn("killing stray builder process %d (%s)...", pid, trim(replaceStrings(cmdline, "\0"s, " ")));
} catch (SystemError &) {
}
}
@ -120,17 +123,18 @@ static CgroupStats destroyCgroup(const std::filesystem::path & cgroup, bool retu
std::string_view userPrefix = "user_usec ";
if (hasPrefix(line, userPrefix)) {
auto n = string2Int<uint64_t>(line.substr(userPrefix.size()));
if (n) stats.cpuUser = std::chrono::microseconds(*n);
if (n)
stats.cpuUser = std::chrono::microseconds(*n);
}
std::string_view systemPrefix = "system_usec ";
if (hasPrefix(line, systemPrefix)) {
auto n = string2Int<uint64_t>(line.substr(systemPrefix.size()));
if (n) stats.cpuSystem = std::chrono::microseconds(*n);
if (n)
stats.cpuSystem = std::chrono::microseconds(*n);
}
}
}
}
if (rmdir(cgroup.c_str()) == -1)
@ -163,4 +167,4 @@ std::string getRootCgroup()
return rootCgroup;
}
}
} // namespace nix

View file

@ -34,4 +34,4 @@ std::string getCurrentCgroup();
*/
std::string getRootCgroup();
}
} // namespace nix

View file

@ -32,4 +32,4 @@ bool userNamespacesSupported();
bool mountAndPidNamespacesSupported();
}
} // namespace nix

View file

@ -15,36 +15,27 @@ namespace nix {
bool userNamespacesSupported()
{
static auto res = [&]() -> bool
{
static auto res = [&]() -> bool {
if (!pathExists("/proc/self/ns/user")) {
debug("'/proc/self/ns/user' does not exist; your kernel was likely built without CONFIG_USER_NS=y");
return false;
}
Path maxUserNamespaces = "/proc/sys/user/max_user_namespaces";
if (!pathExists(maxUserNamespaces) ||
trim(readFile(maxUserNamespaces)) == "0")
{
if (!pathExists(maxUserNamespaces) || trim(readFile(maxUserNamespaces)) == "0") {
debug("user namespaces appear to be disabled; check '/proc/sys/user/max_user_namespaces'");
return false;
}
Path procSysKernelUnprivilegedUsernsClone = "/proc/sys/kernel/unprivileged_userns_clone";
if (pathExists(procSysKernelUnprivilegedUsernsClone)
&& trim(readFile(procSysKernelUnprivilegedUsernsClone)) == "0")
{
&& trim(readFile(procSysKernelUnprivilegedUsernsClone)) == "0") {
debug("user namespaces appear to be disabled; check '/proc/sys/kernel/unprivileged_userns_clone'");
return false;
}
try {
Pid pid = startProcess([&]()
{
_exit(0);
}, {
.cloneFlags = CLONE_NEWUSER
});
Pid pid = startProcess([&]() { _exit(0); }, {.cloneFlags = CLONE_NEWUSER});
auto r = pid.wait();
assert(!r);
@ -60,27 +51,25 @@ bool userNamespacesSupported()
bool mountAndPidNamespacesSupported()
{
static auto res = [&]() -> bool
{
static auto res = [&]() -> bool {
try {
Pid pid = startProcess([&]()
{
/* Make sure we don't remount the parent's /proc. */
if (mount(0, "/", 0, MS_PRIVATE | MS_REC, 0) == -1)
_exit(1);
Pid pid = startProcess(
[&]() {
/* Make sure we don't remount the parent's /proc. */
if (mount(0, "/", 0, MS_PRIVATE | MS_REC, 0) == -1)
_exit(1);
/* Test whether we can remount /proc. The kernel disallows
this if /proc is not fully visible, i.e. if there are
filesystems mounted on top of files inside /proc. See
https://lore.kernel.org/lkml/87tvsrjai0.fsf@xmission.com/T/. */
if (mount("none", "/proc", "proc", 0, 0) == -1)
_exit(2);
/* Test whether we can remount /proc. The kernel disallows
this if /proc is not fully visible, i.e. if there are
filesystems mounted on top of files inside /proc. See
https://lore.kernel.org/lkml/87tvsrjai0.fsf@xmission.com/T/. */
if (mount("none", "/proc", "proc", 0, 0) == -1)
_exit(2);
_exit(0);
}, {
.cloneFlags = CLONE_NEWNS | CLONE_NEWPID | (userNamespacesSupported() ? CLONE_NEWUSER : 0)
});
_exit(0);
},
{.cloneFlags = CLONE_NEWNS | CLONE_NEWPID | (userNamespacesSupported() ? CLONE_NEWUSER : 0)});
if (pid.wait()) {
debug("PID namespaces do not work on this system: cannot remount /proc");
@ -97,7 +86,6 @@ bool mountAndPidNamespacesSupported()
return res;
}
//////////////////////////////////////////////////////////////////////
static AutoCloseFD fdSavedMountNamespace;
@ -143,4 +131,4 @@ void tryUnshareFilesystem()
throw SysError("unsharing filesystem state");
}
}
} // namespace nix

View file

@ -24,6 +24,7 @@ ActivityId getCurActivity()
{
return curActivity;
}
void setCurActivity(const ActivityId activityId)
{
curActivity = activityId;
@ -46,7 +47,7 @@ void Logger::writeToStdout(std::string_view s)
Logger::Suspension Logger::suspend()
{
pause();
return Suspension { ._finalize = {[this](){this->resume();}} };
return Suspension{._finalize = {[this]() { this->resume(); }}};
}
std::optional<Logger::Suspension> Logger::suspendIf(bool cond)
@ -70,25 +71,42 @@ public:
tty = isTTY();
}
bool isVerbose() override {
bool isVerbose() override
{
return printBuildLogs;
}
void log(Verbosity lvl, std::string_view s) override
{
if (lvl > verbosity) return;
if (lvl > verbosity)
return;
std::string prefix;
if (systemd) {
char c;
switch (lvl) {
case lvlError: c = '3'; break;
case lvlWarn: c = '4'; break;
case lvlNotice: case lvlInfo: c = '5'; break;
case lvlTalkative: case lvlChatty: c = '6'; break;
case lvlDebug: case lvlVomit: c = '7'; break;
default: c = '7'; break; // should not happen, and missing enum case is reported by -Werror=switch-enum
case lvlError:
c = '3';
break;
case lvlWarn:
c = '4';
break;
case lvlNotice:
case lvlInfo:
c = '5';
break;
case lvlTalkative:
case lvlChatty:
c = '6';
break;
case lvlDebug:
case lvlVomit:
c = '7';
break;
default:
c = '7';
break; // should not happen, and missing enum case is reported by -Werror=switch-enum
}
prefix = std::string("<") + c + ">";
}
@ -104,9 +122,13 @@ public:
log(ei.level, toView(oss));
}
void startActivity(ActivityId act, Verbosity lvl, ActivityType type,
const std::string & s, const Fields & fields, ActivityId parent)
override
void startActivity(
ActivityId act,
Verbosity lvl,
ActivityType type,
const std::string & s,
const Fields & fields,
ActivityId parent) override
{
if (lvl <= verbosity && !s.empty())
log(lvl, s + "...");
@ -117,8 +139,7 @@ public:
if (type == resBuildLogLine && printBuildLogs) {
auto lastLine = fields[0].s;
printError(lastLine);
}
else if (type == resPostBuildLogLine && printBuildLogs) {
} else if (type == resPostBuildLogLine && printBuildLogs) {
auto lastLine = fields[0].s;
printError("post-build-hook: " + lastLine);
}
@ -130,9 +151,7 @@ Verbosity verbosity = lvlInfo;
void writeToStderr(std::string_view s)
{
try {
writeFull(
getStandardError(),
s, false);
writeFull(getStandardError(), s, false);
} catch (SystemError & e) {
/* Ignore failing writes to stderr. We need to ignore write
errors to ensure that cleanup code that logs to stderr runs
@ -157,9 +176,15 @@ static uint64_t getPid()
#endif
}
Activity::Activity(Logger & logger, Verbosity lvl, ActivityType type,
const std::string & s, const Logger::Fields & fields, ActivityId parent)
: logger(logger), id(nextId++ + (((uint64_t) getPid()) << 32))
Activity::Activity(
Logger & logger,
Verbosity lvl,
ActivityType type,
const std::string & s,
const Logger::Fields & fields,
ActivityId parent)
: logger(logger)
, id(nextId++ + (((uint64_t) getPid()) << 32))
{
logger.startActivity(id, lvl, type, s, fields, parent);
}
@ -179,18 +204,24 @@ void to_json(nlohmann::json & json, std::shared_ptr<Pos> pos)
}
}
struct JSONLogger : Logger {
struct JSONLogger : Logger
{
Descriptor fd;
JSONLogger(Descriptor fd) : fd(fd) { }
JSONLogger(Descriptor fd)
: fd(fd)
{
}
bool isVerbose() override {
bool isVerbose() override
{
return true;
}
void addFields(nlohmann::json & json, const Fields & fields)
{
if (fields.empty()) return;
if (fields.empty())
return;
auto & arr = json["fields"] = nlohmann::json::array();
for (auto & f : fields)
if (f.type == Logger::Field::tInt)
@ -242,8 +273,13 @@ struct JSONLogger : Logger {
write(json);
}
void startActivity(ActivityId act, Verbosity lvl, ActivityType type,
const std::string & s, const Fields & fields, ActivityId parent) override
void startActivity(
ActivityId act,
Verbosity lvl,
ActivityType type,
const std::string & s,
const Fields & fields,
ActivityId parent) override
{
nlohmann::json json;
json["action"] = "start";
@ -288,27 +324,30 @@ static Logger::Fields getFields(nlohmann::json & json)
fields.emplace_back(Logger::Field(f.get<uint64_t>()));
else if (f.type() == nlohmann::json::value_t::string)
fields.emplace_back(Logger::Field(f.get<std::string>()));
else throw Error("unsupported JSON type %d", (int) f.type());
else
throw Error("unsupported JSON type %d", (int) f.type());
}
return fields;
}
std::optional<nlohmann::json> parseJSONMessage(const std::string & msg, std::string_view source)
{
if (!hasPrefix(msg, "@nix ")) return std::nullopt;
if (!hasPrefix(msg, "@nix "))
return std::nullopt;
try {
return nlohmann::json::parse(std::string(msg, 5));
} catch (std::exception & e) {
printError("bad JSON log message from %s: %s",
Uncolored(source),
e.what());
printError("bad JSON log message from %s: %s", Uncolored(source), e.what());
}
return std::nullopt;
}
bool handleJSONLogMessage(nlohmann::json & json,
const Activity & act, std::map<ActivityId, Activity> & activities,
std::string_view source, bool trusted)
bool handleJSONLogMessage(
nlohmann::json & json,
const Activity & act,
std::map<ActivityId, Activity> & activities,
std::string_view source,
bool trusted)
{
try {
std::string action = json["action"];
@ -316,10 +355,11 @@ bool handleJSONLogMessage(nlohmann::json & json,
if (action == "start") {
auto type = (ActivityType) json["type"];
if (trusted || type == actFileTransfer)
activities.emplace(std::piecewise_construct,
activities.emplace(
std::piecewise_construct,
std::forward_as_tuple(json["id"]),
std::forward_as_tuple(*logger, (Verbosity) json["level"], type,
json["text"], getFields(json["fields"]), act.id));
std::forward_as_tuple(
*logger, (Verbosity) json["level"], type, json["text"], getFields(json["fields"]), act.id));
}
else if (action == "stop")
@ -342,21 +382,22 @@ bool handleJSONLogMessage(nlohmann::json & json,
}
return true;
} catch (const nlohmann::json::exception &e) {
warn(
"Unable to handle a JSON message from %s: %s",
Uncolored(source),
e.what()
);
} catch (const nlohmann::json::exception & e) {
warn("Unable to handle a JSON message from %s: %s", Uncolored(source), e.what());
return false;
}
}
bool handleJSONLogMessage(const std::string & msg,
const Activity & act, std::map<ActivityId, Activity> & activities, std::string_view source, bool trusted)
bool handleJSONLogMessage(
const std::string & msg,
const Activity & act,
std::map<ActivityId, Activity> & activities,
std::string_view source,
bool trusted)
{
auto json = parseJSONMessage(msg, source);
if (!json) return false;
if (!json)
return false;
return handleJSONLogMessage(*json, act, activities, source, trusted);
}
@ -370,4 +411,4 @@ Activity::~Activity()
}
}
}
} // namespace nix

View file

@ -2,15 +2,13 @@
namespace nix {
MemorySourceAccessor::File *
MemorySourceAccessor::open(const CanonPath & path, std::optional<File> create)
MemorySourceAccessor::File * MemorySourceAccessor::open(const CanonPath & path, std::optional<File> create)
{
File * cur = &root;
bool newF = false;
for (std::string_view name : path)
{
for (std::string_view name : path) {
auto * curDirP = std::get_if<File::Directory>(&cur->raw);
if (!curDirP)
return nullptr;
@ -22,16 +20,19 @@ MemorySourceAccessor::open(const CanonPath & path, std::optional<File> create)
return nullptr;
else {
newF = true;
i = curDir.contents.insert(i, {
std::string { name },
File::Directory {},
});
i = curDir.contents.insert(
i,
{
std::string{name},
File::Directory{},
});
}
}
cur = &i->second;
}
if (newF && create) *cur = std::move(*create);
if (newF && create)
*cur = std::move(*create);
return cur;
}
@ -54,32 +55,33 @@ bool MemorySourceAccessor::pathExists(const CanonPath & path)
MemorySourceAccessor::Stat MemorySourceAccessor::File::lstat() const
{
return std::visit(overloaded {
[](const Regular & r) {
return Stat {
.type = tRegular,
.fileSize = r.contents.size(),
.isExecutable = r.executable,
};
return std::visit(
overloaded{
[](const Regular & r) {
return Stat{
.type = tRegular,
.fileSize = r.contents.size(),
.isExecutable = r.executable,
};
},
[](const Directory &) {
return Stat{
.type = tDirectory,
};
},
[](const Symlink &) {
return Stat{
.type = tSymlink,
};
},
},
[](const Directory &) {
return Stat {
.type = tDirectory,
};
},
[](const Symlink &) {
return Stat {
.type = tSymlink,
};
},
}, this->raw);
this->raw);
}
std::optional<MemorySourceAccessor::Stat>
MemorySourceAccessor::maybeLstat(const CanonPath & path)
std::optional<MemorySourceAccessor::Stat> MemorySourceAccessor::maybeLstat(const CanonPath & path)
{
const auto * f = open(path, std::nullopt);
return f ? std::optional { f->lstat() } : std::nullopt;
return f ? std::optional{f->lstat()} : std::nullopt;
}
MemorySourceAccessor::DirEntries MemorySourceAccessor::readDirectory(const CanonPath & path)
@ -110,7 +112,7 @@ std::string MemorySourceAccessor::readLink(const CanonPath & path)
SourcePath MemorySourceAccessor::addFile(CanonPath path, std::string && contents)
{
auto * f = open(path, File { File::Regular {} });
auto * f = open(path, File{File::Regular{}});
if (!f)
throw Error("file '%s' cannot be made because some parent file is not a directory", path);
if (auto * r = std::get_if<File::Regular>(&f->raw))
@ -121,12 +123,11 @@ SourcePath MemorySourceAccessor::addFile(CanonPath path, std::string && contents
return SourcePath{ref(shared_from_this()), path};
}
using File = MemorySourceAccessor::File;
void MemorySink::createDirectory(const CanonPath & path)
{
auto * f = dst.open(path, File { File::Directory { } });
auto * f = dst.open(path, File{File::Directory{}});
if (!f)
throw Error("file '%s' cannot be made because some parent file is not a directory", path);
@ -134,25 +135,27 @@ void MemorySink::createDirectory(const CanonPath & path)
throw Error("file '%s' is not a directory", path);
};
struct CreateMemoryRegularFile : CreateRegularFileSink {
struct CreateMemoryRegularFile : CreateRegularFileSink
{
File::Regular & regularFile;
CreateMemoryRegularFile(File::Regular & r)
: regularFile(r)
{ }
{
}
void operator () (std::string_view data) override;
void operator()(std::string_view data) override;
void isExecutable() override;
void preallocateContents(uint64_t size) override;
};
void MemorySink::createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)> func)
{
auto * f = dst.open(path, File { File::Regular {} });
auto * f = dst.open(path, File{File::Regular{}});
if (!f)
throw Error("file '%s' cannot be made because some parent file is not a directory", path);
if (auto * rp = std::get_if<File::Regular>(&f->raw)) {
CreateMemoryRegularFile crf { *rp };
CreateMemoryRegularFile crf{*rp};
func(crf);
} else
throw Error("file '%s' is not a regular file", path);
@ -168,14 +171,14 @@ void CreateMemoryRegularFile::preallocateContents(uint64_t len)
regularFile.contents.reserve(len);
}
void CreateMemoryRegularFile::operator () (std::string_view data)
void CreateMemoryRegularFile::operator()(std::string_view data)
{
regularFile.contents += data;
}
void MemorySink::createSymlink(const CanonPath & path, const std::string & target)
{
auto * f = dst.open(path, File { File::Symlink { } });
auto * f = dst.open(path, File{File::Symlink{}});
if (!f)
throw Error("file '%s' cannot be made because some parent file is not a directory", path);
if (auto * s = std::get_if<File::Symlink>(&f->raw))
@ -194,4 +197,4 @@ ref<SourceAccessor> makeEmptySourceAccessor()
return empty;
}
}
} // namespace nix

View file

@ -76,4 +76,4 @@ ref<SourceAccessor> makeMountedSourceAccessor(std::map<CanonPath, ref<SourceAcce
return make_ref<MountedSourceAccessor>(std::move(mounts));
}
}
} // namespace nix

Some files were not shown because too many files have changed in this diff Show more