Compare commits
20 Commits
failed-val
...
nario
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8633ce4f8 | ||
|
|
377b60ee9b | ||
|
|
429812cdb8 | ||
|
|
f6802a8ccf | ||
|
|
bdbc739d6e | ||
|
|
c0b35c71cd | ||
|
|
ef5fedbc0d | ||
|
|
5db4b0699c | ||
|
|
462b9ac49c | ||
|
|
4df1a3ca76 | ||
|
|
9dbc2cae4f | ||
|
|
9f2b6a1b94 | ||
|
|
4f8c50fb77 | ||
|
|
c0fd9146d6 | ||
|
|
3898a7343a | ||
|
|
37eec84bc1 | ||
|
|
fe5b669534 | ||
|
|
5e46df973f | ||
|
|
9df99e0658 | ||
|
|
fa048e4383 |
@@ -3,6 +3,6 @@
|
||||
# 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'
|
||||
if host_machine.cpu_family() in [ 'arm', 'ppc' ]
|
||||
deps_other += cxx.find_library('atomic')
|
||||
endif
|
||||
|
||||
@@ -95,6 +95,7 @@ this_library = library(
|
||||
'nixcmd',
|
||||
sources,
|
||||
config_priv_h,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -50,6 +50,7 @@ subdir('nix-meson-build-support/windows-version')
|
||||
this_library = library(
|
||||
'nixexprc',
|
||||
sources,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "nix_api_util_internal.h"
|
||||
|
||||
#if NIX_USE_BOEHMGC
|
||||
# include <mutex>
|
||||
# include <boost/unordered/concurrent_flat_map.hpp>
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -207,28 +207,20 @@ void nix_state_free(EvalState * state)
|
||||
}
|
||||
|
||||
#if NIX_USE_BOEHMGC
|
||||
std::unordered_map<
|
||||
boost::concurrent_flat_map<
|
||||
const void *,
|
||||
unsigned int,
|
||||
std::hash<const void *>,
|
||||
std::equal_to<const void *>,
|
||||
traceable_allocator<std::pair<const void * const, unsigned int>>>
|
||||
nix_refcounts;
|
||||
|
||||
std::mutex nix_refcount_lock;
|
||||
nix_refcounts{};
|
||||
|
||||
nix_err nix_gc_incref(nix_c_context * context, const void * p)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
std::scoped_lock lock(nix_refcount_lock);
|
||||
auto f = nix_refcounts.find(p);
|
||||
if (f != nix_refcounts.end()) {
|
||||
f->second++;
|
||||
} else {
|
||||
nix_refcounts[p] = 1;
|
||||
}
|
||||
nix_refcounts.insert_or_visit({p, 1}, [](auto & kv) { kv.second++; });
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
@@ -239,12 +231,12 @@ nix_err nix_gc_decref(nix_c_context * context, const void * p)
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
std::scoped_lock lock(nix_refcount_lock);
|
||||
auto f = nix_refcounts.find(p);
|
||||
if (f != nix_refcounts.end()) {
|
||||
if (--f->second == 0)
|
||||
nix_refcounts.erase(f);
|
||||
} else
|
||||
bool fail = true;
|
||||
nix_refcounts.erase_if(p, [&](auto & kv) {
|
||||
fail = false;
|
||||
return !--kv.second;
|
||||
});
|
||||
if (fail)
|
||||
throw std::runtime_error("nix_gc_decref: object was not referenced");
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
|
||||
@@ -44,6 +44,7 @@ subdir('nix-meson-build-support/windows-version')
|
||||
this_library = library(
|
||||
'nix-expr-test-support',
|
||||
sources,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
# TODO: Remove `-lrapidcheck` when https://github.com/emil-e/rapidcheck/pull/326
|
||||
|
||||
@@ -110,8 +110,8 @@ std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v
|
||||
{
|
||||
Value * v2;
|
||||
try {
|
||||
auto dummyArgs = state.allocBindings(0);
|
||||
v2 = findAlongAttrPath(state, "meta.position", *dummyArgs, v).first;
|
||||
auto & dummyArgs = Bindings::emptyBindings;
|
||||
v2 = findAlongAttrPath(state, "meta.position", dummyArgs, v).first;
|
||||
} catch (Error &) {
|
||||
throw NoPositionInfo("package '%s' has no source location information", what);
|
||||
}
|
||||
|
||||
@@ -5,13 +5,15 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
Bindings Bindings::emptyBindings;
|
||||
|
||||
/* Allocate a new array of attributes for an attribute set with a specific
|
||||
capacity. The space is implicitly reserved after the Bindings
|
||||
structure. */
|
||||
Bindings * EvalState::allocBindings(size_t capacity)
|
||||
{
|
||||
if (capacity == 0)
|
||||
return &emptyBindings;
|
||||
return &Bindings::emptyBindings;
|
||||
if (capacity > std::numeric_limits<Bindings::size_t>::max())
|
||||
throw Error("attribute set of size %d is too big", capacity);
|
||||
nrAttrsets++;
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
|
||||
#endif
|
||||
|
||||
namespace nix {
|
||||
|
||||
#if NIX_USE_BOEHMGC
|
||||
|
||||
/*
|
||||
* Ensure that Boehm satisfies our alignment requirements. This is the default configuration [^]
|
||||
* and this assertion should never break for any platform. Let's assert it just in case.
|
||||
@@ -35,9 +39,6 @@
|
||||
*/
|
||||
static_assert(sizeof(void *) * 2 == GC_GRANULE_BYTES, "Boehm GC must use GC_GRANULE_WORDS = 2");
|
||||
|
||||
namespace nix {
|
||||
|
||||
#if NIX_USE_BOEHMGC
|
||||
/* Called when the Boehm GC runs out of memory. */
|
||||
static void * oomHandler(size_t requested)
|
||||
{
|
||||
|
||||
@@ -202,7 +202,6 @@ EvalState::EvalState(
|
||||
, settings{settings}
|
||||
, symbols(StaticEvalSymbols::staticSymbolTable())
|
||||
, repair(NoRepair)
|
||||
, emptyBindings(Bindings())
|
||||
, storeFS(makeMountedSourceAccessor({
|
||||
{CanonPath::root, makeEmptySourceAccessor()},
|
||||
/* In the pure eval case, we can simply require
|
||||
@@ -285,10 +284,6 @@ EvalState::EvalState(
|
||||
|
||||
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
|
||||
|
||||
vEmptyList.mkList(buildList(0));
|
||||
vNull.mkNull();
|
||||
vTrue.mkBool(true);
|
||||
vFalse.mkBool(false);
|
||||
vStringRegular.mkStringNoCopy("regular");
|
||||
vStringDirectory.mkStringNoCopy("directory");
|
||||
vStringSymlink.mkStringNoCopy("symlink");
|
||||
@@ -895,7 +890,7 @@ ListBuilder::ListBuilder(EvalState & state, size_t size)
|
||||
|
||||
Value * EvalState::getBool(bool b)
|
||||
{
|
||||
return b ? &vTrue : &vFalse;
|
||||
return b ? &Value::vTrue : &Value::vFalse;
|
||||
}
|
||||
|
||||
unsigned long nrThunks = 0;
|
||||
@@ -1090,7 +1085,9 @@ void EvalState::evalFile(const SourcePath & path, Value & v, bool mustBeTrivial)
|
||||
void EvalState::resetFileCache()
|
||||
{
|
||||
fileEvalCache.clear();
|
||||
fileEvalCache.rehash(0);
|
||||
fileParseCache.clear();
|
||||
fileParseCache.rehash(0);
|
||||
inputCache->clear();
|
||||
}
|
||||
|
||||
@@ -1301,7 +1298,7 @@ void ExprList::eval(EvalState & state, Env & env, Value & v)
|
||||
Value * ExprList::maybeThunk(EvalState & state, Env & env)
|
||||
{
|
||||
if (elems.empty()) {
|
||||
return &state.vEmptyList;
|
||||
return &Value::vEmptyList;
|
||||
}
|
||||
return Expr::maybeThunk(state, env);
|
||||
}
|
||||
@@ -2375,10 +2372,9 @@ StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePat
|
||||
if (nix::isDerivation(path.path.abs()))
|
||||
error<EvalError>("file names are not allowed to end in '%1%'", drvExtension).debugThrow();
|
||||
|
||||
auto dstPathCached = get(*srcToStore.lock(), path);
|
||||
|
||||
auto dstPath = dstPathCached ? *dstPathCached : [&]() {
|
||||
auto dstPath = fetchToStore(
|
||||
std::optional<StorePath> dstPath;
|
||||
if (!srcToStore.cvisit(path, [&dstPath](const auto & kv) { dstPath.emplace(kv.second); })) {
|
||||
dstPath.emplace(fetchToStore(
|
||||
fetchSettings,
|
||||
*store,
|
||||
path.resolveSymlinks(SymlinkResolution::Ancestors),
|
||||
@@ -2386,15 +2382,14 @@ StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePat
|
||||
path.baseName(),
|
||||
ContentAddressMethod::Raw::NixArchive,
|
||||
nullptr,
|
||||
repair);
|
||||
allowPath(dstPath);
|
||||
srcToStore.lock()->try_emplace(path, dstPath);
|
||||
printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(dstPath));
|
||||
return dstPath;
|
||||
}();
|
||||
repair));
|
||||
allowPath(*dstPath);
|
||||
srcToStore.try_emplace(path, *dstPath);
|
||||
printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(*dstPath));
|
||||
}
|
||||
|
||||
context.insert(NixStringContextElem::Opaque{.path = dstPath});
|
||||
return dstPath;
|
||||
context.insert(NixStringContextElem::Opaque{.path = *dstPath});
|
||||
return *dstPath;
|
||||
}
|
||||
|
||||
SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, NixStringContext & context, std::string_view errorCtx)
|
||||
|
||||
@@ -54,6 +54,12 @@ public:
|
||||
typedef uint32_t size_t;
|
||||
PosIdx pos;
|
||||
|
||||
/**
|
||||
* An instance of bindings objects with 0 attributes.
|
||||
* This object must never be modified.
|
||||
*/
|
||||
static Bindings emptyBindings;
|
||||
|
||||
private:
|
||||
size_t size_ = 0;
|
||||
Attr attrs[0];
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
// For `NIX_USE_BOEHMGC`, and if that's set, `GC_THREADS`
|
||||
#include "nix/expr/config.hh"
|
||||
|
||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
@@ -162,7 +164,7 @@ typedef std::
|
||||
map<std::string, Value *, std::less<std::string>, traceable_allocator<std::pair<const std::string, Value *>>>
|
||||
ValMap;
|
||||
|
||||
typedef std::unordered_map<PosIdx, DocComment> DocCommentMap;
|
||||
typedef boost::unordered_flat_map<PosIdx, DocComment, std::hash<PosIdx>> DocCommentMap;
|
||||
|
||||
struct Env
|
||||
{
|
||||
@@ -313,34 +315,6 @@ public:
|
||||
*/
|
||||
RepairFlag repair;
|
||||
|
||||
Bindings emptyBindings;
|
||||
|
||||
/**
|
||||
* Empty list constant.
|
||||
*/
|
||||
Value vEmptyList;
|
||||
|
||||
/**
|
||||
* `null` constant.
|
||||
*
|
||||
* This is _not_ a singleton. Pointer equality is _not_ sufficient.
|
||||
*/
|
||||
Value vNull;
|
||||
|
||||
/**
|
||||
* `true` constant.
|
||||
*
|
||||
* This is _not_ a singleton. Pointer equality is _not_ sufficient.
|
||||
*/
|
||||
Value vTrue;
|
||||
|
||||
/**
|
||||
* `true` constant.
|
||||
*
|
||||
* This is _not_ a singleton. Pointer equality is _not_ sufficient.
|
||||
*/
|
||||
Value vFalse;
|
||||
|
||||
/** `"regular"` */
|
||||
Value vStringRegular;
|
||||
/** `"directory"` */
|
||||
@@ -395,7 +369,7 @@ public:
|
||||
bool inDebugger = false;
|
||||
int trylevel;
|
||||
std::list<DebugTrace> debugTraces;
|
||||
std::map<const Expr *, const std::shared_ptr<const StaticEnv>> exprEnvs;
|
||||
boost::unordered_flat_map<const Expr *, const std::shared_ptr<const StaticEnv>> exprEnvs;
|
||||
|
||||
const std::shared_ptr<const StaticEnv> getStaticEnv(const Expr & expr) const
|
||||
{
|
||||
@@ -438,12 +412,12 @@ private:
|
||||
|
||||
/* Cache for calls to addToStore(); maps source paths to the store
|
||||
paths. */
|
||||
Sync<std::unordered_map<SourcePath, StorePath>> srcToStore;
|
||||
boost::concurrent_flat_map<SourcePath, StorePath, std::hash<SourcePath>> srcToStore;
|
||||
|
||||
/**
|
||||
* A cache from path names to parse trees.
|
||||
*/
|
||||
typedef std::unordered_map<
|
||||
typedef boost::unordered_flat_map<
|
||||
SourcePath,
|
||||
Expr *,
|
||||
std::hash<SourcePath>,
|
||||
@@ -455,7 +429,7 @@ private:
|
||||
/**
|
||||
* A cache from path names to values.
|
||||
*/
|
||||
typedef std::unordered_map<
|
||||
typedef boost::unordered_flat_map<
|
||||
SourcePath,
|
||||
Value,
|
||||
std::hash<SourcePath>,
|
||||
@@ -468,11 +442,12 @@ private:
|
||||
* Associate source positions of certain AST nodes with their preceding doc comment, if they have one.
|
||||
* Grouped by file.
|
||||
*/
|
||||
std::unordered_map<SourcePath, DocCommentMap> positionToDocComment;
|
||||
boost::unordered_flat_map<SourcePath, DocCommentMap, std::hash<SourcePath>> positionToDocComment;
|
||||
|
||||
LookupPath lookupPath;
|
||||
|
||||
std::map<std::string, std::optional<SourcePath>> lookupPathResolved;
|
||||
boost::unordered_flat_map<std::string, std::optional<SourcePath>, StringViewHash, std::equal_to<>>
|
||||
lookupPathResolved;
|
||||
|
||||
/**
|
||||
* Cache used by prim_match().
|
||||
@@ -746,11 +721,11 @@ public:
|
||||
/**
|
||||
* Internal primops not exposed to the user.
|
||||
*/
|
||||
std::unordered_map<
|
||||
boost::unordered_flat_map<
|
||||
std::string,
|
||||
Value *,
|
||||
std::hash<std::string>,
|
||||
std::equal_to<std::string>,
|
||||
StringViewHash,
|
||||
std::equal_to<>,
|
||||
traceable_allocator<std::pair<const std::string, Value *>>>
|
||||
internalPrimOps;
|
||||
|
||||
@@ -1017,10 +992,10 @@ private:
|
||||
|
||||
bool countCalls;
|
||||
|
||||
typedef std::map<std::string, size_t> PrimOpCalls;
|
||||
typedef boost::unordered_flat_map<std::string, size_t, StringViewHash, std::equal_to<>> PrimOpCalls;
|
||||
PrimOpCalls primOpCalls;
|
||||
|
||||
typedef std::map<ExprLambda *, size_t> FunctionCalls;
|
||||
typedef boost::unordered_flat_map<ExprLambda *, size_t> FunctionCalls;
|
||||
FunctionCalls functionCalls;
|
||||
|
||||
/** Evaluation/call profiler. */
|
||||
@@ -1028,7 +1003,7 @@ private:
|
||||
|
||||
void incrFunctionCall(ExprLambda * fun);
|
||||
|
||||
typedef std::map<PosIdx, size_t> AttrSelects;
|
||||
typedef boost::unordered_flat_map<PosIdx, size_t, std::hash<PosIdx>> AttrSelects;
|
||||
AttrSelects attrSelects;
|
||||
|
||||
friend struct ExprOpUpdate;
|
||||
|
||||
@@ -71,7 +71,7 @@ struct LexerState
|
||||
/**
|
||||
* @brief Maps some positions to a DocComment, where the comment is relevant to the location.
|
||||
*/
|
||||
std::unordered_map<PosIdx, DocComment> & positionToDocComment;
|
||||
DocCommentMap & positionToDocComment;
|
||||
|
||||
PosTable & positions;
|
||||
PosTable::Origin origin;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "nix/expr/print-options.hh"
|
||||
#include "nix/util/checked-arithmetic.hh"
|
||||
|
||||
#include <boost/unordered/unordered_flat_map_fwd.hpp>
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
|
||||
namespace nix {
|
||||
@@ -833,6 +834,35 @@ struct Value : public ValueStorage<sizeof(void *)>
|
||||
{
|
||||
friend std::string showType(const Value & v);
|
||||
|
||||
/**
|
||||
* Empty list constant.
|
||||
*
|
||||
* This is _not_ a singleton. Pointer equality is _not_ sufficient.
|
||||
*/
|
||||
static Value vEmptyList;
|
||||
|
||||
/**
|
||||
* `null` constant.
|
||||
*
|
||||
* This is _not_ a singleton. Pointer equality is _not_ sufficient.
|
||||
*/
|
||||
static Value vNull;
|
||||
|
||||
/**
|
||||
* `true` constant.
|
||||
*
|
||||
* This is _not_ a singleton. Pointer equality is _not_ sufficient.
|
||||
*/
|
||||
static Value vTrue;
|
||||
|
||||
/**
|
||||
* `true` constant.
|
||||
*
|
||||
* This is _not_ a singleton. Pointer equality is _not_ sufficient.
|
||||
*/
|
||||
static Value vFalse;
|
||||
|
||||
private:
|
||||
template<InternalType... discriminator>
|
||||
bool isa() const noexcept
|
||||
{
|
||||
@@ -1166,7 +1196,7 @@ void Value::mkBlackhole()
|
||||
}
|
||||
|
||||
typedef std::vector<Value *, traceable_allocator<Value *>> ValueVector;
|
||||
typedef std::unordered_map<
|
||||
typedef boost::unordered_flat_map<
|
||||
Symbol,
|
||||
Value *,
|
||||
std::hash<Symbol>,
|
||||
|
||||
@@ -163,6 +163,7 @@ sources = files(
|
||||
'search-path.cc',
|
||||
'value-to-json.cc',
|
||||
'value-to-xml.cc',
|
||||
'value.cc',
|
||||
'value/context.cc',
|
||||
)
|
||||
|
||||
@@ -180,6 +181,7 @@ this_library = library(
|
||||
parser_tab,
|
||||
lexer_tab,
|
||||
generated_headers,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
typedef std::unordered_map<PosIdx, DocComment> DocCommentMap;
|
||||
typedef boost::unordered_flat_map<PosIdx, DocComment, std::hash<PosIdx>> DocCommentMap;
|
||||
|
||||
Expr * parseExprFromBuf(
|
||||
char * text,
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "nix/util/sort.hh"
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -1075,11 +1077,11 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value ** args, Val
|
||||
try {
|
||||
state.forceValue(*args[0], pos);
|
||||
attrs.insert(state.s.value, args[0]);
|
||||
attrs.insert(state.symbols.create("success"), &state.vTrue);
|
||||
attrs.insert(state.symbols.create("success"), &Value::vTrue);
|
||||
} catch (AssertionError & e) {
|
||||
// `value = false;` is unfortunate but removing it is a breaking change.
|
||||
attrs.insert(state.s.value, &state.vFalse);
|
||||
attrs.insert(state.symbols.create("success"), &state.vFalse);
|
||||
attrs.insert(state.s.value, &Value::vFalse);
|
||||
attrs.insert(state.symbols.create("success"), &Value::vFalse);
|
||||
}
|
||||
|
||||
// restore the debugRepl pointer if we saved it earlier.
|
||||
@@ -1750,7 +1752,7 @@ static void derivationStrictInternal(EvalState & state, std::string_view drvName
|
||||
read them later. */
|
||||
{
|
||||
auto h = hashDerivationModulo(*state.store, drv, false);
|
||||
drvHashes.lock()->insert_or_assign(drvPath, h);
|
||||
drvHashes.insert_or_assign(drvPath, std::move(h));
|
||||
}
|
||||
|
||||
auto result = state.buildBindings(1 + drv.outputs.size());
|
||||
@@ -3326,14 +3328,14 @@ static void prim_functionArgs(EvalState & state, const PosIdx pos, Value ** args
|
||||
{
|
||||
state.forceValue(*args[0], pos);
|
||||
if (args[0]->isPrimOpApp() || args[0]->isPrimOp()) {
|
||||
v.mkAttrs(&state.emptyBindings);
|
||||
v.mkAttrs(&Bindings::emptyBindings);
|
||||
return;
|
||||
}
|
||||
if (!args[0]->isLambda())
|
||||
state.error<TypeError>("'functionArgs' requires a function").atPos(pos).debugThrow();
|
||||
|
||||
if (!args[0]->lambda().fun->hasFormals()) {
|
||||
v.mkAttrs(&state.emptyBindings);
|
||||
v.mkAttrs(&Bindings::emptyBindings);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4027,7 +4029,7 @@ static void prim_groupBy(EvalState & state, const PosIdx pos, Value ** args, Val
|
||||
auto name = state.forceStringNoCtx(
|
||||
res, pos, "while evaluating the return value of the grouping function passed to builtins.groupBy");
|
||||
auto sym = state.symbols.create(name);
|
||||
auto vector = attrs.try_emplace(sym, ValueVector()).first;
|
||||
auto vector = attrs.try_emplace<ValueVector>(sym, {}).first;
|
||||
vector->second.push_back(vElem);
|
||||
}
|
||||
|
||||
@@ -4562,27 +4564,21 @@ static RegisterPrimOp primop_convertHash({
|
||||
|
||||
struct RegexCache
|
||||
{
|
||||
struct State
|
||||
{
|
||||
std::unordered_map<std::string, std::regex, StringViewHash, std::equal_to<>> cache;
|
||||
};
|
||||
|
||||
Sync<State> state_;
|
||||
boost::concurrent_flat_map<std::string, std::regex, StringViewHash, std::equal_to<>> cache;
|
||||
|
||||
std::regex get(std::string_view re)
|
||||
{
|
||||
auto state(state_.lock());
|
||||
auto it = state->cache.find(re);
|
||||
if (it != state->cache.end())
|
||||
return it->second;
|
||||
std::regex regex;
|
||||
/* No std::regex constructor overload from std::string_view, but can be constructed
|
||||
from a pointer + size or an iterator range. */
|
||||
return state->cache
|
||||
.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(re),
|
||||
std::forward_as_tuple(/*s=*/re.data(), /*count=*/re.size(), std::regex::extended))
|
||||
.first->second;
|
||||
cache.try_emplace_and_cvisit(
|
||||
re,
|
||||
/*s=*/re.data(),
|
||||
/*count=*/re.size(),
|
||||
std::regex::extended,
|
||||
[®ex](const auto & kv) { regex = kv.second; },
|
||||
[®ex](const auto & kv) { regex = kv.second; });
|
||||
return regex;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4613,7 +4609,7 @@ void prim_match(EvalState & state, const PosIdx pos, Value ** args, Value & v)
|
||||
auto list = state.buildList(match.size() - 1);
|
||||
for (const auto & [i, v2] : enumerate(list))
|
||||
if (!match[i + 1].matched)
|
||||
v2 = &state.vNull;
|
||||
v2 = &Value::vNull;
|
||||
else
|
||||
v2 = mkString(state, match[i + 1]);
|
||||
v.mkList(list);
|
||||
@@ -4705,7 +4701,7 @@ void prim_split(EvalState & state, const PosIdx pos, Value ** args, Value & v)
|
||||
auto list2 = state.buildList(slen);
|
||||
for (const auto & [si, v2] : enumerate(list2)) {
|
||||
if (!match[si + 1].matched)
|
||||
v2 = &state.vNull;
|
||||
v2 = &Value::vNull;
|
||||
else
|
||||
v2 = mkString(state, match[si + 1]);
|
||||
}
|
||||
@@ -4826,7 +4822,7 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value ** ar
|
||||
from.emplace_back(state.forceString(
|
||||
*elem, pos, "while evaluating one of the strings to replace passed to builtins.replaceStrings"));
|
||||
|
||||
std::unordered_map<size_t, std::string_view> cache;
|
||||
boost::unordered_flat_map<size_t, std::string_view> cache;
|
||||
auto to = args[1]->listView();
|
||||
|
||||
NixStringContext context;
|
||||
@@ -5059,7 +5055,7 @@ void EvalState::createBaseEnv(const EvalSettings & evalSettings)
|
||||
|
||||
addConstant(
|
||||
"null",
|
||||
&vNull,
|
||||
&Value::vNull,
|
||||
{
|
||||
.type = nNull,
|
||||
.doc = R"(
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include <limits>
|
||||
#include <unordered_set>
|
||||
#include <sstream>
|
||||
|
||||
#include "nix/expr/print.hh"
|
||||
@@ -10,6 +9,8 @@
|
||||
#include "nix/util/english.hh"
|
||||
#include "nix/expr/eval.hh"
|
||||
|
||||
#include <boost/unordered/unordered_flat_set.hpp>
|
||||
|
||||
namespace nix {
|
||||
|
||||
void printElided(
|
||||
@@ -81,7 +82,7 @@ std::ostream & printLiteralBool(std::ostream & str, bool boolean)
|
||||
// For example `or' doesn't need to be quoted.
|
||||
bool isReservedKeyword(const std::string_view str)
|
||||
{
|
||||
static const std::unordered_set<std::string_view> reservedKeywords = {
|
||||
static const boost::unordered_flat_set<std::string_view> reservedKeywords = {
|
||||
"if", "then", "else", "assert", "with", "let", "in", "rec", "inherit"};
|
||||
return reservedKeywords.contains(str);
|
||||
}
|
||||
|
||||
29
src/libexpr/value.cc
Normal file
29
src/libexpr/value.cc
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "nix/expr/value.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
Value Value::vEmptyList = []() {
|
||||
Value res;
|
||||
res.setStorage(List{.size = 0, .elems = nullptr});
|
||||
return res;
|
||||
}();
|
||||
|
||||
Value Value::vNull = []() {
|
||||
Value res;
|
||||
res.mkNull();
|
||||
return res;
|
||||
}();
|
||||
|
||||
Value Value::vTrue = []() {
|
||||
Value res;
|
||||
res.mkBool(true);
|
||||
return res;
|
||||
}();
|
||||
|
||||
Value Value::vFalse = []() {
|
||||
Value res;
|
||||
res.mkBool(false);
|
||||
return res;
|
||||
}();
|
||||
|
||||
} // namespace nix
|
||||
@@ -53,6 +53,7 @@ subdir('nix-meson-build-support/windows-version')
|
||||
this_library = library(
|
||||
'nixfetchersc',
|
||||
sources,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "nix/fetchers/filtering-source-accessor.hh"
|
||||
|
||||
#include <boost/unordered/unordered_flat_set.hpp>
|
||||
|
||||
namespace nix {
|
||||
|
||||
std::optional<std::filesystem::path> FilteringSourceAccessor::getPhysicalPath(const CanonPath & path)
|
||||
@@ -57,12 +59,12 @@ void FilteringSourceAccessor::checkAccess(const CanonPath & path)
|
||||
struct AllowListSourceAccessorImpl : AllowListSourceAccessor
|
||||
{
|
||||
std::set<CanonPath> allowedPrefixes;
|
||||
std::unordered_set<CanonPath> allowedPaths;
|
||||
boost::unordered_flat_set<CanonPath, std::hash<CanonPath>> allowedPaths;
|
||||
|
||||
AllowListSourceAccessorImpl(
|
||||
ref<SourceAccessor> next,
|
||||
std::set<CanonPath> && allowedPrefixes,
|
||||
std::unordered_set<CanonPath> && allowedPaths,
|
||||
boost::unordered_flat_set<CanonPath, std::hash<CanonPath>> && allowedPaths,
|
||||
MakeNotAllowedError && makeNotAllowedError)
|
||||
: AllowListSourceAccessor(SourcePath(next), std::move(makeNotAllowedError))
|
||||
, allowedPrefixes(std::move(allowedPrefixes))
|
||||
@@ -84,7 +86,7 @@ struct AllowListSourceAccessorImpl : AllowListSourceAccessor
|
||||
ref<AllowListSourceAccessor> AllowListSourceAccessor::create(
|
||||
ref<SourceAccessor> next,
|
||||
std::set<CanonPath> && allowedPrefixes,
|
||||
std::unordered_set<CanonPath> && allowedPaths,
|
||||
boost::unordered_flat_set<CanonPath, std::hash<CanonPath>> && allowedPaths,
|
||||
MakeNotAllowedError && makeNotAllowedError)
|
||||
{
|
||||
return make_ref<AllowListSourceAccessorImpl>(
|
||||
|
||||
@@ -30,8 +30,9 @@
|
||||
#include <git2/sys/mempack.h>
|
||||
#include <git2/tree.h>
|
||||
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_set.hpp>
|
||||
#include <iostream>
|
||||
#include <unordered_set>
|
||||
#include <queue>
|
||||
#include <regex>
|
||||
#include <span>
|
||||
@@ -315,7 +316,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
|
||||
uint64_t getRevCount(const Hash & rev) override
|
||||
{
|
||||
std::unordered_set<git_oid> done;
|
||||
boost::unordered_flat_set<git_oid, std::hash<git_oid>> done;
|
||||
std::queue<Commit> todo;
|
||||
|
||||
todo.push(peelObject<Commit>(lookupObject(*this, hashToOID(rev)).get(), GIT_OBJECT_COMMIT));
|
||||
@@ -569,7 +570,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||
void verifyCommit(const Hash & rev, const std::vector<fetchers::PublicKey> & publicKeys) override
|
||||
{
|
||||
// Map of SSH key types to their internal OpenSSH representations
|
||||
static const std::unordered_map<std::string_view, std::string_view> keyTypeMap = {
|
||||
static const boost::unordered_flat_map<std::string_view, std::string_view> keyTypeMap = {
|
||||
{"ssh-dsa", "ssh-dsa"},
|
||||
{"ssh-ecdsa", "ssh-ecdsa"},
|
||||
{"ssh-ecdsa-sk", "sk-ecdsa-sha2-nistp256@openssh.com"},
|
||||
@@ -816,7 +817,7 @@ struct GitSourceAccessor : SourceAccessor
|
||||
return toHash(*git_tree_entry_id(entry));
|
||||
}
|
||||
|
||||
std::unordered_map<CanonPath, TreeEntry> lookupCache;
|
||||
boost::unordered_flat_map<CanonPath, TreeEntry, std::hash<CanonPath>> lookupCache;
|
||||
|
||||
/* Recursively look up 'path' relative to the root. */
|
||||
git_tree_entry * lookup(State & state, const CanonPath & path)
|
||||
@@ -1253,7 +1254,7 @@ GitRepoImpl::getAccessor(const WorkdirInfo & wd, bool exportIgnore, MakeNotAllow
|
||||
makeFSSourceAccessor(path),
|
||||
std::set<CanonPath>{wd.files},
|
||||
// Always allow access to the root, but not its children.
|
||||
std::unordered_set<CanonPath>{CanonPath::root},
|
||||
boost::unordered_flat_set<CanonPath, std::hash<CanonPath>>{CanonPath::root},
|
||||
std::move(makeNotAllowedError))
|
||||
.cast<SourceAccessor>();
|
||||
if (exportIgnore)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "nix/util/source-path.hh"
|
||||
|
||||
#include <unordered_set>
|
||||
#include <boost/unordered/unordered_flat_set_fwd.hpp>
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -72,7 +72,7 @@ struct AllowListSourceAccessor : public FilteringSourceAccessor
|
||||
static ref<AllowListSourceAccessor> create(
|
||||
ref<SourceAccessor> next,
|
||||
std::set<CanonPath> && allowedPrefixes,
|
||||
std::unordered_set<CanonPath> && allowedPaths,
|
||||
boost::unordered_flat_set<CanonPath, std::hash<CanonPath>> && allowedPaths,
|
||||
MakeNotAllowedError && makeNotAllowedError);
|
||||
|
||||
using FilteringSourceAccessor::FilteringSourceAccessor;
|
||||
|
||||
@@ -61,6 +61,7 @@ subdir('nix-meson-build-support/windows-version')
|
||||
this_library = library(
|
||||
'nixfetchers',
|
||||
sources,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -53,6 +53,7 @@ subdir('nix-meson-build-support/windows-version')
|
||||
this_library = library(
|
||||
'nixflakec',
|
||||
sources,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include <unordered_set>
|
||||
|
||||
#include "nix/fetchers/fetch-settings.hh"
|
||||
#include "nix/flake/settings.hh"
|
||||
#include "nix/flake/lockfile.hh"
|
||||
@@ -9,6 +7,7 @@
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/unordered/unordered_flat_set.hpp>
|
||||
#include <iterator>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -162,7 +161,7 @@ std::pair<nlohmann::json, LockFile::KeyMap> LockFile::toJSON() const
|
||||
{
|
||||
nlohmann::json nodes;
|
||||
KeyMap nodeKeys;
|
||||
std::unordered_set<std::string> keys;
|
||||
boost::unordered_flat_set<std::string> keys;
|
||||
|
||||
std::function<std::string(const std::string & key, ref<const Node> node)> dumpNode;
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ this_library = library(
|
||||
'nixflake',
|
||||
sources,
|
||||
generated_headers,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -45,6 +45,7 @@ subdir('nix-meson-build-support/windows-version')
|
||||
this_library = library(
|
||||
'nixmainc',
|
||||
sources,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -77,6 +77,7 @@ this_library = library(
|
||||
'nixmain',
|
||||
sources,
|
||||
config_priv_h,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -46,6 +46,7 @@ subdir('nix-meson-build-support/windows-version')
|
||||
this_library = library(
|
||||
'nixstorec',
|
||||
sources,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -44,6 +44,7 @@ subdir('nix-meson-build-support/windows-version')
|
||||
this_library = library(
|
||||
'nix-store-test-support',
|
||||
sources,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
# TODO: Remove `-lrapidcheck` when https://github.com/emil-e/rapidcheck/pull/326
|
||||
|
||||
Binary file not shown.
@@ -20,9 +20,9 @@ struct ServeProtoTest : VersionedProtoTest<ServeProto, serveProtoDir>
|
||||
{
|
||||
/**
|
||||
* For serializers that don't care about the minimum version, we
|
||||
* used the oldest one: 1.0.
|
||||
* used the oldest one: 2.5.
|
||||
*/
|
||||
ServeProto::Version defaultVersion = 2 << 8 | 0;
|
||||
ServeProto::Version defaultVersion = 2 << 8 | 5;
|
||||
};
|
||||
|
||||
VERSIONED_CHARACTERIZATION_TEST(
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "nix/util/json-utils.hh"
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace nix {
|
||||
@@ -834,7 +835,7 @@ DerivationType BasicDerivation::type() const
|
||||
throw Error("can't mix derivation output types");
|
||||
}
|
||||
|
||||
Sync<DrvHashes> drvHashes;
|
||||
DrvHashes drvHashes;
|
||||
|
||||
/* pathDerivationModulo and hashDerivationModulo are mutually recursive
|
||||
*/
|
||||
@@ -844,16 +845,13 @@ Sync<DrvHashes> drvHashes;
|
||||
*/
|
||||
static const DrvHash pathDerivationModulo(Store & store, const StorePath & drvPath)
|
||||
{
|
||||
{
|
||||
auto hashes = drvHashes.lock();
|
||||
auto h = hashes->find(drvPath);
|
||||
if (h != hashes->end()) {
|
||||
return h->second;
|
||||
}
|
||||
std::optional<DrvHash> hash;
|
||||
if (drvHashes.cvisit(drvPath, [&hash](const auto & kv) { hash.emplace(kv.second); })) {
|
||||
return *hash;
|
||||
}
|
||||
auto h = hashDerivationModulo(store, store.readInvalidDerivation(drvPath), false);
|
||||
// Cache it
|
||||
drvHashes.lock()->insert_or_assign(drvPath, h);
|
||||
drvHashes.insert_or_assign(drvPath, h);
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,94 +1,116 @@
|
||||
#include "nix/store/export-import.hh"
|
||||
#include "nix/util/serialise.hh"
|
||||
#include "nix/store/store-api.hh"
|
||||
#include "nix/util/archive.hh"
|
||||
#include "nix/store/common-protocol.hh"
|
||||
#include "nix/store/common-protocol-impl.hh"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace nix {
|
||||
|
||||
void Store::exportPaths(const StorePathSet & paths, Sink & sink)
|
||||
static const uint32_t exportMagicV1 = 0x4558494e;
|
||||
|
||||
void exportPaths(Store & store, const StorePathSet & paths, Sink & sink, unsigned int version)
|
||||
{
|
||||
auto sorted = topoSortPaths(paths);
|
||||
auto sorted = store.topoSortPaths(paths);
|
||||
std::reverse(sorted.begin(), sorted.end());
|
||||
|
||||
for (auto & path : sorted) {
|
||||
sink << 1;
|
||||
exportPath(path, sink);
|
||||
auto dumpNar = [&](const ValidPathInfo & info) {
|
||||
HashSink hashSink(HashAlgorithm::SHA256);
|
||||
TeeSink teeSink(sink, hashSink);
|
||||
|
||||
store.narFromPath(info.path, teeSink);
|
||||
|
||||
/* Refuse to export paths that have changed. This prevents
|
||||
filesystem corruption from spreading to other machines.
|
||||
Don't complain if the stored hash is zero (unknown). */
|
||||
Hash hash = hashSink.currentHash().hash;
|
||||
if (hash != info.narHash && info.narHash != Hash(info.narHash.algo))
|
||||
throw Error(
|
||||
"hash of path '%s' has changed from '%s' to '%s'!",
|
||||
store.printStorePath(info.path),
|
||||
info.narHash.to_string(HashFormat::Nix32, true),
|
||||
hash.to_string(HashFormat::Nix32, true));
|
||||
};
|
||||
|
||||
switch (version) {
|
||||
|
||||
case 1:
|
||||
for (auto & path : sorted) {
|
||||
sink << 1;
|
||||
auto info = store.queryPathInfo(path);
|
||||
dumpNar(*info);
|
||||
sink << exportMagicV1 << store.printStorePath(path);
|
||||
CommonProto::write(store, CommonProto::WriteConn{.to = sink}, info->references);
|
||||
sink << (info->deriver ? store.printStorePath(*info->deriver) : "") << 0;
|
||||
}
|
||||
sink << 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Error("unsupported nario version %d", version);
|
||||
}
|
||||
|
||||
sink << 0;
|
||||
}
|
||||
|
||||
void Store::exportPath(const StorePath & path, Sink & sink)
|
||||
{
|
||||
auto info = queryPathInfo(path);
|
||||
|
||||
HashSink hashSink(HashAlgorithm::SHA256);
|
||||
TeeSink teeSink(sink, hashSink);
|
||||
|
||||
narFromPath(path, teeSink);
|
||||
|
||||
/* Refuse to export paths that have changed. This prevents
|
||||
filesystem corruption from spreading to other machines.
|
||||
Don't complain if the stored hash is zero (unknown). */
|
||||
Hash hash = hashSink.currentHash().hash;
|
||||
if (hash != info->narHash && info->narHash != Hash(info->narHash.algo))
|
||||
throw Error(
|
||||
"hash of path '%s' has changed from '%s' to '%s'!",
|
||||
printStorePath(path),
|
||||
info->narHash.to_string(HashFormat::Nix32, true),
|
||||
hash.to_string(HashFormat::Nix32, true));
|
||||
|
||||
teeSink << exportMagic << printStorePath(path);
|
||||
CommonProto::write(*this, CommonProto::WriteConn{.to = teeSink}, info->references);
|
||||
teeSink << (info->deriver ? printStorePath(*info->deriver) : "") << 0;
|
||||
}
|
||||
|
||||
StorePaths Store::importPaths(Source & source, CheckSigsFlag checkSigs)
|
||||
StorePaths importPaths(Store & store, Source & source, CheckSigsFlag checkSigs)
|
||||
{
|
||||
StorePaths res;
|
||||
while (true) {
|
||||
auto n = readNum<uint64_t>(source);
|
||||
if (n == 0)
|
||||
break;
|
||||
if (n != 1)
|
||||
throw Error("input doesn't look like something created by 'nix-store --export'");
|
||||
|
||||
/* Extract the NAR from the source. */
|
||||
StringSink saved;
|
||||
TeeSource tee{source, saved};
|
||||
NullFileSystemObjectSink ether;
|
||||
parseDump(ether, tee);
|
||||
auto version = readNum<uint64_t>(source);
|
||||
|
||||
uint32_t magic = readInt(source);
|
||||
if (magic != exportMagic)
|
||||
throw Error("Nix archive cannot be imported; wrong format");
|
||||
/* Note: nario version 1 lacks an explicit header. The first
|
||||
integer denotes whether a store path follows or not. So look
|
||||
for 0 or 1. */
|
||||
switch (version) {
|
||||
|
||||
auto path = parseStorePath(readString(source));
|
||||
case 0:
|
||||
/* Empty version 1 nario, nothing to do. */
|
||||
break;
|
||||
|
||||
// Activity act(*logger, lvlInfo, "importing path '%s'", info.path);
|
||||
case 1:
|
||||
/* Non-empty version 1 nario. */
|
||||
while (true) {
|
||||
/* Extract the NAR from the source. */
|
||||
StringSink saved;
|
||||
TeeSource tee{source, saved};
|
||||
NullFileSystemObjectSink ether;
|
||||
parseDump(ether, tee);
|
||||
|
||||
auto references = CommonProto::Serialise<StorePathSet>::read(*this, CommonProto::ReadConn{.from = source});
|
||||
auto deriver = readString(source);
|
||||
auto narHash = hashString(HashAlgorithm::SHA256, saved.s);
|
||||
uint32_t magic = readInt(source);
|
||||
if (magic != exportMagicV1)
|
||||
throw Error("nario cannot be imported; wrong format");
|
||||
|
||||
ValidPathInfo info{path, narHash};
|
||||
if (deriver != "")
|
||||
info.deriver = parseStorePath(deriver);
|
||||
info.references = references;
|
||||
info.narSize = saved.s.size();
|
||||
auto path = store.parseStorePath(readString(source));
|
||||
|
||||
// Ignore optional legacy signature.
|
||||
if (readInt(source) == 1)
|
||||
readString(source);
|
||||
auto references = CommonProto::Serialise<StorePathSet>::read(store, CommonProto::ReadConn{.from = source});
|
||||
auto deriver = readString(source);
|
||||
auto narHash = hashString(HashAlgorithm::SHA256, saved.s);
|
||||
|
||||
// Can't use underlying source, which would have been exhausted
|
||||
auto source = StringSource(saved.s);
|
||||
addToStore(info, source, NoRepair, checkSigs);
|
||||
ValidPathInfo info{path, narHash};
|
||||
if (deriver != "")
|
||||
info.deriver = store.parseStorePath(deriver);
|
||||
info.references = references;
|
||||
info.narSize = saved.s.size();
|
||||
|
||||
res.push_back(info.path);
|
||||
// Ignore optional legacy signature.
|
||||
if (readInt(source) == 1)
|
||||
readString(source);
|
||||
|
||||
// Can't use underlying source, which would have been exhausted.
|
||||
auto source2 = StringSource(saved.s);
|
||||
store.addToStore(info, source2, NoRepair, checkSigs);
|
||||
|
||||
res.push_back(info.path);
|
||||
|
||||
auto n = readNum<uint64_t>(source);
|
||||
if (n == 0)
|
||||
break;
|
||||
if (n != 1)
|
||||
throw Error("input doesn't look like a nario");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Error("input doesn't look like a nario");
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "nix/store/derivations.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/local-store.hh"
|
||||
#include "nix/store/path.hh"
|
||||
#include "nix/util/finally.hh"
|
||||
#include "nix/util/unix-domain-socket.hh"
|
||||
#include "nix/util/signals.hh"
|
||||
@@ -13,14 +14,10 @@
|
||||
# include "nix/util/processes.hh"
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_set.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
||||
#include <climits>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -314,7 +311,12 @@ Roots LocalStore::findRoots(bool censor)
|
||||
/**
|
||||
* Key is a mere string because cannot has path with macOS's libc++
|
||||
*/
|
||||
typedef std::unordered_map<std::string, std::unordered_set<std::string>> UncheckedRoots;
|
||||
typedef boost::unordered_flat_map<
|
||||
std::string,
|
||||
boost::unordered_flat_set<std::string, StringViewHash, std::equal_to<>>,
|
||||
StringViewHash,
|
||||
std::equal_to<>>
|
||||
UncheckedRoots;
|
||||
|
||||
static void readProcLink(const std::filesystem::path & file, UncheckedRoots & roots)
|
||||
{
|
||||
@@ -328,7 +330,7 @@ static void readProcLink(const std::filesystem::path & file, UncheckedRoots & ro
|
||||
throw;
|
||||
}
|
||||
if (buf.is_absolute())
|
||||
roots[buf.string()].emplace(file.string());
|
||||
roots[buf].emplace(file.string());
|
||||
}
|
||||
|
||||
static std::string quoteRegexChars(const std::string & raw)
|
||||
@@ -463,13 +465,13 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||
bool gcKeepOutputs = settings.gcKeepOutputs;
|
||||
bool gcKeepDerivations = settings.gcKeepDerivations;
|
||||
|
||||
std::unordered_set<StorePath> roots, dead, alive;
|
||||
boost::unordered_flat_set<StorePath, std::hash<StorePath>> roots, dead, alive;
|
||||
|
||||
struct Shared
|
||||
{
|
||||
// The temp roots only store the hash part to make it easier to
|
||||
// ignore suffixes like '.lock', '.chroot' and '.check'.
|
||||
std::unordered_set<std::string> tempRoots;
|
||||
boost::unordered_flat_set<std::string, StringViewHash, std::equal_to<>> tempRoots;
|
||||
|
||||
// Hash part of the store path currently being deleted, if
|
||||
// any.
|
||||
@@ -578,9 +580,9 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||
auto storePath = maybeParseStorePath(path);
|
||||
if (storePath) {
|
||||
debug("got new GC root '%s'", path);
|
||||
auto hashPart = std::string(storePath->hashPart());
|
||||
auto hashPart = storePath->hashPart();
|
||||
auto shared(_shared.lock());
|
||||
shared->tempRoots.insert(hashPart);
|
||||
shared->tempRoots.emplace(hashPart);
|
||||
/* If this path is currently being
|
||||
deleted, then we have to wait until
|
||||
deletion is finished to ensure that
|
||||
@@ -632,7 +634,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||
Roots tempRoots;
|
||||
findTempRoots(tempRoots, true);
|
||||
for (auto & root : tempRoots) {
|
||||
_shared.lock()->tempRoots.insert(std::string(root.first.hashPart()));
|
||||
_shared.lock()->tempRoots.emplace(root.first.hashPart());
|
||||
roots.insert(root.first);
|
||||
}
|
||||
|
||||
@@ -672,7 +674,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<StorePath, StorePathSet> referrersCache;
|
||||
boost::unordered_flat_map<StorePath, StorePathSet, std::hash<StorePath>> referrersCache;
|
||||
|
||||
/* Helper function that visits all paths reachable from `start`
|
||||
via the referrers edges and optionally derivers and derivation
|
||||
@@ -739,7 +741,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||
return;
|
||||
|
||||
{
|
||||
auto hashPart = std::string(path->hashPart());
|
||||
auto hashPart = path->hashPart();
|
||||
auto shared(_shared.lock());
|
||||
if (shared->tempRoots.count(hashPart)) {
|
||||
debug("cannot delete '%s' because it's a temporary root", printStorePath(*path));
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "nix/util/sync.hh"
|
||||
#include "nix/util/variant-wrapper.hh"
|
||||
|
||||
#include <map>
|
||||
#include <boost/unordered/concurrent_flat_map_fwd.hpp>
|
||||
#include <variant>
|
||||
|
||||
namespace nix {
|
||||
@@ -507,13 +507,23 @@ DrvHash hashDerivationModulo(Store & store, const Derivation & drv, bool maskOut
|
||||
*/
|
||||
std::map<std::string, Hash> staticOutputHashes(Store & store, const Derivation & drv);
|
||||
|
||||
struct DrvHashFct
|
||||
{
|
||||
using is_avalanching = std::true_type;
|
||||
|
||||
std::size_t operator()(const StorePath & path) const noexcept
|
||||
{
|
||||
return std::hash<std::string_view>{}(path.to_string());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Memoisation of hashDerivationModulo().
|
||||
*/
|
||||
typedef std::map<StorePath, DrvHash> DrvHashes;
|
||||
typedef boost::concurrent_flat_map<StorePath, DrvHash, DrvHashFct> DrvHashes;
|
||||
|
||||
// FIXME: global, though at least thread-safe.
|
||||
extern Sync<DrvHashes> drvHashes;
|
||||
extern DrvHashes drvHashes;
|
||||
|
||||
struct Source;
|
||||
struct Sink;
|
||||
|
||||
19
src/libstore/include/nix/store/export-import.hh
Normal file
19
src/libstore/include/nix/store/export-import.hh
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "nix/store/store-api.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
/**
|
||||
* Export multiple paths in the format expected by `nix-store
|
||||
* --import`. The paths will be sorted topologically.
|
||||
*/
|
||||
void exportPaths(Store & store, const StorePathSet & paths, Sink & sink, unsigned int version);
|
||||
|
||||
/**
|
||||
* Import a sequence of NAR dumps created by `exportPaths()` into the
|
||||
* Nix store.
|
||||
*/
|
||||
StorePaths importPaths(Store & store, Source & source, CheckSigsFlag checkSigs = CheckSigs);
|
||||
|
||||
} // namespace nix
|
||||
@@ -1,13 +1,17 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "nix/store/store-api.hh"
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_set.hpp>
|
||||
|
||||
namespace nix {
|
||||
|
||||
typedef std::unordered_map<StorePath, std::unordered_set<std::string>> Roots;
|
||||
typedef boost::unordered_flat_map<
|
||||
StorePath,
|
||||
boost::unordered_flat_set<std::string, StringViewHash, std::equal_to<>>,
|
||||
std::hash<StorePath>>
|
||||
Roots;
|
||||
|
||||
struct GCOptions
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <boost/unordered/unordered_flat_set.hpp>
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -442,7 +442,7 @@ private:
|
||||
|
||||
std::pair<std::filesystem::path, AutoCloseFD> createTempDirInStore();
|
||||
|
||||
typedef std::unordered_set<ino_t> InodeHash;
|
||||
typedef boost::unordered_flat_set<ino_t> InodeHash;
|
||||
|
||||
InodeHash loadInodeHash();
|
||||
Strings readDirectoryIgnoringInodes(const Path & path, const InodeHash & inodeHash);
|
||||
|
||||
@@ -34,6 +34,7 @@ headers = [ config_pub_h ] + files(
|
||||
'derived-path-map.hh',
|
||||
'derived-path.hh',
|
||||
'downstream-placeholder.hh',
|
||||
'export-import.hh',
|
||||
'filetransfer.hh',
|
||||
'gc-store.hh',
|
||||
'globals.hh',
|
||||
|
||||
@@ -82,8 +82,6 @@ struct ServeProto::BasicClientConnection
|
||||
BuildResult getBuildDerivationResponse(const StoreDirConfig & store);
|
||||
|
||||
void narFromPath(const StoreDirConfig & store, const StorePath & path, std::function<void(Source &)> fun);
|
||||
|
||||
void importPaths(const StoreDirConfig & store, std::function<void(Sink &)> fun);
|
||||
};
|
||||
|
||||
struct ServeProto::BasicServerConnection
|
||||
|
||||
@@ -108,8 +108,6 @@ enum struct ServeProto::Command : uint64_t {
|
||||
QueryValidPaths = 1,
|
||||
QueryPathInfos = 2,
|
||||
DumpStorePath = 3,
|
||||
ImportPaths = 4,
|
||||
ExportPaths = 5,
|
||||
BuildPaths = 6,
|
||||
QueryClosure = 7,
|
||||
BuildDerivation = 8,
|
||||
|
||||
@@ -48,11 +48,6 @@ enum CheckSigsFlag : bool { NoCheckSigs = false, CheckSigs = true };
|
||||
|
||||
enum SubstituteFlag : bool { NoSubstitute = false, Substitute = true };
|
||||
|
||||
/**
|
||||
* Magic header of exportPath() output (obsolete).
|
||||
*/
|
||||
const uint32_t exportMagic = 0x4558494e;
|
||||
|
||||
enum BuildMode : uint8_t { bmNormal, bmRepair, bmCheck };
|
||||
|
||||
enum TrustedFlag : bool { NotTrusted = false, Trusted = true };
|
||||
@@ -804,21 +799,6 @@ public:
|
||||
*/
|
||||
StorePaths topoSortPaths(const StorePathSet & paths);
|
||||
|
||||
/**
|
||||
* Export multiple paths in the format expected by ‘nix-store
|
||||
* --import’.
|
||||
*/
|
||||
void exportPaths(const StorePathSet & paths, Sink & sink);
|
||||
|
||||
void exportPath(const StorePath & path, Sink & sink);
|
||||
|
||||
/**
|
||||
* Import a sequence of NAR dumps created by exportPaths() into the
|
||||
* Nix store. Optionally, the contents of the NARs are preloaded
|
||||
* into the specified FS accessor to speed up subsequent access.
|
||||
*/
|
||||
StorePaths importPaths(Source & source, CheckSigsFlag checkSigs = CheckSigs);
|
||||
|
||||
struct Stats
|
||||
{
|
||||
std::atomic<uint64_t> narInfoRead{0};
|
||||
|
||||
@@ -105,9 +105,6 @@ std::map<StorePath, UnkeyedValidPathInfo> LegacySSHStore::queryPathInfosUncached
|
||||
{
|
||||
auto conn(connections->get());
|
||||
|
||||
/* No longer support missing NAR hash */
|
||||
assert(GET_PROTOCOL_MINOR(conn->remoteVersion) >= 4);
|
||||
|
||||
debug(
|
||||
"querying remote host '%s' for info on '%s'",
|
||||
config->authority.host,
|
||||
@@ -152,40 +149,21 @@ void LegacySSHStore::addToStore(const ValidPathInfo & info, Source & source, Rep
|
||||
|
||||
auto conn(connections->get());
|
||||
|
||||
if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 5) {
|
||||
|
||||
conn->to << ServeProto::Command::AddToStoreNar << printStorePath(info.path)
|
||||
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
||||
<< info.narHash.to_string(HashFormat::Base16, false);
|
||||
ServeProto::write(*this, *conn, info.references);
|
||||
conn->to << info.registrationTime << info.narSize << info.ultimate << info.sigs
|
||||
<< renderContentAddress(info.ca);
|
||||
try {
|
||||
copyNAR(source, conn->to);
|
||||
} catch (...) {
|
||||
conn->good = false;
|
||||
throw;
|
||||
}
|
||||
conn->to.flush();
|
||||
|
||||
if (readInt(conn->from) != 1)
|
||||
throw Error(
|
||||
"failed to add path '%s' to remote host '%s'", printStorePath(info.path), config->authority.host);
|
||||
|
||||
} else {
|
||||
|
||||
conn->importPaths(*this, [&](Sink & sink) {
|
||||
try {
|
||||
copyNAR(source, sink);
|
||||
} catch (...) {
|
||||
conn->good = false;
|
||||
throw;
|
||||
}
|
||||
sink << exportMagic << printStorePath(info.path);
|
||||
ServeProto::write(*this, *conn, info.references);
|
||||
sink << (info.deriver ? printStorePath(*info.deriver) : "") << 0 << 0;
|
||||
});
|
||||
conn->to << ServeProto::Command::AddToStoreNar << printStorePath(info.path)
|
||||
<< (info.deriver ? printStorePath(*info.deriver) : "")
|
||||
<< info.narHash.to_string(HashFormat::Base16, false);
|
||||
ServeProto::write(*this, *conn, info.references);
|
||||
conn->to << info.registrationTime << info.narSize << info.ultimate << info.sigs << renderContentAddress(info.ca);
|
||||
try {
|
||||
copyNAR(source, conn->to);
|
||||
} catch (...) {
|
||||
conn->good = false;
|
||||
throw;
|
||||
}
|
||||
conn->to.flush();
|
||||
|
||||
if (readInt(conn->from) != 1)
|
||||
throw Error("failed to add path '%s' to remote host '%s'", printStorePath(info.path), config->authority.host);
|
||||
}
|
||||
|
||||
void LegacySSHStore::narFromPath(const StorePath & path, Sink & sink)
|
||||
|
||||
@@ -363,6 +363,7 @@ this_library = library(
|
||||
generated_headers,
|
||||
sources,
|
||||
config_priv_h,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include <unordered_set>
|
||||
|
||||
#include "nix/store/derivations.hh"
|
||||
#include "nix/store/parsed-derivations.hh"
|
||||
#include "nix/store/derivation-options.hh"
|
||||
@@ -13,6 +11,8 @@
|
||||
#include "nix/store/filetransfer.hh"
|
||||
#include "nix/util/strings.hh"
|
||||
|
||||
#include <boost/unordered/unordered_flat_set.hpp>
|
||||
|
||||
namespace nix {
|
||||
|
||||
void Store::computeFSClosure(
|
||||
@@ -106,7 +106,7 @@ MissingPaths Store::queryMissing(const std::vector<DerivedPath> & targets)
|
||||
|
||||
struct State
|
||||
{
|
||||
std::unordered_set<std::string> done;
|
||||
boost::unordered_flat_set<std::string> done;
|
||||
MissingPaths res;
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ ServeProto::Version ServeProto::BasicClientConnection::handshake(
|
||||
if (magic != SERVE_MAGIC_2)
|
||||
throw Error("'nix-store --serve' protocol mismatch from '%s'", host);
|
||||
auto remoteVersion = readInt(from);
|
||||
if (GET_PROTOCOL_MAJOR(remoteVersion) != 0x200)
|
||||
if (GET_PROTOCOL_MAJOR(remoteVersion) != 0x200 || GET_PROTOCOL_MINOR(remoteVersion) < 5)
|
||||
throw Error("unsupported 'nix-store --serve' protocol version on '%s'", host);
|
||||
return std::min(remoteVersion, localVersion);
|
||||
}
|
||||
@@ -93,14 +93,4 @@ void ServeProto::BasicClientConnection::narFromPath(
|
||||
fun(from);
|
||||
}
|
||||
|
||||
void ServeProto::BasicClientConnection::importPaths(const StoreDirConfig & store, std::function<void(Sink &)> fun)
|
||||
{
|
||||
to << ServeProto::Command::ImportPaths;
|
||||
fun(to);
|
||||
to.flush();
|
||||
|
||||
if (readInt(from) != 1)
|
||||
throw Error("remote machine failed to import closure");
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
||||
@@ -53,6 +53,7 @@ this_library = library(
|
||||
'nixutilc',
|
||||
sources,
|
||||
config_priv_h,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -41,6 +41,7 @@ subdir('nix-meson-build-support/windows-version')
|
||||
this_library = library(
|
||||
'nix-util-test-support',
|
||||
sources,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
# TODO: Remove `-lrapidcheck` when https://github.com/emil-e/rapidcheck/pull/326
|
||||
|
||||
@@ -258,7 +258,7 @@ public:
|
||||
*/
|
||||
std::string makeRelative(const CanonPath & path) const;
|
||||
|
||||
friend class std::hash<CanonPath>;
|
||||
friend struct std::hash<CanonPath>;
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream & stream, const CanonPath & path);
|
||||
@@ -268,6 +268,8 @@ std::ostream & operator<<(std::ostream & stream, const CanonPath & path);
|
||||
template<>
|
||||
struct std::hash<nix::CanonPath>
|
||||
{
|
||||
using is_avalanching = std::true_type;
|
||||
|
||||
std::size_t operator()(const nix::CanonPath & s) const noexcept
|
||||
{
|
||||
return std::hash<std::string>{}(s.path);
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
#include "nix/util/file-system.hh"
|
||||
#include "nix/util/finally.hh"
|
||||
|
||||
#include <boost/unordered/unordered_flat_set.hpp>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <regex>
|
||||
#include <unordered_set>
|
||||
#include <thread>
|
||||
|
||||
#include <dirent.h>
|
||||
@@ -76,7 +76,7 @@ static CgroupStats destroyCgroup(const std::filesystem::path & cgroup, bool retu
|
||||
|
||||
int round = 1;
|
||||
|
||||
std::unordered_set<pid_t> pidsShown;
|
||||
boost::unordered_flat_set<pid_t> pidsShown;
|
||||
|
||||
while (true) {
|
||||
auto pids = tokenizeString<std::vector<std::string>>(readFile(procsFile));
|
||||
|
||||
@@ -197,6 +197,7 @@ subdir('nix-meson-build-support/windows-version')
|
||||
this_library = library(
|
||||
'nixutil',
|
||||
sources,
|
||||
soversion : 0,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args : linker_export_flags,
|
||||
|
||||
@@ -104,7 +104,7 @@ std::optional<struct stat> PosixSourceAccessor::cachedLstat(const CanonPath & pa
|
||||
|
||||
if (cache.size() >= 16384)
|
||||
cache.clear();
|
||||
cache.emplace(absPath, st);
|
||||
cache.emplace(std::move(absPath), st);
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment
|
||||
auto outPaths =
|
||||
Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables);
|
||||
|
||||
std::unordered_set<StorePath> done;
|
||||
boost::unordered_flat_set<StorePath, std::hash<StorePath>> done;
|
||||
std::queue<StorePath> todo;
|
||||
for (auto & path : outPaths)
|
||||
todo.push(path);
|
||||
|
||||
@@ -522,7 +522,7 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
auto checkNixOSConfiguration = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
|
||||
try {
|
||||
Activity act(*logger, lvlInfo, actUnknown, fmt("checking NixOS configuration '%s'", attrPath));
|
||||
Bindings & bindings(*state->allocBindings(0));
|
||||
Bindings & bindings = Bindings::emptyBindings;
|
||||
auto vToplevel = findAlongAttrPath(*state, "config.system.build.toplevel", bindings, v).first;
|
||||
state->forceValue(*vToplevel, pos);
|
||||
if (!state->isDerivation(*vToplevel))
|
||||
|
||||
@@ -87,6 +87,7 @@ nix_sources = [ config_priv_h ] + files(
|
||||
'make-content-addressed.cc',
|
||||
'man-pages.cc',
|
||||
'nar.cc',
|
||||
'nario.cc',
|
||||
'optimise-store.cc',
|
||||
'path-from-hash-part.cc',
|
||||
'path-info.cc',
|
||||
|
||||
28
src/nix/nario-export.md
Normal file
28
src/nix/nario-export.md
Normal file
@@ -0,0 +1,28 @@
|
||||
R""(
|
||||
|
||||
# Examples
|
||||
|
||||
* Export the closure of building `nixpkgs#hello`:
|
||||
|
||||
```console
|
||||
# nix nario export --format 1 -r nixpkgs#hello > dump
|
||||
```
|
||||
|
||||
It can be imported in another store:
|
||||
|
||||
```console
|
||||
# nix nario import < dump
|
||||
```
|
||||
|
||||
# Description
|
||||
|
||||
This command prints on standard output a serialization of the specified store paths in `nario` format. This serialization can be imported into another store using `nix nario import`.
|
||||
|
||||
References of a path are not exported by default; use `-r` to export a complete closure.
|
||||
Paths are exported in topographically sorted order (i.e. if path `X` refers to `Y`, then `Y` appears before `X`).
|
||||
|
||||
You must specify the desired `nario` version. Currently the following versions are supported:
|
||||
|
||||
* `1`: This version is compatible with the legacy `nix-store --export` and `nix-store --import` commands.
|
||||
|
||||
)""
|
||||
15
src/nix/nario-import.md
Normal file
15
src/nix/nario-import.md
Normal file
@@ -0,0 +1,15 @@
|
||||
R""(
|
||||
|
||||
# Examples
|
||||
|
||||
* Import store paths from the file named `dump`:
|
||||
|
||||
```console
|
||||
# nix nario import < dump
|
||||
```
|
||||
|
||||
# Description
|
||||
|
||||
This command reads from standard input a serialization of store paths produced by `nix nario export` and adds them to the Nix store.
|
||||
|
||||
)""
|
||||
18
src/nix/nario-list.md
Normal file
18
src/nix/nario-list.md
Normal file
@@ -0,0 +1,18 @@
|
||||
R""(
|
||||
|
||||
# Examples
|
||||
|
||||
* List the contents of a nario file:
|
||||
|
||||
```console
|
||||
# nix nario list < dump
|
||||
/nix/store/4y1jj6cwvslmfh1bzkhbvhx77az6yf00-xgcc-14.2.1.20250322-libgcc: 201856 bytes
|
||||
/nix/store/d8hnbm5hvbg2vza50garppb63y724i94-libunistring-1.3: 2070240 bytes
|
||||
…
|
||||
```
|
||||
|
||||
# Description
|
||||
|
||||
This command lists the contents of a nario file read from standard input.
|
||||
|
||||
)""
|
||||
189
src/nix/nario.cc
Normal file
189
src/nix/nario.cc
Normal file
@@ -0,0 +1,189 @@
|
||||
#include "nix/cmd/command.hh"
|
||||
#include "nix/main/shared.hh"
|
||||
#include "nix/store/store-api.hh"
|
||||
#include "nix/store/export-import.hh"
|
||||
#include "nix/util/callback.hh"
|
||||
#include "nix/util/fs-sink.hh"
|
||||
#include "nix/util/archive.hh"
|
||||
|
||||
using namespace nix;
|
||||
|
||||
struct CmdNario : NixMultiCommand
|
||||
{
|
||||
CmdNario()
|
||||
: NixMultiCommand("nario", RegisterCommand::getCommandsFor({"nario"}))
|
||||
{
|
||||
}
|
||||
|
||||
std::string description() override
|
||||
{
|
||||
return "operations for manipulating nario files";
|
||||
}
|
||||
|
||||
Category category() override
|
||||
{
|
||||
return catUtility;
|
||||
}
|
||||
};
|
||||
|
||||
static auto rCmdNario = registerCommand<CmdNario>("nario");
|
||||
|
||||
struct CmdNarioExport : StorePathsCommand
|
||||
{
|
||||
unsigned int version = 0;
|
||||
|
||||
CmdNarioExport()
|
||||
{
|
||||
addFlag({
|
||||
.longName = "format",
|
||||
.description = "Version of the nario format to use. Must be `1`.",
|
||||
.labels = {"nario-format"},
|
||||
.handler = {&version},
|
||||
});
|
||||
}
|
||||
|
||||
std::string description() override
|
||||
{
|
||||
return "serialize store paths to standard output in nario format";
|
||||
}
|
||||
|
||||
std::string doc() override
|
||||
{
|
||||
return
|
||||
#include "nario-export.md"
|
||||
;
|
||||
}
|
||||
|
||||
void run(ref<Store> store, StorePaths && storePaths) override
|
||||
{
|
||||
if (!version)
|
||||
throw UsageError("`nix nario export` requires `--format` argument");
|
||||
|
||||
FdSink sink(getStandardOutput());
|
||||
exportPaths(*store, StorePathSet(storePaths.begin(), storePaths.end()), sink, version);
|
||||
}
|
||||
};
|
||||
|
||||
static auto rCmdNarioExport = registerCommand2<CmdNarioExport>({"nario", "export"});
|
||||
|
||||
struct CmdNarioImport : StoreCommand
|
||||
{
|
||||
std::string description() override
|
||||
{
|
||||
return "import store paths from a nario file on standard input";
|
||||
}
|
||||
|
||||
std::string doc() override
|
||||
{
|
||||
return
|
||||
#include "nario-import.md"
|
||||
;
|
||||
}
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
FdSource source(getStandardInput());
|
||||
importPaths(*store, source, NoCheckSigs); // FIXME
|
||||
}
|
||||
};
|
||||
|
||||
static auto rCmdNarioImport = registerCommand2<CmdNarioImport>({"nario", "import"});
|
||||
|
||||
struct CmdNarioList : Command
|
||||
{
|
||||
std::string description() override
|
||||
{
|
||||
return "list the contents of a nario file";
|
||||
}
|
||||
|
||||
std::string doc() override
|
||||
{
|
||||
return
|
||||
#include "nario-list.md"
|
||||
;
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
struct Config : StoreConfig
|
||||
{
|
||||
Config(const Params & params)
|
||||
: StoreConfig(params)
|
||||
{
|
||||
}
|
||||
|
||||
ref<Store> openStore() const override
|
||||
{
|
||||
abort();
|
||||
}
|
||||
};
|
||||
|
||||
struct ListingStore : Store
|
||||
{
|
||||
ListingStore(ref<const Config> config)
|
||||
: Store{*config}
|
||||
{
|
||||
}
|
||||
|
||||
void queryPathInfoUncached(
|
||||
const StorePath & path, Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override
|
||||
{
|
||||
callback(nullptr);
|
||||
}
|
||||
|
||||
std::optional<TrustedFlag> isTrustedClient() override
|
||||
{
|
||||
return Trusted;
|
||||
}
|
||||
|
||||
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void
|
||||
addToStore(const ValidPathInfo & info, Source & source, RepairFlag repair, CheckSigsFlag checkSigs) override
|
||||
{
|
||||
logger->cout(fmt("%s: %d bytes", printStorePath(info.path), info.narSize));
|
||||
// Discard the NAR.
|
||||
NullFileSystemObjectSink parseSink;
|
||||
parseDump(parseSink, source);
|
||||
}
|
||||
|
||||
StorePath addToStoreFromDump(
|
||||
Source & dump,
|
||||
std::string_view name,
|
||||
FileSerialisationMethod dumpMethod,
|
||||
ContentAddressMethod hashMethod,
|
||||
HashAlgorithm hashAlgo,
|
||||
const StorePathSet & references,
|
||||
RepairFlag repair) override
|
||||
{
|
||||
unsupported("addToStoreFromDump");
|
||||
}
|
||||
|
||||
void narFromPath(const StorePath & path, Sink & sink) override
|
||||
{
|
||||
unsupported("narFromPath");
|
||||
}
|
||||
|
||||
void queryRealisationUncached(
|
||||
const DrvOutput &, Callback<std::shared_ptr<const Realisation>> callback) noexcept override
|
||||
{
|
||||
callback(nullptr);
|
||||
}
|
||||
|
||||
ref<SourceAccessor> getFSAccessor(bool requireValidPath) override
|
||||
{
|
||||
return makeEmptySourceAccessor();
|
||||
}
|
||||
};
|
||||
|
||||
FdSource source(getStandardInput());
|
||||
auto config = make_ref<Config>(StoreConfig::Params());
|
||||
ListingStore lister(config);
|
||||
importPaths(lister, source, NoCheckSigs);
|
||||
}
|
||||
};
|
||||
|
||||
static auto rCmdNarioList = registerCommand2<CmdNarioList>({"nario", "list"});
|
||||
@@ -158,7 +158,7 @@ static void loadSourceExpr(EvalState & state, const SourcePath & path, Value & v
|
||||
directory). */
|
||||
else if (st.type == SourceAccessor::tDirectory) {
|
||||
auto attrs = state.buildBindings(maxAttrs);
|
||||
attrs.insert(state.symbols.create("_combineChannels"), &state.vEmptyList);
|
||||
attrs.insert(state.symbols.create("_combineChannels"), &Value::vEmptyList);
|
||||
StringSet seen;
|
||||
getAllExprs(state, path, seen, attrs);
|
||||
v.mkAttrs(attrs);
|
||||
|
||||
@@ -24,7 +24,7 @@ PackageInfos queryInstalled(EvalState & state, const Path & userEnv)
|
||||
if (pathExists(manifestFile)) {
|
||||
Value v;
|
||||
state.evalFile(state.rootPath(CanonPath(manifestFile)).resolveSymlinks(), v);
|
||||
Bindings & bindings(*state.allocBindings(0));
|
||||
Bindings & bindings = Bindings::emptyBindings;
|
||||
getDerivations(state, v, "", bindings, elems, false);
|
||||
}
|
||||
return elems;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "nix/util/posix-source-accessor.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/path-with-outputs.hh"
|
||||
#include "nix/store/export-import.hh"
|
||||
|
||||
#include "man-pages.hh"
|
||||
|
||||
@@ -774,7 +775,7 @@ static void opExport(Strings opFlags, Strings opArgs)
|
||||
paths.insert(store->followLinksToStorePath(i));
|
||||
|
||||
FdSink sink(getStandardOutput());
|
||||
store->exportPaths(paths, sink);
|
||||
exportPaths(*store, paths, sink, 1);
|
||||
sink.flush();
|
||||
}
|
||||
|
||||
@@ -787,7 +788,7 @@ static void opImport(Strings opFlags, Strings opArgs)
|
||||
throw UsageError("no arguments expected");
|
||||
|
||||
FdSource source(STDIN_FILENO);
|
||||
auto paths = store->importPaths(source, NoCheckSigs);
|
||||
auto paths = importPaths(*store, source, NoCheckSigs);
|
||||
|
||||
for (auto & i : paths)
|
||||
cout << fmt("%s\n", store->printStorePath(i)) << std::flush;
|
||||
@@ -985,20 +986,6 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||
store->narFromPath(store->parseStorePath(readString(in)), out);
|
||||
break;
|
||||
|
||||
case ServeProto::Command::ImportPaths: {
|
||||
if (!writeAllowed)
|
||||
throw Error("importing paths is not allowed");
|
||||
store->importPaths(in, NoCheckSigs); // FIXME: should we skip sig checking?
|
||||
out << 1; // indicate success
|
||||
break;
|
||||
}
|
||||
|
||||
case ServeProto::Command::ExportPaths: {
|
||||
readInt(in); // obsolete
|
||||
store->exportPaths(ServeProto::Serialise<StorePathSet>::read(*store, rconn), out);
|
||||
break;
|
||||
}
|
||||
|
||||
case ServeProto::Command::BuildPaths: {
|
||||
|
||||
if (!writeAllowed)
|
||||
|
||||
@@ -162,7 +162,7 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
|
||||
auto state = std::make_unique<EvalState>(LookupPath{}, store, fetchSettings, evalSettings);
|
||||
auto v = state->allocValue();
|
||||
state->eval(state->parseExprFromString(res.data, state->rootPath(CanonPath("/no-such-path"))), *v);
|
||||
Bindings & bindings(*state->allocBindings(0));
|
||||
Bindings & bindings = Bindings::emptyBindings;
|
||||
auto v2 = findAlongAttrPath(*state, settings.thisSystem, bindings, *v).first;
|
||||
|
||||
return store->parseStorePath(
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/store-open.hh"
|
||||
#include "nix/util/posix-source-accessor.hh"
|
||||
#include "nix/store/export-import.hh"
|
||||
|
||||
#include <sodium.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
@@ -233,7 +234,7 @@ StoreWrapper::exportPaths(int fd, ...)
|
||||
StorePathSet paths;
|
||||
for (int n = 2; n < items; ++n) paths.insert(THIS->store->parseStorePath(SvPV_nolen(ST(n))));
|
||||
FdSink sink(fd);
|
||||
THIS->store->exportPaths(paths, sink);
|
||||
exportPaths(*THIS->store, paths, sink, 1);
|
||||
} catch (Error & e) {
|
||||
croak("%s", e.what());
|
||||
}
|
||||
@@ -244,7 +245,7 @@ StoreWrapper::importPaths(int fd, int dontCheckSigs)
|
||||
PPCODE:
|
||||
try {
|
||||
FdSource source(fd);
|
||||
THIS->store->importPaths(source, dontCheckSigs ? NoCheckSigs : CheckSigs);
|
||||
importPaths(*THIS->store, source, dontCheckSigs ? NoCheckSigs : CheckSigs);
|
||||
} catch (Error & e) {
|
||||
croak("%s", e.what());
|
||||
}
|
||||
|
||||
@@ -9,9 +9,14 @@ clearStore
|
||||
outPath=$(nix-build dependencies.nix --no-out-link)
|
||||
|
||||
nix-store --export $outPath > $TEST_ROOT/exp
|
||||
nix nario export --format 1 "$outPath" > $TEST_ROOT/exp2
|
||||
cmp "$TEST_ROOT/exp" "$TEST_ROOT/exp2"
|
||||
|
||||
nix-store --export $(nix-store -qR $outPath) > $TEST_ROOT/exp_all
|
||||
|
||||
nix nario export --format 1 -r "$outPath" > $TEST_ROOT/exp_all2
|
||||
cmp "$TEST_ROOT/exp_all" "$TEST_ROOT/exp_all2"
|
||||
|
||||
if nix-store --export $outPath >/dev/full ; then
|
||||
echo "exporting to a bad file descriptor should fail"
|
||||
exit 1
|
||||
@@ -38,3 +43,13 @@ clearStore
|
||||
# Regression test: the derivers in exp_all2 are empty, which shouldn't
|
||||
# cause a failure.
|
||||
nix-store --import < $TEST_ROOT/exp_all2
|
||||
|
||||
|
||||
# Test `nix nario import` on files created by `nix-store --export`.
|
||||
clearStore
|
||||
nix nario import < $TEST_ROOT/exp_all
|
||||
nix path-info "$outPath"
|
||||
|
||||
|
||||
# Test `nix nario list`.
|
||||
nix nario list < $TEST_ROOT/exp_all | grepQuiet "dependencies-input-0: .* bytes"
|
||||
|
||||
Reference in New Issue
Block a user