aboutsummaryrefslogtreecommitdiff
path: root/src/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/archive.cc4
-rw-r--r--src/libutil/args.cc25
-rw-r--r--src/libutil/args.hh15
-rw-r--r--src/libutil/config.cc63
-rw-r--r--src/libutil/config.hh55
-rw-r--r--src/libutil/error.cc6
-rw-r--r--src/libutil/filesystem.cc4
-rw-r--r--src/libutil/fmt.hh15
-rw-r--r--src/libutil/hash.cc13
-rw-r--r--src/libutil/hash.hh2
-rw-r--r--src/libutil/logging.cc13
-rw-r--r--src/libutil/logging.hh12
-rw-r--r--src/libutil/serialise.cc4
-rw-r--r--src/libutil/url-parts.hh2
-rw-r--r--src/libutil/util.cc23
-rw-r--r--src/libutil/util.hh9
16 files changed, 183 insertions, 82 deletions
diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc
index 0e2b9d12c..268a798d9 100644
--- a/src/libutil/archive.cc
+++ b/src/libutil/archive.cc
@@ -87,7 +87,7 @@ static time_t dump(const Path & path, Sink & sink, PathFilter & filter)
std::string name(i.name);
size_t pos = i.name.find(caseHackSuffix);
if (pos != std::string::npos) {
- debug(format("removing case hack suffix from '%1%'") % (path + "/" + i.name));
+ debug("removing case hack suffix from '%1%'", path + "/" + i.name);
name.erase(pos);
}
if (!unhacked.emplace(name, i.name).second)
@@ -262,7 +262,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
if (archiveSettings.useCaseHack) {
auto i = names.find(name);
if (i != names.end()) {
- debug(format("case collision between '%1%' and '%2%'") % i->first % name);
+ debug("case collision between '%1%' and '%2%'", i->first, name);
name += caseHackSuffix;
name += std::to_string(++i->second);
} else
diff --git a/src/libutil/args.cc b/src/libutil/args.cc
index 35686a8aa..fc009592c 100644
--- a/src/libutil/args.cc
+++ b/src/libutil/args.cc
@@ -52,7 +52,7 @@ std::shared_ptr<Completions> completions;
std::string completionMarker = "___COMPLETE___";
-std::optional<std::string> needsCompletion(std::string_view s)
+static std::optional<std::string> needsCompletion(std::string_view s)
{
if (!completions) return {};
auto i = s.find(completionMarker);
@@ -120,6 +120,12 @@ void Args::parseCmdline(const Strings & _cmdline)
if (!argsSeen)
initialFlagsProcessed();
+
+ /* Now that we are done parsing, make sure that any experimental
+ * feature required by the flags is enabled */
+ for (auto & f : flagExperimentalFeatures)
+ experimentalFeatureSettings.require(f);
+
}
bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
@@ -128,12 +134,18 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
auto process = [&](const std::string & name, const Flag & flag) -> bool {
++pos;
+
+ if (auto & f = flag.experimentalFeature)
+ flagExperimentalFeatures.insert(*f);
+
std::vector<std::string> args;
bool anyCompleted = false;
for (size_t n = 0 ; n < flag.handler.arity; ++n) {
if (pos == end) {
if (flag.handler.arity == ArityAny || anyCompleted) break;
- throw UsageError("flag '%s' requires %d argument(s)", name, flag.handler.arity);
+ throw UsageError(
+ "flag '%s' requires %d argument(s), but only %d were given",
+ name, flag.handler.arity, n);
}
if (auto prefix = needsCompletion(*pos)) {
anyCompleted = true;
@@ -152,7 +164,11 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
for (auto & [name, flag] : longFlags) {
if (!hiddenCategories.count(flag->category)
&& hasPrefix(name, std::string(*prefix, 2)))
+ {
+ if (auto & f = flag->experimentalFeature)
+ flagExperimentalFeatures.insert(*f);
completions->add("--" + name, flag->description);
+ }
}
return false;
}
@@ -172,7 +188,8 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
if (prefix == "-") {
completions->add("--");
for (auto & [flagName, flag] : shortFlags)
- completions->add(std::string("-") + flagName, flag->description);
+ if (experimentalFeatureSettings.isEnabled(flag->experimentalFeature))
+ completions->add(std::string("-") + flagName, flag->description);
}
}
@@ -219,6 +236,8 @@ nlohmann::json Args::toJSON()
auto flags = nlohmann::json::object();
for (auto & [name, flag] : longFlags) {
+ /* Skip experimental flags when listing flags. */
+ if (!experimentalFeatureSettings.isEnabled(flag->experimentalFeature)) continue;
auto j = nlohmann::json::object();
if (flag->aliases.count(name)) continue;
if (flag->shortName)
diff --git a/src/libutil/args.hh b/src/libutil/args.hh
index 84866f12b..2969806dd 100644
--- a/src/libutil/args.hh
+++ b/src/libutil/args.hh
@@ -117,6 +117,8 @@ protected:
Handler handler;
std::function<void(size_t, std::string_view)> completer;
+ std::optional<ExperimentalFeature> experimentalFeature;
+
static Flag mkHashTypeFlag(std::string && longName, HashType * ht);
static Flag mkHashTypeOptFlag(std::string && longName, std::optional<HashType> * oht);
};
@@ -188,6 +190,16 @@ public:
friend class MultiCommand;
MultiCommand * parent = nullptr;
+
+private:
+
+ /**
+ * Experimental features needed when parsing args. These are checked
+ * after flag parsing is completed in order to support enabling
+ * experimental features coming after the flag that needs the
+ * experimental feature.
+ */
+ std::set<ExperimentalFeature> flagExperimentalFeatures;
};
/* A command is an argument parser that can be executed by calling its
@@ -198,7 +210,6 @@ struct Command : virtual public Args
virtual ~Command() { }
- virtual void prepare() { };
virtual void run() = 0;
typedef int Category;
@@ -254,8 +265,6 @@ enum CompletionType {
};
extern CompletionType completionType;
-std::optional<std::string> needsCompletion(std::string_view s);
-
void completePath(size_t, std::string_view prefix);
void completeDir(size_t, std::string_view prefix);
diff --git a/src/libutil/config.cc b/src/libutil/config.cc
index b349f2d80..8d63536d6 100644
--- a/src/libutil/config.cc
+++ b/src/libutil/config.cc
@@ -70,10 +70,17 @@ void AbstractConfig::reapplyUnknownSettings()
set(s.first, s.second);
}
+// Whether we should process the option. Excludes aliases, which are handled elsewhere, and disabled features.
+static bool applicable(const Config::SettingData & sd)
+{
+ return !sd.isAlias
+ && experimentalFeatureSettings.isEnabled(sd.setting->experimentalFeature);
+}
+
void Config::getSettings(std::map<std::string, SettingInfo> & res, bool overriddenOnly)
{
for (auto & opt : _settings)
- if (!opt.second.isAlias && (!overriddenOnly || opt.second.setting->overridden))
+ if (applicable(opt.second) && (!overriddenOnly || opt.second.setting->overridden))
res.emplace(opt.first, SettingInfo{opt.second.setting->to_string(), opt.second.setting->description});
}
@@ -147,9 +154,8 @@ nlohmann::json Config::toJSON()
{
auto res = nlohmann::json::object();
for (auto & s : _settings)
- if (!s.second.isAlias) {
+ if (applicable(s.second))
res.emplace(s.first, s.second.setting->toJSON());
- }
return res;
}
@@ -157,24 +163,31 @@ std::string Config::toKeyValue()
{
auto res = std::string();
for (auto & s : _settings)
- if (!s.second.isAlias) {
+ if (applicable(s.second))
res += fmt("%s = %s\n", s.first, s.second.setting->to_string());
- }
return res;
}
void Config::convertToArgs(Args & args, const std::string & category)
{
- for (auto & s : _settings)
+ for (auto & s : _settings) {
+ /* We do include args for settings gated on disabled
+ experimental-features. The args themselves however will also be
+ gated on any experimental feature the underlying setting is. */
if (!s.second.isAlias)
s.second.setting->convertToArg(args, category);
+ }
}
AbstractSetting::AbstractSetting(
const std::string & name,
const std::string & description,
- const std::set<std::string> & aliases)
- : name(name), description(stripIndentation(description)), aliases(aliases)
+ const std::set<std::string> & aliases,
+ std::optional<ExperimentalFeature> experimentalFeature)
+ : name(name)
+ , description(stripIndentation(description))
+ , aliases(aliases)
+ , experimentalFeature(experimentalFeature)
{
}
@@ -210,6 +223,7 @@ void BaseSetting<T>::convertToArg(Args & args, const std::string & category)
.category = category,
.labels = {"value"},
.handler = {[this](std::string s) { overridden = true; set(s); }},
+ .experimentalFeature = experimentalFeature,
});
if (isAppendable())
@@ -219,6 +233,7 @@ void BaseSetting<T>::convertToArg(Args & args, const std::string & category)
.category = category,
.labels = {"value"},
.handler = {[this](std::string s) { overridden = true; set(s, true); }},
+ .experimentalFeature = experimentalFeature,
});
}
@@ -270,13 +285,15 @@ template<> void BaseSetting<bool>::convertToArg(Args & args, const std::string &
.longName = name,
.description = fmt("Enable the `%s` setting.", name),
.category = category,
- .handler = {[this]() { override(true); }}
+ .handler = {[this]() { override(true); }},
+ .experimentalFeature = experimentalFeature,
});
args.addFlag({
.longName = "no-" + name,
.description = fmt("Disable the `%s` setting.", name),
.category = category,
- .handler = {[this]() { override(false); }}
+ .handler = {[this]() { override(false); }},
+ .experimentalFeature = experimentalFeature,
});
}
@@ -444,4 +461,30 @@ GlobalConfig::Register::Register(Config * config)
configRegistrations->emplace_back(config);
}
+ExperimentalFeatureSettings experimentalFeatureSettings;
+
+static GlobalConfig::Register rSettings(&experimentalFeatureSettings);
+
+bool ExperimentalFeatureSettings::isEnabled(const ExperimentalFeature & feature) const
+{
+ auto & f = experimentalFeatures.get();
+ return std::find(f.begin(), f.end(), feature) != f.end();
+}
+
+void ExperimentalFeatureSettings::require(const ExperimentalFeature & feature) const
+{
+ if (!isEnabled(feature))
+ throw MissingExperimentalFeature(feature);
+}
+
+bool ExperimentalFeatureSettings::isEnabled(const std::optional<ExperimentalFeature> & feature) const
+{
+ return !feature || isEnabled(*feature);
+}
+
+void ExperimentalFeatureSettings::require(const std::optional<ExperimentalFeature> & feature) const
+{
+ if (feature) require(*feature);
+}
+
}
diff --git a/src/libutil/config.hh b/src/libutil/config.hh
index 7ac43c854..748d6043b 100644
--- a/src/libutil/config.hh
+++ b/src/libutil/config.hh
@@ -1,12 +1,13 @@
+#pragma once
+
#include <cassert>
#include <map>
#include <set>
-#include "types.hh"
-
#include <nlohmann/json_fwd.hpp>
-#pragma once
+#include "types.hh"
+#include "experimental-features.hh"
namespace nix {
@@ -194,12 +195,15 @@ public:
bool overridden = false;
+ std::optional<ExperimentalFeature> experimentalFeature;
+
protected:
AbstractSetting(
const std::string & name,
const std::string & description,
- const std::set<std::string> & aliases);
+ const std::set<std::string> & aliases,
+ std::optional<ExperimentalFeature> experimentalFeature = std::nullopt);
virtual ~AbstractSetting()
{
@@ -240,8 +244,9 @@ public:
const bool documentDefault,
const std::string & name,
const std::string & description,
- const std::set<std::string> & aliases = {})
- : AbstractSetting(name, description, aliases)
+ const std::set<std::string> & aliases = {},
+ std::optional<ExperimentalFeature> experimentalFeature = std::nullopt)
+ : AbstractSetting(name, description, aliases, experimentalFeature)
, value(def)
, defaultValue(def)
, documentDefault(documentDefault)
@@ -296,8 +301,9 @@ public:
const std::string & name,
const std::string & description,
const std::set<std::string> & aliases = {},
- const bool documentDefault = true)
- : BaseSetting<T>(def, documentDefault, name, description, aliases)
+ const bool documentDefault = true,
+ std::optional<ExperimentalFeature> experimentalFeature = std::nullopt)
+ : BaseSetting<T>(def, documentDefault, name, description, aliases, experimentalFeature)
{
options->addSetting(this);
}
@@ -357,4 +363,37 @@ struct GlobalConfig : public AbstractConfig
extern GlobalConfig globalConfig;
+
+struct ExperimentalFeatureSettings : Config {
+
+ Setting<std::set<ExperimentalFeature>> experimentalFeatures{this, {}, "experimental-features",
+ "Experimental Nix features to enable."};
+
+ /**
+ * Check whether the given experimental feature is enabled.
+ */
+ bool isEnabled(const ExperimentalFeature &) const;
+
+ /**
+ * Require an experimental feature be enabled, throwing an error if it is
+ * not.
+ */
+ void require(const ExperimentalFeature &) const;
+
+ /**
+ * `std::nullopt` pointer means no feature, which means there is nothing that could be
+ * disabled, and so the function returns true in that case.
+ */
+ bool isEnabled(const std::optional<ExperimentalFeature> &) const;
+
+ /**
+ * `std::nullopt` pointer means no feature, which means there is nothing that could be
+ * disabled, and so the function does nothing in that case.
+ */
+ void require(const std::optional<ExperimentalFeature> &) const;
+};
+
+// FIXME: don't use a global variable.
+extern ExperimentalFeatureSettings experimentalFeatureSettings;
+
}
diff --git a/src/libutil/error.cc b/src/libutil/error.cc
index e4f0d4677..c9d61942a 100644
--- a/src/libutil/error.cc
+++ b/src/libutil/error.cc
@@ -302,14 +302,14 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
if (!einfo.traces.empty()) {
size_t count = 0;
for (const auto & trace : einfo.traces) {
+ if (trace.hint.str().empty()) continue;
+ if (frameOnly && !trace.frame) continue;
+
if (!showTrace && count > 3) {
oss << "\n" << ANSI_WARNING "(stack trace truncated; use '--show-trace' to show the full trace)" ANSI_NORMAL << "\n";
break;
}
- if (trace.hint.str().empty()) continue;
- if (frameOnly && !trace.frame) continue;
-
count++;
frameOnly = trace.frame;
diff --git a/src/libutil/filesystem.cc b/src/libutil/filesystem.cc
index 3a732cff8..56be76ecc 100644
--- a/src/libutil/filesystem.cc
+++ b/src/libutil/filesystem.cc
@@ -15,9 +15,9 @@ static Path tempName(Path tmpRoot, const Path & prefix, bool includePid,
{
tmpRoot = canonPath(tmpRoot.empty() ? getEnv("TMPDIR").value_or("/tmp") : tmpRoot, true);
if (includePid)
- return (format("%1%/%2%-%3%-%4%") % tmpRoot % prefix % getpid() % counter++).str();
+ return fmt("%1%/%2%-%3%-%4%", tmpRoot, prefix, getpid(), counter++);
else
- return (format("%1%/%2%-%3%") % tmpRoot % prefix % counter++).str();
+ return fmt("%1%/%2%-%3%", tmpRoot, prefix, counter++);
}
Path createTempDir(const Path & tmpRoot, const Path & prefix,
diff --git a/src/libutil/fmt.hh b/src/libutil/fmt.hh
index e879fd3b8..e11426b88 100644
--- a/src/libutil/fmt.hh
+++ b/src/libutil/fmt.hh
@@ -17,16 +17,6 @@ using boost::format;
struct nop { template<typename... T> nop(T...) {} };
-struct FormatOrString
-{
- std::string s;
- FormatOrString(std::string s) : s(std::move(s)) { };
- template<class F>
- FormatOrString(const F & f) : s(f.str()) { };
- FormatOrString(const char * s) : s(s) { };
-};
-
-
/* A helper for formatting strings. ‘fmt(format, a_0, ..., a_n)’ is
equivalent to ‘boost::format(format) % a_0 % ... %
... a_n’. However, ‘fmt(s)’ is equivalent to ‘s’ (so no %-expansion
@@ -53,11 +43,6 @@ inline std::string fmt(const char * s)
return s;
}
-inline std::string fmt(const FormatOrString & fs)
-{
- return fs.s;
-}
-
template<typename... Args>
inline std::string fmt(const std::string & fs, const Args & ... args)
{
diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc
index d2fd0c15a..5735e4715 100644
--- a/src/libutil/hash.cc
+++ b/src/libutil/hash.cc
@@ -71,12 +71,13 @@ const std::string base16Chars = "0123456789abcdef";
static std::string printHash16(const Hash & hash)
{
- char buf[hash.hashSize * 2];
+ std::string buf;
+ buf.reserve(hash.hashSize * 2);
for (unsigned int i = 0; i < hash.hashSize; i++) {
- buf[i * 2] = base16Chars[hash.hash[i] >> 4];
- buf[i * 2 + 1] = base16Chars[hash.hash[i] & 0x0f];
+ buf.push_back(base16Chars[hash.hash[i] >> 4]);
+ buf.push_back(base16Chars[hash.hash[i] & 0x0f]);
}
- return std::string(buf, hash.hashSize * 2);
+ return buf;
}
@@ -130,7 +131,7 @@ std::string Hash::to_string(Base base, bool includeType) const
break;
case Base64:
case SRI:
- s += base64Encode(std::string((const char *) hash, hashSize));
+ s += base64Encode(std::string_view((const char *) hash, hashSize));
break;
}
return s;
@@ -403,7 +404,7 @@ HashType parseHashType(std::string_view s)
throw UsageError("unknown hash algorithm '%1%'", s);
}
-std::string printHashType(HashType ht)
+std::string_view printHashType(HashType ht)
{
switch (ht) {
case htMD5: return "md5";
diff --git a/src/libutil/hash.hh b/src/libutil/hash.hh
index 00f70a572..38d09646e 100644
--- a/src/libutil/hash.hh
+++ b/src/libutil/hash.hh
@@ -133,7 +133,7 @@ HashType parseHashType(std::string_view s);
std::optional<HashType> parseHashTypeOpt(std::string_view s);
/* And the reverse. */
-std::string printHashType(HashType ht);
+std::string_view printHashType(HashType ht);
union Ctx;
diff --git a/src/libutil/logging.cc b/src/libutil/logging.cc
index 904ba6ebe..7cac75ce1 100644
--- a/src/libutil/logging.cc
+++ b/src/libutil/logging.cc
@@ -32,7 +32,8 @@ void Logger::warn(const std::string & msg)
void Logger::writeToStdout(std::string_view s)
{
- std::cout << s << "\n";
+ writeFull(STDOUT_FILENO, s);
+ writeFull(STDOUT_FILENO, "\n");
}
class SimpleLogger : public Logger
@@ -53,7 +54,7 @@ public:
return printBuildLogs;
}
- void log(Verbosity lvl, const FormatOrString & fs) override
+ void log(Verbosity lvl, std::string_view s) override
{
if (lvl > verbosity) return;
@@ -71,7 +72,7 @@ public:
prefix = std::string("<") + c + ">";
}
- writeToStderr(prefix + filterANSIEscapes(fs.s, !tty) + "\n");
+ writeToStderr(prefix + filterANSIEscapes(s, !tty) + "\n");
}
void logEI(const ErrorInfo & ei) override
@@ -84,7 +85,7 @@ public:
void startActivity(ActivityId act, Verbosity lvl, ActivityType type,
const std::string & s, const Fields & fields, ActivityId parent)
- override
+ override
{
if (lvl <= verbosity && !s.empty())
log(lvl, s + "...");
@@ -173,12 +174,12 @@ struct JSONLogger : Logger {
prevLogger.log(lvlError, "@nix " + json.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace));
}
- void log(Verbosity lvl, const FormatOrString & fs) override
+ void log(Verbosity lvl, std::string_view s) override
{
nlohmann::json json;
json["action"] = "msg";
json["level"] = lvl;
- json["msg"] = fs.s;
+ json["msg"] = s;
write(json);
}
diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh
index 4642c49f7..59a707eef 100644
--- a/src/libutil/logging.hh
+++ b/src/libutil/logging.hh
@@ -75,11 +75,11 @@ public:
// Whether the logger prints the whole build log
virtual bool isVerbose() { return false; }
- virtual void log(Verbosity lvl, const FormatOrString & fs) = 0;
+ virtual void log(Verbosity lvl, std::string_view s) = 0;
- void log(const FormatOrString & fs)
+ void log(std::string_view s)
{
- log(lvlInfo, fs);
+ log(lvlInfo, s);
}
virtual void logEI(const ErrorInfo & ei) = 0;
@@ -102,11 +102,9 @@ public:
virtual void writeToStdout(std::string_view s);
template<typename... Args>
- inline void cout(const std::string & fs, const Args & ... args)
+ inline void cout(const Args & ... args)
{
- boost::format f(fs);
- formatHelper(f, args...);
- writeToStdout(f.str());
+ writeToStdout(fmt(args...));
}
virtual std::optional<char> ask(std::string_view s)
diff --git a/src/libutil/serialise.cc b/src/libutil/serialise.cc
index c653db9d0..7476e6f6c 100644
--- a/src/libutil/serialise.cc
+++ b/src/libutil/serialise.cc
@@ -415,7 +415,7 @@ Error readError(Source & source)
auto msg = readString(source);
ErrorInfo info {
.level = level,
- .msg = hintformat(std::move(format("%s") % msg)),
+ .msg = hintformat(fmt("%s", msg)),
};
auto havePos = readNum<size_t>(source);
assert(havePos == 0);
@@ -424,7 +424,7 @@ Error readError(Source & source)
havePos = readNum<size_t>(source);
assert(havePos == 0);
info.traces.push_back(Trace {
- .hint = hintformat(std::move(format("%s") % readString(source)))
+ .hint = hintformat(fmt("%s", readString(source)))
});
}
return Error(std::move(info));
diff --git a/src/libutil/url-parts.hh b/src/libutil/url-parts.hh
index d5e6a2736..afc1df98a 100644
--- a/src/libutil/url-parts.hh
+++ b/src/libutil/url-parts.hh
@@ -23,7 +23,7 @@ const static std::string absPathRegex = "(?:(?:/" + segmentRegex + ")*/?)";
const static std::string pathRegex = "(?:" + segmentRegex + "(?:/" + segmentRegex + ")*/?)";
// A Git ref (i.e. branch or tag name).
-const static std::string refRegexS = "[a-zA-Z0-9][a-zA-Z0-9_.\\/-]*"; // FIXME: check
+const static std::string refRegexS = "[a-zA-Z0-9@][a-zA-Z0-9_.\\/@-]*"; // FIXME: check
extern std::regex refRegex;
// Instead of defining what a good Git Ref is, we define what a bad Git Ref is
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 885bae69c..843a10eab 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -54,6 +54,11 @@ std::optional<std::string> getEnv(const std::string & key)
return std::string(value);
}
+std::optional<std::string> getEnvNonEmpty(const std::string & key) {
+ auto value = getEnv(key);
+ if (value == "") return {};
+ return value;
+}
std::map<std::string, std::string> getEnv()
{
@@ -523,7 +528,7 @@ void deletePath(const Path & path)
void deletePath(const Path & path, uint64_t & bytesFreed)
{
- //Activity act(*logger, lvlDebug, format("recursively deleting path '%1%'") % path);
+ //Activity act(*logger, lvlDebug, "recursively deleting path '%1%'", path);
bytesFreed = 0;
_deletePath(path, bytesFreed);
}
@@ -1065,12 +1070,14 @@ static pid_t doFork(bool allowVfork, std::function<void()> fun)
}
+#if __linux__
static int childEntry(void * arg)
{
auto main = (std::function<void()> *) arg;
(*main)();
return 1;
}
+#endif
pid_t startProcess(std::function<void()> fun, const ProcessOptions & options)
@@ -1394,14 +1401,14 @@ std::string statusToString(int status)
{
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
if (WIFEXITED(status))
- return (format("failed with exit code %1%") % WEXITSTATUS(status)).str();
+ return fmt("failed with exit code %1%", WEXITSTATUS(status));
else if (WIFSIGNALED(status)) {
int sig = WTERMSIG(status);
#if HAVE_STRSIGNAL
const char * description = strsignal(sig);
- return (format("failed due to signal %1% (%2%)") % sig % description).str();
+ return fmt("failed due to signal %1% (%2%)", sig, description);
#else
- return (format("failed due to signal %1%") % sig).str();
+ return fmt("failed due to signal %1%", sig);
#endif
}
else
@@ -1470,7 +1477,7 @@ bool shouldANSI()
&& !getEnv("NO_COLOR").has_value();
}
-std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned int width)
+std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int width)
{
std::string t, e;
size_t w = 0;
@@ -1961,7 +1968,7 @@ std::string showBytes(uint64_t bytes)
// FIXME: move to libstore/build
-void commonChildInit(Pipe & logPipe)
+void commonChildInit()
{
logger = makeSimpleLogger();
@@ -1975,10 +1982,6 @@ void commonChildInit(Pipe & logPipe)
if (setsid() == -1)
throw SysError("creating a new session");
- /* Dup the write side of the logger pipe into stderr. */
- if (dup2(logPipe.writeSide.get(), STDERR_FILENO) == -1)
- throw SysError("cannot pipe standard error into log file");
-
/* Dup stderr to stdout. */
if (dup2(STDERR_FILENO, STDOUT_FILENO) == -1)
throw SysError("cannot dup stderr into stdout");
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index b5625ecef..5a3976d02 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -39,6 +39,10 @@ extern const std::string nativeSystem;
/* Return an environment variable. */
std::optional<std::string> getEnv(const std::string & key);
+/* Return a non empty environment variable. Returns nullopt if the env
+variable is set to "" */
+std::optional<std::string> getEnvNonEmpty(const std::string & key);
+
/* Get the entire environment. */
std::map<std::string, std::string> getEnv();
@@ -446,7 +450,6 @@ template<class C> Strings quoteStrings(const C & c)
return res;
}
-
/* Remove trailing whitespace from a string. FIXME: return
std::string_view. */
std::string chomp(std::string_view s);
@@ -569,7 +572,7 @@ bool shouldANSI();
some escape sequences (such as colour setting) are copied but not
included in the character count. Also, tabs are expanded to
spaces. */
-std::string filterANSIEscapes(const std::string & s,
+std::string filterANSIEscapes(std::string_view s,
bool filterAll = false,
unsigned int width = std::numeric_limits<unsigned int>::max());
@@ -700,7 +703,7 @@ typedef std::function<bool(const Path & path)> PathFilter;
extern PathFilter defaultPathFilter;
/* Common initialisation performed in child processes. */
-void commonChildInit(Pipe & logPipe);
+void commonChildInit();
/* Create a Unix domain socket. */
AutoCloseFD createUnixDomainSocket();