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:
jade
2024-08-07 00:50:30 +00:00
committed by Gerrit Code Review
47 changed files with 747 additions and 60 deletions
+1 -1
View File
@@ -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;
+4 -3
View File
@@ -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> {
+11 -2
View File
@@ -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);
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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}; \
+1 -1
View File
@@ -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
View File
@@ -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)
+1 -1
View File
@@ -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");
}
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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,