Merge changes I0fc80718,Ia182b86f,I355f82cb,I8a9b58fa,Id89f8a1f, ... into main
* changes: tree-wide: fix various lint warnings flake & doxygen: update tagline nix flake metadata: print modified dates for input flakes cli: eat terminal codes from stdout also Implement forcing CLI colour on, and document it better manual: fix a syntax error in redirects.js that made it not do anything misc docs/meson tidying build: implement clang-tidy using our plugin
This commit is contained in:
@@ -53,7 +53,7 @@ void ConfigFile::apply()
|
||||
|
||||
bool trusted = whitelist.count(baseName);
|
||||
if (!trusted) {
|
||||
switch (nix::fetchSettings.acceptFlakeConfig) {
|
||||
switch (nix::fetchSettings.acceptFlakeConfig.get()) {
|
||||
case AcceptFlakeConfig::True: {
|
||||
trusted = true;
|
||||
break;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "state.hh"
|
||||
|
||||
#include <charconv>
|
||||
#include <clocale>
|
||||
#include <memory>
|
||||
|
||||
// flip this define when doing parser development to enable some g checks.
|
||||
@@ -254,7 +253,8 @@ struct AttrState : SubexprState {
|
||||
|
||||
std::vector<AttrName> attrs;
|
||||
|
||||
void pushAttr(auto && attr, PosIdx) { attrs.emplace_back(std::move(attr)); }
|
||||
template <typename T>
|
||||
void pushAttr(T && attr, PosIdx) { attrs.emplace_back(std::forward<T>(attr)); }
|
||||
};
|
||||
|
||||
template<> struct BuildAST<grammar::attr::simple> {
|
||||
@@ -290,7 +290,8 @@ struct InheritState : SubexprState {
|
||||
std::unique_ptr<Expr> from;
|
||||
PosIdx fromPos;
|
||||
|
||||
void pushAttr(auto && attr, PosIdx pos) { attrs.emplace_back(std::move(attr), pos); }
|
||||
template <typename T>
|
||||
void pushAttr(T && attr, PosIdx pos) { attrs.emplace_back(std::forward<T>(attr), pos); }
|
||||
};
|
||||
|
||||
template<> struct BuildAST<grammar::inherit::from> {
|
||||
|
||||
@@ -477,8 +477,17 @@ struct curlFileTransfer : public FileTransfer
|
||||
|
||||
~curlFileTransfer()
|
||||
{
|
||||
stopWorkerThread();
|
||||
|
||||
try {
|
||||
stopWorkerThread();
|
||||
} catch (nix::Error e) {
|
||||
// This can only fail if a socket to our own process cannot be
|
||||
// written to, so it is always a bug in the program if it fails.
|
||||
//
|
||||
// Joining the thread would probably only cause a deadlock if this
|
||||
// happened, so just die on purpose.
|
||||
printError("failed to join curl file transfer worker thread: %1%", e.what());
|
||||
std::terminate();
|
||||
}
|
||||
workerThread.join();
|
||||
|
||||
if (curlm) curl_multi_cleanup(curlm);
|
||||
|
||||
@@ -33,7 +33,7 @@ Machine::Machine(decltype(storeUri) storeUri,
|
||||
systemTypes(systemTypes),
|
||||
sshKey(sshKey),
|
||||
maxJobs(maxJobs),
|
||||
speedFactor(speedFactor == 0.0f ? 1.0f : std::move(speedFactor)),
|
||||
speedFactor(speedFactor == 0.0f ? 1.0f : speedFactor),
|
||||
supportedFeatures(supportedFeatures),
|
||||
mandatoryFeatures(mandatoryFeatures),
|
||||
sshPublicHostKey(sshPublicHostKey)
|
||||
|
||||
@@ -192,7 +192,7 @@ static Generator<Entry> parseObject(Source & source, const Path & path)
|
||||
#define EXPECT(raw, kind) \
|
||||
do { \
|
||||
const auto s = readString(source); \
|
||||
if (s != raw) { \
|
||||
if (s != (raw)) { \
|
||||
throw badArchive("expected " kind " tag"); \
|
||||
} \
|
||||
co_yield MetadataString{s}; \
|
||||
|
||||
@@ -131,7 +131,7 @@ AutoCloseFD::AutoCloseFD(AutoCloseFD && that) : fd{that.fd}
|
||||
}
|
||||
|
||||
|
||||
AutoCloseFD & AutoCloseFD::operator =(AutoCloseFD && that)
|
||||
AutoCloseFD & AutoCloseFD::operator =(AutoCloseFD && that) noexcept(false)
|
||||
{
|
||||
close();
|
||||
fd = that.fd;
|
||||
|
||||
+1
-1
@@ -229,7 +229,7 @@ Hash::Hash(std::string_view rest, HashType type, bool isSRI)
|
||||
|
||||
for (unsigned int n = 0; n < rest.size(); ++n) {
|
||||
char c = rest[rest.size() - n - 1];
|
||||
unsigned char digit;
|
||||
size_t digit;
|
||||
for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */
|
||||
if (base32Chars[digit] == c) break;
|
||||
if (digit >= 32)
|
||||
|
||||
@@ -37,7 +37,7 @@ void Logger::warn(const std::string & msg)
|
||||
|
||||
void Logger::writeToStdout(std::string_view s)
|
||||
{
|
||||
writeFull(STDOUT_FILENO, s);
|
||||
writeFull(STDOUT_FILENO, filterANSIEscapes(s, !shouldANSI(), std::numeric_limits<unsigned int>::max(), false));
|
||||
writeFull(STDOUT_FILENO, "\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@ std::vector<std::string> shell_split(const std::string & input)
|
||||
begin = ++iterator;
|
||||
}
|
||||
break;
|
||||
// no other relevant cases; silence exhaustiveness compiler warning
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-5
@@ -9,12 +9,25 @@ namespace nix {
|
||||
|
||||
bool shouldANSI()
|
||||
{
|
||||
return isatty(STDERR_FILENO)
|
||||
&& getEnv("TERM").value_or("dumb") != "dumb"
|
||||
&& !(getEnv("NO_COLOR").has_value() || getEnv("NOCOLOR").has_value());
|
||||
// Implements the behaviour described by https://bixense.com/clicolors/
|
||||
// As well as https://force-color.org/ for compatibility, since it fits in the same shape.
|
||||
// NO_COLOR CLICOLOR CLICOLOR_FORCE Colours?
|
||||
// set x x No
|
||||
// unset x set Yes
|
||||
// unset x unset If attached to a terminal
|
||||
// [we choose the "modern" approach of colour-by-default]
|
||||
auto compute = []() -> bool {
|
||||
bool mustNotColour = getEnv("NO_COLOR").has_value() || getEnv("NOCOLOR").has_value();
|
||||
bool shouldForce = getEnv("CLICOLOR_FORCE").has_value() || getEnv("FORCE_COLOR").has_value();
|
||||
bool isTerminal = isatty(STDERR_FILENO) && getEnv("TERM").value_or("dumb") != "dumb";
|
||||
return !mustNotColour && (shouldForce || isTerminal);
|
||||
};
|
||||
static bool cached = compute();
|
||||
return cached;
|
||||
}
|
||||
|
||||
std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int width)
|
||||
// FIXME(jade): replace with TerminalCodeEater. wowie this is evil code.
|
||||
std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int width, bool eatTabs)
|
||||
{
|
||||
std::string t, e;
|
||||
size_t w = 0;
|
||||
@@ -43,7 +56,7 @@ std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int w
|
||||
t += e;
|
||||
}
|
||||
|
||||
else if (*i == '\t') {
|
||||
else if (*i == '\t' && eatTabs) {
|
||||
i++; t += ' '; w++;
|
||||
while (w < (size_t) width && w % 8) {
|
||||
t += ' '; w++;
|
||||
|
||||
+11
-1
@@ -9,6 +9,15 @@ namespace nix {
|
||||
/**
|
||||
* Determine whether ANSI escape sequences are appropriate for the
|
||||
* present output.
|
||||
*
|
||||
* This follows the rules described on https://bixense.com/clicolors/
|
||||
* with CLICOLOR defaulted to enabled (and thus ignored).
|
||||
*
|
||||
* That is to say, the following procedure is followed in order:
|
||||
* - NO_COLOR or NOCOLOR set -> always disable colour
|
||||
* - CLICOLOR_FORCE or FORCE_COLOR set -> enable colour
|
||||
* - The output is a tty; TERM != "dumb" -> enable colour
|
||||
* - Otherwise -> disable colour
|
||||
*/
|
||||
bool shouldANSI();
|
||||
|
||||
@@ -21,7 +30,8 @@ bool shouldANSI();
|
||||
*/
|
||||
std::string filterANSIEscapes(std::string_view s,
|
||||
bool filterAll = false,
|
||||
unsigned int width = std::numeric_limits<unsigned int>::max());
|
||||
unsigned int width = std::numeric_limits<unsigned int>::max(),
|
||||
bool eatTabs = true);
|
||||
|
||||
/**
|
||||
* Recalculate the window size, updating a global variable. Used in the
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ std::string percentDecode(std::string_view in)
|
||||
if (i + 2 >= in.size())
|
||||
throw BadURL("invalid URI parameter '%s'", in);
|
||||
try {
|
||||
decoded += std::stoul(std::string(in, i + 1, 2), 0, 16);
|
||||
decoded += char8_t(std::stoul(std::string(in, i + 1, 2), 0, 16));
|
||||
i += 3;
|
||||
} catch (...) {
|
||||
throw BadURL("invalid URI parameter '%s'", in);
|
||||
|
||||
+19
-5
@@ -209,6 +209,11 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
|
||||
{
|
||||
auto lockedFlake = lockFlake();
|
||||
auto & flake = lockedFlake.flake;
|
||||
auto formatTime = [](time_t time) -> std::string {
|
||||
std::ostringstream os{};
|
||||
os << std::put_time(std::localtime(&time), "%F %T");
|
||||
return os.str();
|
||||
};
|
||||
|
||||
if (json) {
|
||||
nlohmann::json j;
|
||||
@@ -260,7 +265,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
|
||||
if (auto lastModified = flake.lockedRef.input.getLastModified())
|
||||
logger->cout(
|
||||
ANSI_BOLD "Last modified:" ANSI_NORMAL " %s",
|
||||
std::put_time(std::localtime(&*lastModified), "%F %T"));
|
||||
formatTime(*lastModified));
|
||||
|
||||
if (!lockedFlake.lockFile.root->inputs.empty())
|
||||
logger->cout(ANSI_BOLD "Inputs:" ANSI_NORMAL);
|
||||
@@ -275,16 +280,25 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
|
||||
bool last = i + 1 == node.inputs.size();
|
||||
|
||||
if (auto lockedNode = std::get_if<0>(&input.second)) {
|
||||
logger->cout("%s" ANSI_BOLD "%s" ANSI_NORMAL ": %s",
|
||||
prefix + (last ? treeLast : treeConn), input.first,
|
||||
// ├───agenix: github:ryantm/agenix/8d37c5bdeade12b6479c85acd133063ab53187a0
|
||||
logger->cout("%s%s" ANSI_BOLD "%s" ANSI_NORMAL ": %s",
|
||||
prefix, last ? treeLast : treeConn, input.first,
|
||||
(*lockedNode)->lockedRef);
|
||||
|
||||
// ├───lix: https://git.lix.systems/api/v1/repos/lix-project <....>
|
||||
// │ Last modified: 2024-07-31 21:01:34
|
||||
if (auto lastModified = (*lockedNode)->lockedRef.input.getLastModified()) {
|
||||
logger->cout("%s%s" ANSI_BOLD "%s" ANSI_NORMAL ": %s",
|
||||
prefix, last ? treeNull : treeLine, "Last modified", formatTime(*lastModified));
|
||||
}
|
||||
|
||||
bool firstVisit = visited.insert(*lockedNode).second;
|
||||
|
||||
if (firstVisit) recurse(**lockedNode, prefix + (last ? treeNull : treeLine));
|
||||
} else if (auto follows = std::get_if<1>(&input.second)) {
|
||||
logger->cout("%s" ANSI_BOLD "%s" ANSI_NORMAL " follows input '%s'",
|
||||
prefix + (last ? treeLast : treeConn), input.first,
|
||||
// │ ├───darwin follows input 'flake-utils'
|
||||
logger->cout("%s%s" ANSI_BOLD "%s" ANSI_NORMAL " follows input '%s'",
|
||||
prefix, last ? treeLast : treeConn, input.first,
|
||||
printInputPath(*follows));
|
||||
}
|
||||
}
|
||||
|
||||
+7
-10
@@ -1,8 +1,8 @@
|
||||
generate_manpage_gen = gen_header.process(meson.project_source_root() / 'doc/manual/generate-manpage.nix')
|
||||
|
||||
utils_gen = gen_header.process(meson.project_source_root() / 'doc/manual/utils.nix')
|
||||
|
||||
get_env_gen = gen_header.process('get-env.sh')
|
||||
nix_generated_headers = [
|
||||
gen_header.process(meson.project_source_root() / 'doc/manual/generate-manpage.nix'),
|
||||
gen_header.process(meson.project_source_root() / 'doc/manual/utils.nix'),
|
||||
gen_header.process('get-env.sh'),
|
||||
]
|
||||
|
||||
# src/nix/profile.cc includes src/nix/profile.md, which includes "doc/files/profiles.md.gen.hh".
|
||||
# Unfortunately, https://github.com/mesonbuild/meson/issues/2320.
|
||||
@@ -18,7 +18,7 @@ run_command(
|
||||
meson.current_build_dir() / 'doc/files/profiles.md',
|
||||
check : true,
|
||||
)
|
||||
profiles_md_gen = gen_header.process(
|
||||
nix_generated_headers += gen_header.process(
|
||||
meson.current_build_dir() / 'doc/files/profiles.md',
|
||||
preserve_path_from : meson.current_build_dir(),
|
||||
)
|
||||
@@ -74,10 +74,7 @@ nix_sources = files(
|
||||
nix = executable(
|
||||
'nix',
|
||||
nix_sources,
|
||||
generate_manpage_gen,
|
||||
utils_gen,
|
||||
get_env_gen,
|
||||
profiles_md_gen,
|
||||
nix_generated_headers,
|
||||
nix2_commands_sources,
|
||||
dependencies : [
|
||||
libasanoptions,
|
||||
|
||||
Reference in New Issue
Block a user