Merge remote-tracking branch 'nixos/master'

This commit is contained in:
Max Headroom 2022-03-05 01:18:29 +01:00
commit 397b108e5e
184 changed files with 2198 additions and 1443 deletions

View file

@ -6,9 +6,9 @@ builtins:
concatStrings (map concatStrings (map
(name: (name:
let builtin = builtins.${name}; in let builtin = builtins.${name}; in
"<dt><code>${name} " "<dt id=\"builtins-${name}\"><a href=\"#builtins-${name}\"><code>${name} "
+ concatStringsSep " " (map (s: "<var>${s}</var>") builtin.args) + concatStringsSep " " (map (s: "<var>${s}</var>") builtin.args)
+ "</code></dt>" + "</code></a></dt>"
+ "<dd>\n\n" + "<dd>\n\n"
+ builtin.doc + builtin.doc
+ "\n\n</dd>" + "\n\n</dd>"

View file

@ -72,6 +72,7 @@ $(d)/builtins.json: $(bindir)/nix
@mv $@.tmp $@ @mv $@.tmp $@
# Generate the HTML manual. # Generate the HTML manual.
html: $(docdir)/manual/index.html
install: $(docdir)/manual/index.html install: $(docdir)/manual/index.html
# Generate 'nix' manpages. # Generate 'nix' manpages.

View file

@ -321,8 +321,8 @@ symlink.
This query has one option: This query has one option:
- `--include-outputs` - `--include-outputs`
Also include the output path of store derivations, and their Also include the existing output paths of store derivations,
closures. and their closures.
This query can be used to implement various kinds of deployment. A This query can be used to implement various kinds of deployment. A
*source deployment* is obtained by distributing the closure of a *source deployment* is obtained by distributing the closure of a

View file

@ -1,5 +1,18 @@
# Release X.Y (202?-??-??) # Release X.Y (202?-??-??)
* A number of "default" flake output attributes have been
renamed. These are:
* `defaultPackage.<system>``packages.<system>.default`
* `defaultApps.<system>``apps.<system>.default`
* `defaultTemplate``templates.default`
* `defaultBundler.<system>``bundlers.<system>.default`
* `overlay``overlays.default`
* `devShell.<system>``devShells.<system>.default`
The old flake output attributes still work, but `nix flake check`
will warn about them.
* `nix bundle` breaking API change now supports bundlers of the form * `nix bundle` breaking API change now supports bundlers of the form
`bundler.<system>.<name>= derivation: another-derivation;`. This supports `bundler.<system>.<name>= derivation: another-derivation;`. This supports
additional functionality to inspect evaluation information during bundling. A additional functionality to inspect evaluation information during bundling. A

View file

@ -501,6 +501,12 @@
inherit (self) overlay; inherit (self) overlay;
}); });
tests.sourcehutFlakes = (import ./tests/sourcehut-flakes.nix rec {
system = "x86_64-linux";
inherit nixpkgs;
inherit (self) overlay;
});
tests.setuid = nixpkgs.lib.genAttrs tests.setuid = nixpkgs.lib.genAttrs
["i686-linux" "x86_64-linux"] ["i686-linux" "x86_64-linux"]
(system: (system:

View file

@ -14,9 +14,27 @@ if [ -t 1 ]; then
yellow="" yellow=""
normal="" normal=""
fi fi
(cd tests && env ${TESTS_ENVIRONMENT} init.sh 2>/dev/null > /dev/null)
log="$(cd $(dirname $1) && env ${TESTS_ENVIRONMENT} $(basename $1) 2>&1)" run_test () {
status=$? (cd tests && env ${TESTS_ENVIRONMENT} init.sh 2>/dev/null > /dev/null)
log="$(cd $(dirname $1) && env ${TESTS_ENVIRONMENT} $(basename $1) 2>&1)"
status=$?
}
run_test "$1"
# Hack: Retry the test if it fails with “unexpected EOF reading a line” as these
# appear randomly without anyone knowing why.
# See https://github.com/NixOS/nix/issues/3605 for more info
if [[ $status -ne 0 && $status -ne 99 && \
"$(uname)" == "Darwin" && \
"$log" =~ "unexpected EOF reading a line" \
]]; then
echo "$post_run_msg [${yellow}FAIL$normal] (possibly flaky, so will be retried)"
echo "$log" | sed 's/^/ /'
run_test "$1"
fi
if [ $status -eq 0 ]; then if [ $status -eq 0 ]; then
echo "$post_run_msg [${green}PASS$normal]" echo "$post_run_msg [${green}PASS$normal]"
elif [ $status -eq 99 ]; then elif [ $status -eq 99 ]; then

View file

@ -240,7 +240,7 @@ SV * convertHash(char * algo, char * s, int toBase32)
PPCODE: PPCODE:
try { try {
auto h = Hash::parseAny(s, parseHashType(algo)); auto h = Hash::parseAny(s, parseHashType(algo));
string s = h.to_string(toBase32 ? Base32 : Base16, false); auto s = h.to_string(toBase32 ? Base32 : Base16, false);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());

View file

@ -246,7 +246,8 @@ get_volume_pass() {
verify_volume_pass() { verify_volume_pass() {
local volume_special="$1" # (i.e., disk1s7) local volume_special="$1" # (i.e., disk1s7)
local volume_uuid="$2" local volume_uuid="$2"
/usr/sbin/diskutil apfs unlockVolume "$volume_special" -verify -stdinpassphrase -user "$volume_uuid" _sudo "to confirm the password actually unlocks the volume" \
/usr/sbin/diskutil apfs unlockVolume "$volume_special" -verify -stdinpassphrase -user "$volume_uuid"
} }
volume_pass_works() { volume_pass_works() {
@ -685,22 +686,27 @@ encrypt_volume() {
local volume_uuid="$1" local volume_uuid="$1"
local volume_label="$2" local volume_label="$2"
local password local password
task "Encrypt the Nix volume" >&2
# Note: mount/unmount are late additions to support the right order # Note: mount/unmount are late additions to support the right order
# of operations for creating the volume and then baking its uuid into # of operations for creating the volume and then baking its uuid into
# other artifacts; not as well-trod wrt to potential errors, race # other artifacts; not as well-trod wrt to potential errors, race
# conditions, etc. # conditions, etc.
/usr/sbin/diskutil mount "$volume_label" _sudo "to mount your Nix volume for encrypting" \
/usr/sbin/diskutil mount "$volume_label"
password="$(/usr/bin/xxd -l 32 -p -c 256 /dev/random)" password="$(/usr/bin/xxd -l 32 -p -c 256 /dev/random)"
_sudo "to add your Nix volume's password to Keychain" \ _sudo "to add your Nix volume's password to Keychain" \
/usr/bin/security -i <<EOF /usr/bin/security -i <<EOF
add-generic-password -a "$volume_label" -s "$volume_uuid" -l "$volume_label encryption password" -D "Encrypted volume password" -j "Added automatically by the Nix installer for use by $NIX_VOLUME_MOUNTD_DEST" -w "$password" -T /System/Library/CoreServices/APFSUserAgent -T /System/Library/CoreServices/CSUserAgent -T /usr/bin/security "/Library/Keychains/System.keychain" add-generic-password -a "$volume_label" -s "$volume_uuid" -l "$volume_label encryption password" -D "Encrypted volume password" -j "Added automatically by the Nix installer for use by $NIX_VOLUME_MOUNTD_DEST" -w "$password" -T /System/Library/CoreServices/APFSUserAgent -T /System/Library/CoreServices/CSUserAgent -T /usr/bin/security "/Library/Keychains/System.keychain"
EOF EOF
builtin printf "%s" "$password" | _sudo "to encrypt your Nix volume" \ builtin printf "%s" "$password" | _sudo "to actually encrypt your Nix volume" \
/usr/sbin/diskutil apfs encryptVolume "$volume_label" -user disk -stdinpassphrase /usr/sbin/diskutil apfs encryptVolume "$volume_label" -user disk -stdinpassphrase
/usr/sbin/diskutil unmount force "$volume_label" _sudo "to unmount the encrypted volume" \
/usr/sbin/diskutil unmount force "$volume_label"
} }
create_volume() { create_volume() {

View file

@ -23,10 +23,10 @@ readonly RED='\033[31m'
# installer allows overriding build user count to speed up installation # installer allows overriding build user count to speed up installation
# as creating each user takes non-trivial amount of time on macos # as creating each user takes non-trivial amount of time on macos
readonly NIX_USER_COUNT=${NIX_USER_COUNT:-32} readonly NIX_USER_COUNT=${NIX_USER_COUNT:-32}
readonly NIX_BUILD_GROUP_ID="30000" readonly NIX_BUILD_GROUP_ID="${NIX_BUILD_GROUP_ID:-30000}"
readonly NIX_BUILD_GROUP_NAME="nixbld" readonly NIX_BUILD_GROUP_NAME="nixbld"
# darwin installer needs to override these # darwin installer needs to override these
NIX_FIRST_BUILD_UID="30001" NIX_FIRST_BUILD_UID="${NIX_FIRST_BUILD_UID:-30001}"
NIX_BUILD_USER_NAME_TEMPLATE="nixbld%d" NIX_BUILD_USER_NAME_TEMPLATE="nixbld%d"
# Please don't change this. We don't support it, because the # Please don't change this. We don't support it, because the
# default shell profile that comes with Nix doesn't support it. # default shell profile that comes with Nix doesn't support it.

View file

@ -14,6 +14,7 @@
#include "pathlocks.hh" #include "pathlocks.hh"
#include "globals.hh" #include "globals.hh"
#include "serialise.hh" #include "serialise.hh"
#include "build-result.hh"
#include "store-api.hh" #include "store-api.hh"
#include "derivations.hh" #include "derivations.hh"
#include "local-store.hh" #include "local-store.hh"
@ -32,7 +33,7 @@ std::string escapeUri(std::string uri)
return uri; return uri;
} }
static string currentLoad; static std::string currentLoad;
static AutoCloseFD openSlotLock(const Machine & m, uint64_t slot) static AutoCloseFD openSlotLock(const Machine & m, uint64_t slot)
{ {
@ -97,7 +98,7 @@ static int main_build_remote(int argc, char * * argv)
} }
std::optional<StorePath> drvPath; std::optional<StorePath> drvPath;
string storeUri; std::string storeUri;
while (true) { while (true) {
@ -183,7 +184,7 @@ static int main_build_remote(int argc, char * * argv)
else else
{ {
// build the hint template. // build the hint template.
string errorText = std::string errorText =
"Failed to find a machine for remote build!\n" "Failed to find a machine for remote build!\n"
"derivation: %s\nrequired (system, features): (%s, %s)"; "derivation: %s\nrequired (system, features): (%s, %s)";
errorText += "\n%s available machines:"; errorText += "\n%s available machines:";
@ -193,7 +194,7 @@ static int main_build_remote(int argc, char * * argv)
errorText += "\n(%s, %s, %s, %s)"; errorText += "\n(%s, %s, %s, %s)";
// add the template values. // add the template values.
string drvstr; std::string drvstr;
if (drvPath.has_value()) if (drvPath.has_value())
drvstr = drvPath->to_string(); drvstr = drvPath->to_string();
else else
@ -208,7 +209,7 @@ static int main_build_remote(int argc, char * * argv)
for (auto & m : machines) for (auto & m : machines)
error error
% concatStringsSep<std::vector<string>>(", ", m.systemTypes) % concatStringsSep<std::vector<std::string>>(", ", m.systemTypes)
% m.maxJobs % m.maxJobs
% concatStringsSep<StringSet>(", ", m.supportedFeatures) % concatStringsSep<StringSet>(", ", m.supportedFeatures)
% concatStringsSep<StringSet>(", ", m.mandatoryFeatures); % concatStringsSep<StringSet>(", ", m.mandatoryFeatures);

View file

@ -153,7 +153,7 @@ void BuiltPathsCommand::run(ref<Store> store)
for (auto & p : store->queryAllValidPaths()) for (auto & p : store->queryAllValidPaths())
paths.push_back(BuiltPath::Opaque{p}); paths.push_back(BuiltPath::Opaque{p});
} else { } else {
paths = toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables); paths = Installable::toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
if (recursive) { if (recursive) {
// XXX: This only computes the store path closure, ignoring // XXX: This only computes the store path closure, ignoring
// intermediate realisations // intermediate realisations

View file

@ -5,7 +5,6 @@
#include "common-eval-args.hh" #include "common-eval-args.hh"
#include "path.hh" #include "path.hh"
#include "flake/lockfile.hh" #include "flake/lockfile.hh"
#include "store-api.hh"
#include <optional> #include <optional>
@ -82,14 +81,6 @@ struct MixFlakeOptions : virtual Args, EvalCommand
{ return {}; } { return {}; }
}; };
/* How to handle derivations in commands that operate on store paths. */
enum class OperateOn {
/* Operate on the output path. */
Output,
/* Operate on the .drv path. */
Derivation
};
struct SourceExprCommand : virtual Args, MixFlakeOptions struct SourceExprCommand : virtual Args, MixFlakeOptions
{ {
std::optional<Path> file; std::optional<Path> file;
@ -122,19 +113,6 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
void completeInstallable(std::string_view prefix); void completeInstallable(std::string_view prefix);
}; };
enum class Realise {
/* Build the derivation. Postcondition: the
derivation outputs exist. */
Outputs,
/* Don't build the derivation. Postcondition: the store derivation
exists. */
Derivation,
/* Evaluate in dry-run mode. Postcondition: nothing. */
// FIXME: currently unused, but could be revived if we can
// evaluate derivations in-memory.
Nothing
};
/* A command that operates on a list of "installables", which can be /* A command that operates on a list of "installables", which can be
store paths, attribute paths, Nix expressions, etc. */ store paths, attribute paths, Nix expressions, etc. */
struct InstallablesCommand : virtual Args, SourceExprCommand struct InstallablesCommand : virtual Args, SourceExprCommand
@ -247,38 +225,6 @@ static RegisterCommand registerCommand2(std::vector<std::string> && name)
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); }); return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
} }
BuiltPaths build(
ref<Store> evalStore,
ref<Store> store, Realise mode,
const std::vector<std::shared_ptr<Installable>> & installables,
BuildMode bMode = bmNormal);
std::set<StorePath> toStorePaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
const std::vector<std::shared_ptr<Installable>> & installables);
StorePath toStorePath(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
std::shared_ptr<Installable> installable);
std::set<StorePath> toDerivations(
ref<Store> store,
const std::vector<std::shared_ptr<Installable>> & installables,
bool useDeriver = false);
BuiltPaths toBuiltPaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
const std::vector<std::shared_ptr<Installable>> & installables);
/* Helper function to generate args that invoke $EDITOR on /* Helper function to generate args that invoke $EDITOR on
filename:lineno. */ filename:lineno. */
Strings editorFor(const Pos & pos); Strings editorFor(const Pos & pos);

View file

@ -81,7 +81,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
for (auto & i : autoArgs) { for (auto & i : autoArgs) {
auto v = state.allocValue(); auto v = state.allocValue();
if (i.second[0] == 'E') if (i.second[0] == 'E')
state.mkThunk_(*v, state.parseExprFromString(string(i.second, 1), absPath("."))); state.mkThunk_(*v, state.parseExprFromString(i.second.substr(1), absPath(".")));
else else
v->mkString(((std::string_view) i.second).substr(1)); v->mkString(((std::string_view) i.second).substr(1));
res.insert(state.symbols.create(i.first), v); res.insert(state.symbols.create(i.first), v);
@ -89,17 +89,17 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
return res.finish(); return res.finish();
} }
Path lookupFileArg(EvalState & state, string s) Path lookupFileArg(EvalState & state, std::string_view s)
{ {
if (isUri(s)) { if (isUri(s)) {
return state.store->toRealPath( return state.store->toRealPath(
fetchers::downloadTarball( fetchers::downloadTarball(
state.store, resolveUri(s), "source", false).first.storePath); state.store, resolveUri(s), "source", false).first.storePath);
} else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') { } else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') {
Path p = s.substr(1, s.size() - 2); Path p(s.substr(1, s.size() - 2));
return state.findFile(p); return state.findFile(p);
} else } else
return absPath(s); return absPath(std::string(s));
} }
} }

View file

@ -22,6 +22,6 @@ private:
std::map<std::string, std::string> autoArgs; std::map<std::string, std::string> autoArgs;
}; };
Path lookupFileArg(EvalState & state, string s); Path lookupFileArg(EvalState & state, std::string_view s);
} }

View file

@ -219,7 +219,10 @@ SourceExprCommand::SourceExprCommand()
Strings SourceExprCommand::getDefaultFlakeAttrPaths() Strings SourceExprCommand::getDefaultFlakeAttrPaths()
{ {
return {"defaultPackage." + settings.thisSystem.get()}; return {
"packages." + settings.thisSystem.get() + ".default",
"defaultPackage." + settings.thisSystem.get()
};
} }
Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes() Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes()
@ -538,11 +541,10 @@ std::vector<InstallableValue::DerivationInfo> InstallableAttrPath::toDerivations
std::vector<DerivationInfo> res; std::vector<DerivationInfo> res;
for (auto & drvInfo : drvInfos) { for (auto & drvInfo : drvInfos) {
res.push_back({ auto drvPath = drvInfo.queryDrvPath();
state->store->parseStorePath(drvInfo.queryDrvPath()), if (!drvPath)
state->store->maybeParseStorePath(drvInfo.queryOutPath()), throw Error("'%s' is not a derivation", what());
drvInfo.queryOutputName() res.push_back({ *drvPath, drvInfo.queryOutputName() });
});
} }
return res; return res;
@ -675,9 +677,8 @@ std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> toDerivation
auto drvPath = attr->forceDerivation(); auto drvPath = attr->forceDerivation();
auto drvInfo = InstallableValue::DerivationInfo{ auto drvInfo = DerivationInfo {
std::move(drvPath), std::move(drvPath),
flake.state->store->maybeParseStorePath(attr->getAttr(flake.state->sOutPath)->getString()),
attr->getAttr(flake.state->sOutputName)->getString() attr->getAttr(flake.state->sOutputName)->getString()
}; };
@ -1030,7 +1031,7 @@ BuiltPaths getBuiltPaths(ref<Store> evalStore, ref<Store> store, const DerivedPa
return res; return res;
} }
BuiltPaths build( BuiltPaths Installable::build(
ref<Store> evalStore, ref<Store> evalStore,
ref<Store> store, ref<Store> store,
Realise mode, Realise mode,
@ -1055,7 +1056,7 @@ BuiltPaths build(
return getBuiltPaths(evalStore, store, pathsToBuild); return getBuiltPaths(evalStore, store, pathsToBuild);
} }
BuiltPaths toBuiltPaths( BuiltPaths Installable::toBuiltPaths(
ref<Store> evalStore, ref<Store> evalStore,
ref<Store> store, ref<Store> store,
Realise mode, Realise mode,
@ -1063,19 +1064,19 @@ BuiltPaths toBuiltPaths(
const std::vector<std::shared_ptr<Installable>> & installables) const std::vector<std::shared_ptr<Installable>> & installables)
{ {
if (operateOn == OperateOn::Output) if (operateOn == OperateOn::Output)
return build(evalStore, store, mode, installables); return Installable::build(evalStore, store, mode, installables);
else { else {
if (mode == Realise::Nothing) if (mode == Realise::Nothing)
settings.readOnlyMode = true; settings.readOnlyMode = true;
BuiltPaths res; BuiltPaths res;
for (auto & drvPath : toDerivations(store, installables, true)) for (auto & drvPath : Installable::toDerivations(store, installables, true))
res.push_back(BuiltPath::Opaque{drvPath}); res.push_back(BuiltPath::Opaque{drvPath});
return res; return res;
} }
} }
StorePathSet toStorePaths( StorePathSet Installable::toStorePaths(
ref<Store> evalStore, ref<Store> evalStore,
ref<Store> store, ref<Store> store,
Realise mode, OperateOn operateOn, Realise mode, OperateOn operateOn,
@ -1089,7 +1090,7 @@ StorePathSet toStorePaths(
return outPaths; return outPaths;
} }
StorePath toStorePath( StorePath Installable::toStorePath(
ref<Store> evalStore, ref<Store> evalStore,
ref<Store> store, ref<Store> store,
Realise mode, OperateOn operateOn, Realise mode, OperateOn operateOn,
@ -1103,7 +1104,7 @@ StorePath toStorePath(
return *paths.begin(); return *paths.begin();
} }
StorePathSet toDerivations( StorePathSet Installable::toDerivations(
ref<Store> store, ref<Store> store,
const std::vector<std::shared_ptr<Installable>> & installables, const std::vector<std::shared_ptr<Installable>> & installables,
bool useDeriver) bool useDeriver)

View file

@ -5,6 +5,7 @@
#include "path-with-outputs.hh" #include "path-with-outputs.hh"
#include "derived-path.hh" #include "derived-path.hh"
#include "eval.hh" #include "eval.hh"
#include "store-api.hh"
#include "flake/flake.hh" #include "flake/flake.hh"
#include <optional> #include <optional>
@ -29,6 +30,27 @@ struct UnresolvedApp
App resolve(ref<Store> evalStore, ref<Store> store); App resolve(ref<Store> evalStore, ref<Store> store);
}; };
enum class Realise {
/* Build the derivation. Postcondition: the
derivation outputs exist. */
Outputs,
/* Don't build the derivation. Postcondition: the store derivation
exists. */
Derivation,
/* Evaluate in dry-run mode. Postcondition: nothing. */
// FIXME: currently unused, but could be revived if we can
// evaluate derivations in-memory.
Nothing
};
/* How to handle derivations in commands that operate on store paths. */
enum class OperateOn {
/* Operate on the output path. */
Output,
/* Operate on the .drv path. */
Derivation
};
struct Installable struct Installable
{ {
virtual ~Installable() { } virtual ~Installable() { }
@ -68,6 +90,39 @@ struct Installable
{ {
return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}}); return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}});
} }
static BuiltPaths build(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
const std::vector<std::shared_ptr<Installable>> & installables,
BuildMode bMode = bmNormal);
static std::set<StorePath> toStorePaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
const std::vector<std::shared_ptr<Installable>> & installables);
static StorePath toStorePath(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
std::shared_ptr<Installable> installable);
static std::set<StorePath> toDerivations(
ref<Store> store,
const std::vector<std::shared_ptr<Installable>> & installables,
bool useDeriver = false);
static BuiltPaths toBuiltPaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
const std::vector<std::shared_ptr<Installable>> & installables);
}; };
struct InstallableValue : Installable struct InstallableValue : Installable
@ -79,7 +134,6 @@ struct InstallableValue : Installable
struct DerivationInfo struct DerivationInfo
{ {
StorePath drvPath; StorePath drvPath;
std::optional<StorePath> outPath;
std::string outputName; std::string outputName;
}; };
@ -131,4 +185,9 @@ ref<eval_cache::EvalCache> openEvalCache(
EvalState & state, EvalState & state,
std::shared_ptr<flake::LockedFlake> lockedFlake); std::shared_ptr<flake::LockedFlake> lockedFlake);
BuiltPaths getBuiltPaths(
ref<Store> evalStore,
ref<Store> store,
const DerivedPaths & hopefullyBuiltPaths);
} }

View file

@ -9,7 +9,7 @@ namespace nix {
static Strings parseAttrPath(std::string_view s) static Strings parseAttrPath(std::string_view s)
{ {
Strings res; Strings res;
string cur; std::string cur;
auto i = s.begin(); auto i = s.begin();
while (i != s.end()) { while (i != s.end()) {
if (*i == '.') { if (*i == '.') {
@ -41,7 +41,7 @@ std::vector<Symbol> parseAttrPath(EvalState & state, std::string_view s)
} }
std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const string & attrPath, std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const std::string & attrPath,
Bindings & autoArgs, Value & vIn) Bindings & autoArgs, Value & vIn)
{ {
Strings tokens = parseAttrPath(attrPath); Strings tokens = parseAttrPath(attrPath);
@ -121,7 +121,7 @@ Pos findPackageFilename(EvalState & state, Value & v, std::string what)
std::string filename(pos, 0, colon); std::string filename(pos, 0, colon);
unsigned int lineno; unsigned int lineno;
try { try {
lineno = std::stoi(std::string(pos, colon + 1, string::npos)); lineno = std::stoi(std::string(pos, colon + 1, std::string::npos));
} catch (std::invalid_argument & e) { } catch (std::invalid_argument & e) {
throw ParseError("cannot parse line number '%s'", pos); throw ParseError("cannot parse line number '%s'", pos);
} }

View file

@ -10,8 +10,11 @@ namespace nix {
MakeError(AttrPathNotFound, Error); MakeError(AttrPathNotFound, Error);
MakeError(NoPositionInfo, Error); MakeError(NoPositionInfo, Error);
std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const string & attrPath, std::pair<Value *, Pos> findAlongAttrPath(
Bindings & autoArgs, Value & vIn); EvalState & state,
const std::string & attrPath,
Bindings & autoArgs,
Value & vIn);
/* Heuristic to find the filename and lineno or a nix value. */ /* Heuristic to find the filename and lineno or a nix value. */
Pos findPackageFilename(EvalState & state, Value & v, std::string what); Pos findPackageFilename(EvalState & state, Value & v, std::string what);

View file

@ -105,7 +105,7 @@ public:
for (size_t n = 0; n < size_; n++) for (size_t n = 0; n < size_; n++)
res.emplace_back(&attrs[n]); res.emplace_back(&attrs[n]);
std::sort(res.begin(), res.end(), [](const Attr * a, const Attr * b) { std::sort(res.begin(), res.end(), [](const Attr * a, const Attr * b) {
return (const string &) a->name < (const string &) b->name; return (const std::string &) a->name < (const std::string &) b->name;
}); });
return res; return res;
} }

View file

@ -596,7 +596,7 @@ std::vector<Symbol> AttrCursor::getAttrs()
for (auto & attr : *getValue().attrs) for (auto & attr : *getValue().attrs)
attrs.push_back(attr.name); attrs.push_back(attr.name);
std::sort(attrs.begin(), attrs.end(), [](const Symbol & a, const Symbol & b) { std::sort(attrs.begin(), attrs.end(), [](const Symbol & a, const Symbol & b) {
return (const string &) a < (const string &) b; return (const std::string &) a < (const std::string &) b;
}); });
if (root->db) if (root->db)

View file

@ -86,15 +86,10 @@ RootValue allocRootValue(Value * v)
} }
void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v) void printValue(std::ostream & str, std::set<const void *> & seen, const Value & v)
{ {
checkInterrupt(); checkInterrupt();
if (!active.insert(&v).second) {
str << "<CYCLE>";
return;
}
switch (v.internalType) { switch (v.internalType) {
case tInt: case tInt:
str << v.integer; str << v.integer;
@ -120,24 +115,32 @@ void printValue(std::ostream & str, std::set<const Value *> & active, const Valu
str << "null"; str << "null";
break; break;
case tAttrs: { case tAttrs: {
str << "{ "; if (!v.attrs->empty() && !seen.insert(v.attrs).second)
for (auto & i : v.attrs->lexicographicOrder()) { str << "<REPEAT>";
str << i->name << " = "; else {
printValue(str, active, *i->value); str << "{ ";
str << "; "; for (auto & i : v.attrs->lexicographicOrder()) {
str << i->name << " = ";
printValue(str, seen, *i->value);
str << "; ";
}
str << "}";
} }
str << "}";
break; break;
} }
case tList1: case tList1:
case tList2: case tList2:
case tListN: case tListN:
str << "[ "; if (v.listSize() && !seen.insert(v.listElems()).second)
for (auto v2 : v.listItems()) { str << "<REPEAT>";
printValue(str, active, *v2); else {
str << " "; str << "[ ";
for (auto v2 : v.listItems()) {
printValue(str, seen, *v2);
str << " ";
}
str << "]";
} }
str << "]";
break; break;
case tThunk: case tThunk:
case tApp: case tApp:
@ -161,20 +164,18 @@ void printValue(std::ostream & str, std::set<const Value *> & active, const Valu
default: default:
abort(); abort();
} }
active.erase(&v);
} }
std::ostream & operator << (std::ostream & str, const Value & v) std::ostream & operator << (std::ostream & str, const Value & v)
{ {
std::set<const Value *> active; std::set<const void *> seen;
printValue(str, active, v); printValue(str, seen, v);
return str; return str;
} }
const Value *getPrimOp(const Value &v) { const Value * getPrimOp(const Value &v) {
const Value * primOp = &v; const Value * primOp = &v;
while (primOp->isPrimOpApp()) { while (primOp->isPrimOpApp()) {
primOp = primOp->primOpApp.left; primOp = primOp->primOpApp.left;
@ -183,7 +184,7 @@ const Value *getPrimOp(const Value &v) {
return primOp; return primOp;
} }
string showType(ValueType type) std::string_view showType(ValueType type)
{ {
switch (type) { switch (type) {
case nInt: return "an integer"; case nInt: return "an integer";
@ -202,20 +203,20 @@ string showType(ValueType type)
} }
string showType(const Value & v) std::string showType(const Value & v)
{ {
switch (v.internalType) { switch (v.internalType) {
case tString: return v.string.context ? "a string with context" : "a string"; case tString: return v.string.context ? "a string with context" : "a string";
case tPrimOp: case tPrimOp:
return fmt("the built-in function '%s'", string(v.primOp->name)); return fmt("the built-in function '%s'", std::string(v.primOp->name));
case tPrimOpApp: case tPrimOpApp:
return fmt("the partially applied built-in function '%s'", string(getPrimOp(v)->primOp->name)); return fmt("the partially applied built-in function '%s'", std::string(getPrimOp(v)->primOp->name));
case tExternal: return v.external->showType(); case tExternal: return v.external->showType();
case tThunk: return "a thunk"; case tThunk: return "a thunk";
case tApp: return "a function application"; case tApp: return "a function application";
case tBlackhole: return "a black hole"; case tBlackhole: return "a black hole";
default: default:
return showType(v.type()); return std::string(showType(v.type()));
} }
} }
@ -356,7 +357,7 @@ void initGC()
/* Very hacky way to parse $NIX_PATH, which is colon-separated, but /* Very hacky way to parse $NIX_PATH, which is colon-separated, but
can contain URLs (e.g. "nixpkgs=https://bla...:foo=https://"). */ can contain URLs (e.g. "nixpkgs=https://bla...:foo=https://"). */
static Strings parseNixPath(const string & s) static Strings parseNixPath(const std::string & s)
{ {
Strings res; Strings res;
@ -517,6 +518,14 @@ void EvalState::allowPath(const StorePath & storePath)
allowedPaths->insert(store->toRealPath(storePath)); allowedPaths->insert(store->toRealPath(storePath));
} }
void EvalState::allowAndSetStorePathString(const StorePath &storePath, Value & v)
{
allowPath(storePath);
auto path = store->printStorePath(storePath);
v.mkString(path, PathSet({path}));
}
Path EvalState::checkSourcePath(const Path & path_) Path EvalState::checkSourcePath(const Path & path_)
{ {
if (!allowedPaths) return path_; if (!allowedPaths) return path_;
@ -606,7 +615,7 @@ Path EvalState::toRealPath(const Path & path, const PathSet & context)
} }
Value * EvalState::addConstant(const string & name, Value & v) Value * EvalState::addConstant(const std::string & name, Value & v)
{ {
Value * v2 = allocValue(); Value * v2 = allocValue();
*v2 = v; *v2 = v;
@ -615,19 +624,19 @@ Value * EvalState::addConstant(const string & name, Value & v)
} }
void EvalState::addConstant(const string & name, Value * v) void EvalState::addConstant(const std::string & name, Value * v)
{ {
staticBaseEnv.vars.emplace_back(symbols.create(name), baseEnvDispl); staticBaseEnv.vars.emplace_back(symbols.create(name), baseEnvDispl);
baseEnv.values[baseEnvDispl++] = v; baseEnv.values[baseEnvDispl++] = v;
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; auto name2 = name.substr(0, 2) == "__" ? name.substr(2) : name;
baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v)); baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v));
} }
Value * EvalState::addPrimOp(const string & name, Value * EvalState::addPrimOp(const std::string & name,
size_t arity, PrimOpFun primOp) size_t arity, PrimOpFun primOp)
{ {
auto name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; auto name2 = name.substr(0, 2) == "__" ? name.substr(2) : name;
Symbol sym = symbols.create(name2); Symbol sym = symbols.create(name2);
/* Hack to make constants lazy: turn them into a application of /* Hack to make constants lazy: turn them into a application of
@ -675,7 +684,7 @@ Value * EvalState::addPrimOp(PrimOp && primOp)
} }
Value & EvalState::getBuiltin(const string & name) Value & EvalState::getBuiltin(const std::string & name)
{ {
return *baseEnv.values[0]->attrs->find(symbols.create(name))->value; return *baseEnv.values[0]->attrs->find(symbols.create(name))->value;
} }
@ -703,12 +712,12 @@ std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
evaluator. So here are some helper functions for throwing evaluator. So here are some helper functions for throwing
exceptions. */ exceptions. */
LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2)) LocalNoInlineNoReturn(void throwEvalError(const char * s, const std::string & s2))
{ {
throw EvalError(s, s2); throw EvalError(s, s2);
} }
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2)) LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const std::string & s2))
{ {
throw EvalError({ throw EvalError({
.msg = hintfmt(s, s2), .msg = hintfmt(s, s2),
@ -716,12 +725,12 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const
}); });
} }
LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3)) LocalNoInlineNoReturn(void throwEvalError(const char * s, const std::string & s2, const std::string & s3))
{ {
throw EvalError(s, s2, s3); throw EvalError(s, s2, s3);
} }
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3)) LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const std::string & s2, const std::string & s3))
{ {
throw EvalError({ throw EvalError({
.msg = hintfmt(s, s2, s3), .msg = hintfmt(s, s2, s3),
@ -759,7 +768,7 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v))
throw TypeError(s, showType(v)); throw TypeError(s, showType(v));
} }
LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1)) LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const std::string & s1))
{ {
throw AssertionError({ throw AssertionError({
.msg = hintfmt(s, s1), .msg = hintfmt(s, s1),
@ -767,7 +776,7 @@ LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s,
}); });
} }
LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1)) LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const std::string & s1))
{ {
throw UndefinedVarError({ throw UndefinedVarError({
.msg = hintfmt(s, s1), .msg = hintfmt(s, s1),
@ -775,7 +784,7 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char *
}); });
} }
LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1)) LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const std::string & s1))
{ {
throw MissingArgumentError({ throw MissingArgumentError({
.msg = hintfmt(s, s1), .msg = hintfmt(s, s1),
@ -783,12 +792,12 @@ LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char
}); });
} }
LocalNoInline(void addErrorTrace(Error & e, const char * s, const string & s2)) LocalNoInline(void addErrorTrace(Error & e, const char * s, const std::string & s2))
{ {
e.addTrace(std::nullopt, s, s2); e.addTrace(std::nullopt, s, s2);
} }
LocalNoInline(void addErrorTrace(Error & e, const Pos & pos, const char * s, const string & s2)) LocalNoInline(void addErrorTrace(Error & e, const Pos & pos, const char * s, const std::string & s2))
{ {
e.addTrace(pos, s, s2); e.addTrace(pos, s, s2);
} }
@ -1221,7 +1230,7 @@ void ExprVar::eval(EvalState & state, Env & env, Value & v)
} }
static string showAttrPath(EvalState & state, Env & env, const AttrPath & attrPath) static std::string showAttrPath(EvalState & state, Env & env, const AttrPath & attrPath)
{ {
std::ostringstream out; std::ostringstream out;
bool first = true; bool first = true;
@ -1395,7 +1404,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
if (loggerSettings.showTrace.get()) { if (loggerSettings.showTrace.get()) {
addErrorTrace(e, lambda.pos, "while evaluating %s", addErrorTrace(e, lambda.pos, "while evaluating %s",
(lambda.name.set() (lambda.name.set()
? "'" + (string) lambda.name + "'" ? "'" + (const std::string &) lambda.name + "'"
: "anonymous lambda")); : "anonymous lambda"));
addErrorTrace(e, pos, "from call site%s", ""); addErrorTrace(e, pos, "from call site%s", "");
} }
@ -1883,7 +1892,7 @@ std::string_view EvalState::forceString(Value & v, const Pos & pos)
/* Decode a context string !<name>!<path> into a pair <path, /* Decode a context string !<name>!<path> into a pair <path,
name>. */ name>. */
std::pair<string, string> decodeContext(std::string_view s) std::pair<std::string, std::string> decodeContext(std::string_view s)
{ {
if (s.at(0) == '!') { if (s.at(0) == '!') {
size_t index = s.find("!", 1); size_t index = s.find("!", 1);
@ -1946,7 +1955,7 @@ bool EvalState::isDerivation(Value & v)
} }
std::optional<string> EvalState::tryAttrsToString(const Pos & pos, Value & v, std::optional<std::string> EvalState::tryAttrsToString(const Pos & pos, Value & v,
PathSet & context, bool coerceMore, bool copyToStore) PathSet & context, bool coerceMore, bool copyToStore)
{ {
auto i = v.attrs->find(sToString); auto i = v.attrs->find(sToString);
@ -2001,7 +2010,7 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet &
if (v.type() == nNull) return ""; if (v.type() == nNull) return "";
if (v.isList()) { if (v.isList()) {
string result; std::string result;
for (auto [n, v2] : enumerate(v.listItems())) { for (auto [n, v2] : enumerate(v.listItems())) {
result += *coerceToString(pos, *v2, context, coerceMore, copyToStore); result += *coerceToString(pos, *v2, context, coerceMore, copyToStore);
if (n < v.listSize() - 1 if (n < v.listSize() - 1
@ -2017,7 +2026,7 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet &
} }
string EvalState::copyPathToStore(PathSet & context, const Path & path) std::string EvalState::copyPathToStore(PathSet & context, const Path & path)
{ {
if (nix::isDerivation(path)) if (nix::isDerivation(path))
throwEvalError("file names are not allowed to end in '%1%'", drvExtension); throwEvalError("file names are not allowed to end in '%1%'", drvExtension);
@ -2043,13 +2052,25 @@ string EvalState::copyPathToStore(PathSet & context, const Path & path)
Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context) Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context)
{ {
string path = coerceToString(pos, v, context, false, false).toOwned(); auto path = coerceToString(pos, v, context, false, false).toOwned();
if (path == "" || path[0] != '/') if (path == "" || path[0] != '/')
throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path); throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path);
return path; return path;
} }
StorePath EvalState::coerceToStorePath(const Pos & pos, Value & v, PathSet & context)
{
auto path = coerceToString(pos, v, context, false, false).toOwned();
if (auto storePath = store->maybeParseStorePath(path))
return *storePath;
throw EvalError({
.msg = hintfmt("path '%1%' is not in the Nix store", path),
.errPos = pos
});
}
bool EvalState::eqValues(Value & v1, Value & v2) bool EvalState::eqValues(Value & v1, Value & v2)
{ {
forceValue(v1, noPos); forceValue(v1, noPos);
@ -2213,11 +2234,11 @@ void EvalState::printStats()
for (auto & i : functionCalls) { for (auto & i : functionCalls) {
auto obj = list.object(); auto obj = list.object();
if (i.first->name.set()) if (i.first->name.set())
obj.attr("name", (const string &) i.first->name); obj.attr("name", (const std::string &) i.first->name);
else else
obj.attr("name", nullptr); obj.attr("name", nullptr);
if (i.first->pos) { if (i.first->pos) {
obj.attr("file", (const string &) i.first->pos.file); obj.attr("file", (const std::string &) i.first->pos.file);
obj.attr("line", i.first->pos.line); obj.attr("line", i.first->pos.line);
obj.attr("column", i.first->pos.column); obj.attr("column", i.first->pos.column);
} }
@ -2229,7 +2250,7 @@ void EvalState::printStats()
for (auto & i : attrSelects) { for (auto & i : attrSelects) {
auto obj = list.object(); auto obj = list.object();
if (i.first) { if (i.first) {
obj.attr("file", (const string &) i.first.file); obj.attr("file", (const std::string &) i.first.file);
obj.attr("line", i.first.line); obj.attr("line", i.first.line);
obj.attr("column", i.first.column); obj.attr("column", i.first.column);
} }
@ -2246,7 +2267,7 @@ void EvalState::printStats()
} }
string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const std::string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const
{ {
throw TypeError({ throw TypeError({
.msg = hintfmt("cannot coerce %1% to a string", showType()), .msg = hintfmt("cannot coerce %1% to a string", showType()),

View file

@ -150,7 +150,7 @@ public:
const Pos & pos const Pos & pos
); );
void addToSearchPath(const string & s); void addToSearchPath(const std::string & s);
SearchPath getSearchPath() { return searchPath; } SearchPath getSearchPath() { return searchPath; }
@ -161,6 +161,9 @@ public:
the real store path if `store` is a chroot store. */ the real store path if `store` is a chroot store. */
void allowPath(const StorePath & storePath); void allowPath(const StorePath & storePath);
/* Allow access to a store path and return it as a string. */
void allowAndSetStorePathString(const StorePath & storePath, Value & v);
/* Check whether access to a path is allowed and throw an error if /* Check whether access to a path is allowed and throw an error if
not. Otherwise return the canonicalised path. */ not. Otherwise return the canonicalised path. */
Path checkSourcePath(const Path & path); Path checkSourcePath(const Path & path);
@ -251,7 +254,7 @@ public:
set with attribute `type = "derivation"'). */ set with attribute `type = "derivation"'). */
bool isDerivation(Value & v); bool isDerivation(Value & v);
std::optional<string> tryAttrsToString(const Pos & pos, Value & v, std::optional<std::string> tryAttrsToString(const Pos & pos, Value & v,
PathSet & context, bool coerceMore = false, bool copyToStore = true); PathSet & context, bool coerceMore = false, bool copyToStore = true);
/* String coercion. Converts strings, paths and derivations to a /* String coercion. Converts strings, paths and derivations to a
@ -262,13 +265,16 @@ public:
bool coerceMore = false, bool copyToStore = true, bool coerceMore = false, bool copyToStore = true,
bool canonicalizePath = true); bool canonicalizePath = true);
string copyPathToStore(PathSet & context, const Path & path); std::string copyPathToStore(PathSet & context, const Path & path);
/* Path coercion. Converts strings, paths and derivations to a /* Path coercion. Converts strings, paths and derivations to a
path. The result is guaranteed to be a canonicalised, absolute path. The result is guaranteed to be a canonicalised, absolute
path. Nothing is copied to the store. */ path. Nothing is copied to the store. */
Path coerceToPath(const Pos & pos, Value & v, PathSet & context); Path coerceToPath(const Pos & pos, Value & v, PathSet & context);
/* Like coerceToPath, but the result must be a store path. */
StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context);
public: public:
/* The base environment, containing the builtin functions and /* The base environment, containing the builtin functions and
@ -284,18 +290,18 @@ private:
void createBaseEnv(); void createBaseEnv();
Value * addConstant(const string & name, Value & v); Value * addConstant(const std::string & name, Value & v);
void addConstant(const string & name, Value * v); void addConstant(const std::string & name, Value * v);
Value * addPrimOp(const string & name, Value * addPrimOp(const std::string & name,
size_t arity, PrimOpFun primOp); size_t arity, PrimOpFun primOp);
Value * addPrimOp(PrimOp && primOp); Value * addPrimOp(PrimOp && primOp);
public: public:
Value & getBuiltin(const string & name); Value & getBuiltin(const std::string & name);
struct Doc struct Doc
{ {
@ -414,12 +420,12 @@ private:
/* Return a string representing the type of the value `v'. */ /* Return a string representing the type of the value `v'. */
string showType(ValueType type); std::string_view showType(ValueType type);
string showType(const Value & v); std::string showType(const Value & v);
/* Decode a context string !<name>!<path> into a pair <path, /* Decode a context string !<name>!<path> into a pair <path,
name>. */ name>. */
std::pair<string, string> decodeContext(std::string_view s); std::pair<std::string, std::string> decodeContext(std::string_view s);
/* If `path' refers to a directory, then append "/default.nix". */ /* If `path' refers to a directory, then append "/default.nix". */
Path resolveExprPath(Path path); Path resolveExprPath(Path path);

View file

@ -1,5 +1,6 @@
#include "flake.hh" #include "flake.hh"
#include "globals.hh" #include "globals.hh"
#include "fetch-settings.hh"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -53,7 +54,7 @@ void ConfigFile::apply()
auto trustedList = readTrustedList(); auto trustedList = readTrustedList();
bool trusted = false; bool trusted = false;
if (nix::settings.acceptFlakeConfig){ if (nix::fetchSettings.acceptFlakeConfig){
trusted = true; trusted = true;
} else if (auto saved = get(get(trustedList, name).value_or(std::map<std::string, bool>()), valueS)) { } else if (auto saved = get(get(trustedList, name).value_or(std::map<std::string, bool>()), valueS)) {
trusted = *saved; trusted = *saved;

View file

@ -6,6 +6,7 @@
#include "store-api.hh" #include "store-api.hh"
#include "fetchers.hh" #include "fetchers.hh"
#include "finally.hh" #include "finally.hh"
#include "fetch-settings.hh"
namespace nix { namespace nix {
@ -254,7 +255,7 @@ static Flake getFlake(
for (auto & setting : *nixConfig->value->attrs) { for (auto & setting : *nixConfig->value->attrs) {
forceTrivialValue(state, *setting.value, *setting.pos); forceTrivialValue(state, *setting.value, *setting.pos);
if (setting.value->type() == nString) if (setting.value->type() == nString)
flake.config.settings.insert({setting.name, string(state.forceStringNoCtx(*setting.value, *setting.pos))}); flake.config.settings.insert({setting.name, std::string(state.forceStringNoCtx(*setting.value, *setting.pos))});
else if (setting.value->type() == nPath) { else if (setting.value->type() == nPath) {
PathSet emptyContext = {}; PathSet emptyContext = {};
flake.config.settings.emplace( flake.config.settings.emplace(
@ -315,7 +316,7 @@ LockedFlake lockFlake(
FlakeCache flakeCache; FlakeCache flakeCache;
auto useRegistries = lockFlags.useRegistries.value_or(settings.useRegistries); auto useRegistries = lockFlags.useRegistries.value_or(fetchSettings.useRegistries);
auto flake = getFlake(state, topRef, useRegistries, flakeCache); auto flake = getFlake(state, topRef, useRegistries, flakeCache);
@ -501,7 +502,7 @@ LockedFlake lockFlake(
this input. */ this input. */
debug("creating new input '%s'", inputPathS); debug("creating new input '%s'", inputPathS);
if (!lockFlags.allowMutable && !input.ref->input.isImmutable()) if (!lockFlags.allowMutable && !input.ref->input.isLocked())
throw Error("cannot update flake input '%s' in pure mode", inputPathS); throw Error("cannot update flake input '%s' in pure mode", inputPathS);
if (input.isFlake) { if (input.isFlake) {
@ -591,7 +592,7 @@ LockedFlake lockFlake(
if (lockFlags.writeLockFile) { if (lockFlags.writeLockFile) {
if (auto sourcePath = topRef.input.getSourcePath()) { if (auto sourcePath = topRef.input.getSourcePath()) {
if (!newLockFile.isImmutable()) { if (!newLockFile.isImmutable()) {
if (settings.warnDirty) if (fetchSettings.warnDirty)
warn("will not write lock file of flake '%s' because it has a mutable input", topRef); warn("will not write lock file of flake '%s' because it has a mutable input", topRef);
} else { } else {
if (!lockFlags.updateLockFile) if (!lockFlags.updateLockFile)
@ -618,7 +619,7 @@ LockedFlake lockFlake(
if (lockFlags.commitLockFile) { if (lockFlags.commitLockFile) {
std::string cm; std::string cm;
cm = settings.commitLockFileSummary.get(); cm = fetchSettings.commitLockFileSummary.get();
if (cm == "") { if (cm == "") {
cm = fmt("%s: %s", relPath, lockFileExists ? "Update" : "Add"); cm = fmt("%s: %s", relPath, lockFileExists ? "Update" : "Add");
@ -650,7 +651,7 @@ LockedFlake lockFlake(
now. Corner case: we could have reverted from a now. Corner case: we could have reverted from a
dirty to a clean tree! */ dirty to a clean tree! */
if (flake.lockedRef.input == prevLockedRef.input if (flake.lockedRef.input == prevLockedRef.input
&& !flake.lockedRef.input.isImmutable()) && !flake.lockedRef.input.isLocked())
throw Error("'%s' did not change after I updated its 'flake.lock' file; is 'flake.lock' under version control?", flake.originalRef); throw Error("'%s' did not change after I updated its 'flake.lock' file; is 'flake.lock' under version control?", flake.originalRef);
} }
} else } else
@ -707,16 +708,16 @@ static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Va
{ {
state.requireExperimentalFeatureOnEvaluation(Xp::Flakes, "builtins.getFlake", pos); state.requireExperimentalFeatureOnEvaluation(Xp::Flakes, "builtins.getFlake", pos);
string flakeRefS(state.forceStringNoCtx(*args[0], pos)); std::string flakeRefS(state.forceStringNoCtx(*args[0], pos));
auto flakeRef = parseFlakeRef(flakeRefS, {}, true); auto flakeRef = parseFlakeRef(flakeRefS, {}, true);
if (evalSettings.pureEval && !flakeRef.input.isImmutable()) if (evalSettings.pureEval && !flakeRef.input.isLocked())
throw Error("cannot call 'getFlake' on mutable flake reference '%s', at %s (use --impure to override)", flakeRefS, pos); throw Error("cannot call 'getFlake' on unlocked flake reference '%s', at %s (use --impure to override)", flakeRefS, pos);
callFlake(state, callFlake(state,
lockFlake(state, flakeRef, lockFlake(state, flakeRef,
LockFlags { LockFlags {
.updateLockFile = false, .updateLockFile = false,
.useRegistries = !evalSettings.pureEval && settings.useRegistries, .useRegistries = !evalSettings.pureEval && fetchSettings.useRegistries,
.allowMutable = !evalSettings.pureEval, .allowMutable = !evalSettings.pureEval,
}), }),
v); v);

View file

@ -98,7 +98,7 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
if (std::regex_match(url, match, flakeRegex)) { if (std::regex_match(url, match, flakeRegex)) {
auto parsedURL = ParsedURL{ auto parsedURL = ParsedURL{
.url = url, .url = url,
.base = "flake:" + std::string(match[1]), .base = "flake:" + match.str(1),
.scheme = "flake", .scheme = "flake",
.authority = "", .authority = "",
.path = match[1], .path = match[1],
@ -106,12 +106,12 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
return std::make_pair( return std::make_pair(
FlakeRef(Input::fromURL(parsedURL), ""), FlakeRef(Input::fromURL(parsedURL), ""),
percentDecode(std::string(match[6]))); percentDecode(match.str(6)));
} }
else if (std::regex_match(url, match, pathUrlRegex)) { else if (std::regex_match(url, match, pathUrlRegex)) {
std::string path = match[1]; std::string path = match[1];
std::string fragment = percentDecode(std::string(match[3])); std::string fragment = percentDecode(match.str(3));
if (baseDir) { if (baseDir) {
/* Check if 'url' is a path (either absolute or relative /* Check if 'url' is a path (either absolute or relative

View file

@ -35,7 +35,7 @@ LockedNode::LockedNode(const nlohmann::json & json)
, originalRef(getFlakeRef(json, "original", nullptr)) , originalRef(getFlakeRef(json, "original", nullptr))
, isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true) , isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true)
{ {
if (!lockedRef.input.isImmutable()) if (!lockedRef.input.isLocked())
throw Error("lockfile contains mutable lock '%s'", throw Error("lockfile contains mutable lock '%s'",
fetchers::attrsToJSON(lockedRef.input.toAttrs())); fetchers::attrsToJSON(lockedRef.input.toAttrs()));
} }
@ -220,7 +220,7 @@ bool LockFile::isImmutable() const
for (auto & i : nodes) { for (auto & i : nodes) {
if (i == root) continue; if (i == root) continue;
auto lockedNode = std::dynamic_pointer_cast<const LockedNode>(i); auto lockedNode = std::dynamic_pointer_cast<const LockedNode>(i);
if (lockedNode && !lockedNode->lockedRef.input.isImmutable()) return false; if (lockedNode && !lockedNode->lockedRef.input.isLocked()) return false;
} }
return true; return true;

View file

@ -11,8 +11,8 @@
namespace nix { namespace nix {
DrvInfo::DrvInfo(EvalState & state, const string & attrPath, Bindings * attrs) DrvInfo::DrvInfo(EvalState & state, std::string attrPath, Bindings * attrs)
: state(&state), attrs(attrs), attrPath(attrPath) : state(&state), attrs(attrs), attrPath(std::move(attrPath))
{ {
} }
@ -22,7 +22,7 @@ DrvInfo::DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPat
{ {
auto [drvPath, selectedOutputs] = parsePathWithOutputs(*store, drvPathWithOutputs); auto [drvPath, selectedOutputs] = parsePathWithOutputs(*store, drvPathWithOutputs);
this->drvPath = store->printStorePath(drvPath); this->drvPath = drvPath;
auto drv = store->derivationFromPath(drvPath); auto drv = store->derivationFromPath(drvPath);
@ -41,13 +41,11 @@ DrvInfo::DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPat
throw Error("derivation '%s' does not have output '%s'", store->printStorePath(drvPath), outputName); throw Error("derivation '%s' does not have output '%s'", store->printStorePath(drvPath), outputName);
auto & [outputName, output] = *i; auto & [outputName, output] = *i;
auto optStorePath = output.path(*store, drv.name, outputName); outPath = {output.path(*store, drv.name, outputName)};
if (optStorePath)
outPath = store->printStorePath(*optStorePath);
} }
string DrvInfo::queryName() const std::string DrvInfo::queryName() const
{ {
if (name == "" && attrs) { if (name == "" && attrs) {
auto i = attrs->find(state->sName); auto i = attrs->find(state->sName);
@ -58,7 +56,7 @@ string DrvInfo::queryName() const
} }
string DrvInfo::querySystem() const std::string DrvInfo::querySystem() const
{ {
if (system == "" && attrs) { if (system == "" && attrs) {
auto i = attrs->find(state->sSystem); auto i = attrs->find(state->sSystem);
@ -68,24 +66,35 @@ string DrvInfo::querySystem() const
} }
string DrvInfo::queryDrvPath() const std::optional<StorePath> DrvInfo::queryDrvPath() const
{ {
if (drvPath == "" && attrs) { if (!drvPath && attrs) {
Bindings::iterator i = attrs->find(state->sDrvPath); Bindings::iterator i = attrs->find(state->sDrvPath);
PathSet context; PathSet context;
drvPath = i != attrs->end() ? state->coerceToPath(*i->pos, *i->value, context) : ""; if (i == attrs->end())
drvPath = {std::nullopt};
else
drvPath = {state->coerceToStorePath(*i->pos, *i->value, context)};
} }
return drvPath; return drvPath.value_or(std::nullopt);
} }
string DrvInfo::queryOutPath() const StorePath DrvInfo::requireDrvPath() const
{
if (auto drvPath = queryDrvPath())
return *drvPath;
throw Error("derivation does not contain a 'drvPath' attribute");
}
StorePath DrvInfo::queryOutPath() const
{ {
if (!outPath && attrs) { if (!outPath && attrs) {
Bindings::iterator i = attrs->find(state->sOutPath); Bindings::iterator i = attrs->find(state->sOutPath);
PathSet context; PathSet context;
if (i != attrs->end()) if (i != attrs->end())
outPath = state->coerceToPath(*i->pos, *i->value, context); outPath = state->coerceToStorePath(*i->pos, *i->value, context);
} }
if (!outPath) if (!outPath)
throw UnimplementedError("CA derivations are not yet supported"); throw UnimplementedError("CA derivations are not yet supported");
@ -104,7 +113,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
/* For each output... */ /* For each output... */
for (auto elem : i->value->listItems()) { for (auto elem : i->value->listItems()) {
/* Evaluate the corresponding set. */ /* Evaluate the corresponding set. */
string name(state->forceStringNoCtx(*elem, *i->pos)); std::string name(state->forceStringNoCtx(*elem, *i->pos));
Bindings::iterator out = attrs->find(state->symbols.create(name)); Bindings::iterator out = attrs->find(state->symbols.create(name));
if (out == attrs->end()) continue; // FIXME: throw error? if (out == attrs->end()) continue; // FIXME: throw error?
state->forceAttrs(*out->value, *i->pos); state->forceAttrs(*out->value, *i->pos);
@ -113,10 +122,10 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath); Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error? if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
PathSet context; PathSet context;
outputs[name] = state->coerceToPath(*outPath->pos, *outPath->value, context); outputs.emplace(name, state->coerceToStorePath(*outPath->pos, *outPath->value, context));
} }
} else } else
outputs["out"] = queryOutPath(); outputs.emplace("out", queryOutPath());
} }
if (!onlyOutputsToInstall || !attrs) if (!onlyOutputsToInstall || !attrs)
return outputs; return outputs;
@ -138,7 +147,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
} }
string DrvInfo::queryOutputName() const std::string DrvInfo::queryOutputName() const
{ {
if (outputName == "" && attrs) { if (outputName == "" && attrs) {
Bindings::iterator i = attrs->find(state->sOutputName); Bindings::iterator i = attrs->find(state->sOutputName);
@ -190,7 +199,7 @@ bool DrvInfo::checkMeta(Value & v)
} }
Value * DrvInfo::queryMeta(const string & name) Value * DrvInfo::queryMeta(const std::string & name)
{ {
if (!getMeta()) return 0; if (!getMeta()) return 0;
Bindings::iterator a = meta->find(state->symbols.create(name)); Bindings::iterator a = meta->find(state->symbols.create(name));
@ -199,7 +208,7 @@ Value * DrvInfo::queryMeta(const string & name)
} }
string DrvInfo::queryMetaString(const string & name) std::string DrvInfo::queryMetaString(const std::string & name)
{ {
Value * v = queryMeta(name); Value * v = queryMeta(name);
if (!v || v->type() != nString) return ""; if (!v || v->type() != nString) return "";
@ -207,7 +216,7 @@ string DrvInfo::queryMetaString(const string & name)
} }
NixInt DrvInfo::queryMetaInt(const string & name, NixInt def) NixInt DrvInfo::queryMetaInt(const std::string & name, NixInt def)
{ {
Value * v = queryMeta(name); Value * v = queryMeta(name);
if (!v) return def; if (!v) return def;
@ -221,7 +230,7 @@ NixInt DrvInfo::queryMetaInt(const string & name, NixInt def)
return def; return def;
} }
NixFloat DrvInfo::queryMetaFloat(const string & name, NixFloat def) NixFloat DrvInfo::queryMetaFloat(const std::string & name, NixFloat def)
{ {
Value * v = queryMeta(name); Value * v = queryMeta(name);
if (!v) return def; if (!v) return def;
@ -236,7 +245,7 @@ NixFloat DrvInfo::queryMetaFloat(const string & name, NixFloat def)
} }
bool DrvInfo::queryMetaBool(const string & name, bool def) bool DrvInfo::queryMetaBool(const std::string & name, bool def)
{ {
Value * v = queryMeta(name); Value * v = queryMeta(name);
if (!v) return def; if (!v) return def;
@ -251,7 +260,7 @@ bool DrvInfo::queryMetaBool(const string & name, bool def)
} }
void DrvInfo::setMeta(const string & name, Value * v) void DrvInfo::setMeta(const std::string & name, Value * v)
{ {
getMeta(); getMeta();
auto attrs = state->buildBindings(1 + (meta ? meta->size() : 0)); auto attrs = state->buildBindings(1 + (meta ? meta->size() : 0));
@ -274,7 +283,7 @@ typedef std::set<Bindings *> Done;
The result boolean indicates whether it makes sense The result boolean indicates whether it makes sense
for the caller to recursively search for derivations in `v'. */ for the caller to recursively search for derivations in `v'. */
static bool getDerivation(EvalState & state, Value & v, static bool getDerivation(EvalState & state, Value & v,
const string & attrPath, DrvInfos & drvs, Done & done, const std::string & attrPath, DrvInfos & drvs, Done & done,
bool ignoreAssertionFailures) bool ignoreAssertionFailures)
{ {
try { try {
@ -311,7 +320,7 @@ std::optional<DrvInfo> getDerivation(EvalState & state, Value & v,
} }
static string addToPath(const string & s1, const string & s2) static std::string addToPath(const std::string & s1, const std::string & s2)
{ {
return s1.empty() ? s2 : s1 + "." + s2; return s1.empty() ? s2 : s1 + "." + s2;
} }
@ -321,7 +330,7 @@ static std::regex attrRegex("[A-Za-z_][A-Za-z0-9-_+]*");
static void getDerivations(EvalState & state, Value & vIn, static void getDerivations(EvalState & state, Value & vIn,
const string & pathPrefix, Bindings & autoArgs, const std::string & pathPrefix, Bindings & autoArgs,
DrvInfos & drvs, Done & done, DrvInfos & drvs, Done & done,
bool ignoreAssertionFailures) bool ignoreAssertionFailures)
{ {
@ -346,7 +355,7 @@ static void getDerivations(EvalState & state, Value & vIn,
debug("evaluating attribute '%1%'", i->name); debug("evaluating attribute '%1%'", i->name);
if (!std::regex_match(std::string(i->name), attrRegex)) if (!std::regex_match(std::string(i->name), attrRegex))
continue; continue;
string pathPrefix2 = addToPath(pathPrefix, i->name); std::string pathPrefix2 = addToPath(pathPrefix, i->name);
if (combineChannels) if (combineChannels)
getDerivations(state, *i->value, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures); getDerivations(state, *i->value, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
else if (getDerivation(state, *i->value, pathPrefix2, drvs, done, ignoreAssertionFailures)) { else if (getDerivation(state, *i->value, pathPrefix2, drvs, done, ignoreAssertionFailures)) {
@ -364,7 +373,7 @@ static void getDerivations(EvalState & state, Value & vIn,
else if (v.type() == nList) { else if (v.type() == nList) {
for (auto [n, elem] : enumerate(v.listItems())) { for (auto [n, elem] : enumerate(v.listItems())) {
string pathPrefix2 = addToPath(pathPrefix, fmt("%d", n)); std::string pathPrefix2 = addToPath(pathPrefix, fmt("%d", n));
if (getDerivation(state, *elem, pathPrefix2, drvs, done, ignoreAssertionFailures)) if (getDerivation(state, *elem, pathPrefix2, drvs, done, ignoreAssertionFailures))
getDerivations(state, *elem, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures); getDerivations(state, *elem, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
} }
@ -374,7 +383,7 @@ static void getDerivations(EvalState & state, Value & vIn,
} }
void getDerivations(EvalState & state, Value & v, const string & pathPrefix, void getDerivations(EvalState & state, Value & v, const std::string & pathPrefix,
Bindings & autoArgs, DrvInfos & drvs, bool ignoreAssertionFailures) Bindings & autoArgs, DrvInfos & drvs, bool ignoreAssertionFailures)
{ {
Done done; Done done;

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "eval.hh" #include "eval.hh"
#include "path.hh"
#include <string> #include <string>
#include <map> #include <map>
@ -12,16 +13,16 @@ namespace nix {
struct DrvInfo struct DrvInfo
{ {
public: public:
typedef std::map<string, Path> Outputs; typedef std::map<std::string, StorePath> Outputs;
private: private:
EvalState * state; EvalState * state;
mutable string name; mutable std::string name;
mutable string system; mutable std::string system;
mutable string drvPath; mutable std::optional<std::optional<StorePath>> drvPath;
mutable std::optional<string> outPath; mutable std::optional<StorePath> outPath;
mutable string outputName; mutable std::string outputName;
Outputs outputs; Outputs outputs;
bool failed = false; // set if we get an AssertionError bool failed = false; // set if we get an AssertionError
@ -33,36 +34,37 @@ private:
bool checkMeta(Value & v); bool checkMeta(Value & v);
public: public:
string attrPath; /* path towards the derivation */ std::string attrPath; /* path towards the derivation */
DrvInfo(EvalState & state) : state(&state) { }; DrvInfo(EvalState & state) : state(&state) { };
DrvInfo(EvalState & state, const string & attrPath, Bindings * attrs); DrvInfo(EvalState & state, std::string attrPath, Bindings * attrs);
DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPathWithOutputs); DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPathWithOutputs);
string queryName() const; std::string queryName() const;
string querySystem() const; std::string querySystem() const;
string queryDrvPath() const; std::optional<StorePath> queryDrvPath() const;
string queryOutPath() const; StorePath requireDrvPath() const;
string queryOutputName() const; StorePath queryOutPath() const;
std::string queryOutputName() const;
/** Return the list of outputs. The "outputs to install" are determined by `meta.outputsToInstall`. */ /** Return the list of outputs. The "outputs to install" are determined by `meta.outputsToInstall`. */
Outputs queryOutputs(bool onlyOutputsToInstall = false); Outputs queryOutputs(bool onlyOutputsToInstall = false);
StringSet queryMetaNames(); StringSet queryMetaNames();
Value * queryMeta(const string & name); Value * queryMeta(const std::string & name);
string queryMetaString(const string & name); std::string queryMetaString(const std::string & name);
NixInt queryMetaInt(const string & name, NixInt def); NixInt queryMetaInt(const std::string & name, NixInt def);
NixFloat queryMetaFloat(const string & name, NixFloat def); NixFloat queryMetaFloat(const std::string & name, NixFloat def);
bool queryMetaBool(const string & name, bool def); bool queryMetaBool(const std::string & name, bool def);
void setMeta(const string & name, Value * v); void setMeta(const std::string & name, Value * v);
/* /*
MetaInfo queryMetaInfo(EvalState & state) const; MetaInfo queryMetaInfo(EvalState & state) const;
MetaValue queryMetaInfo(EvalState & state, const string & name) const; MetaValue queryMetaInfo(EvalState & state, const string & name) const;
*/ */
void setName(const string & s) { name = s; } void setName(const std::string & s) { name = s; }
void setDrvPath(const string & s) { drvPath = s; } void setDrvPath(StorePath path) { drvPath = {{std::move(path)}}; }
void setOutPath(const string & s) { outPath = s; } void setOutPath(StorePath path) { outPath = {{std::move(path)}}; }
void setFailed() { failed = true; }; void setFailed() { failed = true; };
bool hasFailed() { return failed; }; bool hasFailed() { return failed; };
@ -81,7 +83,7 @@ typedef std::list<DrvInfo> DrvInfos;
std::optional<DrvInfo> getDerivation(EvalState & state, std::optional<DrvInfo> getDerivation(EvalState & state,
Value & v, bool ignoreAssertionFailures); Value & v, bool ignoreAssertionFailures);
void getDerivations(EvalState & state, Value & v, const string & pathPrefix, void getDerivations(EvalState & state, Value & v, const std::string & pathPrefix,
Bindings & autoArgs, DrvInfos & drvs, Bindings & autoArgs, DrvInfos & drvs,
bool ignoreAssertionFailures); bool ignoreAssertionFailures);

View file

@ -16,10 +16,10 @@ std::ostream & operator << (std::ostream & str, const Expr & e)
return str; return str;
} }
static void showString(std::ostream & str, const string & s) static void showString(std::ostream & str, std::string_view s)
{ {
str << '"'; str << '"';
for (auto c : (string) s) for (auto c : s)
if (c == '"' || c == '\\' || c == '$') str << "\\" << c; if (c == '"' || c == '\\' || c == '$') str << "\\" << c;
else if (c == '\n') str << "\\n"; else if (c == '\n') str << "\\n";
else if (c == '\r') str << "\\r"; else if (c == '\r') str << "\\r";
@ -28,7 +28,7 @@ static void showString(std::ostream & str, const string & s)
str << '"'; str << '"';
} }
static void showId(std::ostream & str, const string & s) static void showId(std::ostream & str, std::string_view s)
{ {
if (s.empty()) if (s.empty())
str << "\"\""; str << "\"\"";
@ -103,11 +103,18 @@ void ExprAttrs::show(std::ostream & str) const
{ {
if (recursive) str << "rec "; if (recursive) str << "rec ";
str << "{ "; str << "{ ";
for (auto & i : attrs) typedef const decltype(attrs)::value_type * Attr;
if (i.second.inherited) std::vector<Attr> sorted;
str << "inherit " << i.first << " " << "; "; for (auto & i : attrs) sorted.push_back(&i);
std::sort(sorted.begin(), sorted.end(), [](Attr a, Attr b) {
return (const std::string &) a->first < (const std::string &) b->first;
});
for (auto & i : sorted) {
if (i->second.inherited)
str << "inherit " << i->first << " " << "; ";
else else
str << i.first << " = " << *i.second.e << "; "; str << i->first << " = " << *i->second.e << "; ";
}
for (auto & i : dynamicAttrs) for (auto & i : dynamicAttrs)
str << "\"${" << *i.nameExpr << "}\" = " << *i.valueExpr << "; "; str << "\"${" << *i.nameExpr << "}\" = " << *i.valueExpr << "; ";
str << "}"; str << "}";
@ -211,7 +218,7 @@ std::ostream & operator << (std::ostream & str, const Pos & pos)
auto f = format(ANSI_BOLD "%1%" ANSI_NORMAL ":%2%:%3%"); auto f = format(ANSI_BOLD "%1%" ANSI_NORMAL ":%2%:%3%");
switch (pos.origin) { switch (pos.origin) {
case foFile: case foFile:
f % (string) pos.file; f % (const std::string &) pos.file;
break; break;
case foStdin: case foStdin:
case foString: case foString:
@ -227,7 +234,7 @@ std::ostream & operator << (std::ostream & str, const Pos & pos)
} }
string showAttrPath(const AttrPath & attrPath) std::string showAttrPath(const AttrPath & attrPath)
{ {
std::ostringstream out; std::ostringstream out;
bool first = true; bool first = true;
@ -461,9 +468,9 @@ void ExprLambda::setName(Symbol & name)
} }
string ExprLambda::showNamePos() const std::string ExprLambda::showNamePos() const
{ {
return (format("%1% at %2%") % (name.set() ? "'" + (string) name + "'" : "anonymous function") % pos).str(); return fmt("%1% at %2%", name.set() ? "'" + (std::string) name + "'" : "anonymous function", pos);
} }

View file

@ -26,18 +26,21 @@ struct Pos
FileOrigin origin; FileOrigin origin;
Symbol file; Symbol file;
unsigned int line, column; unsigned int line, column;
Pos() : origin(foString), line(0), column(0) { };
Pos() : origin(foString), line(0), column(0) { }
Pos(FileOrigin origin, const Symbol & file, unsigned int line, unsigned int column) Pos(FileOrigin origin, const Symbol & file, unsigned int line, unsigned int column)
: origin(origin), file(file), line(line), column(column) { }; : origin(origin), file(file), line(line), column(column) { }
operator bool() const operator bool() const
{ {
return line != 0; return line != 0;
} }
bool operator < (const Pos & p2) const bool operator < (const Pos & p2) const
{ {
if (!line) return p2.line; if (!line) return p2.line;
if (!p2.line) return false; if (!p2.line) return false;
int d = ((string) file).compare((string) p2.file); int d = ((const std::string &) file).compare((const std::string &) p2.file);
if (d < 0) return true; if (d < 0) return true;
if (d > 0) return false; if (d > 0) return false;
if (line < p2.line) return true; if (line < p2.line) return true;
@ -68,7 +71,7 @@ struct AttrName
typedef std::vector<AttrName> AttrPath; typedef std::vector<AttrName> AttrPath;
string showAttrPath(const AttrPath & attrPath); std::string showAttrPath(const AttrPath & attrPath);
/* Abstract syntax of Nix expressions. */ /* Abstract syntax of Nix expressions. */
@ -110,7 +113,7 @@ struct ExprFloat : Expr
struct ExprString : Expr struct ExprString : Expr
{ {
string s; std::string s;
Value v; Value v;
ExprString(std::string s) : s(std::move(s)) { v.mkString(this->s.data()); }; ExprString(std::string s) : s(std::move(s)) { v.mkString(this->s.data()); };
COMMON_METHODS COMMON_METHODS
@ -119,9 +122,9 @@ struct ExprString : Expr
struct ExprPath : Expr struct ExprPath : Expr
{ {
string s; std::string s;
Value v; Value v;
ExprPath(const string & s) : s(s) { v.mkPath(this->s.c_str()); }; ExprPath(std::string s) : s(std::move(s)) { v.mkPath(this->s.c_str()); };
COMMON_METHODS COMMON_METHODS
Value * maybeThunk(EvalState & state, Env & env); Value * maybeThunk(EvalState & state, Env & env);
}; };
@ -249,7 +252,7 @@ struct ExprLambda : Expr
{ {
}; };
void setName(Symbol & name); void setName(Symbol & name);
string showNamePos() const; std::string showNamePos() const;
inline bool hasFormals() const { return formals != nullptr; } inline bool hasFormals() const { return formals != nullptr; }
COMMON_METHODS COMMON_METHODS
}; };

View file

@ -244,7 +244,7 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols,
es2->emplace_back(i->first, e); es2->emplace_back(i->first, e);
}; };
const auto trimString = [&] (const StringToken & t) { const auto trimString = [&] (const StringToken & t) {
string s2; std::string s2;
for (size_t j = 0; j < t.l; ++j) { for (size_t j = 0; j < t.l; ++j) {
if (atStartOfLine) { if (atStartOfLine) {
if (t.p[j] == ' ') { if (t.p[j] == ' ') {
@ -268,9 +268,9 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols,
/* Remove the last line if it is empty and consists only of /* Remove the last line if it is empty and consists only of
spaces. */ spaces. */
if (n == 1) { if (n == 1) {
string::size_type p = s2.find_last_of('\n'); std::string::size_type p = s2.find_last_of('\n');
if (p != string::npos && s2.find_first_not_of(' ', p + 1) == string::npos) if (p != std::string::npos && s2.find_first_not_of(' ', p + 1) == std::string::npos)
s2 = string(s2, 0, p + 1); s2 = std::string(s2, 0, p + 1);
} }
es2->emplace_back(i->first, new ExprString(s2)); es2->emplace_back(i->first, new ExprString(s2));
@ -468,7 +468,7 @@ expr_simple
$$ = new ExprConcatStrings(CUR_POS, false, $2); $$ = new ExprConcatStrings(CUR_POS, false, $2);
} }
| SPATH { | SPATH {
string path($1.p + 1, $1.l - 2); std::string path($1.p + 1, $1.l - 2);
$$ = new ExprCall(CUR_POS, $$ = new ExprCall(CUR_POS,
new ExprVar(data->symbols.create("__findFile")), new ExprVar(data->symbols.create("__findFile")),
{new ExprVar(data->symbols.create("__nixPath")), {new ExprVar(data->symbols.create("__nixPath")),
@ -481,7 +481,7 @@ expr_simple
.msg = hintfmt("URL literals are disabled"), .msg = hintfmt("URL literals are disabled"),
.errPos = CUR_POS .errPos = CUR_POS
}); });
$$ = new ExprString(string($1)); $$ = new ExprString(std::string($1));
} }
| '(' expr ')' { $$ = $2; } | '(' expr ')' { $$ = $2; }
/* Let expressions `let {..., body = ...}' are just desugared /* Let expressions `let {..., body = ...}' are just desugared
@ -496,19 +496,19 @@ expr_simple
; ;
string_parts string_parts
: STR { $$ = new ExprString(string($1)); } : STR { $$ = new ExprString(std::string($1)); }
| string_parts_interpolated { $$ = new ExprConcatStrings(CUR_POS, true, $1); } | string_parts_interpolated { $$ = new ExprConcatStrings(CUR_POS, true, $1); }
| { $$ = new ExprString(""); } | { $$ = new ExprString(""); }
; ;
string_parts_interpolated string_parts_interpolated
: string_parts_interpolated STR : string_parts_interpolated STR
{ $$ = $1; $1->emplace_back(makeCurPos(@2, data), new ExprString(string($2))); } { $$ = $1; $1->emplace_back(makeCurPos(@2, data), new ExprString(std::string($2))); }
| string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $3); } | string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $3); }
| DOLLAR_CURLY expr '}' { $$ = new std::vector<std::pair<Pos, Expr *> >; $$->emplace_back(makeCurPos(@1, data), $2); } | DOLLAR_CURLY expr '}' { $$ = new std::vector<std::pair<Pos, Expr *> >; $$->emplace_back(makeCurPos(@1, data), $2); }
| STR DOLLAR_CURLY expr '}' { | STR DOLLAR_CURLY expr '}' {
$$ = new std::vector<std::pair<Pos, Expr *> >; $$ = new std::vector<std::pair<Pos, Expr *> >;
$$->emplace_back(makeCurPos(@1, data), new ExprString(string($1))); $$->emplace_back(makeCurPos(@1, data), new ExprString(std::string($1)));
$$->emplace_back(makeCurPos(@2, data), $3); $$->emplace_back(makeCurPos(@2, data), $3);
} }
; ;
@ -522,7 +522,7 @@ path_start
$$ = new ExprPath(path); $$ = new ExprPath(path);
} }
| HPATH { | HPATH {
Path path(getHome() + string($1.p + 1, $1.l - 1)); Path path(getHome() + std::string($1.p + 1, $1.l - 1));
$$ = new ExprPath(path); $$ = new ExprPath(path);
} }
; ;
@ -740,16 +740,16 @@ Expr * EvalState::parseStdin()
} }
void EvalState::addToSearchPath(const string & s) void EvalState::addToSearchPath(const std::string & s)
{ {
size_t pos = s.find('='); size_t pos = s.find('=');
string prefix; std::string prefix;
Path path; Path path;
if (pos == string::npos) { if (pos == std::string::npos) {
path = s; path = s;
} else { } else {
prefix = string(s, 0, pos); prefix = std::string(s, 0, pos);
path = string(s, pos + 1); path = std::string(s, pos + 1);
} }
searchPath.emplace_back(prefix, path); searchPath.emplace_back(prefix, path);

View file

@ -141,7 +141,7 @@ static void mkOutputString(
BindingsBuilder & attrs, BindingsBuilder & attrs,
const StorePath & drvPath, const StorePath & drvPath,
const BasicDerivation & drv, const BasicDerivation & drv,
const std::pair<string, DerivationOutput> & o) const std::pair<std::string, DerivationOutput> & o)
{ {
auto optOutputPath = o.second.path(*state.store, drv.name, o.first); auto optOutputPath = o.second.path(*state.store, drv.name, o.first);
attrs.alloc(o.first).mkString( attrs.alloc(o.first).mkString(
@ -314,7 +314,7 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value
{ {
auto path = realisePath(state, pos, *args[0]); auto path = realisePath(state, pos, *args[0]);
string sym(state.forceStringNoCtx(*args[1], pos)); std::string sym(state.forceStringNoCtx(*args[1], pos));
void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
if (!handle) if (!handle)
@ -386,7 +386,7 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
state.forceValue(*args[0], pos); state.forceValue(*args[0], pos);
string t; std::string t;
switch (args[0]->type()) { switch (args[0]->type()) {
case nInt: t = "int"; break; case nInt: t = "int"; break;
case nBool: t = "bool"; break; case nBool: t = "bool"; break;
@ -707,7 +707,7 @@ static RegisterPrimOp primop_abort({
.fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v) .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
string s = state.coerceToString(pos, *args[0], context).toOwned(); auto s = state.coerceToString(pos, *args[0], context).toOwned();
throw Abort("evaluation aborted with the following error message: '%1%'", s); throw Abort("evaluation aborted with the following error message: '%1%'", s);
} }
}); });
@ -725,7 +725,7 @@ static RegisterPrimOp primop_throw({
.fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v) .fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
string s = state.coerceToString(pos, *args[0], context).toOwned(); auto s = state.coerceToString(pos, *args[0], context).toOwned();
throw ThrownError(s); throw ThrownError(s);
} }
}); });
@ -826,7 +826,7 @@ static RegisterPrimOp primop_tryEval({
/* Return an environment variable. Use with care. */ /* Return an environment variable. Use with care. */
static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
string name(state.forceStringNoCtx(*args[0], pos)); std::string name(state.forceStringNoCtx(*args[0], pos));
v.mkString(evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or("")); v.mkString(evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or(""));
} }
@ -935,7 +935,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
pos pos
); );
string drvName; std::string drvName;
Pos & posDrvName(*attr->pos); Pos & posDrvName(*attr->pos);
try { try {
drvName = state.forceStringNoCtx(*attr->value, pos); drvName = state.forceStringNoCtx(*attr->value, pos);
@ -973,7 +973,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
for (auto & i : args[0]->attrs->lexicographicOrder()) { for (auto & i : args[0]->attrs->lexicographicOrder()) {
if (i->name == state.sIgnoreNulls) continue; if (i->name == state.sIgnoreNulls) continue;
const string & key = i->name; const std::string & key = i->name;
vomit("processing attribute '%1%'", key); vomit("processing attribute '%1%'", key);
auto handleHashMode = [&](const std::string_view s) { auto handleHashMode = [&](const std::string_view s) {
@ -1031,7 +1031,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
else if (i->name == state.sArgs) { else if (i->name == state.sArgs) {
state.forceList(*i->value, pos); state.forceList(*i->value, pos);
for (auto elem : i->value->listItems()) { for (auto elem : i->value->listItems()) {
string s = state.coerceToString(posDrvName, *elem, context, true).toOwned(); auto s = state.coerceToString(posDrvName, *elem, context, true).toOwned();
drv.args.push_back(s); drv.args.push_back(s);
} }
} }
@ -1118,7 +1118,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
/* Handle derivation outputs of the form !<name>!<path>. */ /* Handle derivation outputs of the form !<name>!<path>. */
else if (path.at(0) == '!') { else if (path.at(0) == '!') {
std::pair<string, string> ctx = decodeContext(path); auto ctx = decodeContext(path);
drv.inputDrvs[state.store->parseStorePath(ctx.first)].insert(ctx.second); drv.inputDrvs[state.store->parseStorePath(ctx.first)].insert(ctx.second);
} }
@ -1440,8 +1440,8 @@ static RegisterPrimOp primop_dirOf({
static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
auto path = realisePath(state, pos, *args[0]); auto path = realisePath(state, pos, *args[0]);
string s = readFile(path); auto s = readFile(path);
if (s.find((char) 0) != string::npos) if (s.find((char) 0) != std::string::npos)
throw Error("the contents of the file '%1%' cannot be represented as a Nix string", path); throw Error("the contents of the file '%1%' cannot be represented as a Nix string", path);
StorePathSet refs; StorePathSet refs;
if (state.store->isInStore(path)) { if (state.store->isInStore(path)) {
@ -1474,7 +1474,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
for (auto v2 : args[0]->listItems()) { for (auto v2 : args[0]->listItems()) {
state.forceAttrs(*v2, pos); state.forceAttrs(*v2, pos);
string prefix; std::string prefix;
Bindings::iterator i = v2->attrs->find(state.sPrefix); Bindings::iterator i = v2->attrs->find(state.sPrefix);
if (i != v2->attrs->end()) if (i != v2->attrs->end())
prefix = state.forceStringNoCtx(*i->value, pos); prefix = state.forceStringNoCtx(*i->value, pos);
@ -1488,7 +1488,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
); );
PathSet context; PathSet context;
string path = state.coerceToString(pos, *i->value, context, false, false).toOwned(); auto path = state.coerceToString(pos, *i->value, context, false, false).toOwned();
try { try {
auto rewrites = state.realiseContext(context); auto rewrites = state.realiseContext(context);
@ -1754,8 +1754,8 @@ static RegisterPrimOp primop_fromJSON({
static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
string name(state.forceStringNoCtx(*args[0], pos)); std::string name(state.forceStringNoCtx(*args[0], pos));
string contents(state.forceString(*args[1], context, pos)); std::string contents(state.forceString(*args[1], context, pos));
StorePathSet refs; StorePathSet refs;
@ -1863,7 +1863,7 @@ static RegisterPrimOp primop_toFile({
static void addPath( static void addPath(
EvalState & state, EvalState & state,
const Pos & pos, const Pos & pos,
const string & name, const std::string & name,
Path path, Path path,
Value * filterFun, Value * filterFun,
FileIngestionMethod method, FileIngestionMethod method,
@ -1919,20 +1919,15 @@ static void addPath(
if (expectedHash) if (expectedHash)
expectedStorePath = state.store->makeFixedOutputPath(method, *expectedHash, name); expectedStorePath = state.store->makeFixedOutputPath(method, *expectedHash, name);
Path dstPath;
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) { if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
dstPath = state.store->printStorePath(settings.readOnlyMode StorePath dstPath = settings.readOnlyMode
? state.store->computeStorePathForPath(name, path, method, htSHA256, filter).first ? state.store->computeStorePathForPath(name, path, method, htSHA256, filter).first
: state.store->addToStore(name, path, method, htSHA256, filter, state.repair, refs)); : state.store->addToStore(name, path, method, htSHA256, filter, state.repair, refs);
if (expectedHash && expectedStorePath != state.store->parseStorePath(dstPath)) if (expectedHash && expectedStorePath != dstPath)
throw Error("store path mismatch in (possibly filtered) path added from '%s'", path); throw Error("store path mismatch in (possibly filtered) path added from '%s'", path);
state.allowAndSetStorePathString(dstPath, v);
} else } else
dstPath = state.store->printStorePath(*expectedStorePath); state.allowAndSetStorePathString(*expectedStorePath, v);
v.mkString(dstPath, {dstPath});
state.allowPath(dstPath);
} catch (Error & e) { } catch (Error & e) {
e.addTrace(pos, "while adding path '%s'", path); e.addTrace(pos, "while adding path '%s'", path);
throw; throw;
@ -2016,14 +2011,14 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
{ {
state.forceAttrs(*args[0], pos); state.forceAttrs(*args[0], pos);
Path path; Path path;
string name; std::string name;
Value * filterFun = nullptr; Value * filterFun = nullptr;
auto method = FileIngestionMethod::Recursive; auto method = FileIngestionMethod::Recursive;
std::optional<Hash> expectedHash; std::optional<Hash> expectedHash;
PathSet context; PathSet context;
for (auto & attr : *args[0]->attrs) { for (auto & attr : *args[0]->attrs) {
const string & n(attr.name); auto & n(attr.name);
if (n == "path") if (n == "path")
path = state.coerceToPath(*attr.pos, *attr.value, context); path = state.coerceToPath(*attr.pos, *attr.value, context);
else if (attr.name == state.sName) else if (attr.name == state.sName)
@ -3616,7 +3611,7 @@ static void prim_concatStringsSep(EvalState & state, const Pos & pos, Value * *
auto sep = state.forceString(*args[0], context, pos); auto sep = state.forceString(*args[0], context, pos);
state.forceList(*args[1], pos); state.forceList(*args[1], pos);
string res; std::string res;
res.reserve((args[1]->listSize() + 32) * sep.size()); res.reserve((args[1]->listSize() + 32) * sep.size());
bool first = true; bool first = true;
@ -3649,12 +3644,12 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
.errPos = pos .errPos = pos
}); });
std::vector<string> from; std::vector<std::string> from;
from.reserve(args[0]->listSize()); from.reserve(args[0]->listSize());
for (auto elem : args[0]->listItems()) for (auto elem : args[0]->listItems())
from.emplace_back(state.forceString(*elem, pos)); from.emplace_back(state.forceString(*elem, pos));
std::vector<std::pair<string, PathSet>> to; std::vector<std::pair<std::string, PathSet>> to;
to.reserve(args[1]->listSize()); to.reserve(args[1]->listSize());
for (auto elem : args[1]->listItems()) { for (auto elem : args[1]->listItems()) {
PathSet ctx; PathSet ctx;
@ -3665,7 +3660,7 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
PathSet context; PathSet context;
auto s = state.forceString(*args[2], context, pos); auto s = state.forceString(*args[2], context, pos);
string res; std::string res;
// Loops one past last character to handle the case where 'from' contains an empty string. // Loops one past last character to handle the case where 'from' contains an empty string.
for (size_t p = 0; p <= s.size(); ) { for (size_t p = 0; p <= s.size(); ) {
bool found = false; bool found = false;

View file

@ -37,7 +37,7 @@ static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & po
PathSet context2; PathSet context2;
for (auto & p : context) for (auto & p : context)
context2.insert(p.at(0) == '=' ? string(p, 1) : p); context2.insert(p.at(0) == '=' ? std::string(p, 1) : p);
v.mkString(*s, context2); v.mkString(*s, context2);
} }
@ -76,13 +76,13 @@ static void prim_getContext(EvalState & state, const Pos & pos, Value * * args,
auto contextInfos = std::map<Path, ContextInfo>(); auto contextInfos = std::map<Path, ContextInfo>();
for (const auto & p : context) { for (const auto & p : context) {
Path drv; Path drv;
string output; std::string output;
const Path * path = &p; const Path * path = &p;
if (p.at(0) == '=') { if (p.at(0) == '=') {
drv = string(p, 1); drv = std::string(p, 1);
path = &drv; path = &drv;
} else if (p.at(0) == '!') { } else if (p.at(0) == '!') {
std::pair<string, string> ctx = decodeContext(p); std::pair<std::string, std::string> ctx = decodeContext(p);
drv = ctx.first; drv = ctx.first;
output = ctx.second; output = ctx.second;
path = &drv; path = &drv;
@ -166,7 +166,7 @@ static void prim_appendContext(EvalState & state, const Pos & pos, Value * * arg
.errPos = *i.pos .errPos = *i.pos
}); });
} }
context.insert("=" + string(i.name)); context.insert("=" + std::string(i.name));
} }
} }

View file

@ -62,7 +62,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
fetchers::Attrs attrs; fetchers::Attrs attrs;
attrs.insert_or_assign("type", "hg"); attrs.insert_or_assign("type", "hg");
attrs.insert_or_assign("url", url.find("://") != std::string::npos ? url : "file://" + url); attrs.insert_or_assign("url", url.find("://") != std::string::npos ? url : "file://" + url);
attrs.insert_or_assign("name", string(name)); attrs.insert_or_assign("name", std::string(name));
if (ref) attrs.insert_or_assign("ref", *ref); if (ref) attrs.insert_or_assign("ref", *ref);
if (rev) attrs.insert_or_assign("rev", rev->gitRev()); if (rev) attrs.insert_or_assign("rev", rev->gitRev());
auto input = fetchers::Input::fromAttrs(std::move(attrs)); auto input = fetchers::Input::fromAttrs(std::move(attrs));

View file

@ -19,7 +19,7 @@ void emitTreeAttrs(
bool emptyRevFallback, bool emptyRevFallback,
bool forceDirty) bool forceDirty)
{ {
assert(input.isImmutable()); assert(input.isLocked());
auto attrs = state.buildBindings(8); auto attrs = state.buildBindings(8);
@ -166,8 +166,8 @@ static void fetchTree(
if (!evalSettings.pureEval && !input.isDirect()) if (!evalSettings.pureEval && !input.isDirect())
input = lookupInRegistries(state.store, input).first; input = lookupInRegistries(state.store, input).first;
if (evalSettings.pureEval && !input.isImmutable()) if (evalSettings.pureEval && !input.isLocked())
throw Error("in pure evaluation mode, 'fetchTree' requires an immutable input, at %s", pos); throw Error("in pure evaluation mode, 'fetchTree' requires a locked input, at %s", pos);
auto [tree, input2] = input.fetch(state.store); auto [tree, input2] = input.fetch(state.store);
@ -186,7 +186,7 @@ static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, V
static RegisterPrimOp primop_fetchTree("fetchTree", 1, prim_fetchTree); static RegisterPrimOp primop_fetchTree("fetchTree", 1, prim_fetchTree);
static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
const string & who, bool unpack, std::string name) const std::string & who, bool unpack, std::string name)
{ {
std::optional<std::string> url; std::optional<std::string> url;
std::optional<Hash> expectedHash; std::optional<Hash> expectedHash;
@ -198,7 +198,7 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
state.forceAttrs(*args[0], pos); state.forceAttrs(*args[0], pos);
for (auto & attr : *args[0]->attrs) { for (auto & attr : *args[0]->attrs) {
string n(attr.name); std::string n(attr.name);
if (n == "url") if (n == "url")
url = state.forceStringNoCtx(*attr.value, *attr.pos); url = state.forceStringNoCtx(*attr.value, *attr.pos);
else if (n == "sha256") else if (n == "sha256")
@ -230,6 +230,21 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
if (evalSettings.pureEval && !expectedHash) if (evalSettings.pureEval && !expectedHash)
throw Error("in pure evaluation mode, '%s' requires a 'sha256' argument", who); throw Error("in pure evaluation mode, '%s' requires a 'sha256' argument", who);
// early exit if pinned and already in the store
if (expectedHash && expectedHash->type == htSHA256) {
auto expectedPath =
unpack
? state.store->makeFixedOutputPath(FileIngestionMethod::Recursive, *expectedHash, name, {})
: state.store->makeFixedOutputPath(FileIngestionMethod::Flat, *expectedHash, name, {});
if (state.store->isValidPath(expectedPath)) {
state.allowAndSetStorePathString(expectedPath, v);
return;
}
}
// TODO: fetching may fail, yet the path may be substitutable.
// https://github.com/NixOS/nix/issues/4313
auto storePath = auto storePath =
unpack unpack
? fetchers::downloadTarball(state.store, *url, name, (bool) expectedHash).first.storePath ? fetchers::downloadTarball(state.store, *url, name, (bool) expectedHash).first.storePath
@ -244,10 +259,7 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
*url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true)); *url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true));
} }
state.allowPath(storePath); state.allowAndSetStorePathString(storePath, v);
auto path = state.store->printStorePath(storePath);
v.mkString(path, PathSet({path}));
} }
static void prim_fetchurl(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_fetchurl(EvalState & state, const Pos & pos, Value * * args, Value & v)

View file

@ -9,7 +9,7 @@ static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Va
{ {
auto toml = state.forceStringNoCtx(*args[0], pos); auto toml = state.forceStringNoCtx(*args[0], pos);
std::istringstream tomlStream(string{toml}); std::istringstream tomlStream(std::string{toml});
std::function<void(Value &, toml::value)> visit; std::function<void(Value &, toml::value)> visit;

View file

@ -9,7 +9,7 @@
namespace nix { namespace nix {
static XMLAttrs singletonAttrs(const string & name, const string & value) static XMLAttrs singletonAttrs(const std::string & name, const std::string & value)
{ {
XMLAttrs attrs; XMLAttrs attrs;
attrs[name] = value; attrs[name] = value;

View file

@ -114,8 +114,8 @@ struct Value
private: private:
InternalType internalType; InternalType internalType;
friend std::string showType(const Value & v); friend std::string showType(const Value & v);
friend void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v); friend void printValue(std::ostream & str, std::set<const void *> & seen, const Value & v);
public: public:

View file

@ -52,13 +52,13 @@ struct CacheImpl : Cache
const Attrs & inAttrs, const Attrs & inAttrs,
const Attrs & infoAttrs, const Attrs & infoAttrs,
const StorePath & storePath, const StorePath & storePath,
bool immutable) override bool locked) override
{ {
_state.lock()->add.use() _state.lock()->add.use()
(attrsToJSON(inAttrs).dump()) (attrsToJSON(inAttrs).dump())
(attrsToJSON(infoAttrs).dump()) (attrsToJSON(infoAttrs).dump())
(store->printStorePath(storePath)) (store->printStorePath(storePath))
(immutable) (locked)
(time(0)).exec(); (time(0)).exec();
} }
@ -91,7 +91,7 @@ struct CacheImpl : Cache
auto infoJSON = stmt.getStr(0); auto infoJSON = stmt.getStr(0);
auto storePath = store->parseStorePath(stmt.getStr(1)); auto storePath = store->parseStorePath(stmt.getStr(1));
auto immutable = stmt.getInt(2) != 0; auto locked = stmt.getInt(2) != 0;
auto timestamp = stmt.getInt(3); auto timestamp = stmt.getInt(3);
store->addTempRoot(storePath); store->addTempRoot(storePath);
@ -105,7 +105,7 @@ struct CacheImpl : Cache
inAttrsJSON, infoJSON, store->printStorePath(storePath)); inAttrsJSON, infoJSON, store->printStorePath(storePath));
return Result { return Result {
.expired = !immutable && (settings.tarballTtl.get() == 0 || timestamp + settings.tarballTtl < time(0)), .expired = !locked && (settings.tarballTtl.get() == 0 || timestamp + settings.tarballTtl < time(0)),
.infoAttrs = jsonToAttrs(nlohmann::json::parse(infoJSON)), .infoAttrs = jsonToAttrs(nlohmann::json::parse(infoJSON)),
.storePath = std::move(storePath) .storePath = std::move(storePath)
}; };

View file

@ -13,7 +13,7 @@ struct Cache
const Attrs & inAttrs, const Attrs & inAttrs,
const Attrs & infoAttrs, const Attrs & infoAttrs,
const StorePath & storePath, const StorePath & storePath,
bool immutable) = 0; bool locked) = 0;
virtual std::optional<std::pair<Attrs, StorePath>> lookup( virtual std::optional<std::pair<Attrs, StorePath>> lookup(
ref<Store> store, ref<Store> store,

View file

@ -0,0 +1,13 @@
#include "fetch-settings.hh"
namespace nix {
FetchSettings::FetchSettings()
{
}
FetchSettings fetchSettings;
static GlobalConfig::Register rFetchSettings(&fetchSettings);
}

View file

@ -0,0 +1,93 @@
#pragma once
#include "types.hh"
#include "config.hh"
#include "util.hh"
#include <map>
#include <limits>
#include <sys/types.h>
namespace nix {
struct FetchSettings : public Config
{
FetchSettings();
Setting<StringMap> accessTokens{this, {}, "access-tokens",
R"(
Access tokens used to access protected GitHub, GitLab, or
other locations requiring token-based authentication.
Access tokens are specified as a string made up of
space-separated `host=token` values. The specific token
used is selected by matching the `host` portion against the
"host" specification of the input. The actual use of the
`token` value is determined by the type of resource being
accessed:
* Github: the token value is the OAUTH-TOKEN string obtained
as the Personal Access Token from the Github server (see
https://docs.github.com/en/developers/apps/authorizing-oath-apps).
* Gitlab: the token value is either the OAuth2 token or the
Personal Access Token (these are different types tokens
for gitlab, see
https://docs.gitlab.com/12.10/ee/api/README.html#authentication).
The `token` value should be `type:tokenstring` where
`type` is either `OAuth2` or `PAT` to indicate which type
of token is being specified.
Example `~/.config/nix/nix.conf`:
```
access-tokens = github.com=23ac...b289 gitlab.mycompany.com=PAT:A123Bp_Cd..EfG gitlab.com=OAuth2:1jklw3jk
```
Example `~/code/flake.nix`:
```nix
input.foo = {
type = "gitlab";
host = "gitlab.mycompany.com";
owner = "mycompany";
repo = "pro";
};
```
This example specifies three tokens, one each for accessing
github.com, gitlab.mycompany.com, and sourceforge.net.
The `input.foo` uses the "gitlab" fetcher, which might
requires specifying the token type along with the token
value.
)"};
Setting<bool> allowDirty{this, true, "allow-dirty",
"Whether to allow dirty Git/Mercurial trees."};
Setting<bool> warnDirty{this, true, "warn-dirty",
"Whether to warn about dirty Git/Mercurial trees."};
Setting<std::string> flakeRegistry{this, "https://github.com/NixOS/flake-registry/raw/master/flake-registry.json", "flake-registry",
"Path or URI of the global flake registry."};
Setting<bool> useRegistries{this, true, "use-registries",
"Whether to use flake registries to resolve flake references."};
Setting<bool> acceptFlakeConfig{this, false, "accept-flake-config",
"Whether to accept nix configuration from a flake without prompting."};
Setting<std::string> commitLockFileSummary{
this, "", "commit-lockfile-summary",
R"(
The commit summary to use when committing changed flake lock files. If
empty, the summary is generated based on the action performed.
)"};
};
// FIXME: don't use a global variable.
extern FetchSettings fetchSettings;
}

View file

@ -24,11 +24,11 @@ static void fixupInput(Input & input)
input.getType(); input.getType();
input.getRef(); input.getRef();
if (input.getRev()) if (input.getRev())
input.immutable = true; input.locked = true;
input.getRevCount(); input.getRevCount();
input.getLastModified(); input.getLastModified();
if (input.getNarHash()) if (input.getNarHash())
input.immutable = true; input.locked = true;
} }
Input Input::fromURL(const ParsedURL & url) Input Input::fromURL(const ParsedURL & url)
@ -165,7 +165,7 @@ std::pair<Tree, Input> Input::fetch(ref<Store> store) const
input.to_string(), *prevRevCount); input.to_string(), *prevRevCount);
} }
input.immutable = true; input.locked = true;
assert(input.hasAllInfo()); assert(input.hasAllInfo());
@ -209,7 +209,7 @@ StorePath Input::computeStorePath(Store & store) const
{ {
auto narHash = getNarHash(); auto narHash = getNarHash();
if (!narHash) if (!narHash)
throw Error("cannot compute store path for mutable input '%s'", to_string()); throw Error("cannot compute store path for unlocked input '%s'", to_string());
return store.makeFixedOutputPath(FileIngestionMethod::Recursive, *narHash, getName()); return store.makeFixedOutputPath(FileIngestionMethod::Recursive, *narHash, getName());
} }

View file

@ -34,7 +34,7 @@ struct Input
std::shared_ptr<InputScheme> scheme; // note: can be null std::shared_ptr<InputScheme> scheme; // note: can be null
Attrs attrs; Attrs attrs;
bool immutable = false; bool locked = false;
bool direct = true; bool direct = true;
/* path of the parent of this input, used for relative path resolution */ /* path of the parent of this input, used for relative path resolution */
@ -59,9 +59,9 @@ public:
one that goes through a registry. */ one that goes through a registry. */
bool isDirect() const { return direct; } bool isDirect() const { return direct; }
/* Check whether this is an "immutable" input, that is, /* Check whether this is a "locked" input, that is,
one that contains a commit hash or content hash. */ one that contains a commit hash or content hash. */
bool isImmutable() const { return immutable; } bool isLocked() const { return locked; }
bool hasAllInfo() const; bool hasAllInfo() const;
@ -69,6 +69,8 @@ public:
bool contains(const Input & other) const; bool contains(const Input & other) const;
/* Fetch the input into the Nix store, returning the location in
the Nix store and the locked input. */
std::pair<Tree, Input> fetch(ref<Store> store) const; std::pair<Tree, Input> fetch(ref<Store> store) const;
Input applyOverrides( Input applyOverrides(
@ -146,14 +148,14 @@ DownloadFileResult downloadFile(
ref<Store> store, ref<Store> store,
const std::string & url, const std::string & url,
const std::string & name, const std::string & name,
bool immutable, bool locked,
const Headers & headers = {}); const Headers & headers = {});
std::pair<Tree, time_t> downloadTarball( std::pair<Tree, time_t> downloadTarball(
ref<Store> store, ref<Store> store,
const std::string & url, const std::string & url,
const std::string & name, const std::string & name,
bool immutable, bool locked,
const Headers & headers = {}); const Headers & headers = {});
} }

View file

@ -6,6 +6,8 @@
#include "url-parts.hh" #include "url-parts.hh"
#include "pathlocks.hh" #include "pathlocks.hh"
#include "fetch-settings.hh"
#include <sys/time.h> #include <sys/time.h>
#include <sys/wait.h> #include <sys/wait.h>
@ -187,7 +189,7 @@ struct GitInputScheme : InputScheme
if (submodules) cacheType += "-submodules"; if (submodules) cacheType += "-submodules";
if (allRefs) cacheType += "-all-refs"; if (allRefs) cacheType += "-all-refs";
auto getImmutableAttrs = [&]() auto getLockedAttrs = [&]()
{ {
return Attrs({ return Attrs({
{"type", cacheType}, {"type", cacheType},
@ -208,7 +210,7 @@ struct GitInputScheme : InputScheme
}; };
if (input.getRev()) { if (input.getRev()) {
if (auto res = getCache()->lookup(store, getImmutableAttrs())) if (auto res = getCache()->lookup(store, getLockedAttrs()))
return makeResult(res->first, std::move(res->second)); return makeResult(res->first, std::move(res->second));
} }
@ -246,10 +248,10 @@ struct GitInputScheme : InputScheme
/* This is an unclean working tree. So copy all tracked files. */ /* This is an unclean working tree. So copy all tracked files. */
if (!settings.allowDirty) if (!fetchSettings.allowDirty)
throw Error("Git tree '%s' is dirty", actualUrl); throw Error("Git tree '%s' is dirty", actualUrl);
if (settings.warnDirty) if (fetchSettings.warnDirty)
warn("Git tree '%s' is dirty", actualUrl); warn("Git tree '%s' is dirty", actualUrl);
auto gitOpts = Strings({ "-C", actualUrl, "ls-files", "-z" }); auto gitOpts = Strings({ "-C", actualUrl, "ls-files", "-z" });
@ -288,7 +290,7 @@ struct GitInputScheme : InputScheme
if (!input.getRef()) input.attrs.insert_or_assign("ref", isLocal ? readHead(actualUrl) : "master"); if (!input.getRef()) input.attrs.insert_or_assign("ref", isLocal ? readHead(actualUrl) : "master");
Attrs mutableAttrs({ Attrs unlockedAttrs({
{"type", cacheType}, {"type", cacheType},
{"name", name}, {"name", name},
{"url", actualUrl}, {"url", actualUrl},
@ -307,7 +309,7 @@ struct GitInputScheme : InputScheme
} else { } else {
if (auto res = getCache()->lookup(store, mutableAttrs)) { if (auto res = getCache()->lookup(store, unlockedAttrs)) {
auto rev2 = Hash::parseAny(getStrAttr(res->first, "rev"), htSHA1); auto rev2 = Hash::parseAny(getStrAttr(res->first, "rev"), htSHA1);
if (!input.getRev() || input.getRev() == rev2) { if (!input.getRev() || input.getRev() == rev2) {
input.attrs.insert_or_assign("rev", rev2.gitRev()); input.attrs.insert_or_assign("rev", rev2.gitRev());
@ -404,7 +406,7 @@ struct GitInputScheme : InputScheme
/* Now that we know the ref, check again whether we have it in /* Now that we know the ref, check again whether we have it in
the store. */ the store. */
if (auto res = getCache()->lookup(store, getImmutableAttrs())) if (auto res = getCache()->lookup(store, getLockedAttrs()))
return makeResult(res->first, std::move(res->second)); return makeResult(res->first, std::move(res->second));
Path tmpDir = createTempDir(); Path tmpDir = createTempDir();
@ -476,14 +478,14 @@ struct GitInputScheme : InputScheme
if (!_input.getRev()) if (!_input.getRev())
getCache()->add( getCache()->add(
store, store,
mutableAttrs, unlockedAttrs,
infoAttrs, infoAttrs,
storePath, storePath,
false); false);
getCache()->add( getCache()->add(
store, store,
getImmutableAttrs(), getLockedAttrs(),
infoAttrs, infoAttrs,
storePath, storePath,
true); true);

View file

@ -1,13 +1,16 @@
#include "filetransfer.hh" #include "filetransfer.hh"
#include "cache.hh" #include "cache.hh"
#include "fetchers.hh"
#include "globals.hh" #include "globals.hh"
#include "store-api.hh" #include "store-api.hh"
#include "types.hh" #include "types.hh"
#include "url-parts.hh" #include "url-parts.hh"
#include "fetchers.hh"
#include "fetch-settings.hh"
#include <optional> #include <optional>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <fstream>
namespace nix::fetchers { namespace nix::fetchers {
@ -17,7 +20,7 @@ struct DownloadUrl
Headers headers; Headers headers;
}; };
// A github or gitlab host // A github, gitlab, or sourcehut host
const static std::string hostRegexS = "[a-zA-Z0-9.]*"; // FIXME: check const static std::string hostRegexS = "[a-zA-Z0-9.]*"; // FIXME: check
std::regex hostRegex(hostRegexS, std::regex::ECMAScript); std::regex hostRegex(hostRegexS, std::regex::ECMAScript);
@ -156,7 +159,7 @@ struct GitArchiveInputScheme : InputScheme
std::optional<std::string> getAccessToken(const std::string & host) const std::optional<std::string> getAccessToken(const std::string & host) const
{ {
auto tokens = settings.accessTokens.get(); auto tokens = fetchSettings.accessTokens.get();
if (auto token = get(tokens, host)) if (auto token = get(tokens, host))
return *token; return *token;
return {}; return {};
@ -192,12 +195,12 @@ struct GitArchiveInputScheme : InputScheme
input.attrs.erase("ref"); input.attrs.erase("ref");
input.attrs.insert_or_assign("rev", rev->gitRev()); input.attrs.insert_or_assign("rev", rev->gitRev());
Attrs immutableAttrs({ Attrs lockedAttrs({
{"type", "git-tarball"}, {"type", "git-tarball"},
{"rev", rev->gitRev()}, {"rev", rev->gitRev()},
}); });
if (auto res = getCache()->lookup(store, immutableAttrs)) { if (auto res = getCache()->lookup(store, lockedAttrs)) {
input.attrs.insert_or_assign("lastModified", getIntAttr(res->first, "lastModified")); input.attrs.insert_or_assign("lastModified", getIntAttr(res->first, "lastModified"));
return {std::move(res->second), input}; return {std::move(res->second), input};
} }
@ -210,7 +213,7 @@ struct GitArchiveInputScheme : InputScheme
getCache()->add( getCache()->add(
store, store,
immutableAttrs, lockedAttrs,
{ {
{"rev", rev->gitRev()}, {"rev", rev->gitRev()},
{"lastModified", uint64_t(lastModified)} {"lastModified", uint64_t(lastModified)}
@ -345,7 +348,95 @@ struct GitLabInputScheme : GitArchiveInputScheme
} }
}; };
struct SourceHutInputScheme : GitArchiveInputScheme
{
std::string type() override { return "sourcehut"; }
std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
{
// SourceHut supports both PAT and OAuth2. See
// https://man.sr.ht/meta.sr.ht/oauth.md
return std::pair<std::string, std::string>("Authorization", fmt("Bearer %s", token));
// Note: This currently serves no purpose, as this kind of authorization
// does not allow for downloading tarballs on sourcehut private repos.
// Once it is implemented, however, should work as expected.
}
Hash getRevFromRef(nix::ref<Store> store, const Input & input) const override
{
// TODO: In the future, when the sourcehut graphql API is implemented for mercurial
// and with anonymous access, this method should use it instead.
auto ref = *input.getRef();
auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
auto base_url = fmt("https://%s/%s/%s",
host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"));
Headers headers = makeHeadersWithAuthTokens(host);
std::string ref_uri;
if (ref == "HEAD") {
auto file = store->toRealPath(
downloadFile(store, fmt("%s/HEAD", base_url), "source", false, headers).storePath);
std::ifstream is(file);
std::string line;
getline(is, line);
auto ref_index = line.find("ref: ");
if (ref_index == std::string::npos) {
throw BadURL("in '%d', couldn't resolve HEAD ref '%d'", input.to_string(), ref);
}
ref_uri = line.substr(ref_index+5, line.length()-1);
} else
ref_uri = fmt("refs/heads/%s", ref);
auto file = store->toRealPath(
downloadFile(store, fmt("%s/info/refs", base_url), "source", false, headers).storePath);
std::ifstream is(file);
std::string line;
std::string id;
while(getline(is, line)) {
auto index = line.find(ref_uri);
if (index != std::string::npos) {
id = line.substr(0, index-1);
break;
}
}
if(id.empty())
throw BadURL("in '%d', couldn't find ref '%d'", input.to_string(), ref);
auto rev = Hash::parseAny(id, htSHA1);
debug("HEAD revision for '%s' is %s", fmt("%s/%s", base_url, ref), rev.gitRev());
return rev;
}
DownloadUrl getDownloadUrl(const Input & input) const override
{
auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
auto url = fmt("https://%s/%s/%s/archive/%s.tar.gz",
host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"),
input.getRev()->to_string(Base16, false));
Headers headers = makeHeadersWithAuthTokens(host);
return DownloadUrl { url, headers };
}
void clone(const Input & input, const Path & destDir) override
{
auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
Input::fromURL(fmt("git+https://%s/%s/%s",
host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo")))
.applyOverrides(input.getRef(), input.getRev())
.clone(destDir);
}
};
static auto rGitHubInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitHubInputScheme>()); }); static auto rGitHubInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitHubInputScheme>()); });
static auto rGitLabInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitLabInputScheme>()); }); static auto rGitLabInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitLabInputScheme>()); });
static auto rSourceHutInputScheme = OnStartup([] { registerInputScheme(std::make_unique<SourceHutInputScheme>()); });
} }

View file

@ -5,6 +5,8 @@
#include "store-api.hh" #include "store-api.hh"
#include "url-parts.hh" #include "url-parts.hh"
#include "fetch-settings.hh"
#include <sys/time.h> #include <sys/time.h>
using namespace std::string_literals; using namespace std::string_literals;
@ -26,7 +28,7 @@ static RunOptions hgOptions(const Strings & args)
} }
// runProgram wrapper that uses hgOptions instead of stock RunOptions. // runProgram wrapper that uses hgOptions instead of stock RunOptions.
static string runHg(const Strings & args, const std::optional<std::string> & input = {}) static std::string runHg(const Strings & args, const std::optional<std::string> & input = {})
{ {
RunOptions opts = hgOptions(args); RunOptions opts = hgOptions(args);
opts.input = input; opts.input = input;
@ -165,10 +167,10 @@ struct MercurialInputScheme : InputScheme
/* This is an unclean working tree. So copy all tracked /* This is an unclean working tree. So copy all tracked
files. */ files. */
if (!settings.allowDirty) if (!fetchSettings.allowDirty)
throw Error("Mercurial tree '%s' is unclean", actualUrl); throw Error("Mercurial tree '%s' is unclean", actualUrl);
if (settings.warnDirty) if (fetchSettings.warnDirty)
warn("Mercurial tree '%s' is unclean", actualUrl); warn("Mercurial tree '%s' is unclean", actualUrl);
input.attrs.insert_or_assign("ref", chomp(runHg({ "branch", "-R", actualUrl }))); input.attrs.insert_or_assign("ref", chomp(runHg({ "branch", "-R", actualUrl })));
@ -199,7 +201,7 @@ struct MercurialInputScheme : InputScheme
if (!input.getRef()) input.attrs.insert_or_assign("ref", "default"); if (!input.getRef()) input.attrs.insert_or_assign("ref", "default");
auto getImmutableAttrs = [&]() auto getLockedAttrs = [&]()
{ {
return Attrs({ return Attrs({
{"type", "hg"}, {"type", "hg"},
@ -218,20 +220,20 @@ struct MercurialInputScheme : InputScheme
}; };
if (input.getRev()) { if (input.getRev()) {
if (auto res = getCache()->lookup(store, getImmutableAttrs())) if (auto res = getCache()->lookup(store, getLockedAttrs()))
return makeResult(res->first, std::move(res->second)); return makeResult(res->first, std::move(res->second));
} }
auto revOrRef = input.getRev() ? input.getRev()->gitRev() : *input.getRef(); auto revOrRef = input.getRev() ? input.getRev()->gitRev() : *input.getRef();
Attrs mutableAttrs({ Attrs unlockedAttrs({
{"type", "hg"}, {"type", "hg"},
{"name", name}, {"name", name},
{"url", actualUrl}, {"url", actualUrl},
{"ref", *input.getRef()}, {"ref", *input.getRef()},
}); });
if (auto res = getCache()->lookup(store, mutableAttrs)) { if (auto res = getCache()->lookup(store, unlockedAttrs)) {
auto rev2 = Hash::parseAny(getStrAttr(res->first, "rev"), htSHA1); auto rev2 = Hash::parseAny(getStrAttr(res->first, "rev"), htSHA1);
if (!input.getRev() || input.getRev() == rev2) { if (!input.getRev() || input.getRev() == rev2) {
input.attrs.insert_or_assign("rev", rev2.gitRev()); input.attrs.insert_or_assign("rev", rev2.gitRev());
@ -254,7 +256,7 @@ struct MercurialInputScheme : InputScheme
runHg({ "pull", "-R", cacheDir, "--", actualUrl }); runHg({ "pull", "-R", cacheDir, "--", actualUrl });
} }
catch (ExecError & e) { catch (ExecError & e) {
string transJournal = cacheDir + "/.hg/store/journal"; auto transJournal = cacheDir + "/.hg/store/journal";
/* hg throws "abandoned transaction" error only if this file exists */ /* hg throws "abandoned transaction" error only if this file exists */
if (pathExists(transJournal)) { if (pathExists(transJournal)) {
runHg({ "recover", "-R", cacheDir }); runHg({ "recover", "-R", cacheDir });
@ -277,7 +279,7 @@ struct MercurialInputScheme : InputScheme
auto revCount = std::stoull(tokens[1]); auto revCount = std::stoull(tokens[1]);
input.attrs.insert_or_assign("ref", tokens[2]); input.attrs.insert_or_assign("ref", tokens[2]);
if (auto res = getCache()->lookup(store, getImmutableAttrs())) if (auto res = getCache()->lookup(store, getLockedAttrs()))
return makeResult(res->first, std::move(res->second)); return makeResult(res->first, std::move(res->second));
Path tmpDir = createTempDir(); Path tmpDir = createTempDir();
@ -297,14 +299,14 @@ struct MercurialInputScheme : InputScheme
if (!_input.getRev()) if (!_input.getRev())
getCache()->add( getCache()->add(
store, store,
mutableAttrs, unlockedAttrs,
infoAttrs, infoAttrs,
storePath, storePath,
false); false);
getCache()->add( getCache()->add(
store, store,
getImmutableAttrs(), getLockedAttrs(),
infoAttrs, infoAttrs,
storePath, storePath,
true); true);

View file

@ -5,6 +5,8 @@
#include "store-api.hh" #include "store-api.hh"
#include "local-fs-store.hh" #include "local-fs-store.hh"
#include "fetch-settings.hh"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
namespace nix::fetchers { namespace nix::fetchers {
@ -150,7 +152,7 @@ void overrideRegistry(
static std::shared_ptr<Registry> getGlobalRegistry(ref<Store> store) static std::shared_ptr<Registry> getGlobalRegistry(ref<Store> store)
{ {
static auto reg = [&]() { static auto reg = [&]() {
auto path = settings.flakeRegistry.get(); auto path = fetchSettings.flakeRegistry.get();
if (!hasPrefix(path, "/")) { if (!hasPrefix(path, "/")) {
auto storePath = downloadFile(store, path, "flake-registry.json", false).storePath; auto storePath = downloadFile(store, path, "flake-registry.json", false).storePath;

View file

@ -13,7 +13,7 @@ DownloadFileResult downloadFile(
ref<Store> store, ref<Store> store,
const std::string & url, const std::string & url,
const std::string & name, const std::string & name,
bool immutable, bool locked,
const Headers & headers) const Headers & headers)
{ {
// FIXME: check store // FIXME: check store
@ -88,7 +88,7 @@ DownloadFileResult downloadFile(
inAttrs, inAttrs,
infoAttrs, infoAttrs,
*storePath, *storePath,
immutable); locked);
if (url != res.effectiveUri) if (url != res.effectiveUri)
getCache()->add( getCache()->add(
@ -100,7 +100,7 @@ DownloadFileResult downloadFile(
}, },
infoAttrs, infoAttrs,
*storePath, *storePath,
immutable); locked);
return { return {
.storePath = std::move(*storePath), .storePath = std::move(*storePath),
@ -113,7 +113,7 @@ std::pair<Tree, time_t> downloadTarball(
ref<Store> store, ref<Store> store,
const std::string & url, const std::string & url,
const std::string & name, const std::string & name,
bool immutable, bool locked,
const Headers & headers) const Headers & headers)
{ {
Attrs inAttrs({ Attrs inAttrs({
@ -130,7 +130,7 @@ std::pair<Tree, time_t> downloadTarball(
getIntAttr(cached->infoAttrs, "lastModified") getIntAttr(cached->infoAttrs, "lastModified")
}; };
auto res = downloadFile(store, url, name, immutable, headers); auto res = downloadFile(store, url, name, locked, headers);
std::optional<StorePath> unpackedStorePath; std::optional<StorePath> unpackedStorePath;
time_t lastModified; time_t lastModified;
@ -160,7 +160,7 @@ std::pair<Tree, time_t> downloadTarball(
inAttrs, inAttrs,
infoAttrs, infoAttrs,
*unpackedStorePath, *unpackedStorePath,
immutable); locked);
return { return {
Tree { .actualPath = store->toRealPath(*unpackedStorePath), .storePath = std::move(*unpackedStorePath) }, Tree { .actualPath = store->toRealPath(*unpackedStorePath), .storePath = std::move(*unpackedStorePath) },
@ -202,7 +202,7 @@ struct TarballInputScheme : InputScheme
Input input; Input input;
input.attrs = attrs; input.attrs = attrs;
//input.immutable = (bool) maybeGetStrAttr(input.attrs, "hash"); //input.locked = (bool) maybeGetStrAttr(input.attrs, "hash");
return input; return input;
} }

View file

@ -4,7 +4,7 @@
namespace nix { namespace nix {
MixCommonArgs::MixCommonArgs(const string & programName) MixCommonArgs::MixCommonArgs(const std::string & programName)
: programName(programName) : programName(programName)
{ {
addFlag({ addFlag({

View file

@ -11,8 +11,8 @@ class MixCommonArgs : public virtual Args
{ {
void initialFlagsProcessed() override; void initialFlagsProcessed() override;
public: public:
string programName; std::string programName;
MixCommonArgs(const string & programName); MixCommonArgs(const std::string & programName);
protected: protected:
virtual void pluginsInited() {} virtual void pluginsInited() {}
}; };

View file

@ -1,6 +1,7 @@
#include "globals.hh" #include "globals.hh"
#include "shared.hh" #include "shared.hh"
#include "store-api.hh" #include "store-api.hh"
#include "gc-store.hh"
#include "util.hh" #include "util.hh"
#include "loggers.hh" #include "loggers.hh"
@ -94,7 +95,7 @@ void printMissing(ref<Store> store, const StorePathSet & willBuild,
} }
string getArg(const string & opt, std::string getArg(const std::string & opt,
Strings::iterator & i, const Strings::iterator & end) Strings::iterator & i, const Strings::iterator & end)
{ {
++i; ++i;
@ -322,14 +323,14 @@ void parseCmdLine(int argc, char * * argv,
} }
void parseCmdLine(const string & programName, const Strings & args, void parseCmdLine(const std::string & programName, const Strings & args,
std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg) std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{ {
LegacyArgs(programName, parseArg).parseCmdline(args); LegacyArgs(programName, parseArg).parseCmdline(args);
} }
void printVersion(const string & programName) void printVersion(const std::string & programName)
{ {
std::cout << format("%1% (Nix Super) %2%") % programName % nixVersion << std::endl; std::cout << format("%1% (Nix Super) %2%") % programName % nixVersion << std::endl;
if (verbosity > lvlInfo) { if (verbosity > lvlInfo) {
@ -352,7 +353,7 @@ void printVersion(const string & programName)
} }
void showManPage(const string & name) void showManPage(const std::string & name)
{ {
restoreProcessContext(); restoreProcessContext();
setenv("MANPATH", settings.nixManDir.c_str(), 1); setenv("MANPATH", settings.nixManDir.c_str(), 1);
@ -361,13 +362,13 @@ void showManPage(const string & name)
} }
int handleExceptions(const string & programName, std::function<void()> fun) int handleExceptions(const std::string & programName, std::function<void()> fun)
{ {
ReceiveInterrupts receiveInterrupts; // FIXME: need better place for this ReceiveInterrupts receiveInterrupts; // FIXME: need better place for this
ErrorInfo::programName = baseNameOf(programName); ErrorInfo::programName = baseNameOf(programName);
string error = ANSI_RED "error:" ANSI_NORMAL " "; std::string error = ANSI_RED "error:" ANSI_NORMAL " ";
try { try {
try { try {
fun(); fun();
@ -407,7 +408,7 @@ RunPager::RunPager()
if (!isatty(STDOUT_FILENO)) return; if (!isatty(STDOUT_FILENO)) return;
char * pager = getenv("NIX_PAGER"); char * pager = getenv("NIX_PAGER");
if (!pager) pager = getenv("PAGER"); if (!pager) pager = getenv("PAGER");
if (pager && ((string) pager == "" || (string) pager == "cat")) return; if (pager && ((std::string) pager == "" || (std::string) pager == "cat")) return;
Pipe toPager; Pipe toPager;
toPager.create(); toPager.create();

View file

@ -22,7 +22,7 @@ public:
virtual ~Exit(); virtual ~Exit();
}; };
int handleExceptions(const string & programName, std::function<void()> fun); int handleExceptions(const std::string & programName, std::function<void()> fun);
/* Don't forget to call initPlugins() after settings are initialized! */ /* Don't forget to call initPlugins() after settings are initialized! */
void initNix(); void initNix();
@ -30,10 +30,10 @@ void initNix();
void parseCmdLine(int argc, char * * argv, void parseCmdLine(int argc, char * * argv,
std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg); std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg);
void parseCmdLine(const string & programName, const Strings & args, void parseCmdLine(const std::string & programName, const Strings & args,
std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg); std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg);
void printVersion(const string & programName); void printVersion(const std::string & programName);
/* Ugh. No better place to put this. */ /* Ugh. No better place to put this. */
void printGCWarning(); void printGCWarning();
@ -50,10 +50,10 @@ void printMissing(ref<Store> store, const StorePathSet & willBuild,
const StorePathSet & willSubstitute, const StorePathSet & unknown, const StorePathSet & willSubstitute, const StorePathSet & unknown,
uint64_t downloadSize, uint64_t narSize, Verbosity lvl = lvlInfo); uint64_t downloadSize, uint64_t narSize, Verbosity lvl = lvlInfo);
string getArg(const string & opt, std::string getArg(const std::string & opt,
Strings::iterator & i, const Strings::iterator & end); Strings::iterator & i, const Strings::iterator & end);
template<class N> N getIntArg(const string & opt, template<class N> N getIntArg(const std::string & opt,
Strings::iterator & i, const Strings::iterator & end, bool allowUnit) Strings::iterator & i, const Strings::iterator & end, bool allowUnit)
{ {
++i; ++i;
@ -76,7 +76,7 @@ struct LegacyArgs : public MixCommonArgs
/* Show the manual page for the specified program. */ /* Show the manual page for the specified program. */
void showManPage(const string & name); void showManPage(const std::string & name);
/* The constructor of this class starts a pager if stdout is a /* The constructor of this class starts a pager if stdout is a
terminal and $PAGER is set. Stdout is redirected to the pager. */ terminal and $PAGER is set. Stdout is redirected to the pager. */
@ -96,7 +96,7 @@ extern volatile ::sig_atomic_t blockInt;
/* GC helpers. */ /* GC helpers. */
string showBytes(uint64_t bytes); std::string showBytes(uint64_t bytes);
struct GCResults; struct GCResults;

View file

@ -385,8 +385,14 @@ void BinaryCacheStore::queryPathInfoUncached(const StorePath & storePath,
}}); }});
} }
StorePath BinaryCacheStore::addToStore(const string & name, const Path & srcPath, StorePath BinaryCacheStore::addToStore(
FileIngestionMethod method, HashType hashAlgo, PathFilter & filter, RepairFlag repair, const StorePathSet & references) std::string_view name,
const Path & srcPath,
FileIngestionMethod method,
HashType hashAlgo,
PathFilter & filter,
RepairFlag repair,
const StorePathSet & references)
{ {
/* FIXME: Make BinaryCacheStore::addToStoreCommon support /* FIXME: Make BinaryCacheStore::addToStoreCommon support
non-recursive+sha256 so we can just use the default non-recursive+sha256 so we can just use the default
@ -418,8 +424,11 @@ StorePath BinaryCacheStore::addToStore(const string & name, const Path & srcPath
})->path; })->path;
} }
StorePath BinaryCacheStore::addTextToStore(const string & name, const string & s, StorePath BinaryCacheStore::addTextToStore(
const StorePathSet & references, RepairFlag repair) std::string_view name,
std::string_view s,
const StorePathSet & references,
RepairFlag repair)
{ {
auto textHash = hashString(htSHA256, s); auto textHash = hashString(htSHA256, s);
auto path = makeTextPath(name, textHash, references); auto path = makeTextPath(name, textHash, references);

View file

@ -101,12 +101,20 @@ public:
StorePath addToStoreFromDump(Source & dump, std::string_view name, StorePath addToStoreFromDump(Source & dump, std::string_view name,
FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references) override; FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references) override;
StorePath addToStore(const string & name, const Path & srcPath, StorePath addToStore(
FileIngestionMethod method, HashType hashAlgo, std::string_view name,
PathFilter & filter, RepairFlag repair, const StorePathSet & references) override; const Path & srcPath,
FileIngestionMethod method,
HashType hashAlgo,
PathFilter & filter,
RepairFlag repair,
const StorePathSet & references) override;
StorePath addTextToStore(const string & name, const string & s, StorePath addTextToStore(
const StorePathSet & references, RepairFlag repair) override; std::string_view name,
std::string_view s,
const StorePathSet & references,
RepairFlag repair) override;
void registerDrvOutput(const Realisation & info) override; void registerDrvOutput(const Realisation & info) override;

View file

@ -0,0 +1,77 @@
#pragma once
#include "realisation.hh"
#include <string>
#include <chrono>
namespace nix {
struct BuildResult
{
/* Note: don't remove status codes, and only add new status codes
at the end of the list, to prevent client/server
incompatibilities in the nix-store --serve protocol. */
enum Status {
Built = 0,
Substituted,
AlreadyValid,
PermanentFailure,
InputRejected,
OutputRejected,
TransientFailure, // possibly transient
CachedFailure, // no longer used
TimedOut,
MiscFailure,
DependencyFailed,
LogLimitExceeded,
NotDeterministic,
ResolvesToAlreadyValid,
} status = MiscFailure;
std::string errorMsg;
std::string toString() const {
auto strStatus = [&]() {
switch (status) {
case Built: return "Built";
case Substituted: return "Substituted";
case AlreadyValid: return "AlreadyValid";
case PermanentFailure: return "PermanentFailure";
case InputRejected: return "InputRejected";
case OutputRejected: return "OutputRejected";
case TransientFailure: return "TransientFailure";
case CachedFailure: return "CachedFailure";
case TimedOut: return "TimedOut";
case MiscFailure: return "MiscFailure";
case DependencyFailed: return "DependencyFailed";
case LogLimitExceeded: return "LogLimitExceeded";
case NotDeterministic: return "NotDeterministic";
case ResolvesToAlreadyValid: return "ResolvesToAlreadyValid";
default: return "Unknown";
};
}();
return strStatus + ((errorMsg == "") ? "" : " : " + errorMsg);
}
/* How many times this build was performed. */
unsigned int timesBuilt = 0;
/* If timesBuilt > 1, whether some builds did not produce the same
result. (Note that 'isNonDeterministic = false' does not mean
the build is deterministic, just that we don't have evidence of
non-determinism.) */
bool isNonDeterministic = false;
DrvOutputs builtOutputs;
/* The start/stop times of the build (or one of the rounds, if it
was repeated). */
time_t startTime = 0, stopTime = 0;
bool success() {
return status == Built || status == Substituted || status == AlreadyValid || status == ResolvesToAlreadyValid;
}
};
}

View file

@ -116,7 +116,7 @@ DerivationGoal::~DerivationGoal()
} }
string DerivationGoal::key() std::string DerivationGoal::key()
{ {
/* Ensure that derivations get built in order of their name, /* Ensure that derivations get built in order of their name,
i.e. a derivation named "aardvark" always comes before i.e. a derivation named "aardvark" always comes before
@ -1013,7 +1013,7 @@ HookReply DerivationGoal::tryBuildHook()
/* Read the first line of input, which should be a word indicating /* Read the first line of input, which should be a word indicating
whether the hook wishes to perform the build. */ whether the hook wishes to perform the build. */
string reply; std::string reply;
while (true) { while (true) {
auto s = [&]() { auto s = [&]() {
try { try {
@ -1025,8 +1025,8 @@ HookReply DerivationGoal::tryBuildHook()
}(); }();
if (handleJSONLogMessage(s, worker.act, worker.hook->activities, true)) if (handleJSONLogMessage(s, worker.act, worker.hook->activities, true))
; ;
else if (string(s, 0, 2) == "# ") { else if (s.substr(0, 2) == "# ") {
reply = string(s, 2); reply = s.substr(2);
break; break;
} }
else { else {
@ -1140,10 +1140,10 @@ Path DerivationGoal::openLogFile()
logDir = localStore->logDir; logDir = localStore->logDir;
else else
logDir = settings.nixLogDir; logDir = settings.nixLogDir;
Path dir = fmt("%s/%s/%s/", logDir, LocalFSStore::drvsLogDir, string(baseName, 0, 2)); Path dir = fmt("%s/%s/%s/", logDir, LocalFSStore::drvsLogDir, baseName.substr(0, 2));
createDirs(dir); createDirs(dir);
Path logFileName = fmt("%s/%s%s", dir, string(baseName, 2), Path logFileName = fmt("%s/%s%s", dir, baseName.substr(2),
settings.compressLog ? ".bz2" : ""); settings.compressLog ? ".bz2" : "");
fdLogFile = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0666); fdLogFile = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
@ -1175,7 +1175,8 @@ bool DerivationGoal::isReadDesc(int fd)
return fd == hook->builderOut.readSide.get(); return fd == hook->builderOut.readSide.get();
} }
void DerivationGoal::handleChildOutput(int fd, const string & data)
void DerivationGoal::handleChildOutput(int fd, std::string_view data)
{ {
// local & `ssh://`-builds are dealt with here. // local & `ssh://`-builds are dealt with here.
auto isWrittenToLog = isReadDesc(fd); auto isWrittenToLog = isReadDesc(fd);

View file

@ -2,6 +2,7 @@
#include "parsed-derivations.hh" #include "parsed-derivations.hh"
#include "lock.hh" #include "lock.hh"
#include "build-result.hh"
#include "store-api.hh" #include "store-api.hh"
#include "pathlocks.hh" #include "pathlocks.hh"
#include "goal.hh" #include "goal.hh"
@ -145,7 +146,7 @@ struct DerivationGoal : public Goal
void timedOut(Error && ex) override; void timedOut(Error && ex) override;
string key() override; std::string key() override;
void work() override; void work() override;
@ -200,7 +201,7 @@ struct DerivationGoal : public Goal
virtual bool isReadDesc(int fd); virtual bool isReadDesc(int fd);
/* Callback used by the worker to write to the log. */ /* Callback used by the worker to write to the log. */
void handleChildOutput(int fd, const string & data) override; void handleChildOutput(int fd, std::string_view data) override;
void handleEOF(int fd) override; void handleEOF(int fd) override;
void flushLine(); void flushLine();

View file

@ -137,7 +137,7 @@ void DrvOutputSubstitutionGoal::finished()
amDone(ecSuccess); amDone(ecSuccess);
} }
string DrvOutputSubstitutionGoal::key() std::string DrvOutputSubstitutionGoal::key()
{ {
/* "a$" ensures substitution goals happen before derivation /* "a$" ensures substitution goals happen before derivation
goals. */ goals. */

View file

@ -51,7 +51,7 @@ public:
void timedOut(Error && ex) override { abort(); }; void timedOut(Error && ex) override { abort(); };
string key() override; std::string key() override;
void work() override; void work() override;
void handleEOF(int fd) override; void handleEOF(int fd) override;

View file

@ -5,8 +5,8 @@ namespace nix {
bool CompareGoalPtrs::operator() (const GoalPtr & a, const GoalPtr & b) const { bool CompareGoalPtrs::operator() (const GoalPtr & a, const GoalPtr & b) const {
string s1 = a->key(); std::string s1 = a->key();
string s2 = b->key(); std::string s2 = b->key();
return s1 < s2; return s1 < s2;
} }

View file

@ -50,7 +50,7 @@ struct Goal : public std::enable_shared_from_this<Goal>
unsigned int nrIncompleteClosure; unsigned int nrIncompleteClosure;
/* Name of this goal for debugging purposes. */ /* Name of this goal for debugging purposes. */
string name; std::string name;
/* Whether the goal is finished. */ /* Whether the goal is finished. */
ExitCode exitCode; ExitCode exitCode;
@ -75,7 +75,7 @@ struct Goal : public std::enable_shared_from_this<Goal>
virtual void waiteeDone(GoalPtr waitee, ExitCode result); virtual void waiteeDone(GoalPtr waitee, ExitCode result);
virtual void handleChildOutput(int fd, const string & data) virtual void handleChildOutput(int fd, std::string_view data)
{ {
abort(); abort();
} }
@ -87,7 +87,7 @@ struct Goal : public std::enable_shared_from_this<Goal>
void trace(const FormatOrString & fs); void trace(const FormatOrString & fs);
string getName() std::string getName()
{ {
return name; return name;
} }
@ -97,7 +97,7 @@ struct Goal : public std::enable_shared_from_this<Goal>
by the worker (important!), etc. */ by the worker (important!), etc. */
virtual void timedOut(Error && ex) = 0; virtual void timedOut(Error && ex) = 0;
virtual string key() = 0; virtual std::string key() = 0;
void amDone(ExitCode result, std::optional<Error> ex = {}); void amDone(ExitCode result, std::optional<Error> ex = {});

View file

@ -1,4 +1,5 @@
#include "local-derivation-goal.hh" #include "local-derivation-goal.hh"
#include "gc-store.hh"
#include "hook-instance.hh" #include "hook-instance.hh"
#include "worker.hh" #include "worker.hh"
#include "builtins.hh" #include "builtins.hh"
@ -481,12 +482,12 @@ void LocalDerivationGoal::startBuilder()
temporary build directory. The text files have the format used temporary build directory. The text files have the format used
by `nix-store --register-validity'. However, the deriver by `nix-store --register-validity'. However, the deriver
fields are left empty. */ fields are left empty. */
string s = get(drv->env, "exportReferencesGraph").value_or(""); auto s = get(drv->env, "exportReferencesGraph").value_or("");
Strings ss = tokenizeString<Strings>(s); Strings ss = tokenizeString<Strings>(s);
if (ss.size() % 2 != 0) if (ss.size() % 2 != 0)
throw BuildError("odd number of tokens in 'exportReferencesGraph': '%1%'", s); throw BuildError("odd number of tokens in 'exportReferencesGraph': '%1%'", s);
for (Strings::iterator i = ss.begin(); i != ss.end(); ) { for (Strings::iterator i = ss.begin(); i != ss.end(); ) {
string fileName = *i++; auto fileName = *i++;
static std::regex regex("[A-Za-z_][A-Za-z0-9_.-]*"); static std::regex regex("[A-Za-z_][A-Za-z0-9_.-]*");
if (!std::regex_match(fileName, regex)) if (!std::regex_match(fileName, regex))
throw Error("invalid file name '%s' in 'exportReferencesGraph'", fileName); throw Error("invalid file name '%s' in 'exportReferencesGraph'", fileName);
@ -517,10 +518,10 @@ void LocalDerivationGoal::startBuilder()
i.pop_back(); i.pop_back();
} }
size_t p = i.find('='); size_t p = i.find('=');
if (p == string::npos) if (p == std::string::npos)
dirsInChroot[i] = {i, optional}; dirsInChroot[i] = {i, optional};
else else
dirsInChroot[string(i, 0, p)] = {string(i, p + 1), optional}; dirsInChroot[i.substr(0, p)] = {i.substr(p + 1), optional};
} }
dirsInChroot[tmpDirInSandbox] = tmpDir; dirsInChroot[tmpDirInSandbox] = tmpDir;
@ -671,9 +672,10 @@ void LocalDerivationGoal::startBuilder()
auto state = stBegin; auto state = stBegin;
auto lines = runProgram(settings.preBuildHook, false, args); auto lines = runProgram(settings.preBuildHook, false, args);
auto lastPos = std::string::size_type{0}; auto lastPos = std::string::size_type{0};
for (auto nlPos = lines.find('\n'); nlPos != string::npos; for (auto nlPos = lines.find('\n'); nlPos != std::string::npos;
nlPos = lines.find('\n', lastPos)) { nlPos = lines.find('\n', lastPos))
auto line = std::string{lines, lastPos, nlPos - lastPos}; {
auto line = lines.substr(lastPos, nlPos - lastPos);
lastPos = nlPos + 1; lastPos = nlPos + 1;
if (state == stBegin) { if (state == stBegin) {
if (line == "extra-sandbox-paths" || line == "extra-chroot-dirs") { if (line == "extra-sandbox-paths" || line == "extra-chroot-dirs") {
@ -686,10 +688,10 @@ void LocalDerivationGoal::startBuilder()
state = stBegin; state = stBegin;
} else { } else {
auto p = line.find('='); auto p = line.find('=');
if (p == string::npos) if (p == std::string::npos)
dirsInChroot[line] = line; dirsInChroot[line] = line;
else else
dirsInChroot[string(line, 0, p)] = string(line, p + 1); dirsInChroot[line.substr(0, p)] = line.substr(p + 1);
} }
} }
} }
@ -941,7 +943,7 @@ void LocalDerivationGoal::startBuilder()
/* Check if setting up the build environment failed. */ /* Check if setting up the build environment failed. */
std::vector<std::string> msgs; std::vector<std::string> msgs;
while (true) { while (true) {
string msg = [&]() { std::string msg = [&]() {
try { try {
return readLine(builderOut.readSide.get()); return readLine(builderOut.readSide.get());
} catch (Error & e) { } catch (Error & e) {
@ -953,8 +955,8 @@ void LocalDerivationGoal::startBuilder()
throw; throw;
} }
}(); }();
if (string(msg, 0, 1) == "\2") break; if (msg.substr(0, 1) == "\2") break;
if (string(msg, 0, 1) == "\1") { if (msg.substr(0, 1) == "\1") {
FdSource source(builderOut.readSide.get()); FdSource source(builderOut.readSide.get());
auto ex = readError(source); auto ex = readError(source);
ex.addTrace({}, "while setting up the build environment"); ex.addTrace({}, "while setting up the build environment");
@ -990,7 +992,7 @@ void LocalDerivationGoal::initTmpDir() {
env[i.first] = i.second; env[i.first] = i.second;
} else { } else {
auto hash = hashString(htSHA256, i.first); auto hash = hashString(htSHA256, i.first);
string fn = ".attr-" + hash.to_string(Base32, false); std::string fn = ".attr-" + hash.to_string(Base32, false);
Path p = tmpDir + "/" + fn; Path p = tmpDir + "/" + fn;
writeFile(p, rewriteStrings(i.second, inputRewrites)); writeFile(p, rewriteStrings(i.second, inputRewrites));
chownToBuilder(p); chownToBuilder(p);
@ -1081,7 +1083,7 @@ void LocalDerivationGoal::writeStructuredAttrs()
for (auto & [i, v] : json["outputs"].get<nlohmann::json::object_t>()) { for (auto & [i, v] : json["outputs"].get<nlohmann::json::object_t>()) {
/* The placeholder must have a rewrite, so we use it to cover both the /* The placeholder must have a rewrite, so we use it to cover both the
cases where we know or don't know the output path ahead of time. */ cases where we know or don't know the output path ahead of time. */
rewritten[i] = rewriteStrings(v, inputRewrites); rewritten[i] = rewriteStrings((std::string) v, inputRewrites);
} }
json["outputs"] = rewritten; json["outputs"] = rewritten;
@ -1126,7 +1128,7 @@ struct RestrictedStoreConfig : virtual LocalFSStoreConfig
/* A wrapper around LocalStore that only allows building/querying of /* A wrapper around LocalStore that only allows building/querying of
paths that are in the input closures of the build or were added via paths that are in the input closures of the build or were added via
recursive Nix calls. */ recursive Nix calls. */
struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual LocalFSStore struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual LocalFSStore, public virtual GcStore
{ {
ref<LocalStore> next; ref<LocalStore> next;
@ -1187,10 +1189,14 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
{ throw Error("queryPathFromHashPart"); } { throw Error("queryPathFromHashPart"); }
StorePath addToStore(const string & name, const Path & srcPath, StorePath addToStore(
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, std::string_view name,
PathFilter & filter = defaultPathFilter, RepairFlag repair = NoRepair, const Path & srcPath,
const StorePathSet & references = StorePathSet()) override FileIngestionMethod method,
HashType hashAlgo,
PathFilter & filter,
RepairFlag repair,
const StorePathSet & references) override
{ throw Error("addToStore"); } { throw Error("addToStore"); }
void addToStore(const ValidPathInfo & info, Source & narSource, void addToStore(const ValidPathInfo & info, Source & narSource,
@ -1200,17 +1206,24 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
goal.addDependency(info.path); goal.addDependency(info.path);
} }
StorePath addTextToStore(const string & name, const string & s, StorePath addTextToStore(
const StorePathSet & references, RepairFlag repair = NoRepair) override std::string_view name,
std::string_view s,
const StorePathSet & references,
RepairFlag repair = NoRepair) override
{ {
auto path = next->addTextToStore(name, s, references, repair); auto path = next->addTextToStore(name, s, references, repair);
goal.addDependency(path); goal.addDependency(path);
return path; return path;
} }
StorePath addToStoreFromDump(Source & dump, std::string_view name, StorePath addToStoreFromDump(
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair, Source & dump,
const StorePathSet & references = StorePathSet()) override std::string_view name,
FileIngestionMethod method,
HashType hashAlgo,
RepairFlag repair,
const StorePathSet & references) override
{ {
auto path = next->addToStoreFromDump(dump, name, method, hashAlgo, repair, references); auto path = next->addToStoreFromDump(dump, name, method, hashAlgo, repair, references);
goal.addDependency(path); goal.addDependency(path);
@ -1921,7 +1934,7 @@ void LocalDerivationGoal::runChild()
"can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin",
i.first, i.second.source); i.first, i.second.source);
string path = i.first; std::string path = i.first;
struct stat st; struct stat st;
if (lstat(path.c_str(), &st)) { if (lstat(path.c_str(), &st)) {
if (i.second.optional && errno == ENOENT) if (i.second.optional && errno == ENOENT)
@ -1973,7 +1986,7 @@ void LocalDerivationGoal::runChild()
args.push_back("IMPORT_DIR=" + settings.nixDataDir + "/nix/sandbox/"); args.push_back("IMPORT_DIR=" + settings.nixDataDir + "/nix/sandbox/");
if (allowLocalNetworking) { if (allowLocalNetworking) {
args.push_back("-D"); args.push_back("-D");
args.push_back(string("_ALLOW_LOCAL_NETWORKING=1")); args.push_back(std::string("_ALLOW_LOCAL_NETWORKING=1"));
} }
args.push_back(drv->builder); args.push_back(drv->builder);
} else { } else {
@ -1992,7 +2005,7 @@ void LocalDerivationGoal::runChild()
args.push_back(rewriteStrings(i, inputRewrites)); args.push_back(rewriteStrings(i, inputRewrites));
/* Indicate that we managed to set up the build environment. */ /* Indicate that we managed to set up the build environment. */
writeFull(STDERR_FILENO, string("\2\n")); writeFull(STDERR_FILENO, std::string("\2\n"));
/* Execute the program. This should not return. */ /* Execute the program. This should not return. */
if (drv->isBuiltin()) { if (drv->isBuiltin()) {
@ -2010,7 +2023,7 @@ void LocalDerivationGoal::runChild()
else if (drv->builder == "builtin:unpack-channel") else if (drv->builder == "builtin:unpack-channel")
builtinUnpackChannel(drv2); builtinUnpackChannel(drv2);
else else
throw Error("unsupported builtin builder '%1%'", string(drv->builder, 8)); throw Error("unsupported builtin builder '%1%'", drv->builder.substr(8));
_exit(0); _exit(0);
} catch (std::exception & e) { } catch (std::exception & e) {
writeFull(STDERR_FILENO, e.what() + std::string("\n")); writeFull(STDERR_FILENO, e.what() + std::string("\n"));
@ -2371,14 +2384,10 @@ void LocalDerivationGoal::registerOutputs()
[&](DerivationOutputCAFloating dof) { [&](DerivationOutputCAFloating dof) {
return newInfoFromCA(dof); return newInfoFromCA(dof);
}, },
[&](DerivationOutputDeferred) { [&](DerivationOutputDeferred) -> ValidPathInfo {
// No derivation should reach that point without having been // No derivation should reach that point without having been
// rewritten first // rewritten first
assert(false); assert(false);
// Ugly, but the compiler insists on having this return a value
// of type `ValidPathInfo` despite the `assert(false)`, so
// let's provide it
return *(ValidPathInfo*)0;
}, },
}, output.output); }, output.output);
@ -2694,7 +2703,7 @@ void LocalDerivationGoal::checkOutputs(const std::map<Path, ValidPathInfo> & out
} }
if (!badPaths.empty()) { if (!badPaths.empty()) {
string badPathsStr; std::string badPathsStr;
for (auto & i : badPaths) { for (auto & i : badPaths) {
badPathsStr += "\n "; badPathsStr += "\n ";
badPathsStr += worker.store.printStorePath(i); badPathsStr += worker.store.printStorePath(i);

View file

@ -58,11 +58,11 @@ struct LocalDerivationGoal : public DerivationGoal
typedef map<Path, ChrootPath> DirsInChroot; // maps target path to source path typedef map<Path, ChrootPath> DirsInChroot; // maps target path to source path
DirsInChroot dirsInChroot; DirsInChroot dirsInChroot;
typedef map<string, string> Environment; typedef map<std::string, std::string> Environment;
Environment env; Environment env;
#if __APPLE__ #if __APPLE__
typedef string SandboxProfile; typedef std::string SandboxProfile;
SandboxProfile additionalSandboxProfile; SandboxProfile additionalSandboxProfile;
#endif #endif

View file

@ -272,7 +272,7 @@ void PathSubstitutionGoal::finished()
} }
void PathSubstitutionGoal::handleChildOutput(int fd, const string & data) void PathSubstitutionGoal::handleChildOutput(int fd, std::string_view data)
{ {
} }

View file

@ -59,7 +59,7 @@ public:
void timedOut(Error && ex) override { abort(); }; void timedOut(Error && ex) override { abort(); };
string key() override std::string key() override
{ {
/* "a$" ensures substitution goals happen before derivation /* "a$" ensures substitution goals happen before derivation
goals. */ goals. */
@ -77,7 +77,7 @@ public:
void finished(); void finished();
/* Callback used by the worker to write to the log. */ /* Callback used by the worker to write to the log. */
void handleChildOutput(int fd, const string & data) override; void handleChildOutput(int fd, std::string_view data) override;
void handleEOF(int fd) override; void handleEOF(int fd) override;
void cleanup() override; void cleanup() override;

View file

@ -394,7 +394,7 @@ void Worker::waitForInput()
} else { } else {
printMsg(lvlVomit, "%1%: read %2% bytes", printMsg(lvlVomit, "%1%: read %2% bytes",
goal->getName(), rd); goal->getName(), rd);
string data((char *) buffer.data(), rd); std::string data((char *) buffer.data(), rd);
j->lastOutput = after; j->lastOutput = after;
goal->handleChildOutput(k, data); goal->handleChildOutput(k, data);
} }

View file

@ -123,7 +123,7 @@ void buildProfile(const Path & out, Packages && pkgs)
createLinks(state, pkgDir, out, priority); createLinks(state, pkgDir, out, priority);
try { try {
for (const auto & p : tokenizeString<std::vector<string>>( for (const auto & p : tokenizeString<std::vector<std::string>>(
readFile(pkgDir + "/nix-support/propagated-user-env-packages"), " \n")) readFile(pkgDir + "/nix-support/propagated-user-env-packages"), " \n"))
if (!done.count(p)) if (!done.count(p))
postponed.insert(p); postponed.insert(p);
@ -161,7 +161,7 @@ void buildProfile(const Path & out, Packages && pkgs)
void builtinBuildenv(const BasicDerivation & drv) void builtinBuildenv(const BasicDerivation & drv)
{ {
auto getAttr = [&](const string & name) { auto getAttr = [&](const std::string & name) {
auto i = drv.env.find(name); auto i = drv.env.find(name);
if (i == drv.env.end()) throw Error("attribute '%s' missing", name); if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
return i->second; return i->second;

View file

@ -16,7 +16,7 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
writeFile(settings.netrcFile, netrcData, 0600); writeFile(settings.netrcFile, netrcData, 0600);
} }
auto getAttr = [&](const string & name) { auto getAttr = [&](const std::string & name) {
auto i = drv.env.find(name); auto i = drv.env.find(name);
if (i == drv.env.end()) throw Error("attribute '%s' missing", name); if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
return i->second; return i->second;

View file

@ -5,7 +5,7 @@ namespace nix {
void builtinUnpackChannel(const BasicDerivation & drv) void builtinUnpackChannel(const BasicDerivation & drv)
{ {
auto getAttr = [&](const string & name) { auto getAttr = [&](const std::string & name) {
auto i = drv.env.find(name); auto i = drv.env.find(name);
if (i == drv.env.end()) throw Error("attribute '%s' missing", name); if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
return i->second; return i->second;

View file

@ -1,7 +1,9 @@
#include "daemon.hh" #include "daemon.hh"
#include "monitor-fd.hh" #include "monitor-fd.hh"
#include "worker-protocol.hh" #include "worker-protocol.hh"
#include "build-result.hh"
#include "store-api.hh" #include "store-api.hh"
#include "gc-store.hh"
#include "path-with-outputs.hh" #include "path-with-outputs.hh"
#include "finally.hh" #include "finally.hh"
#include "archive.hh" #include "archive.hh"
@ -479,8 +481,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
} }
case wopAddTextToStore: { case wopAddTextToStore: {
string suffix = readString(from); std::string suffix = readString(from);
string s = readString(from); std::string s = readString(from);
auto refs = worker_proto::read(*store, from, Phantom<StorePathSet> {}); auto refs = worker_proto::read(*store, from, Phantom<StorePathSet> {});
logger->startWork(); logger->startWork();
auto path = store->addTextToStore(suffix, s, refs, NoRepair); auto path = store->addTextToStore(suffix, s, refs, NoRepair);
@ -622,9 +624,12 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
case wopAddIndirectRoot: { case wopAddIndirectRoot: {
Path path = absPath(readString(from)); Path path = absPath(readString(from));
logger->startWork(); logger->startWork();
store->addIndirectRoot(path); auto & gcStore = requireGcStore(*store);
gcStore.addIndirectRoot(path);
logger->stopWork(); logger->stopWork();
to << 1; to << 1;
break; break;
} }
@ -639,7 +644,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
case wopFindRoots: { case wopFindRoots: {
logger->startWork(); logger->startWork();
Roots roots = store->findRoots(!trusted); auto & gcStore = requireGcStore(*store);
Roots roots = gcStore.findRoots(!trusted);
logger->stopWork(); logger->stopWork();
size_t size = 0; size_t size = 0;
@ -670,7 +676,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
logger->startWork(); logger->startWork();
if (options.ignoreLiveness) if (options.ignoreLiveness)
throw Error("you are not allowed to ignore liveness"); throw Error("you are not allowed to ignore liveness");
store->collectGarbage(options, results); auto & gcStore = requireGcStore(*store);
gcStore.collectGarbage(options, results);
logger->stopWork(); logger->stopWork();
to << results.paths << results.bytesFreed << 0 /* obsolete */; to << results.paths << results.bytesFreed << 0 /* obsolete */;
@ -698,8 +705,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
if (GET_PROTOCOL_MINOR(clientVersion) >= 12) { if (GET_PROTOCOL_MINOR(clientVersion) >= 12) {
unsigned int n = readInt(from); unsigned int n = readInt(from);
for (unsigned int i = 0; i < n; i++) { for (unsigned int i = 0; i < n; i++) {
string name = readString(from); auto name = readString(from);
string value = readString(from); auto value = readString(from);
clientSettings.overrides.emplace(name, value); clientSettings.overrides.emplace(name, value);
} }
} }

View file

@ -82,7 +82,7 @@ bool derivationIsImpure(DerivationType dt) {
bool BasicDerivation::isBuiltin() const bool BasicDerivation::isBuiltin() const
{ {
return string(builder, 0, 8) == "builtin:"; return builder.substr(0, 8) == "builtin:";
} }
@ -104,19 +104,19 @@ StorePath writeDerivation(Store & store,
/* Read string `s' from stream `str'. */ /* Read string `s' from stream `str'. */
static void expect(std::istream & str, const string & s) static void expect(std::istream & str, std::string_view s)
{ {
char s2[s.size()]; char s2[s.size()];
str.read(s2, s.size()); str.read(s2, s.size());
if (string(s2, s.size()) != s) if (std::string(s2, s.size()) != s)
throw FormatError("expected string '%1%'", s); throw FormatError("expected string '%1%'", s);
} }
/* Read a C-style string from stream `str'. */ /* Read a C-style string from stream `str'. */
static string parseString(std::istream & str) static std::string parseString(std::istream & str)
{ {
string res; std::string res;
expect(str, "\""); expect(str, "\"");
int c; int c;
while ((c = str.get()) != '"') while ((c = str.get()) != '"')
@ -172,7 +172,7 @@ static DerivationOutput parseDerivationOutput(const Store & store,
{ {
if (hashAlgo != "") { if (hashAlgo != "") {
auto method = FileIngestionMethod::Flat; auto method = FileIngestionMethod::Flat;
if (string(hashAlgo, 0, 2) == "r:") { if (hashAlgo.substr(0, 2) == "r:") {
method = FileIngestionMethod::Recursive; method = FileIngestionMethod::Recursive;
hashAlgo = hashAlgo.substr(2); hashAlgo = hashAlgo.substr(2);
} }
@ -260,8 +260,8 @@ Derivation parseDerivation(const Store & store, std::string && s, std::string_vi
/* Parse the environment variables. */ /* Parse the environment variables. */
expect(str, ",["); expect(str, ",[");
while (!endOfList(str)) { while (!endOfList(str)) {
expect(str, "("); string name = parseString(str); expect(str, "("); auto name = parseString(str);
expect(str, ","); string value = parseString(str); expect(str, ","); auto value = parseString(str);
expect(str, ")"); expect(str, ")");
drv.env[name] = value; drv.env[name] = value;
} }
@ -271,7 +271,7 @@ Derivation parseDerivation(const Store & store, std::string && s, std::string_vi
} }
static void printString(string & res, std::string_view s) static void printString(std::string & res, std::string_view s)
{ {
boost::container::small_vector<char, 64 * 1024> buffer; boost::container::small_vector<char, 64 * 1024> buffer;
buffer.reserve(s.size() * 2 + 2); buffer.reserve(s.size() * 2 + 2);
@ -289,7 +289,7 @@ static void printString(string & res, std::string_view s)
} }
static void printUnquotedString(string & res, std::string_view s) static void printUnquotedString(std::string & res, std::string_view s)
{ {
res += '"'; res += '"';
res.append(s); res.append(s);
@ -298,7 +298,7 @@ static void printUnquotedString(string & res, std::string_view s)
template<class ForwardIterator> template<class ForwardIterator>
static void printStrings(string & res, ForwardIterator i, ForwardIterator j) static void printStrings(std::string & res, ForwardIterator i, ForwardIterator j)
{ {
res += '['; res += '[';
bool first = true; bool first = true;
@ -311,7 +311,7 @@ static void printStrings(string & res, ForwardIterator i, ForwardIterator j)
template<class ForwardIterator> template<class ForwardIterator>
static void printUnquotedStrings(string & res, ForwardIterator i, ForwardIterator j) static void printUnquotedStrings(std::string & res, ForwardIterator i, ForwardIterator j)
{ {
res += '['; res += '[';
bool first = true; bool first = true;
@ -323,10 +323,10 @@ static void printUnquotedStrings(string & res, ForwardIterator i, ForwardIterato
} }
string Derivation::unparse(const Store & store, bool maskOutputs, std::string Derivation::unparse(const Store & store, bool maskOutputs,
std::map<std::string, StringSet> * actualInputs) const std::map<std::string, StringSet> * actualInputs) const
{ {
string s; std::string s;
s.reserve(65536); s.reserve(65536);
s += "Derive(["; s += "Derive([";
@ -401,7 +401,7 @@ string Derivation::unparse(const Store & store, bool maskOutputs,
// FIXME: remove // FIXME: remove
bool isDerivation(const string & fileName) bool isDerivation(const std::string & fileName)
{ {
return hasSuffix(fileName, drvExtension); return hasSuffix(fileName, drvExtension);
} }
@ -593,7 +593,7 @@ std::map<std::string, Hash> staticOutputHashes(Store & store, const Derivation &
} }
bool wantOutput(const string & output, const std::set<string> & wanted) bool wantOutput(const std::string & output, const std::set<std::string> & wanted)
{ {
return wanted.empty() || wanted.find(output) != wanted.end(); return wanted.empty() || wanted.find(output) != wanted.end();
} }

View file

@ -59,21 +59,19 @@ struct DerivationOutput
std::optional<StorePath> path(const Store & store, std::string_view drvName, std::string_view outputName) const; std::optional<StorePath> path(const Store & store, std::string_view drvName, std::string_view outputName) const;
}; };
typedef std::map<string, DerivationOutput> DerivationOutputs; typedef std::map<std::string, DerivationOutput> DerivationOutputs;
/* These are analogues to the previous DerivationOutputs data type, but they /* These are analogues to the previous DerivationOutputs data type, but they
also contains, for each output, the (optional) store path in which it would also contains, for each output, the (optional) store path in which it would
be written. To calculate values of these types, see the corresponding be written. To calculate values of these types, see the corresponding
functions in BasicDerivation */ functions in BasicDerivation */
typedef std::map<string, std::pair<DerivationOutput, std::optional<StorePath>>> typedef std::map<std::string, std::pair<DerivationOutput, std::optional<StorePath>>>
DerivationOutputsAndOptPaths; DerivationOutputsAndOptPaths;
/* For inputs that are sub-derivations, we specify exactly which /* For inputs that are sub-derivations, we specify exactly which
output IDs we are interested in. */ output IDs we are interested in. */
typedef std::map<StorePath, StringSet> DerivationInputs; typedef std::map<StorePath, StringSet> DerivationInputs;
typedef std::map<string, string> StringPairs;
enum struct DerivationType : uint8_t { enum struct DerivationType : uint8_t {
InputAddressed, InputAddressed,
DeferredInputAddressed, DeferredInputAddressed,
@ -103,7 +101,7 @@ struct BasicDerivation
{ {
DerivationOutputs outputs; /* keyed on symbolic IDs */ DerivationOutputs outputs; /* keyed on symbolic IDs */
StorePathSet inputSrcs; /* inputs that are sources */ StorePathSet inputSrcs; /* inputs that are sources */
string platform; std::string platform;
Path builder; Path builder;
Strings args; Strings args;
StringPairs env; StringPairs env;
@ -164,7 +162,7 @@ StorePath writeDerivation(Store & store,
Derivation parseDerivation(const Store & store, std::string && s, std::string_view name); Derivation parseDerivation(const Store & store, std::string && s, std::string_view name);
// FIXME: remove // FIXME: remove
bool isDerivation(const string & fileName); bool isDerivation(const std::string & fileName);
/* Calculate the name that will be used for the store path for this /* Calculate the name that will be used for the store path for this
output. output.
@ -222,7 +220,7 @@ typedef std::map<StorePath, DrvHashModulo> DrvHashes;
// FIXME: global, though at least thread-safe. // FIXME: global, though at least thread-safe.
extern Sync<DrvHashes> drvHashes; extern Sync<DrvHashes> drvHashes;
bool wantOutput(const string & output, const std::set<string> & wanted); bool wantOutput(const std::string & output, const std::set<std::string> & wanted);
struct Source; struct Source;
struct Sink; struct Sink;

View file

@ -75,9 +75,9 @@ DerivedPath::Built DerivedPath::Built::parse(const Store & store, std::string_vi
assert(n != s.npos); assert(n != s.npos);
auto drvPath = store.parseStorePath(s.substr(0, n)); auto drvPath = store.parseStorePath(s.substr(0, n));
auto outputsS = s.substr(n + 1); auto outputsS = s.substr(n + 1);
std::set<string> outputs; std::set<std::string> outputs;
if (outputsS != "*") if (outputsS != "*")
outputs = tokenizeString<std::set<string>>(outputsS, ","); outputs = tokenizeString<std::set<std::string>>(outputsS, ",");
return {drvPath, outputs}; return {drvPath, outputs};
} }

View file

@ -21,7 +21,7 @@ struct DummyStore : public virtual DummyStoreConfig, public virtual Store
, Store(params) , Store(params)
{ } { }
string getUri() override std::string getUri() override
{ {
return *uriSchemes().begin(); return *uriSchemes().begin();
} }
@ -43,8 +43,11 @@ struct DummyStore : public virtual DummyStoreConfig, public virtual Store
RepairFlag repair, CheckSigsFlag checkSigs) override RepairFlag repair, CheckSigsFlag checkSigs) override
{ unsupported("addToStore"); } { unsupported("addToStore"); }
StorePath addTextToStore(const string & name, const string & s, StorePath addTextToStore(
const StorePathSet & references, RepairFlag repair) override std::string_view name,
std::string_view s,
const StorePathSet & references,
RepairFlag repair) override
{ unsupported("addTextToStore"); } { unsupported("addTextToStore"); }
void narFromPath(const StorePath & path, Sink & sink) override void narFromPath(const StorePath & path, Sink & sink) override

View file

@ -33,12 +33,12 @@ FileTransferSettings fileTransferSettings;
static GlobalConfig::Register rFileTransferSettings(&fileTransferSettings); static GlobalConfig::Register rFileTransferSettings(&fileTransferSettings);
std::string resolveUri(const std::string & uri) std::string resolveUri(std::string_view uri)
{ {
if (uri.compare(0, 8, "channel:") == 0) if (uri.compare(0, 8, "channel:") == 0)
return "https://nixos.org/channels/" + std::string(uri, 8) + "/nixexprs.tar.xz"; return "https://nixos.org/channels/" + std::string(uri.substr(8)) + "/nixexprs.tar.xz";
else else
return uri; return std::string(uri);
} }
struct curlFileTransfer : public FileTransfer struct curlFileTransfer : public FileTransfer
@ -197,15 +197,15 @@ struct curlFileTransfer : public FileTransfer
result.etag = ""; result.etag = "";
result.data.clear(); result.data.clear();
result.bodySize = 0; result.bodySize = 0;
statusMsg = trim(match[1]); statusMsg = trim(match.str(1));
acceptRanges = false; acceptRanges = false;
encoding = ""; encoding = "";
} else { } else {
auto i = line.find(':'); auto i = line.find(':');
if (i != string::npos) { if (i != std::string::npos) {
string name = toLower(trim(string(line, 0, i))); std::string name = toLower(trim(line.substr(0, i)));
if (name == "etag") { if (name == "etag") {
result.etag = trim(string(line, i + 1)); result.etag = trim(line.substr(i + 1));
/* Hack to work around a GitHub bug: it sends /* Hack to work around a GitHub bug: it sends
ETags, but ignores If-None-Match. So if we get ETags, but ignores If-None-Match. So if we get
the expected ETag on a 200 response, then shut the expected ETag on a 200 response, then shut
@ -218,8 +218,8 @@ struct curlFileTransfer : public FileTransfer
return 0; return 0;
} }
} else if (name == "content-encoding") } else if (name == "content-encoding")
encoding = trim(string(line, i + 1)); encoding = trim(line.substr(i + 1));
else if (name == "accept-ranges" && toLower(trim(std::string(line, i + 1))) == "bytes") else if (name == "accept-ranges" && toLower(trim(line.substr(i + 1))) == "bytes")
acceptRanges = true; acceptRanges = true;
} }
} }
@ -866,18 +866,18 @@ FileTransferError::FileTransferError(FileTransfer::Error error, std::optional<st
// FIXME: Due to https://github.com/NixOS/nix/issues/3841 we don't know how // FIXME: Due to https://github.com/NixOS/nix/issues/3841 we don't know how
// to print different messages for different verbosity levels. For now // to print different messages for different verbosity levels. For now
// we add some heuristics for detecting when we want to show the response. // we add some heuristics for detecting when we want to show the response.
if (response && (response->size() < 1024 || response->find("<html>") != string::npos)) if (response && (response->size() < 1024 || response->find("<html>") != std::string::npos))
err.msg = hintfmt("%1%\n\nresponse body:\n\n%2%", normaltxt(hf.str()), chomp(*response)); err.msg = hintfmt("%1%\n\nresponse body:\n\n%2%", normaltxt(hf.str()), chomp(*response));
else else
err.msg = hf; err.msg = hf;
} }
bool isUri(const string & s) bool isUri(std::string_view s)
{ {
if (s.compare(0, 8, "channel:") == 0) return true; if (s.compare(0, 8, "channel:") == 0) return true;
size_t pos = s.find("://"); size_t pos = s.find("://");
if (pos == string::npos) return false; if (pos == std::string::npos) return false;
string scheme(s, 0, pos); std::string scheme(s, 0, pos);
return scheme == "http" || scheme == "https" || scheme == "file" || scheme == "channel" || scheme == "git" || scheme == "s3" || scheme == "ssh"; return scheme == "http" || scheme == "https" || scheme == "file" || scheme == "channel" || scheme == "git" || scheme == "s3" || scheme == "ssh";
} }

View file

@ -119,17 +119,17 @@ class FileTransferError : public Error
{ {
public: public:
FileTransfer::Error error; FileTransfer::Error error;
std::optional<string> response; // intentionally optional std::optional<std::string> response; // intentionally optional
template<typename... Args> template<typename... Args>
FileTransferError(FileTransfer::Error error, std::optional<string> response, const Args & ... args); FileTransferError(FileTransfer::Error error, std::optional<std::string> response, const Args & ... args);
virtual const char* sname() const override { return "FileTransferError"; } virtual const char* sname() const override { return "FileTransferError"; }
}; };
bool isUri(const string & s); bool isUri(std::string_view s);
/* Resolve deprecated 'channel:<foo>' URLs. */ /* Resolve deprecated 'channel:<foo>' URLs. */
std::string resolveUri(const std::string & uri); std::string resolveUri(std::string_view uri);
} }

13
src/libstore/gc-store.cc Normal file
View file

@ -0,0 +1,13 @@
#include "gc-store.hh"
namespace nix {
GcStore & requireGcStore(Store & store)
{
auto * gcStore = dynamic_cast<GcStore *>(&store);
if (!gcStore)
throw UsageError("Garbage collection not supported by this store");
return *gcStore;
}
}

84
src/libstore/gc-store.hh Normal file
View file

@ -0,0 +1,84 @@
#pragma once
#include "store-api.hh"
namespace nix {
typedef std::unordered_map<StorePath, std::unordered_set<std::string>> Roots;
struct GCOptions
{
/* Garbage collector operation:
- `gcReturnLive': return the set of paths reachable from
(i.e. in the closure of) the roots.
- `gcReturnDead': return the set of paths not reachable from
the roots.
- `gcDeleteDead': actually delete the latter set.
- `gcDeleteSpecific': delete the paths listed in
`pathsToDelete', insofar as they are not reachable.
*/
typedef enum {
gcReturnLive,
gcReturnDead,
gcDeleteDead,
gcDeleteSpecific,
} GCAction;
GCAction action{gcDeleteDead};
/* If `ignoreLiveness' is set, then reachability from the roots is
ignored (dangerous!). However, the paths must still be
unreferenced *within* the store (i.e., there can be no other
store paths that depend on them). */
bool ignoreLiveness{false};
/* For `gcDeleteSpecific', the paths to delete. */
StorePathSet pathsToDelete;
/* Stop after at least `maxFreed' bytes have been freed. */
uint64_t maxFreed{std::numeric_limits<uint64_t>::max()};
};
struct GCResults
{
/* Depending on the action, the GC roots, or the paths that would
be or have been deleted. */
PathSet paths;
/* For `gcReturnDead', `gcDeleteDead' and `gcDeleteSpecific', the
number of bytes that would be or was freed. */
uint64_t bytesFreed = 0;
};
struct GcStore : public virtual Store
{
/* Add an indirect root, which is merely a symlink to `path' from
/nix/var/nix/gcroots/auto/<hash of `path'>. `path' is supposed
to be a symlink to a store path. The garbage collector will
automatically remove the indirect root when it finds that
`path' has disappeared. */
virtual void addIndirectRoot(const Path & path) = 0;
/* Find the roots of the garbage collector. Each root is a pair
(link, storepath) where `link' is the path of the symlink
outside of the Nix store that point to `storePath'. If
'censor' is true, privacy-sensitive information about roots
found in /proc is censored. */
virtual Roots findRoots(bool censor) = 0;
/* Perform a garbage collection. */
virtual void collectGarbage(const GCOptions & options, GCResults & results) = 0;
};
GcStore & requireGcStore(Store & store);
}

View file

@ -47,9 +47,8 @@ static void makeSymlink(const Path & link, const Path & target)
void LocalStore::addIndirectRoot(const Path & path) void LocalStore::addIndirectRoot(const Path & path)
{ {
string hash = hashString(htSHA1, path).to_string(Base32, false); std::string hash = hashString(htSHA1, path).to_string(Base32, false);
Path realRoot = canonPath((format("%1%/%2%/auto/%3%") Path realRoot = canonPath(fmt("%1%/%2%/auto/%3%", stateDir, gcRootsDir, hash));
% stateDir % gcRootsDir % hash).str());
makeSymlink(realRoot, path); makeSymlink(realRoot, path);
} }
@ -162,7 +161,7 @@ void LocalStore::addTempRoot(const StorePath & path)
} }
/* Append the store path to the temporary roots file. */ /* Append the store path to the temporary roots file. */
string s = printStorePath(path) + '\0'; auto s = printStorePath(path) + '\0';
writeFull(state->fdTempRoots.get(), s); writeFull(state->fdTempRoots.get(), s);
} }
@ -203,12 +202,12 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor)
} }
/* Read the entire file. */ /* Read the entire file. */
string contents = readFile(fd.get()); auto contents = readFile(fd.get());
/* Extract the roots. */ /* Extract the roots. */
string::size_type pos = 0, end; std::string::size_type pos = 0, end;
while ((end = contents.find((char) 0, pos)) != string::npos) { while ((end = contents.find((char) 0, pos)) != std::string::npos) {
Path root(contents, pos, end - pos); Path root(contents, pos, end - pos);
debug("got temporary root '%s'", root); debug("got temporary root '%s'", root);
tempRoots[parseStorePath(root)].emplace(censor ? censored : fmt("{temp:%d}", pid)); tempRoots[parseStorePath(root)].emplace(censor ? censored : fmt("{temp:%d}", pid));
@ -305,7 +304,7 @@ Roots LocalStore::findRoots(bool censor)
typedef std::unordered_map<Path, std::unordered_set<std::string>> UncheckedRoots; typedef std::unordered_map<Path, std::unordered_set<std::string>> UncheckedRoots;
static void readProcLink(const string & file, UncheckedRoots & roots) static void readProcLink(const std::string & file, UncheckedRoots & roots)
{ {
/* 64 is the starting buffer size gnu readlink uses... */ /* 64 is the starting buffer size gnu readlink uses... */
auto bufsiz = ssize_t{64}; auto bufsiz = ssize_t{64};
@ -328,7 +327,7 @@ try_again:
.emplace(file); .emplace(file);
} }
static string quoteRegexChars(const string & raw) static std::string quoteRegexChars(const std::string & raw)
{ {
static auto specialRegex = std::regex(R"([.^$\\*+?()\[\]{}|])"); static auto specialRegex = std::regex(R"([.^$\\*+?()\[\]{}|])");
return std::regex_replace(raw, specialRegex, R"(\$&)"); return std::regex_replace(raw, specialRegex, R"(\$&)");
@ -383,7 +382,7 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
try { try {
auto mapFile = fmt("/proc/%s/maps", ent->d_name); auto mapFile = fmt("/proc/%s/maps", ent->d_name);
auto mapLines = tokenizeString<std::vector<string>>(readFile(mapFile), "\n"); auto mapLines = tokenizeString<std::vector<std::string>>(readFile(mapFile), "\n");
for (const auto & line : mapLines) { for (const auto & line : mapLines) {
auto match = std::smatch{}; auto match = std::smatch{};
if (std::regex_match(line, match, mapRegex)) if (std::regex_match(line, match, mapRegex))
@ -414,7 +413,7 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
try { try {
std::regex lsofRegex(R"(^n(/.*)$)"); std::regex lsofRegex(R"(^n(/.*)$)");
auto lsofLines = auto lsofLines =
tokenizeString<std::vector<string>>(runProgram(LSOF, true, { "-n", "-w", "-F", "n" }), "\n"); tokenizeString<std::vector<std::string>>(runProgram(LSOF, true, { "-n", "-w", "-F", "n" }), "\n");
for (const auto & line : lsofLines) { for (const auto & line : lsofLines) {
std::smatch match; std::smatch match;
if (std::regex_match(line, match, lsofRegex)) if (std::regex_match(line, match, lsofRegex))
@ -784,7 +783,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
struct dirent * dirent; struct dirent * dirent;
while (errno = 0, dirent = readdir(dir.get())) { while (errno = 0, dirent = readdir(dir.get())) {
checkInterrupt(); checkInterrupt();
string name = dirent->d_name; std::string name = dirent->d_name;
if (name == "." || name == ".." || name == linksName) continue; if (name == "." || name == ".." || name == linksName) continue;
if (auto storePath = maybeParseStorePath(storeDir + "/" + name)) if (auto storePath = maybeParseStorePath(storeDir + "/" + name))
@ -825,7 +824,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
struct dirent * dirent; struct dirent * dirent;
while (errno = 0, dirent = readdir(dir.get())) { while (errno = 0, dirent = readdir(dir.get())) {
checkInterrupt(); checkInterrupt();
string name = dirent->d_name; std::string name = dirent->d_name;
if (name == "." || name == "..") continue; if (name == "." || name == "..") continue;
Path path = linksDir + "/" + name; Path path = linksDir + "/" + name;

View file

@ -100,7 +100,7 @@ std::vector<Path> getUserConfigFiles()
// Use the paths specified in NIX_USER_CONF_FILES if it has been defined // Use the paths specified in NIX_USER_CONF_FILES if it has been defined
auto nixConfFiles = getEnv("NIX_USER_CONF_FILES"); auto nixConfFiles = getEnv("NIX_USER_CONF_FILES");
if (nixConfFiles.has_value()) { if (nixConfFiles.has_value()) {
return tokenizeString<std::vector<string>>(nixConfFiles.value(), ":"); return tokenizeString<std::vector<std::string>>(nixConfFiles.value(), ":");
} }
// Use the paths specified by the XDG spec // Use the paths specified by the XDG spec
@ -180,7 +180,7 @@ bool Settings::isWSL1()
return hasSuffix(utsbuf.release, "-Microsoft"); return hasSuffix(utsbuf.release, "-Microsoft");
} }
const string nixVersion = PACKAGE_VERSION; const std::string nixVersion = PACKAGE_VERSION;
NLOHMANN_JSON_SERIALIZE_ENUM(SandboxMode, { NLOHMANN_JSON_SERIALIZE_ENUM(SandboxMode, {
{SandboxMode::smEnabled, true}, {SandboxMode::smEnabled, true},

View file

@ -113,7 +113,7 @@ public:
bool verboseBuild = true; bool verboseBuild = true;
Setting<size_t> logLines{this, 10, "log-lines", Setting<size_t> logLines{this, 10, "log-lines",
"If `verbose-build` is false, the number of lines of the tail of " "The number of lines of the tail of "
"the log to show if a build fails."}; "the log to show if a build fails."};
MaxBuildJobsSetting maxBuildJobs{ MaxBuildJobsSetting maxBuildJobs{
@ -880,55 +880,6 @@ public:
are loaded as plugins (non-recursively). are loaded as plugins (non-recursively).
)"}; )"};
Setting<StringMap> accessTokens{this, {}, "access-tokens",
R"(
Access tokens used to access protected GitHub, GitLab, or
other locations requiring token-based authentication.
Access tokens are specified as a string made up of
space-separated `host=token` values. The specific token
used is selected by matching the `host` portion against the
"host" specification of the input. The actual use of the
`token` value is determined by the type of resource being
accessed:
* Github: the token value is the OAUTH-TOKEN string obtained
as the Personal Access Token from the Github server (see
https://docs.github.com/en/developers/apps/authorizing-oath-apps).
* Gitlab: the token value is either the OAuth2 token or the
Personal Access Token (these are different types tokens
for gitlab, see
https://docs.gitlab.com/12.10/ee/api/README.html#authentication).
The `token` value should be `type:tokenstring` where
`type` is either `OAuth2` or `PAT` to indicate which type
of token is being specified.
Example `~/.config/nix/nix.conf`:
```
access-tokens = github.com=23ac...b289 gitlab.mycompany.com=PAT:A123Bp_Cd..EfG gitlab.com=OAuth2:1jklw3jk
```
Example `~/code/flake.nix`:
```nix
input.foo = {
type = "gitlab";
host = "gitlab.mycompany.com";
owner = "mycompany";
repo = "pro";
};
```
This example specifies three tokens, one each for accessing
github.com, gitlab.mycompany.com, and sourceforge.net.
The `input.foo` uses the "gitlab" fetcher, which might
requires specifying the token type along with the token
value.
)"};
Setting<std::set<ExperimentalFeature>> experimentalFeatures{this, {}, "experimental-features", Setting<std::set<ExperimentalFeature>> experimentalFeatures{this, {}, "experimental-features",
"Experimental Nix features to enable."}; "Experimental Nix features to enable."};
@ -936,18 +887,9 @@ public:
void requireExperimentalFeature(const ExperimentalFeature &); void requireExperimentalFeature(const ExperimentalFeature &);
Setting<bool> allowDirty{this, true, "allow-dirty",
"Whether to allow dirty Git/Mercurial trees."};
Setting<bool> warnDirty{this, true, "warn-dirty",
"Whether to warn about dirty Git/Mercurial trees."};
Setting<size_t> narBufferSize{this, 32 * 1024 * 1024, "nar-buffer-size", Setting<size_t> narBufferSize{this, 32 * 1024 * 1024, "nar-buffer-size",
"Maximum size of NARs before spilling them to disk."}; "Maximum size of NARs before spilling them to disk."};
Setting<std::string> flakeRegistry{this, "https://github.com/NixOS/flake-registry/raw/master/flake-registry.json", "flake-registry",
"Path or URI of the global flake registry."};
Setting<bool> allowSymlinkedStore{ Setting<bool> allowSymlinkedStore{
this, false, "allow-symlinked-store", this, false, "allow-symlinked-store",
R"( R"(
@ -960,19 +902,6 @@ public:
resolves to a different location from that of the build machine. You resolves to a different location from that of the build machine. You
can enable this setting if you are sure you're not going to do that. can enable this setting if you are sure you're not going to do that.
)"}; )"};
Setting<bool> useRegistries{this, true, "use-registries",
"Whether to use flake registries to resolve flake references."};
Setting<bool> acceptFlakeConfig{this, false, "accept-flake-config",
"Whether to accept nix configuration from a flake without prompting."};
Setting<std::string> commitLockFileSummary{
this, "", "commit-lockfile-summary",
R"(
The commit summary to use when committing changed flake lock files. If
empty, the summary is generated based on the action performed.
)"};
}; };
@ -988,6 +917,6 @@ void loadConfFile();
// Used by the Settings constructor // Used by the Settings constructor
std::vector<Path> getUserConfigFiles(); std::vector<Path> getUserConfigFiles();
extern const string nixVersion; extern const std::string nixVersion;
} }

View file

@ -2,6 +2,7 @@
#include "pool.hh" #include "pool.hh"
#include "remote-store.hh" #include "remote-store.hh"
#include "serve-protocol.hh" #include "serve-protocol.hh"
#include "build-result.hh"
#include "store-api.hh" #include "store-api.hh"
#include "path-with-outputs.hh" #include "path-with-outputs.hh"
#include "worker-protocol.hh" #include "worker-protocol.hh"
@ -48,7 +49,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
static std::set<std::string> uriSchemes() { return {"ssh"}; } static std::set<std::string> uriSchemes() { return {"ssh"}; }
LegacySSHStore(const string & scheme, const string & host, const Params & params) LegacySSHStore(const std::string & scheme, const std::string & host, const Params & params)
: StoreConfig(params) : StoreConfig(params)
, LegacySSHStoreConfig(params) , LegacySSHStoreConfig(params)
, Store(params) , Store(params)
@ -107,7 +108,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
return conn; return conn;
}; };
string getUri() override std::string getUri() override
{ {
return *uriSchemes().begin() + "://" + host; return *uriSchemes().begin() + "://" + host;
} }
@ -225,13 +226,21 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
{ unsupported("queryPathFromHashPart"); } { unsupported("queryPathFromHashPart"); }
StorePath addToStore(const string & name, const Path & srcPath, StorePath addToStore(
FileIngestionMethod method, HashType hashAlgo, std::string_view name,
PathFilter & filter, RepairFlag repair, const StorePathSet & references) override const Path & srcPath,
FileIngestionMethod method,
HashType hashAlgo,
PathFilter & filter,
RepairFlag repair,
const StorePathSet & references) override
{ unsupported("addToStore"); } { unsupported("addToStore"); }
StorePath addTextToStore(const string & name, const string & s, StorePath addTextToStore(
const StorePathSet & references, RepairFlag repair) override std::string_view name,
std::string_view s,
const StorePathSet & references,
RepairFlag repair) override
{ unsupported("addTextToStore"); } { unsupported("addTextToStore"); }
private: private:

View file

@ -85,7 +85,7 @@ void LocalFSStore::narFromPath(const StorePath & path, Sink & sink)
dumpPath(getRealStoreDir() + std::string(printStorePath(path), storeDir.size()), sink); dumpPath(getRealStoreDir() + std::string(printStorePath(path), storeDir.size()), sink);
} }
const string LocalFSStore::drvsLogDir = "drvs"; const std::string LocalFSStore::drvsLogDir = "drvs";
std::optional<std::string> LocalFSStore::getBuildLog(const StorePath & path_) std::optional<std::string> LocalFSStore::getBuildLog(const StorePath & path_)
{ {

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "store-api.hh" #include "store-api.hh"
#include "gc-store.hh"
namespace nix { namespace nix {
@ -23,11 +24,11 @@ struct LocalFSStoreConfig : virtual StoreConfig
"physical path to the Nix store"}; "physical path to the Nix store"};
}; };
class LocalFSStore : public virtual LocalFSStoreConfig, public virtual Store class LocalFSStore : public virtual LocalFSStoreConfig, public virtual Store, virtual GcStore
{ {
public: public:
const static string drvsLogDir; const static std::string drvsLogDir;
LocalFSStore(const Params & params); LocalFSStore(const Params & params);

View file

@ -70,7 +70,7 @@ int getSchema(Path schemaPath)
{ {
int curSchema = 0; int curSchema = 0;
if (pathExists(schemaPath)) { if (pathExists(schemaPath)) {
string s = readFile(schemaPath); auto s = readFile(schemaPath);
auto n = string2Int<int>(s); auto n = string2Int<int>(s);
if (!n) if (!n)
throw Error("'%1%' is corrupt", schemaPath); throw Error("'%1%' is corrupt", schemaPath);
@ -239,7 +239,7 @@ LocalStore::LocalStore(const Params & params)
res = posix_fallocate(fd.get(), 0, settings.reservedSize); res = posix_fallocate(fd.get(), 0, settings.reservedSize);
#endif #endif
if (res == -1) { if (res == -1) {
writeFull(fd.get(), string(settings.reservedSize, 'X')); writeFull(fd.get(), std::string(settings.reservedSize, 'X'));
[[gnu::unused]] auto res2 = ftruncate(fd.get(), settings.reservedSize); [[gnu::unused]] auto res2 = ftruncate(fd.get(), settings.reservedSize);
} }
} }
@ -450,7 +450,7 @@ void LocalStore::openDB(State & state, bool create)
throw SysError("Nix database directory '%1%' is not writable", dbDir); throw SysError("Nix database directory '%1%' is not writable", dbDir);
/* Open the Nix database. */ /* Open the Nix database. */
string dbPath = dbDir + "/db.sqlite"; std::string dbPath = dbDir + "/db.sqlite";
auto & db(state.db); auto & db(state.db);
state.db = SQLite(dbPath, create); state.db = SQLite(dbPath, create);
@ -471,19 +471,19 @@ void LocalStore::openDB(State & state, bool create)
should be safe enough. If the user asks for it, don't sync at should be safe enough. If the user asks for it, don't sync at
all. This can cause database corruption if the system all. This can cause database corruption if the system
crashes. */ crashes. */
string syncMode = settings.fsyncMetadata ? "normal" : "off"; std::string syncMode = settings.fsyncMetadata ? "normal" : "off";
db.exec("pragma synchronous = " + syncMode); db.exec("pragma synchronous = " + syncMode);
/* Set the SQLite journal mode. WAL mode is fastest, so it's the /* Set the SQLite journal mode. WAL mode is fastest, so it's the
default. */ default. */
string mode = settings.useSQLiteWAL ? "wal" : "truncate"; std::string mode = settings.useSQLiteWAL ? "wal" : "truncate";
string prevMode; std::string prevMode;
{ {
SQLiteStmt stmt; SQLiteStmt stmt;
stmt.create(db, "pragma main.journal_mode;"); stmt.create(db, "pragma main.journal_mode;");
if (sqlite3_step(stmt) != SQLITE_ROW) if (sqlite3_step(stmt) != SQLITE_ROW)
throwSQLiteError(db, "querying journal mode"); throwSQLiteError(db, "querying journal mode");
prevMode = string((const char *) sqlite3_column_text(stmt, 0)); prevMode = std::string((const char *) sqlite3_column_text(stmt, 0));
} }
if (prevMode != mode && if (prevMode != mode &&
sqlite3_exec(db, ("pragma main.journal_mode = " + mode + ";").c_str(), 0, 0, 0) != SQLITE_OK) sqlite3_exec(db, ("pragma main.journal_mode = " + mode + ";").c_str(), 0, 0, 0) != SQLITE_OK)
@ -679,7 +679,7 @@ void LocalStore::checkDerivationOutputs(const StorePath & drvPath, const Derivat
{ {
assert(drvPath.isDerivation()); assert(drvPath.isDerivation());
std::string drvName(drvPath.name()); std::string drvName(drvPath.name());
drvName = string(drvName, 0, drvName.size() - drvExtension.size()); drvName = drvName.substr(0, drvName.size() - drvExtension.size());
auto envHasRightPath = [&](const StorePath & actual, const std::string & varName) auto envHasRightPath = [&](const StorePath & actual, const std::string & varName)
{ {
@ -786,7 +786,11 @@ void LocalStore::registerDrvOutput(const Realisation & info)
}); });
} }
void LocalStore::cacheDrvOutputMapping(State & state, const uint64_t deriver, const string & outputName, const StorePath & output) void LocalStore::cacheDrvOutputMapping(
State & state,
const uint64_t deriver,
const std::string & outputName,
const StorePath & output)
{ {
retrySQLite<void>([&]() { retrySQLite<void>([&]() {
state.stmts->AddDerivationOutput.use() state.stmts->AddDerivationOutput.use()
@ -795,7 +799,6 @@ void LocalStore::cacheDrvOutputMapping(State & state, const uint64_t deriver, co
(printStorePath(output)) (printStorePath(output))
.exec(); .exec();
}); });
} }
@ -1436,7 +1439,9 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name
} }
StorePath LocalStore::addTextToStore(const string & name, const string & s, StorePath LocalStore::addTextToStore(
std::string_view name,
std::string_view s,
const StorePathSet & references, RepairFlag repair) const StorePathSet & references, RepairFlag repair)
{ {
auto hash = hashString(htSHA256, s); auto hash = hashString(htSHA256, s);
@ -1548,7 +1553,7 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
for (auto & link : readDirectory(linksDir)) { for (auto & link : readDirectory(linksDir)) {
printMsg(lvlTalkative, "checking contents of '%s'", link.name); printMsg(lvlTalkative, "checking contents of '%s'", link.name);
Path linkPath = linksDir + "/" + link.name; Path linkPath = linksDir + "/" + link.name;
string hash = hashPath(htSHA256, linkPath).first.to_string(Base32, false); std::string hash = hashPath(htSHA256, linkPath).first.to_string(Base32, false);
if (hash != link.name) { if (hash != link.name) {
printError("link '%s' was modified! expected hash '%s', got '%s'", printError("link '%s' was modified! expected hash '%s', got '%s'",
linkPath, link.name, hash); linkPath, link.name, hash);

View file

@ -5,6 +5,7 @@
#include "pathlocks.hh" #include "pathlocks.hh"
#include "store-api.hh" #include "store-api.hh"
#include "local-fs-store.hh" #include "local-fs-store.hh"
#include "gc-store.hh"
#include "sync.hh" #include "sync.hh"
#include "util.hh" #include "util.hh"
@ -43,7 +44,7 @@ struct LocalStoreConfig : virtual LocalFSStoreConfig
}; };
class LocalStore : public virtual LocalStoreConfig, public virtual LocalFSStore class LocalStore : public virtual LocalStoreConfig, public virtual LocalFSStore, public virtual GcStore
{ {
private: private:
@ -147,8 +148,11 @@ public:
StorePath addToStoreFromDump(Source & dump, std::string_view name, StorePath addToStoreFromDump(Source & dump, std::string_view name,
FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references) override; FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references) override;
StorePath addTextToStore(const string & name, const string & s, StorePath addTextToStore(
const StorePathSet & references, RepairFlag repair) override; std::string_view name,
std::string_view s,
const StorePathSet & references,
RepairFlag repair) override;
void addTempRoot(const StorePath & path) override; void addTempRoot(const StorePath & path) override;
@ -204,7 +208,11 @@ public:
derivation 'deriver'. */ derivation 'deriver'. */
void registerDrvOutput(const Realisation & info) override; void registerDrvOutput(const Realisation & info) override;
void registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs) override; void registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs) override;
void cacheDrvOutputMapping(State & state, const uint64_t deriver, const string & outputName, const StorePath & output); void cacheDrvOutputMapping(
State & state,
const uint64_t deriver,
const std::string & outputName,
const StorePath & output);
std::optional<const Realisation> queryRealisation_(State & state, const DrvOutput & id); std::optional<const Realisation> queryRealisation_(State & state, const DrvOutput & id);
std::optional<std::pair<int64_t, Realisation>> queryRealisationCore_(State & state, const DrvOutput & id); std::optional<std::pair<int64_t, Realisation>> queryRealisationCore_(State & state, const DrvOutput & id);

View file

@ -13,7 +13,7 @@ private:
AutoCloseFD fdUserLock; AutoCloseFD fdUserLock;
bool isEnabled = false; bool isEnabled = false;
string user; std::string user;
uid_t uid = 0; uid_t uid = 0;
gid_t gid = 0; gid_t gid = 0;
std::vector<gid_t> supplementaryGIDs; std::vector<gid_t> supplementaryGIDs;
@ -23,7 +23,7 @@ public:
void kill(); void kill();
string getUser() { return user; } std::string getUser() { return user; }
uid_t getUID() { assert(uid); return uid; } uid_t getUID() { assert(uid); return uid; }
uid_t getGID() { assert(gid); return gid; } uid_t getGID() { assert(gid); return gid; }
std::vector<gid_t> getSupplementaryGIDs() { return supplementaryGIDs; } std::vector<gid_t> getSupplementaryGIDs() { return supplementaryGIDs; }

View file

@ -39,19 +39,19 @@ Machine::Machine(decltype(storeUri) storeUri,
sshPublicHostKey(sshPublicHostKey) sshPublicHostKey(sshPublicHostKey)
{} {}
bool Machine::allSupported(const std::set<string> & features) const bool Machine::allSupported(const std::set<std::string> & features) const
{ {
return std::all_of(features.begin(), features.end(), return std::all_of(features.begin(), features.end(),
[&](const string & feature) { [&](const std::string & feature) {
return supportedFeatures.count(feature) || return supportedFeatures.count(feature) ||
mandatoryFeatures.count(feature); mandatoryFeatures.count(feature);
}); });
} }
bool Machine::mandatoryMet(const std::set<string> & features) const bool Machine::mandatoryMet(const std::set<std::string> & features) const
{ {
return std::all_of(mandatoryFeatures.begin(), mandatoryFeatures.end(), return std::all_of(mandatoryFeatures.begin(), mandatoryFeatures.end(),
[&](const string & feature) { [&](const std::string & feature) {
return features.count(feature); return features.count(feature);
}); });
} }
@ -89,7 +89,7 @@ ref<Store> Machine::openStore() const
static std::vector<std::string> expandBuilderLines(const std::string & builders) static std::vector<std::string> expandBuilderLines(const std::string & builders)
{ {
std::vector<std::string> result; std::vector<std::string> result;
for (auto line : tokenizeString<std::vector<string>>(builders, "\n;")) { for (auto line : tokenizeString<std::vector<std::string>>(builders, "\n;")) {
trim(line); trim(line);
line.erase(std::find(line.begin(), line.end(), '#'), line.end()); line.erase(std::find(line.begin(), line.end(), '#'), line.end());
if (line.empty()) continue; if (line.empty()) continue;
@ -117,7 +117,7 @@ static std::vector<std::string> expandBuilderLines(const std::string & builders)
static Machine parseBuilderLine(const std::string & line) static Machine parseBuilderLine(const std::string & line)
{ {
const auto tokens = tokenizeString<std::vector<string>>(line); const auto tokens = tokenizeString<std::vector<std::string>>(line);
auto isSet = [&](size_t fieldIndex) { auto isSet = [&](size_t fieldIndex) {
return tokens.size() > fieldIndex && tokens[fieldIndex] != "" && tokens[fieldIndex] != "-"; return tokens.size() > fieldIndex && tokens[fieldIndex] != "" && tokens[fieldIndex] != "-";
@ -146,17 +146,18 @@ static Machine parseBuilderLine(const std::string & line)
return { return {
tokens[0], tokens[0],
isSet(1) ? tokenizeString<std::vector<string>>(tokens[1], ",") : std::vector<string>{settings.thisSystem}, isSet(1) ? tokenizeString<std::vector<std::string>>(tokens[1], ",") : std::vector<std::string>{settings.thisSystem},
isSet(2) ? tokens[2] : "", isSet(2) ? tokens[2] : "",
isSet(3) ? parseUnsignedIntField(3) : 1U, isSet(3) ? parseUnsignedIntField(3) : 1U,
isSet(4) ? parseUnsignedIntField(4) : 1U, isSet(4) ? parseUnsignedIntField(4) : 1U,
isSet(5) ? tokenizeString<std::set<string>>(tokens[5], ",") : std::set<string>{}, isSet(5) ? tokenizeString<std::set<std::string>>(tokens[5], ",") : std::set<std::string>{},
isSet(6) ? tokenizeString<std::set<string>>(tokens[6], ",") : std::set<string>{}, isSet(6) ? tokenizeString<std::set<std::string>>(tokens[6], ",") : std::set<std::string>{},
isSet(7) ? ensureBase64(7) : "" isSet(7) ? ensureBase64(7) : ""
}; };
} }
static Machines parseBuilderLines(const std::vector<std::string>& builders) { static Machines parseBuilderLines(const std::vector<std::string> & builders)
{
Machines result; Machines result;
std::transform(builders.begin(), builders.end(), std::back_inserter(result), parseBuilderLine); std::transform(builders.begin(), builders.end(), std::back_inserter(result), parseBuilderLine);
return result; return result;

View file

@ -90,7 +90,7 @@ struct NarAccessor : public FSAccessor
void receiveContents(std::string_view data) override void receiveContents(std::string_view data) override
{ } { }
void createSymlink(const Path & path, const string & target) override void createSymlink(const Path & path, const std::string & target) override
{ {
createMember(path, createMember(path,
NarMember{FSAccessor::Type::tSymlink, false, 0, 0, target}); NarMember{FSAccessor::Type::tSymlink, false, 0, 0, target});

View file

@ -11,7 +11,7 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
return Error("NAR info file '%1%' is corrupt", whence); return Error("NAR info file '%1%' is corrupt", whence);
}; };
auto parseHashField = [&](const string & s) { auto parseHashField = [&](const std::string & s) {
try { try {
return Hash::parseAnyPrefixed(s); return Hash::parseAnyPrefixed(s);
} catch (BadHash &) { } catch (BadHash &) {

View file

@ -77,7 +77,7 @@ Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHa
continue; continue;
} }
string name = dirent->d_name; std::string name = dirent->d_name;
if (name == "." || name == "..") continue; if (name == "." || name == "..") continue;
names.push_back(name); names.push_back(name);
} }

View file

@ -22,9 +22,9 @@ DerivedPath StorePathWithOutputs::toDerivedPath() const
std::vector<DerivedPath> toDerivedPaths(const std::vector<StorePathWithOutputs> ss) std::vector<DerivedPath> toDerivedPaths(const std::vector<StorePathWithOutputs> ss)
{ {
std::vector<DerivedPath> reqs; std::vector<DerivedPath> reqs;
for (auto & s : ss) reqs.push_back(s.toDerivedPath()); for (auto & s : ss) reqs.push_back(s.toDerivedPath());
return reqs; return reqs;
} }
@ -49,9 +49,9 @@ std::pair<std::string_view, StringSet> parsePathWithOutputs(std::string_view s)
{ {
size_t n = s.find("!"); size_t n = s.find("!");
return n == s.npos return n == s.npos
? std::make_pair(s, std::set<string>()) ? std::make_pair(s, std::set<std::string>())
: std::make_pair(((std::string_view) s).substr(0, n), : std::make_pair(((std::string_view) s).substr(0, n),
tokenizeString<std::set<string>>(((std::string_view) s).substr(n + 1), ",")); tokenizeString<std::set<std::string>>(((std::string_view) s).substr(n + 1), ","));
} }

View file

@ -62,7 +62,7 @@ public:
typedef std::set<StorePath> StorePathSet; typedef std::set<StorePath> StorePathSet;
typedef std::vector<StorePath> StorePaths; typedef std::vector<StorePath> StorePaths;
typedef std::map<string, StorePath> OutputPathMap; typedef std::map<std::string, StorePath> OutputPathMap;
typedef std::map<StorePath, std::optional<ContentAddress>> StorePathCAMap; typedef std::map<StorePath, std::optional<ContentAddress>> StorePathCAMap;

View file

@ -74,7 +74,7 @@ PathLocks::PathLocks()
} }
PathLocks::PathLocks(const PathSet & paths, const string & waitMsg) PathLocks::PathLocks(const PathSet & paths, const std::string & waitMsg)
: deletePaths(false) : deletePaths(false)
{ {
lockPaths(paths, waitMsg); lockPaths(paths, waitMsg);
@ -82,7 +82,7 @@ PathLocks::PathLocks(const PathSet & paths, const string & waitMsg)
bool PathLocks::lockPaths(const PathSet & paths, bool PathLocks::lockPaths(const PathSet & paths,
const string & waitMsg, bool wait) const std::string & waitMsg, bool wait)
{ {
assert(fds.empty()); assert(fds.empty());

View file

@ -26,9 +26,9 @@ private:
public: public:
PathLocks(); PathLocks();
PathLocks(const PathSet & paths, PathLocks(const PathSet & paths,
const string & waitMsg = ""); const std::string & waitMsg = "");
bool lockPaths(const PathSet & _paths, bool lockPaths(const PathSet & _paths,
const string & waitMsg = "", const std::string & waitMsg = "",
bool wait = true); bool wait = true);
~PathLocks(); ~PathLocks();
void unlock(); void unlock();

View file

@ -15,12 +15,12 @@ namespace nix {
/* Parse a generation name of the format /* Parse a generation name of the format
`<profilename>-<number>-link'. */ `<profilename>-<number>-link'. */
static std::optional<GenerationNumber> parseName(const string & profileName, const string & name) static std::optional<GenerationNumber> parseName(const std::string & profileName, const std::string & name)
{ {
if (string(name, 0, profileName.size() + 1) != profileName + "-") return {}; if (name.substr(0, profileName.size() + 1) != profileName + "-") return {};
string s = string(name, profileName.size() + 1); auto s = name.substr(profileName.size() + 1);
string::size_type p = s.find("-link"); auto p = s.find("-link");
if (p == string::npos) return {}; if (p == std::string::npos) return {};
if (auto n = string2Int<unsigned int>(s.substr(0, p))) if (auto n = string2Int<unsigned int>(s.substr(0, p)))
return *n; return *n;
else else
@ -209,13 +209,13 @@ void deleteGenerationsOlderThan(const Path & profile, time_t t, bool dryRun)
} }
void deleteGenerationsOlderThan(const Path & profile, const string & timeSpec, bool dryRun) void deleteGenerationsOlderThan(const Path & profile, std::string_view timeSpec, bool dryRun)
{ {
if (timeSpec.empty() || timeSpec[timeSpec.size() - 1] != 'd') if (timeSpec.empty() || timeSpec[timeSpec.size() - 1] != 'd')
throw UsageError("invalid number of days specifier '%1%', expected something like '14d'", timeSpec); throw UsageError("invalid number of days specifier '%1%', expected something like '14d'", timeSpec);
time_t curTime = time(0); time_t curTime = time(0);
string strDays = string(timeSpec, 0, timeSpec.size() - 1); auto strDays = timeSpec.substr(0, timeSpec.size() - 1);
auto days = string2Int<int>(strDays); auto days = string2Int<int>(strDays);
if (!days || *days < 1) if (!days || *days < 1)
@ -274,7 +274,7 @@ void lockProfile(PathLocks & lock, const Path & profile)
} }
string optimisticLockProfile(const Path & profile) std::string optimisticLockProfile(const Path & profile)
{ {
return pathExists(profile) ? readLink(profile) : ""; return pathExists(profile) ? readLink(profile) : "";
} }

View file

@ -42,7 +42,7 @@ void deleteOldGenerations(const Path & profile, bool dryRun);
void deleteGenerationsOlderThan(const Path & profile, time_t t, bool dryRun); void deleteGenerationsOlderThan(const Path & profile, time_t t, bool dryRun);
void deleteGenerationsOlderThan(const Path & profile, const string & timeSpec, bool dryRun); void deleteGenerationsOlderThan(const Path & profile, std::string_view timeSpec, bool dryRun);
void switchLink(Path link, Path target); void switchLink(Path link, Path target);
@ -66,7 +66,7 @@ void lockProfile(PathLocks & lock, const Path & profile);
generally cheap, since the build results are still in the Nix generally cheap, since the build results are still in the Nix
store. Most of the time, only the user environment has to be store. Most of the time, only the user environment has to be
rebuilt. */ rebuilt. */
string optimisticLockProfile(const Path & profile); std::string optimisticLockProfile(const Path & profile);
/* Resolve ~/.nix-profile. If ~/.nix-profile doesn't exist yet, create /* Resolve ~/.nix-profile. If ~/.nix-profile doesn't exist yet, create
it. */ it. */

View file

@ -68,7 +68,7 @@ void RefScanSink::operator () (std::string_view data)
std::pair<StorePathSet, HashResult> scanForReferences( std::pair<StorePathSet, HashResult> scanForReferences(
const string & path, const std::string & path,
const StorePathSet & refs) const StorePathSet & refs)
{ {
HashSink hashSink { htSHA256 }; HashSink hashSink { htSHA256 };
@ -121,7 +121,7 @@ void RewritingSink::operator () (std::string_view data)
s.append(data); s.append(data);
size_t j = 0; size_t j = 0;
while ((j = s.find(from, j)) != string::npos) { while ((j = s.find(from, j)) != std::string::npos) {
matches.push_back(pos + j); matches.push_back(pos + j);
s.replace(j, from.size(), to); s.replace(j, from.size(), to);
} }

View file

@ -1,7 +1,9 @@
#include "serialise.hh" #include "serialise.hh"
#include "util.hh" #include "util.hh"
#include "path-with-outputs.hh" #include "path-with-outputs.hh"
#include "gc-store.hh"
#include "remote-fs-accessor.hh" #include "remote-fs-accessor.hh"
#include "build-result.hh"
#include "remote-store.hh" #include "remote-store.hh"
#include "worker-protocol.hh" #include "worker-protocol.hh"
#include "archive.hh" #include "archive.hh"
@ -661,8 +663,11 @@ void RemoteStore::addMultipleToStore(
} }
StorePath RemoteStore::addTextToStore(const string & name, const string & s, StorePath RemoteStore::addTextToStore(
const StorePathSet & references, RepairFlag repair) std::string_view name,
std::string_view s,
const StorePathSet & references,
RepairFlag repair)
{ {
StringSource source(s); StringSource source(s);
return addCAToStore(source, name, TextHashMethod{}, references, repair)->path; return addCAToStore(source, name, TextHashMethod{}, references, repair)->path;
@ -1000,7 +1005,7 @@ std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source *
auto msg = readNum<uint64_t>(from); auto msg = readNum<uint64_t>(from);
if (msg == STDERR_WRITE) { if (msg == STDERR_WRITE) {
string s = readString(from); auto s = readString(from);
if (!sink) throw Error("no sink"); if (!sink) throw Error("no sink");
(*sink)(s); (*sink)(s);
} }
@ -1017,7 +1022,7 @@ std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source *
if (GET_PROTOCOL_MINOR(daemonVersion) >= 26) { if (GET_PROTOCOL_MINOR(daemonVersion) >= 26) {
return std::make_exception_ptr(readError(from)); return std::make_exception_ptr(readError(from));
} else { } else {
string error = readString(from); auto error = readString(from);
unsigned int status = readInt(from); unsigned int status = readInt(from);
return std::make_exception_ptr(Error(status, error)); return std::make_exception_ptr(Error(status, error));
} }

Some files were not shown because too many files have changed in this diff Show more