1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-07-07 06:01:48 +02:00

Merge remote-tracking branch 'origin/master' into flake-substitution

This commit is contained in:
Eelco Dolstra 2024-11-08 16:42:12 +01:00
commit ecb418e163
157 changed files with 881 additions and 670 deletions

View file

@ -1,3 +1,4 @@
#include <algorithm>
#include <nlohmann/json.hpp>
#include "command.hh"
@ -9,8 +10,7 @@
#include "profiles.hh"
#include "repl.hh"
#include "strings.hh"
extern char * * environ __attribute__((weak));
#include "environment-variables.hh"
namespace nix {
@ -23,7 +23,8 @@ nix::Commands RegisterCommand::getCommandsFor(const std::vector<std::string> & p
if (name.size() == prefix.size() + 1) {
bool equal = true;
for (size_t i = 0; i < prefix.size(); ++i)
if (name[i] != prefix[i]) equal = false;
if (name[i] != prefix[i])
equal = false;
if (equal)
res.insert_or_assign(name[prefix.size()], command);
}
@ -42,16 +43,16 @@ void NixMultiCommand::run()
std::set<std::string> subCommandTextLines;
for (auto & [name, _] : commands)
subCommandTextLines.insert(fmt("- `%s`", name));
std::string markdownError = fmt("`nix %s` requires a sub-command. Available sub-commands:\n\n%s\n",
commandName, concatStringsSep("\n", subCommandTextLines));
std::string markdownError =
fmt("`nix %s` requires a sub-command. Available sub-commands:\n\n%s\n",
commandName,
concatStringsSep("\n", subCommandTextLines));
throw UsageError(renderMarkdownToTerminal(markdownError));
}
command->second->run();
}
StoreCommand::StoreCommand()
{
}
StoreCommand::StoreCommand() {}
ref<Store> StoreCommand::getStore()
{
@ -126,10 +127,8 @@ ref<Store> EvalCommand::getEvalStore()
ref<EvalState> EvalCommand::getEvalState()
{
if (!evalState) {
evalState =
std::allocate_shared<EvalState>(
traceable_allocator<EvalState>(),
lookupPath, getEvalStore(), fetchSettings, evalSettings, getStore());
evalState = std::allocate_shared<EvalState>(
traceable_allocator<EvalState>(), lookupPath, getEvalStore(), fetchSettings, evalSettings, getStore());
evalState->repair = repair;
@ -144,7 +143,8 @@ MixOperateOnOptions::MixOperateOnOptions()
{
addFlag({
.longName = "derivation",
.description = "Operate on the [store derivation](@docroot@/glossary.md#gloss-store-derivation) rather than its outputs.",
.description =
"Operate on the [store derivation](@docroot@/glossary.md#gloss-store-derivation) rather than its outputs.",
.category = installablesCategory,
.handler = {&operateOn, OperateOn::Derivation},
});
@ -233,46 +233,48 @@ void StorePathCommand::run(ref<Store> store, StorePaths && storePaths)
MixProfile::MixProfile()
{
addFlag({
.longName = "profile",
.description = "The profile to operate on.",
.labels = {"path"},
.handler = {&profile},
.completer = completePath
});
addFlag(
{.longName = "profile",
.description = "The profile to operate on.",
.labels = {"path"},
.handler = {&profile},
.completer = completePath});
}
void MixProfile::updateProfile(const StorePath & storePath)
{
if (!profile) return;
if (!profile)
return;
auto store = getStore().dynamic_pointer_cast<LocalFSStore>();
if (!store) throw Error("'--profile' is not supported for this Nix store");
if (!store)
throw Error("'--profile' is not supported for this Nix store");
auto profile2 = absPath(*profile);
switchLink(profile2,
createGeneration(*store, profile2, storePath));
switchLink(profile2, createGeneration(*store, profile2, storePath));
}
void MixProfile::updateProfile(const BuiltPaths & buildables)
{
if (!profile) return;
if (!profile)
return;
StorePaths result;
for (auto & buildable : buildables) {
std::visit(overloaded {
[&](const BuiltPath::Opaque & bo) {
result.push_back(bo.path);
std::visit(
overloaded{
[&](const BuiltPath::Opaque & bo) { result.push_back(bo.path); },
[&](const BuiltPath::Built & bfd) {
for (auto & output : bfd.outputs) {
result.push_back(output.second);
}
},
},
[&](const BuiltPath::Built & bfd) {
for (auto & output : bfd.outputs) {
result.push_back(output.second);
}
},
}, buildable.raw());
buildable.raw());
}
if (result.size() != 1)
throw UsageError("'--profile' requires that the arguments produce a single store path, but there are %d", result.size());
throw UsageError(
"'--profile' requires that the arguments produce a single store path, but there are %d", result.size());
updateProfile(result[0]);
}
@ -282,51 +284,85 @@ MixDefaultProfile::MixDefaultProfile()
profile = getDefaultProfile();
}
MixEnvironment::MixEnvironment() : ignoreEnvironment(false)
MixEnvironment::MixEnvironment()
: ignoreEnvironment(false)
{
addFlag({
.longName = "ignore-environment",
.longName = "ignore-env",
.aliases = {"ignore-environment"},
.shortName = 'i',
.description = "Clear the entire environment (except those specified with `--keep`).",
.description = "Clear the entire environment, except for those specified with `--keep-env-var`.",
.category = environmentVariablesCategory,
.handler = {&ignoreEnvironment, true},
});
addFlag({
.longName = "keep",
.longName = "keep-env-var",
.aliases = {"keep"},
.shortName = 'k',
.description = "Keep the environment variable *name*.",
.description = "Keep the environment variable *name*, when using `--ignore-env`.",
.category = environmentVariablesCategory,
.labels = {"name"},
.handler = {[&](std::string s) { keep.insert(s); }},
.handler = {[&](std::string s) { keepVars.insert(s); }},
});
addFlag({
.longName = "unset",
.longName = "unset-env-var",
.aliases = {"unset"},
.shortName = 'u',
.description = "Unset the environment variable *name*.",
.category = environmentVariablesCategory,
.labels = {"name"},
.handler = {[&](std::string s) { unset.insert(s); }},
.handler = {[&](std::string name) {
if (setVars.contains(name))
throw UsageError("Cannot unset environment variable '%s' that is set with '%s'", name, "--set-env-var");
unsetVars.insert(name);
}},
});
addFlag({
.longName = "set-env-var",
.shortName = 's',
.description = "Sets an environment variable *name* with *value*.",
.category = environmentVariablesCategory,
.labels = {"name", "value"},
.handler = {[&](std::string name, std::string value) {
if (unsetVars.contains(name))
throw UsageError(
"Cannot set environment variable '%s' that is unset with '%s'", name, "--unset-env-var");
if (setVars.contains(name))
throw UsageError(
"Duplicate definition of environment variable '%s' with '%s' is ambiguous", name, "--set-env-var");
setVars.insert_or_assign(name, value);
}},
});
}
void MixEnvironment::setEnviron() {
if (ignoreEnvironment) {
if (!unset.empty())
throw UsageError("--unset does not make sense with --ignore-environment");
void MixEnvironment::setEnviron()
{
if (ignoreEnvironment && !unsetVars.empty())
throw UsageError("--unset-env-var does not make sense with --ignore-env");
for (const auto & var : keep) {
auto val = getenv(var.c_str());
if (val) stringsEnv.emplace_back(fmt("%s=%s", var.c_str(), val));
}
if (!ignoreEnvironment && !keepVars.empty())
throw UsageError("--keep-env-var does not make sense without --ignore-env");
vectorEnv = stringsToCharPtrs(stringsEnv);
environ = vectorEnv.data();
} else {
if (!keep.empty())
throw UsageError("--keep does not make sense without --ignore-environment");
auto env = getEnv();
for (const auto & var : unset)
unsetenv(var.c_str());
}
if (ignoreEnvironment)
std::erase_if(env, [&](const auto & var) { return !keepVars.contains(var.first); });
for (const auto & [name, value] : setVars)
env[name] = value;
if (!unsetVars.empty())
std::erase_if(env, [&](const auto & var) { return unsetVars.contains(var.first); });
replaceEnv(env);
return;
}
}

View file

@ -13,7 +13,7 @@ namespace nix {
extern std::string programPath;
extern char * * savedArgv;
extern char ** savedArgv;
class EvalState;
struct Pos;
@ -24,7 +24,8 @@ static constexpr Command::Category catSecondary = 100;
static constexpr Command::Category catUtility = 101;
static constexpr Command::Category catNixInstallation = 102;
static constexpr auto installablesCategory = "Options that change the interpretation of [installables](@docroot@/command-ref/new-cli/nix.md#installables)";
static constexpr auto installablesCategory =
"Options that change the interpretation of [installables](@docroot@/command-ref/new-cli/nix.md#installables)";
struct NixMultiCommand : MultiCommand, virtual Command
{
@ -112,7 +113,9 @@ struct MixFlakeOptions : virtual Args, EvalCommand
* arguments) so that the completions for these flags can use them.
*/
virtual std::vector<FlakeRef> getFlakeRefsForCompletion()
{ return {}; }
{
return {};
}
};
struct SourceExprCommand : virtual Args, MixFlakeOptions
@ -122,11 +125,9 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
SourceExprCommand();
Installables parseInstallables(
ref<Store> store, std::vector<std::string> ss);
Installables parseInstallables(ref<Store> store, std::vector<std::string> ss);
ref<Installable> parseInstallable(
ref<Store> store, const std::string & installable);
ref<Installable> parseInstallable(ref<Store> store, const std::string & installable);
virtual Strings getDefaultFlakeAttrPaths();
@ -272,10 +273,10 @@ struct RegisterCommand
typedef std::map<std::vector<std::string>, std::function<ref<Command>()>> Commands;
static Commands * commands;
RegisterCommand(std::vector<std::string> && name,
std::function<ref<Command>()> command)
RegisterCommand(std::vector<std::string> && name, std::function<ref<Command>()> command)
{
if (!commands) commands = new Commands;
if (!commands)
commands = new Commands;
commands->emplace(name, command);
}
@ -285,13 +286,13 @@ struct RegisterCommand
template<class T>
static RegisterCommand registerCommand(const std::string & name)
{
return RegisterCommand({name}, [](){ return make_ref<T>(); });
return RegisterCommand({name}, []() { return make_ref<T>(); });
}
template<class T>
static RegisterCommand registerCommand2(std::vector<std::string> && name)
{
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
return RegisterCommand(std::move(name), []() { return make_ref<T>(); });
}
struct MixProfile : virtual StoreCommand
@ -313,19 +314,21 @@ struct MixDefaultProfile : MixProfile
MixDefaultProfile();
};
struct MixEnvironment : virtual Args {
struct MixEnvironment : virtual Args
{
StringSet keep, unset;
Strings stringsEnv;
std::vector<char*> vectorEnv;
StringSet keepVars;
StringSet unsetVars;
std::map<std::string, std::string> setVars;
bool ignoreEnvironment;
MixEnvironment();
/***
* Modify global environ based on `ignoreEnvironment`, `keep`, and
* `unset`. It's expected that exec will be called before this class
* goes out of scope, otherwise `environ` will become invalid.
* Modify global environ based on `ignoreEnvironment`, `keep`,
* `unset`, and `added`. It's expected that exec will be called
* before this class goes out of scope, otherwise `environ` will
* become invalid.
*/
void setEnviron();
};
@ -349,9 +352,6 @@ void completeFlakeRefWithFragment(
std::string showVersions(const std::set<std::string> & versions);
void printClosureDiff(
ref<Store> store,
const StorePath & beforePath,
const StorePath & afterPath,
std::string_view indent);
ref<Store> store, const StorePath & beforePath, const StorePath & afterPath, std::string_view indent);
}

View file

@ -75,6 +75,7 @@ headers = [config_h] + files(
headers += files('nix_api_expr_internal.h')
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
this_library = library(
'nixexprc',

View file

@ -56,6 +56,7 @@ headers = files(
)
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
this_library = library(
'nix-expr-test-support',

View file

@ -28,6 +28,7 @@ subdir('build-utils-meson/subprojects')
subdir('build-utils-meson/threads')
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
rapidcheck = dependency('rapidcheck')
deps_private += rapidcheck

View file

@ -2834,7 +2834,9 @@ void EvalState::printStatistics()
#endif
#if HAVE_BOEHMGC
{GC_is_incremental_mode() ? "gcNonIncremental" : "gc", gcFullOnlyTime},
#ifndef _WIN32 // TODO implement
{GC_is_incremental_mode() ? "gcNonIncrementalFraction" : "gcFraction", gcFullOnlyTime / cpuTime},
#endif
#endif
};
topObj["envs"] = {

View file

@ -27,6 +27,7 @@ subdir('build-utils-meson/subprojects')
subdir('build-utils-meson/threads')
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
rapidcheck = dependency('rapidcheck')
deps_private += rapidcheck

View file

@ -217,8 +217,12 @@ static void initRepoAtomically(std::filesystem::path &path, bool bare) {
try {
std::filesystem::rename(tmpDir, path);
} catch (std::filesystem::filesystem_error & e) {
if (e.code() == std::errc::file_exists) // Someone might race us to create the repository.
// Someone may race us to create the repository.
if (e.code() == std::errc::file_exists
// `path` may be attempted to be deleted by s::f::rename, in which case the code is:
|| e.code() == std::errc::directory_not_empty) {
return;
}
else
throw SysError("moving temporary git repository from %s to %s", tmpDir, path);
}

View file

@ -27,6 +27,7 @@ subdir('build-utils-meson/subprojects')
subdir('build-utils-meson/threads')
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
rapidcheck = dependency('rapidcheck')
deps_private += rapidcheck

View file

@ -68,6 +68,7 @@ headers = [config_h] + files(
)
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
this_library = library(
'nixmainc',

View file

@ -543,7 +543,7 @@ public:
auto state(state_.lock());
if (!state->active) return {};
std::cerr << fmt("\r\e[K%s ", msg);
auto s = trim(readLine(STDIN_FILENO));
auto s = trim(readLine(getStandardInput(), true));
if (s.size() != 1) return {};
draw(*state);
return s[0];

View file

@ -67,6 +67,7 @@ headers = [config_h] + files(
headers += files('nix_api_store_internal.h')
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
this_library = library(
'nixstorec',

View file

@ -58,6 +58,7 @@ headers = files(
)
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
this_library = library(
'nix-store-test-support',

View file

@ -28,6 +28,7 @@ subdir('build-utils-meson/subprojects')
subdir('build-utils-meson/threads')
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
sqlite = dependency('sqlite3', 'sqlite', version : '>=3.6.19')
deps_private += sqlite

View file

@ -38,15 +38,19 @@ mkMesonExecutable (finalAttrs: {
(fileset.fileFilter (file: file.hasExt "hh") ./.)
];
buildInputs = [
nix-store
nix-store-c
nix-store-test-support
# Hack for sake of the dev shell
passthru.externalBuildInputs = [
sqlite
rapidcheck
gtest
];
buildInputs = finalAttrs.passthru.externalBuildInputs ++ [
nix-store
nix-store-c
nix-store-test-support
];
preConfigure =
# "Inline" .version so it's not a symlink, and includes the suffix.
# Do the meson utils, without modification.

View file

@ -459,21 +459,14 @@ TEST_F(ServeProtoTest, handshake_client_truncated_replay_throws)
CharacterizationTest::readTest("handshake-to-client", [&](std::string toClientLog) {
for (size_t len = 0; len < toClientLog.size(); ++len) {
NullBufferedSink nullSink;
StringSource in {
// truncate
toClientLog.substr(0, len)
};
auto substring = toClientLog.substr(0, len);
StringSource in{substring};
if (len < 8) {
EXPECT_THROW(
ServeProto::BasicClientConnection::handshake(
nullSink, in, defaultVersion, "blah"),
EndOfFile);
ServeProto::BasicClientConnection::handshake(nullSink, in, defaultVersion, "blah"), EndOfFile);
} else {
// Not sure why cannot keep on checking for `EndOfFile`.
EXPECT_THROW(
ServeProto::BasicClientConnection::handshake(
nullSink, in, defaultVersion, "blah"),
Error);
EXPECT_THROW(ServeProto::BasicClientConnection::handshake(nullSink, in, defaultVersion, "blah"), Error);
}
}
});

View file

@ -725,21 +725,14 @@ TEST_F(WorkerProtoTest, handshake_client_truncated_replay_throws)
CharacterizationTest::readTest("handshake-to-client", [&](std::string toClientLog) {
for (size_t len = 0; len < toClientLog.size(); ++len) {
NullBufferedSink nullSink;
StringSource in {
// truncate
toClientLog.substr(0, len)
};
auto substring = toClientLog.substr(0, len);
StringSource in{substring};
if (len < 8) {
EXPECT_THROW(
WorkerProto::BasicClientConnection::handshake(
nullSink, in, defaultVersion, {}),
EndOfFile);
WorkerProto::BasicClientConnection::handshake(nullSink, in, defaultVersion, {}), EndOfFile);
} else {
// Not sure why cannot keep on checking for `EndOfFile`.
EXPECT_THROW(
WorkerProto::BasicClientConnection::handshake(
nullSink, in, defaultVersion, {}),
Error);
EXPECT_THROW(WorkerProto::BasicClientConnection::handshake(nullSink, in, defaultVersion, {}), Error);
}
}
});

View file

@ -34,6 +34,8 @@ subdir('build-utils-meson/subprojects')
run_command('ln', '-s',
meson.project_build_root() / '__nothing_link_target',
meson.project_build_root() / '__nothing_symlink',
# native doesn't allow dangling symlinks, which the tests require
env : { 'MSYS' : 'winsymlinks:lnk' },
check : true,
)
can_link_symlink = run_command('ln',
@ -74,6 +76,12 @@ if host_machine.system() == 'darwin'
deps_other += [sandbox]
endif
if host_machine.system() == 'windows'
wsock32 = cxx.find_library('wsock32')
deps_other += [wsock32]
endif
subdir('build-utils-meson/libatomic')
subdir('build-utils-meson/threads')
boost = dependency(
@ -410,6 +418,7 @@ foreach name, value : cpp_str_defines
endforeach
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
this_library = library(
'nixstore',

View file

@ -63,6 +63,7 @@ headers = [config_h] + files(
headers += files('nix_api_util_internal.h')
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
this_library = library(
'nixutilc',

View file

@ -53,6 +53,7 @@ headers = files(
)
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
this_library = library(
'nix-util-test-support',

View file

@ -28,6 +28,7 @@ subdir('build-utils-meson/subprojects')
subdir('build-utils-meson/threads')
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
rapidcheck = dependency('rapidcheck')
deps_private += rapidcheck

View file

@ -7,6 +7,8 @@
#include <gtest/gtest.h>
#include <memory>
namespace nixC {
TEST_F(nix_api_util_context, nix_context_error)
@ -57,6 +59,14 @@ struct MySettings : nix::Config
MySettings mySettings;
static nix::GlobalConfig::Register rs(&mySettings);
static auto createOwnedNixContext()
{
return std::unique_ptr<nix_c_context, decltype([](nix_c_context * ctx) {
if (ctx)
nix_c_context_free(ctx);
})>(nix_c_context_create(), {});
}
TEST_F(nix_api_util_context, nix_setting_get)
{
ASSERT_EQ(ctx->last_err_code, NIX_OK);
@ -97,7 +107,8 @@ TEST_F(nix_api_util_context, nix_err_msg)
// advanced usage
unsigned int sz;
err_msg = nix_err_msg(nix_c_context_create(), ctx, &sz);
auto new_ctx = createOwnedNixContext();
err_msg = nix_err_msg(new_ctx.get(), ctx, &sz);
ASSERT_EQ(sz, err_msg.size());
}
@ -113,7 +124,8 @@ TEST_F(nix_api_util_context, nix_err_info_msg)
} catch (...) {
nix_context_error(ctx);
}
nix_err_info_msg(nix_c_context_create(), ctx, OBSERVE_STRING(err_info));
auto new_ctx = createOwnedNixContext();
nix_err_info_msg(new_ctx.get(), ctx, OBSERVE_STRING(err_info));
ASSERT_STREQ("testing error", err_info.c_str());
}
@ -130,7 +142,8 @@ TEST_F(nix_api_util_context, nix_err_name)
} catch (...) {
nix_context_error(ctx);
}
nix_err_name(nix_c_context_create(), ctx, OBSERVE_STRING(err_name));
auto new_ctx = createOwnedNixContext();
nix_err_name(new_ctx.get(), ctx, OBSERVE_STRING(err_name));
ASSERT_EQ(std::string(err_name), "nix::Error");
}

View file

@ -13,6 +13,8 @@
namespace nix {
static constexpr auto environmentVariablesCategory = "Options that change environment variables";
/**
* @return an environment variable.
*/

View file

@ -77,8 +77,13 @@ void writeFull(Descriptor fd, std::string_view s, bool allowInterrupts = true);
/**
* Read a line from a file descriptor.
*
* @param fd The file descriptor to read from
* @param eofOk If true, return an unterminated line if EOF is reached. (e.g. the empty string)
*
* @return A line of text ending in `\n`, or a string without `\n` if `eofOk` is true and EOF is reached.
*/
std::string readLine(Descriptor fd);
std::string readLine(Descriptor fd, bool eofOk = false);
/**
* Write a line to a file descriptor.
@ -101,8 +106,25 @@ void drainFD(
#endif
);
/**
* Get [Standard Input](https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin))
*/
[[gnu::always_inline]]
inline Descriptor getStandardOut() {
inline Descriptor getStandardInput()
{
#ifndef _WIN32
return STDIN_FILENO;
#else
return GetStdHandle(STD_INPUT_HANDLE);
#endif
}
/**
* Get [Standard Output](https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout))
*/
[[gnu::always_inline]]
inline Descriptor getStandardOutput()
{
#ifndef _WIN32
return STDOUT_FILENO;
#else
@ -110,6 +132,19 @@ inline Descriptor getStandardOut() {
#endif
}
/**
* Get [Standard Error](https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr))
*/
[[gnu::always_inline]]
inline Descriptor getStandardError()
{
#ifndef _WIN32
return STDERR_FILENO;
#else
return GetStdHandle(STD_ERROR_HANDLE);
#endif
}
/**
* Automatic cleanup of resources.
*/

View file

@ -38,7 +38,7 @@ void Logger::warn(const std::string & msg)
void Logger::writeToStdout(std::string_view s)
{
Descriptor standard_out = getStandardOut();
Descriptor standard_out = getStandardOutput();
writeFull(standard_out, s);
writeFull(standard_out, "\n");
}
@ -118,11 +118,7 @@ void writeToStderr(std::string_view s)
{
try {
writeFull(
#ifdef _WIN32
GetStdHandle(STD_ERROR_HANDLE),
#else
STDERR_FILENO,
#endif
getStandardError(),
s, false);
} catch (SystemError & e) {
/* Ignore failing writes to stderr. We need to ignore write

View file

@ -53,16 +53,9 @@ endforeach
configdata.set('HAVE_DECL_AT_SYMLINK_NOFOLLOW', cxx.has_header_symbol('fcntl.h', 'AT_SYMLINK_NOFOLLOW').to_int())
subdir('build-utils-meson/libatomic')
subdir('build-utils-meson/threads')
# Check if -latomic is needed
# This is needed for std::atomic on some platforms
# We did not manage to test this reliably on all platforms, so we hardcode
# it for now.
if host_machine.cpu_family() == 'arm'
deps_other += cxx.find_library('atomic')
endif
if host_machine.system() == 'windows'
socket = cxx.find_library('ws2_32')
deps_other += socket
@ -265,6 +258,7 @@ else
endif
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
this_library = library(
'nixutil',

View file

@ -7,8 +7,8 @@
namespace nix {
PosixSourceAccessor::PosixSourceAccessor(std::filesystem::path && root)
: root(std::move(root))
PosixSourceAccessor::PosixSourceAccessor(std::filesystem::path && argRoot)
: root(std::move(argRoot))
{
assert(root.empty() || root.is_absolute());
displayPrefix = root.string();

View file

@ -2,6 +2,7 @@
///@file
#include <memory>
#include <type_traits>
#include "types.hh"
#include "util.hh"
@ -202,7 +203,14 @@ struct StringSource : Source
{
std::string_view s;
size_t pos;
// NOTE: Prevent unintentional dangling views when an implicit conversion
// 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)) {}
size_t read(char * data, size_t len) override;
};

View file

@ -47,7 +47,7 @@ void writeFull(int fd, std::string_view s, bool allowInterrupts)
}
std::string readLine(int fd)
std::string readLine(int fd, bool eofOk)
{
std::string s;
while (1) {
@ -58,8 +58,12 @@ std::string readLine(int fd)
if (rd == -1) {
if (errno != EINTR)
throw SysError("reading a line");
} else if (rd == 0)
throw EndOfFile("unexpected EOF reading a line");
} else if (rd == 0) {
if (eofOk)
return s;
else
throw EndOfFile("unexpected EOF reading a line");
}
else {
if (ch == '\n') return s;
s += ch;

View file

@ -61,7 +61,7 @@ void writeFull(HANDLE handle, std::string_view s, bool allowInterrupts)
}
std::string readLine(HANDLE handle)
std::string readLine(HANDLE handle, bool eofOk)
{
std::string s;
while (1) {
@ -71,8 +71,12 @@ std::string readLine(HANDLE handle)
DWORD rd;
if (!ReadFile(handle, &ch, 1, &rd, NULL)) {
throw WinError("reading a line");
} else if (rd == 0)
throw EndOfFile("unexpected EOF reading a line");
} else if (rd == 0) {
if (eofOk)
return s;
else
throw EndOfFile("unexpected EOF reading a line");
}
else {
if (ch == '\n') return s;
s += ch;

View file

@ -536,7 +536,7 @@ static void main_nix_build(int argc, char * * argv)
env["__ETC_PROFILE_SOURCED"] = "1";
}
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmpDir.path();
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmpDir.path().string();
env["NIX_STORE"] = store->storeDir;
env["NIX_BUILD_CORES"] = std::to_string(settings.buildCores);

View file

@ -694,7 +694,7 @@ static void opDump(Strings opFlags, Strings opArgs)
if (!opFlags.empty()) throw UsageError("unknown flag");
if (opArgs.size() != 1) throw UsageError("only one argument allowed");
FdSink sink(getStandardOut());
FdSink sink(getStandardOutput());
std::string path = *opArgs.begin();
dumpPath(path, sink);
sink.flush();
@ -722,7 +722,7 @@ static void opExport(Strings opFlags, Strings opArgs)
for (auto & i : opArgs)
paths.insert(store->followLinksToStorePath(i));
FdSink sink(getStandardOut());
FdSink sink(getStandardOutput());
store->exportPaths(paths, sink);
sink.flush();
}
@ -835,7 +835,7 @@ static void opServe(Strings opFlags, Strings opArgs)
if (!opArgs.empty()) throw UsageError("no arguments expected");
FdSource in(STDIN_FILENO);
FdSink out(getStandardOut());
FdSink out(getStandardOutput());
/* Exchange the greeting. */
ServeProto::Version clientVersion =

View file

@ -16,7 +16,7 @@ struct MixCat : virtual Args
throw Error("path '%1%' is not a regular file", path);
stopProgressBar();
writeFull(getStandardOut(), accessor->readFile(CanonPath(path)));
writeFull(getStandardOutput(), accessor->readFile(CanonPath(path)));
}
};

View file

@ -20,7 +20,7 @@ struct CmdDumpPath : StorePathCommand
void run(ref<Store> store, const StorePath & storePath) override
{
FdSink sink(getStandardOut());
FdSink sink(getStandardOutput());
store->narFromPath(storePath, sink);
sink.flush();
}
@ -55,7 +55,7 @@ struct CmdDumpPath2 : Command
void run() override
{
FdSink sink(getStandardOut());
FdSink sink(getStandardOutput());
dumpPath(path, sink);
sink.flush();
}

View file

@ -115,7 +115,7 @@ struct CmdEval : MixJSON, InstallableValueCommand, MixReadOnlyOption
else if (raw) {
stopProgressBar();
writeFull(getStandardOut(), *state->coerceToString(noPos, *v, context, "while generating the eval command output"));
writeFull(getStandardOutput(), *state->coerceToString(noPos, *v, context, "while generating the eval command output"));
}
else if (json) {

View file

@ -17,7 +17,6 @@
#include "eval-cache.hh"
#include "markdown.hh"
#include "users.hh"
#include "terminal.hh"
#include <filesystem>
#include <nlohmann/json.hpp>
@ -1275,97 +1274,25 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
auto showDerivation = [&]()
{
auto name = visitor.getAttr(state->sName)->getString();
std::optional<std::string> description;
if (auto aMeta = visitor.maybeGetAttr(state->sMeta)) {
if (auto aDescription = aMeta->maybeGetAttr(state->sDescription))
description = aDescription->getString();
}
if (json) {
std::optional<std::string> description;
if (auto aMeta = visitor.maybeGetAttr(state->sMeta)) {
if (auto aDescription = aMeta->maybeGetAttr(state->sDescription))
description = aDescription->getString();
}
j.emplace("type", "derivation");
j.emplace("name", name);
j.emplace("description", description ? *description : "");
} else {
auto type =
logger->cout("%s: %s '%s'",
headerPrefix,
attrPath.size() == 2 && attrPathS[0] == "devShell" ? "development environment" :
attrPath.size() >= 2 && attrPathS[0] == "devShells" ? "development environment" :
attrPath.size() == 3 && attrPathS[0] == "checks" ? "derivation" :
attrPath.size() >= 1 && attrPathS[0] == "hydraJobs" ? "derivation" :
"package";
if (description && !description->empty()) {
// Takes a string and returns the # of characters displayed
auto columnLengthOfString = [](std::string_view s) -> unsigned int {
unsigned int columnCount = 0;
for (auto i = s.begin(); i < s.end();) {
// Test first character to determine if it is one of
// treeConn, treeLast, treeLine
if (*i == -30) {
i += 3;
++columnCount;
}
// Escape sequences
// https://en.wikipedia.org/wiki/ANSI_escape_code
else if (*i == '\e') {
// Eat '['
if (*(++i) == '[') {
++i;
// Eat parameter bytes
while(*i >= 0x30 && *i <= 0x3f) ++i;
// Eat intermediate bytes
while(*i >= 0x20 && *i <= 0x2f) ++i;
// Eat final byte
if(*i >= 0x40 && *i <= 0x73) ++i;
}
else {
// Eat Fe Escape sequence
if (*i >= 0x40 && *i <= 0x5f) ++i;
}
}
else {
++i;
++columnCount;
}
}
return columnCount;
};
// Maximum length to print
size_t maxLength = getWindowSize().second > 0 ? getWindowSize().second : 80;
// Trim the description and only use the first line
auto trimmed = trim(*description);
auto newLinePos = trimmed.find('\n');
auto length = newLinePos != std::string::npos ? newLinePos : trimmed.length();
auto beginningOfLine = fmt("%s: %s '%s'", headerPrefix, type, name);
auto line = fmt("%s: %s '%s' - '%s'", headerPrefix, type, name, trimmed.substr(0, length));
// If we are already over the maximum length then do not trim
// and don't print the description (preserves existing behavior)
if (columnLengthOfString(beginningOfLine) >= maxLength) {
logger->cout("%s", beginningOfLine);
}
// If the entire line fits then print that
else if (columnLengthOfString(line) < maxLength) {
logger->cout("%s", line);
}
// Otherwise we need to truncate
else {
auto lineLength = columnLengthOfString(line);
auto chopOff = lineLength - maxLength;
line.resize(line.length() - chopOff);
line = line.replace(line.length() - 3, 3, "...");
logger->cout("%s", line);
}
}
else {
logger->cout("%s: %s '%s'", headerPrefix, type, name);
}
"package",
name);
}
};

View file

@ -57,7 +57,7 @@ struct CmdLog : InstallableCommand
if (!log) continue;
stopProgressBar();
printInfo("got build log for '%s' from '%s'", installable->what(), logSub.getUri());
writeFull(getStandardOut(), *log);
writeFull(getStandardOutput(), *log);
return;
}

View file

@ -35,6 +35,7 @@ subdir('build-utils-meson/subprojects')
subdir('build-utils-meson/threads')
subdir('build-utils-meson/export-all-symbols')
subdir('build-utils-meson/windows-version')
configdata = configuration_data()
@ -229,6 +230,8 @@ foreach linkname : nix_symlinks
t = custom_target(
command: ['ln', '-sf', fs.name(this_exe), '@OUTPUT@'],
output: linkname + executable_suffix,
# native doesn't allow dangling symlinks, but the target executable often doesn't exist at this time
env : { 'MSYS' : 'winsymlinks:lnk' },
# TODO(Ericson2314): Don't do this once we have the `meson.override_find_program` working)
build_by_default: true
)
@ -247,6 +250,8 @@ install_symlink(
custom_target(
command: ['ln', '-sf', fs.name(this_exe), '@OUTPUT@'],
output: 'build-remote' + executable_suffix,
# native doesn't allow dangling symlinks, but the target executable often doesn't exist at this time
env : { 'MSYS' : 'winsymlinks:lnk' },
# TODO(Ericson2314): Don't do this once we have the `meson.override_find_program` working)
build_by_default: true
)

View file

@ -177,7 +177,7 @@ struct CmdKeyGenerateSecret : Command
throw UsageError("required argument '--key-name' is missing");
stopProgressBar();
writeFull(getStandardOut(), SecretKey::generate(*keyName).to_string());
writeFull(getStandardOutput(), SecretKey::generate(*keyName).to_string());
}
};
@ -199,7 +199,7 @@ struct CmdKeyConvertSecretToPublic : Command
{
SecretKey secretKey(drainFD(STDIN_FILENO));
stopProgressBar();
writeFull(getStandardOut(), secretKey.toPublicKey().to_string());
writeFull(getStandardOutput(), secretKey.toPublicKey().to_string());
}
};