mirror of
https://github.com/NixOS/nix
synced 2025-07-07 22:33:57 +02:00
Merge branch 'master' into lfs
This commit is contained in:
commit
787cc04514
24 changed files with 1129 additions and 840 deletions
|
@ -14,6 +14,16 @@
|
|||
#include "nix_api_util.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef __has_c_attribute
|
||||
# define __has_c_attribute(x) 0
|
||||
#endif
|
||||
|
||||
#if __has_c_attribute(deprecated)
|
||||
# define NIX_DEPRECATED(msg) [[deprecated(msg)]]
|
||||
#else
|
||||
# define NIX_DEPRECATED(msg)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -45,7 +55,7 @@ typedef struct EvalState EvalState; // nix::EvalState
|
|||
* @see nix_value_incref, nix_value_decref
|
||||
*/
|
||||
typedef struct nix_value nix_value;
|
||||
[[deprecated("use nix_value instead")]] typedef nix_value Value;
|
||||
NIX_DEPRECATED("use nix_value instead") typedef nix_value Value;
|
||||
|
||||
// Function prototypes
|
||||
/**
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include "eval.hh"
|
||||
#include "eval-inline.hh"
|
||||
#include "store-api.hh"
|
||||
// Need specialization involving `SymbolStr` just in this one module.
|
||||
#include "strings-inline.hh"
|
||||
|
||||
namespace nix::eval_cache {
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ struct StringToken
|
|||
operator std::string_view() const { return {p, l}; }
|
||||
};
|
||||
|
||||
// This type must be trivially copyable; see YYLTYPE_IS_TRIVIAL in parser.y.
|
||||
struct ParserLocation
|
||||
{
|
||||
int beginOffset;
|
||||
|
@ -86,7 +87,7 @@ struct ParserState
|
|||
|
||||
void dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos);
|
||||
void dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos);
|
||||
void addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr * e, const PosIdx pos);
|
||||
void addAttr(ExprAttrs * attrs, AttrPath && attrPath, const ParserLocation & loc, Expr * e, const ParserLocation & exprLoc);
|
||||
Formals * validateFormals(Formals * formals, PosIdx pos = noPos, Symbol arg = {});
|
||||
Expr * stripIndentation(const PosIdx pos,
|
||||
std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>> && es);
|
||||
|
@ -110,11 +111,12 @@ inline void ParserState::dupAttr(Symbol attr, const PosIdx pos, const PosIdx pre
|
|||
});
|
||||
}
|
||||
|
||||
inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr * e, const PosIdx pos)
|
||||
inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, const ParserLocation & loc, Expr * e, const ParserLocation & exprLoc)
|
||||
{
|
||||
AttrPath::iterator i;
|
||||
// All attrpaths have at least one attr
|
||||
assert(!attrPath.empty());
|
||||
auto pos = at(loc);
|
||||
// Checking attrPath validity.
|
||||
// ===========================
|
||||
for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) {
|
||||
|
@ -179,6 +181,12 @@ inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr *
|
|||
} else {
|
||||
attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, e, pos));
|
||||
}
|
||||
|
||||
auto it = lexerState.positionToDocComment.find(pos);
|
||||
if (it != lexerState.positionToDocComment.end()) {
|
||||
e->setDocComment(it->second);
|
||||
lexerState.positionToDocComment.emplace(at(exprLoc), it->second);
|
||||
}
|
||||
}
|
||||
|
||||
inline Formals * ParserState::validateFormals(Formals * formals, PosIdx pos, Symbol arg)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
%glr-parser
|
||||
%define api.location.type { ::nix::ParserLocation }
|
||||
%define api.pure
|
||||
%locations
|
||||
%define parse.error verbose
|
||||
|
@ -8,8 +8,7 @@
|
|||
%parse-param { nix::ParserState * state }
|
||||
%lex-param { void * scanner }
|
||||
%lex-param { nix::ParserState * state }
|
||||
%expect 1
|
||||
%expect-rr 1
|
||||
%expect 0
|
||||
|
||||
%code requires {
|
||||
|
||||
|
@ -27,7 +26,17 @@
|
|||
#include "eval-settings.hh"
|
||||
#include "parser-state.hh"
|
||||
|
||||
#define YYLTYPE ::nix::ParserLocation
|
||||
// Bison seems to have difficulty growing the parser stack when using C++ with
|
||||
// a custom location type. This undocumented macro tells Bison that our
|
||||
// location type is "trivially copyable" in C++-ese, so it is safe to use the
|
||||
// same memcpy macro it uses to grow the stack that it uses with its own
|
||||
// default location type. Without this, we get "error: memory exhausted" when
|
||||
// parsing some large Nix files. Our other options are to increase the initial
|
||||
// stack size (200 by default) to be as large as we ever want to support (so
|
||||
// that growing the stack is unnecessary), or redefine the stack-relocation
|
||||
// macro ourselves (which is also undocumented).
|
||||
#define YYLTYPE_IS_TRIVIAL 1
|
||||
|
||||
#define YY_DECL int yylex \
|
||||
(YYSTYPE * yylval_param, YYLTYPE * yylloc_param, yyscan_t yyscanner, nix::ParserState * state)
|
||||
|
||||
|
@ -77,7 +86,7 @@ YY_DECL;
|
|||
|
||||
using namespace nix;
|
||||
|
||||
#define CUR_POS state->at(*yylocp)
|
||||
#define CUR_POS state->at(yyloc)
|
||||
|
||||
|
||||
void yyerror(YYLTYPE * loc, yyscan_t scanner, ParserState * state, const char * error)
|
||||
|
@ -133,8 +142,8 @@ static Expr * makeCall(PosIdx pos, Expr * fn, Expr * arg) {
|
|||
%type <e> expr_select expr_simple expr_app
|
||||
%type <e> expr_pipe_from expr_pipe_into
|
||||
%type <list> expr_list
|
||||
%type <attrs> binds
|
||||
%type <formals> formals
|
||||
%type <attrs> binds binds1
|
||||
%type <formals> formals formal_set
|
||||
%type <formal> formal
|
||||
%type <attrNames> attrpath
|
||||
%type <inheritAttrs> attrs
|
||||
|
@ -180,22 +189,22 @@ expr_function
|
|||
$$ = me;
|
||||
SET_DOC_POS(me, @1);
|
||||
}
|
||||
| '{' formals '}' ':' expr_function
|
||||
{ auto me = new ExprLambda(CUR_POS, state->validateFormals($2), $5);
|
||||
| formal_set ':' expr_function[body]
|
||||
{ auto me = new ExprLambda(CUR_POS, state->validateFormals($formal_set), $body);
|
||||
$$ = me;
|
||||
SET_DOC_POS(me, @1);
|
||||
}
|
||||
| '{' formals '}' '@' ID ':' expr_function
|
||||
| formal_set '@' ID ':' expr_function[body]
|
||||
{
|
||||
auto arg = state->symbols.create($5);
|
||||
auto me = new ExprLambda(CUR_POS, arg, state->validateFormals($2, CUR_POS, arg), $7);
|
||||
auto arg = state->symbols.create($ID);
|
||||
auto me = new ExprLambda(CUR_POS, arg, state->validateFormals($formal_set, CUR_POS, arg), $body);
|
||||
$$ = me;
|
||||
SET_DOC_POS(me, @1);
|
||||
}
|
||||
| ID '@' '{' formals '}' ':' expr_function
|
||||
| ID '@' formal_set ':' expr_function[body]
|
||||
{
|
||||
auto arg = state->symbols.create($1);
|
||||
auto me = new ExprLambda(CUR_POS, arg, state->validateFormals($4, CUR_POS, arg), $7);
|
||||
auto arg = state->symbols.create($ID);
|
||||
auto me = new ExprLambda(CUR_POS, arg, state->validateFormals($formal_set, CUR_POS, arg), $body);
|
||||
$$ = me;
|
||||
SET_DOC_POS(me, @1);
|
||||
}
|
||||
|
@ -311,11 +320,13 @@ expr_simple
|
|||
/* Let expressions `let {..., body = ...}' are just desugared
|
||||
into `(rec {..., body = ...}).body'. */
|
||||
| LET '{' binds '}'
|
||||
{ $3->recursive = true; $$ = new ExprSelect(noPos, $3, state->s.body); }
|
||||
{ $3->recursive = true; $3->pos = CUR_POS; $$ = new ExprSelect(noPos, $3, state->s.body); }
|
||||
| REC '{' binds '}'
|
||||
{ $3->recursive = true; $$ = $3; }
|
||||
| '{' binds '}'
|
||||
{ $$ = $2; }
|
||||
{ $3->recursive = true; $3->pos = CUR_POS; $$ = $3; }
|
||||
| '{' binds1 '}'
|
||||
{ $2->pos = CUR_POS; $$ = $2; }
|
||||
| '{' '}'
|
||||
{ $$ = new ExprAttrs(CUR_POS); }
|
||||
| '[' expr_list ']' { $$ = $2; }
|
||||
;
|
||||
|
||||
|
@ -364,52 +375,50 @@ ind_string_parts
|
|||
;
|
||||
|
||||
binds
|
||||
: binds attrpath '=' expr ';' {
|
||||
$$ = $1;
|
||||
: binds1
|
||||
| { $$ = new ExprAttrs; }
|
||||
;
|
||||
|
||||
auto pos = state->at(@2);
|
||||
auto exprPos = state->at(@4);
|
||||
{
|
||||
auto it = state->lexerState.positionToDocComment.find(pos);
|
||||
if (it != state->lexerState.positionToDocComment.end()) {
|
||||
$4->setDocComment(it->second);
|
||||
state->lexerState.positionToDocComment.emplace(exprPos, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
state->addAttr($$, std::move(*$2), $4, pos);
|
||||
delete $2;
|
||||
binds1
|
||||
: binds1[accum] attrpath '=' expr ';'
|
||||
{ $$ = $accum;
|
||||
state->addAttr($$, std::move(*$attrpath), @attrpath, $expr, @expr);
|
||||
delete $attrpath;
|
||||
}
|
||||
| binds INHERIT attrs ';'
|
||||
{ $$ = $1;
|
||||
for (auto & [i, iPos] : *$3) {
|
||||
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
||||
state->dupAttr(i.symbol, iPos, $$->attrs[i.symbol].pos);
|
||||
$$->attrs.emplace(
|
||||
| binds[accum] INHERIT attrs ';'
|
||||
{ $$ = $accum;
|
||||
for (auto & [i, iPos] : *$attrs) {
|
||||
if ($accum->attrs.find(i.symbol) != $accum->attrs.end())
|
||||
state->dupAttr(i.symbol, iPos, $accum->attrs[i.symbol].pos);
|
||||
$accum->attrs.emplace(
|
||||
i.symbol,
|
||||
ExprAttrs::AttrDef(new ExprVar(iPos, i.symbol), iPos, ExprAttrs::AttrDef::Kind::Inherited));
|
||||
}
|
||||
delete $3;
|
||||
delete $attrs;
|
||||
}
|
||||
| binds INHERIT '(' expr ')' attrs ';'
|
||||
{ $$ = $1;
|
||||
if (!$$->inheritFromExprs)
|
||||
$$->inheritFromExprs = std::make_unique<std::vector<Expr *>>();
|
||||
$$->inheritFromExprs->push_back($4);
|
||||
auto from = new nix::ExprInheritFrom(state->at(@4), $$->inheritFromExprs->size() - 1);
|
||||
for (auto & [i, iPos] : *$6) {
|
||||
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
||||
state->dupAttr(i.symbol, iPos, $$->attrs[i.symbol].pos);
|
||||
$$->attrs.emplace(
|
||||
| binds[accum] INHERIT '(' expr ')' attrs ';'
|
||||
{ $$ = $accum;
|
||||
if (!$accum->inheritFromExprs)
|
||||
$accum->inheritFromExprs = std::make_unique<std::vector<Expr *>>();
|
||||
$accum->inheritFromExprs->push_back($expr);
|
||||
auto from = new nix::ExprInheritFrom(state->at(@expr), $accum->inheritFromExprs->size() - 1);
|
||||
for (auto & [i, iPos] : *$attrs) {
|
||||
if ($accum->attrs.find(i.symbol) != $accum->attrs.end())
|
||||
state->dupAttr(i.symbol, iPos, $accum->attrs[i.symbol].pos);
|
||||
$accum->attrs.emplace(
|
||||
i.symbol,
|
||||
ExprAttrs::AttrDef(
|
||||
new ExprSelect(iPos, from, i.symbol),
|
||||
iPos,
|
||||
ExprAttrs::AttrDef::Kind::InheritedFrom));
|
||||
}
|
||||
delete $6;
|
||||
delete $attrs;
|
||||
}
|
||||
| attrpath '=' expr ';'
|
||||
{ $$ = new ExprAttrs;
|
||||
state->addAttr($$, std::move(*$attrpath), @attrpath, $expr, @expr);
|
||||
delete $attrpath;
|
||||
}
|
||||
| { $$ = new ExprAttrs(state->at(@0)); }
|
||||
;
|
||||
|
||||
attrs
|
||||
|
@ -467,15 +476,19 @@ expr_list
|
|||
| { $$ = new ExprList; }
|
||||
;
|
||||
|
||||
formal_set
|
||||
: '{' formals ',' ELLIPSIS '}' { $$ = $formals; $$->ellipsis = true; }
|
||||
| '{' ELLIPSIS '}' { $$ = new Formals; $$->ellipsis = true; }
|
||||
| '{' formals ',' '}' { $$ = $formals; $$->ellipsis = false; }
|
||||
| '{' formals '}' { $$ = $formals; $$->ellipsis = false; }
|
||||
| '{' '}' { $$ = new Formals; $$->ellipsis = false; }
|
||||
;
|
||||
|
||||
formals
|
||||
: formal ',' formals
|
||||
{ $$ = $3; $$->formals.emplace_back(*$1); delete $1; }
|
||||
: formals[accum] ',' formal
|
||||
{ $$ = $accum; $$->formals.emplace_back(*$formal); delete $formal; }
|
||||
| formal
|
||||
{ $$ = new Formals; $$->formals.emplace_back(*$1); $$->ellipsis = false; delete $1; }
|
||||
|
|
||||
{ $$ = new Formals; $$->ellipsis = false; }
|
||||
| ELLIPSIS
|
||||
{ $$ = new Formals; $$->ellipsis = true; }
|
||||
{ $$ = new Formals; $$->formals.emplace_back(*$formal); delete $formal; }
|
||||
;
|
||||
|
||||
formal
|
||||
|
|
|
@ -145,8 +145,10 @@ Goal::Co PathSubstitutionGoal::init()
|
|||
/* None left. Terminate this goal and let someone else deal
|
||||
with it. */
|
||||
|
||||
worker.failedSubstitutions++;
|
||||
worker.updateProgress();
|
||||
if (substituterFailed) {
|
||||
worker.failedSubstitutions++;
|
||||
worker.updateProgress();
|
||||
}
|
||||
|
||||
/* Hack: don't indicate failure if there were no substituters.
|
||||
In that case the calling derivation should just do a
|
||||
|
@ -158,7 +160,7 @@ Goal::Co PathSubstitutionGoal::init()
|
|||
}
|
||||
|
||||
|
||||
Goal::Co PathSubstitutionGoal::tryToRun(StorePath subPath, nix::ref<Store> sub, std::shared_ptr<const ValidPathInfo> info, bool& substituterFailed)
|
||||
Goal::Co PathSubstitutionGoal::tryToRun(StorePath subPath, nix::ref<Store> sub, std::shared_ptr<const ValidPathInfo> info, bool & substituterFailed)
|
||||
{
|
||||
trace("all references realised");
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ public:
|
|||
*/
|
||||
Co init() override;
|
||||
Co gotInfo();
|
||||
Co tryToRun(StorePath subPath, nix::ref<Store> sub, std::shared_ptr<const ValidPathInfo> info, bool& substituterFailed);
|
||||
Co tryToRun(StorePath subPath, nix::ref<Store> sub, std::shared_ptr<const ValidPathInfo> info, bool & substituterFailed);
|
||||
Co finished();
|
||||
|
||||
/**
|
||||
|
|
|
@ -220,8 +220,6 @@ std::string S3BinaryCacheStoreConfig::doc()
|
|||
|
||||
struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual S3BinaryCacheStore
|
||||
{
|
||||
std::string bucketName;
|
||||
|
||||
Stats stats;
|
||||
|
||||
S3Helper s3Helper;
|
||||
|
|
|
@ -4,6 +4,21 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
template<class C>
|
||||
C tokenizeString(std::string_view s, std::string_view separators)
|
||||
{
|
||||
C result;
|
||||
auto pos = s.find_first_not_of(separators, 0);
|
||||
while (pos != s.npos) {
|
||||
auto end = s.find_first_of(separators, pos + 1);
|
||||
if (end == s.npos)
|
||||
end = s.size();
|
||||
result.insert(result.end(), std::string(s, pos, end - pos));
|
||||
pos = s.find_first_not_of(separators, end);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
std::string concatStringsSep(const std::string_view sep, const C & ss)
|
||||
{
|
||||
|
@ -28,4 +43,30 @@ std::string concatStringsSep(const std::string_view sep, const C & ss)
|
|||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
std::string dropEmptyInitThenConcatStringsSep(const std::string_view sep, const C & ss)
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
// TODO? remove to make sure we don't rely on the empty item ignoring behavior,
|
||||
// or just get rid of this function by understanding the remaining calls.
|
||||
// for (auto & i : ss) {
|
||||
// // Make sure we don't rely on the empty item ignoring behavior
|
||||
// assert(!i.empty());
|
||||
// break;
|
||||
// }
|
||||
|
||||
// need a cast to string_view since this is also called with Symbols
|
||||
for (const auto & s : ss)
|
||||
size += sep.size() + std::string_view(s).size();
|
||||
std::string s;
|
||||
s.reserve(size);
|
||||
for (auto & i : ss) {
|
||||
if (s.size() != 0)
|
||||
s += sep;
|
||||
s += i;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
#include <string>
|
||||
|
||||
#include "strings-inline.hh"
|
||||
#include "util.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
template std::string concatStringsSep(std::string_view, const Strings &);
|
||||
template std::string concatStringsSep(std::string_view, const StringSet &);
|
||||
template std::list<std::string> tokenizeString(std::string_view s, std::string_view separators);
|
||||
template std::set<std::string> tokenizeString(std::string_view s, std::string_view separators);
|
||||
template std::vector<std::string> tokenizeString(std::string_view s, std::string_view separators);
|
||||
|
||||
template std::string concatStringsSep(std::string_view, const std::list<std::string> &);
|
||||
template std::string concatStringsSep(std::string_view, const std::set<std::string> &);
|
||||
template std::string concatStringsSep(std::string_view, const std::vector<std::string> &);
|
||||
|
||||
typedef std::string_view strings_2[2];
|
||||
|
@ -16,4 +19,8 @@ template std::string concatStringsSep(std::string_view, const strings_3 &);
|
|||
typedef std::string_view strings_4[4];
|
||||
template std::string concatStringsSep(std::string_view, const strings_4 &);
|
||||
|
||||
template std::string dropEmptyInitThenConcatStringsSep(std::string_view, const std::list<std::string> &);
|
||||
template std::string dropEmptyInitThenConcatStringsSep(std::string_view, const std::set<std::string> &);
|
||||
template std::string dropEmptyInitThenConcatStringsSep(std::string_view, const std::vector<std::string> &);
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
@ -8,6 +8,18 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
/**
|
||||
* String tokenizer.
|
||||
*
|
||||
* See also `basicSplitString()`, which preserves empty strings between separators, as well as at the start and end.
|
||||
*/
|
||||
template<class C>
|
||||
C tokenizeString(std::string_view s, std::string_view separators = " \t\n\r");
|
||||
|
||||
extern template std::list<std::string> tokenizeString(std::string_view s, std::string_view separators);
|
||||
extern template std::set<std::string> tokenizeString(std::string_view s, std::string_view separators);
|
||||
extern template std::vector<std::string> tokenizeString(std::string_view s, std::string_view separators);
|
||||
|
||||
/**
|
||||
* Concatenate the given strings with a separator between the elements.
|
||||
*/
|
||||
|
@ -18,4 +30,20 @@ extern template std::string concatStringsSep(std::string_view, const std::list<s
|
|||
extern template std::string concatStringsSep(std::string_view, const std::set<std::string> &);
|
||||
extern template std::string concatStringsSep(std::string_view, const std::vector<std::string> &);
|
||||
|
||||
/**
|
||||
* Ignore any empty strings at the start of the list, and then concatenate the
|
||||
* given strings with a separator between the elements.
|
||||
*
|
||||
* @deprecated This function exists for historical reasons. You probably just
|
||||
* want to use `concatStringsSep`.
|
||||
*/
|
||||
template<class C>
|
||||
[[deprecated(
|
||||
"Consider removing the empty string dropping behavior. If acceptable, use concatStringsSep instead.")]] std::string
|
||||
dropEmptyInitThenConcatStringsSep(const std::string_view sep, const C & ss);
|
||||
|
||||
extern template std::string dropEmptyInitThenConcatStringsSep(std::string_view, const std::list<std::string> &);
|
||||
extern template std::string dropEmptyInitThenConcatStringsSep(std::string_view, const std::set<std::string> &);
|
||||
extern template std::string dropEmptyInitThenConcatStringsSep(std::string_view, const std::vector<std::string> &);
|
||||
|
||||
}
|
||||
|
|
|
@ -53,24 +53,6 @@ std::vector<char *> stringsToCharPtrs(const Strings & ss)
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
template<class C> C tokenizeString(std::string_view s, std::string_view separators)
|
||||
{
|
||||
C result;
|
||||
auto pos = s.find_first_not_of(separators, 0);
|
||||
while (pos != s.npos) {
|
||||
auto end = s.find_first_of(separators, pos + 1);
|
||||
if (end == s.npos) end = s.size();
|
||||
result.insert(result.end(), std::string(s, pos, end - pos));
|
||||
pos = s.find_first_not_of(separators, end);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template Strings tokenizeString(std::string_view s, std::string_view separators);
|
||||
template StringSet tokenizeString(std::string_view s, std::string_view separators);
|
||||
template std::vector<std::string> tokenizeString(std::string_view s, std::string_view separators);
|
||||
|
||||
|
||||
std::string chomp(std::string_view s)
|
||||
{
|
||||
size_t i = s.find_last_not_of(" \n\r\t");
|
||||
|
|
|
@ -28,49 +28,11 @@ std::vector<char *> stringsToCharPtrs(const Strings & ss);
|
|||
MakeError(FormatError, Error);
|
||||
|
||||
|
||||
/**
|
||||
* String tokenizer.
|
||||
*/
|
||||
template<class C> C tokenizeString(std::string_view s, std::string_view separators = " \t\n\r");
|
||||
|
||||
|
||||
/**
|
||||
* Ignore any empty strings at the start of the list, and then concatenate the
|
||||
* given strings with a separator between the elements.
|
||||
*
|
||||
* @deprecated This function exists for historical reasons. You probably just
|
||||
* want to use `concatStringsSep`.
|
||||
*/
|
||||
template<class C>
|
||||
[[deprecated("Consider removing the empty string dropping behavior. If acceptable, use concatStringsSep instead.")]]
|
||||
std::string dropEmptyInitThenConcatStringsSep(const std::string_view sep, const C & ss)
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
// TODO? remove to make sure we don't rely on the empty item ignoring behavior,
|
||||
// or just get rid of this function by understanding the remaining calls.
|
||||
// for (auto & i : ss) {
|
||||
// // Make sure we don't rely on the empty item ignoring behavior
|
||||
// assert(!i.empty());
|
||||
// break;
|
||||
// }
|
||||
|
||||
// need a cast to string_view since this is also called with Symbols
|
||||
for (const auto & s : ss) size += sep.size() + std::string_view(s).size();
|
||||
std::string s;
|
||||
s.reserve(size);
|
||||
for (auto & i : ss) {
|
||||
if (s.size() != 0) s += sep;
|
||||
s += i;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class ... Parts>
|
||||
auto concatStrings(Parts && ... parts)
|
||||
template<class... Parts>
|
||||
auto concatStrings(Parts &&... parts)
|
||||
-> std::enable_if_t<(... && std::is_convertible_v<Parts, std::string_view>), std::string>
|
||||
{
|
||||
std::string_view views[sizeof...(parts)] = { parts... };
|
||||
std::string_view views[sizeof...(parts)] = {parts...};
|
||||
return concatStringsSep({}, views);
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ The following types of installable are supported by most commands:
|
|||
- [Nix file](#nix-file), optionally qualified by an attribute path
|
||||
- Specified with `--file`/`-f`
|
||||
- [Nix expression](#nix-expression), optionally qualified by an attribute path
|
||||
- Specified with `--expr`/`-E`
|
||||
- Specified with `--expr`
|
||||
|
||||
For most commands, if no installable is specified, `.` is assumed.
|
||||
That is, Nix will operate on the default flake output attribute of the flake in the current directory.
|
||||
|
@ -200,17 +200,17 @@ operate are determined as follows:
|
|||
…
|
||||
```
|
||||
|
||||
For `-e`/`--expr` and `-f`/`--file`, the derivation output is specified as part of the attribute path:
|
||||
For `--expr` and `-f`/`--file`, the derivation output is specified as part of the attribute path:
|
||||
|
||||
```console
|
||||
$ nix build -f '<nixpkgs>' 'glibc^dev,static'
|
||||
$ nix build --impure -E 'import <nixpkgs> { }' 'glibc^dev,static'
|
||||
$ nix build --impure --expr 'import <nixpkgs> { }' 'glibc^dev,static'
|
||||
```
|
||||
|
||||
This syntax is the same even if the actual attribute path is empty:
|
||||
|
||||
```console
|
||||
$ nix build -E 'let pkgs = import <nixpkgs> { }; in pkgs.glibc' '^dev,static'
|
||||
$ nix build --impure --expr 'let pkgs = import <nixpkgs> { }; in pkgs.glibc' '^dev,static'
|
||||
```
|
||||
|
||||
* You can also specify that *all* outputs should be used using the
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue