Merge remote-tracking branch 'upstream/master' into path-info

This commit is contained in:
John Ericson 2020-10-12 20:48:35 +00:00
commit a0f369aa3f
127 changed files with 650 additions and 549 deletions

1
.gitignore vendored
View file

@ -5,7 +5,6 @@ perl/Makefile.config
/aclocal.m4 /aclocal.m4
/autom4te.cache /autom4te.cache
/precompiled-headers.h.gch /precompiled-headers.h.gch
/precompiled-headers.h.pch
/config.* /config.*
/configure /configure
/stamp-h1 /stamp-h1

View file

@ -52,5 +52,4 @@ in
command: command:
"Title: nix\n\n" showCommand { command = "nix"; section = "#"; def = command; }
+ showCommand { command = "nix"; section = "#"; def = command; }

View file

@ -18,13 +18,22 @@ dist-files += $(man-pages)
nix-eval = $(bindir)/nix eval --experimental-features nix-command -I nix/corepkgs=corepkgs --store dummy:// --impure --raw --expr nix-eval = $(bindir)/nix eval --experimental-features nix-command -I nix/corepkgs=corepkgs --store dummy:// --impure --raw --expr
$(d)/%.1: $(d)/src/command-ref/%.md $(d)/%.1: $(d)/src/command-ref/%.md
$(trace-gen) lowdown -sT man $^ -o $@ @printf "Title: %s\n\n" "$$(basename $@ .1)" > $^.tmp
@cat $^ >> $^.tmp
$(trace-gen) lowdown -sT man $^.tmp -o $@
@rm $^.tmp
$(d)/%.8: $(d)/src/command-ref/%.md $(d)/%.8: $(d)/src/command-ref/%.md
$(trace-gen) lowdown -sT man $^ -o $@ @printf "Title: %s\n\n" "$$(basename $@ .8)" > $^.tmp
@cat $^ >> $^.tmp
$(trace-gen) lowdown -sT man $^.tmp -o $@
@rm $^.tmp
$(d)/nix.conf.5: $(d)/src/command-ref/conf-file.md $(d)/nix.conf.5: $(d)/src/command-ref/conf-file.md
$(trace-gen) lowdown -sT man $^ -o $@ @printf "Title: %s\n\n" "$$(basename $@ .5)" > $^.tmp
@cat $^ >> $^.tmp
$(trace-gen) lowdown -sT man $^.tmp -o $@
@rm $^.tmp
$(d)/src/command-ref/nix.md: $(d)/nix.json $(d)/generate-manpage.nix $(bindir)/nix $(d)/src/command-ref/nix.md: $(d)/nix.json $(d)/generate-manpage.nix $(bindir)/nix
$(trace-gen) $(nix-eval) 'import doc/manual/generate-manpage.nix (builtins.fromJSON (builtins.readFile $<))' > $@.tmp $(trace-gen) $(nix-eval) 'import doc/manual/generate-manpage.nix (builtins.fromJSON (builtins.readFile $<))' > $@.tmp
@ -40,7 +49,7 @@ $(d)/nix.json: $(bindir)/nix
@mv $@.tmp $@ @mv $@.tmp $@
$(d)/conf-file.json: $(bindir)/nix $(d)/conf-file.json: $(bindir)/nix
$(trace-gen) env -i NIX_CONF_DIR=/dummy HOME=/dummy $(bindir)/nix show-config --json --experimental-features nix-command > $@.tmp $(trace-gen) env -i NIX_CONF_DIR=/dummy HOME=/dummy NIX_SSL_CERT_FILE=/dummy/no-ca-bundle.crt $(bindir)/nix show-config --json --experimental-features nix-command > $@.tmp
@mv $@.tmp $@ @mv $@.tmp $@
$(d)/src/expressions/builtins.md: $(d)/builtins.json $(d)/generate-builtins.nix $(d)/src/expressions/builtins-prefix.md $(bindir)/nix $(d)/src/expressions/builtins.md: $(d)/builtins.json $(d)/generate-builtins.nix $(d)/src/expressions/builtins-prefix.md $(bindir)/nix

View file

@ -1,5 +1,3 @@
Title: nix.conf
# Name # Name
`nix.conf` - Nix configuration file `nix.conf` - Nix configuration file

View file

@ -1,5 +1,3 @@
Title: nix-build
# Name # Name
`nix-build` - build a Nix expression `nix-build` - build a Nix expression

View file

@ -1,5 +1,3 @@
Title: nix-channel
# Name # Name
`nix-channel` - manage Nix channels `nix-channel` - manage Nix channels

View file

@ -1,5 +1,3 @@
Title: nix-collect-garbage
# Name # Name
`nix-collect-garbage` - delete unreachable store paths `nix-collect-garbage` - delete unreachable store paths

View file

@ -1,5 +1,3 @@
Title: nix-copy-closure
# Name # Name
`nix-copy-closure` - copy a closure to or from a remote machine via SSH `nix-copy-closure` - copy a closure to or from a remote machine via SSH

View file

@ -1,5 +1,3 @@
Title: nix-daemon
# Name # Name
`nix-daemon` - Nix multi-user support daemon `nix-daemon` - Nix multi-user support daemon

View file

@ -1,5 +1,3 @@
Title: nix-env
# Name # Name
`nix-env` - manipulate or query Nix user environments `nix-env` - manipulate or query Nix user environments

View file

@ -1,5 +1,3 @@
Title: nix-hash
# Name # Name
`nix-hash` - compute the cryptographic hash of a path `nix-hash` - compute the cryptographic hash of a path

View file

@ -1,5 +1,3 @@
Title: nix-instantiate
# Name # Name
`nix-instantiate` - instantiate store derivations from Nix expressions `nix-instantiate` - instantiate store derivations from Nix expressions

View file

@ -1,5 +1,3 @@
Title: nix-prefetch-url
# Name # Name
`nix-prefetch-url` - copy a file from a URL into the store and print its hash `nix-prefetch-url` - copy a file from a URL into the store and print its hash

View file

@ -1,5 +1,3 @@
Title: nix-shell
# Name # Name
`nix-shell` - start an interactive shell based on a Nix expression `nix-shell` - start an interactive shell based on a Nix expression

View file

@ -1,5 +1,3 @@
Title: nix-store
# Name # Name
`nix-store` - manipulate or query the Nix store `nix-store` - manipulate or query the Nix store

View file

@ -11,6 +11,6 @@ GLOBAL_CXXFLAGS += -Wno-deprecated-declarations
$(foreach i, config.h $(wildcard src/lib*/*.hh), \ $(foreach i, config.h $(wildcard src/lib*/*.hh), \
$(eval $(call install-file-in, $(i), $(includedir)/nix, 0644))) $(eval $(call install-file-in, $(i), $(includedir)/nix, 0644)))
$(GCH) $(PCH): src/libutil/util.hh config.h $(GCH): src/libutil/util.hh config.h
GCH_CXXFLAGS = -I src/libutil GCH_CXXFLAGS = -I src/libutil

View file

@ -4,13 +4,14 @@ function _complete_nix {
_get_comp_words_by_ref -n ':=&' words cword cur _get_comp_words_by_ref -n ':=&' words cword cur
local have_type local have_type
while IFS= read -r line; do while IFS= read -r line; do
local completion=${line%% *}
if [[ -z $have_type ]]; then if [[ -z $have_type ]]; then
have_type=1 have_type=1
if [[ $line = filenames ]]; then if [[ $completion = filenames ]]; then
compopt -o filenames compopt -o filenames
fi fi
else else
COMPREPLY+=("$line") COMPREPLY+=("$completion")
fi fi
done < <(NIX_GET_COMPLETIONS=$cword "${words[@]}") done < <(NIX_GET_COMPLETIONS=$cword "${words[@]}")
__ltrim_colon_completions "$cur" __ltrim_colon_completions "$cur"

21
misc/zsh/completion.zsh Normal file
View file

@ -0,0 +1,21 @@
function _nix() {
local ifs_bk="$IFS"
local input=("${(Q)words[@]}")
IFS=$'\n'
local res=($(NIX_GET_COMPLETIONS=$((CURRENT - 1)) "$input[@]"))
IFS="$ifs_bk"
local tpe="${${res[1]}%%> *}"
local -a suggestions
declare -a suggestions
for suggestion in ${res:1}; do
# FIXME: This doesn't work properly if the suggestion word contains a `:`
# itself
suggestions+="${suggestion/ /:}"
done
if [[ "$tpe" == filenames ]]; then
compadd -f
fi
_describe 'nix' suggestions
}
compdef _nix nix

View file

@ -10,33 +10,12 @@ $(GCH): precompiled-headers.h
@mkdir -p "$(dir $@)" @mkdir -p "$(dir $@)"
$(trace-gen) $(CXX) -x c++-header -o $@ $< $(GLOBAL_CXXFLAGS) $(GCH_CXXFLAGS) $(trace-gen) $(CXX) -x c++-header -o $@ $< $(GLOBAL_CXXFLAGS) $(GCH_CXXFLAGS)
PCH = $(buildprefix)precompiled-headers.h.pch clean-files += $(GCH)
$(PCH): precompiled-headers.h
@rm -f $@
@mkdir -p "$(dir $@)"
$(trace-gen) $(CXX) -x c++-header -o $@ $< $(GLOBAL_CXXFLAGS) $(GCH_CXXFLAGS)
clean-files += $(GCH) $(PCH)
ifeq ($(PRECOMPILE_HEADERS), 1) ifeq ($(PRECOMPILE_HEADERS), 1)
ifeq ($(findstring g++,$(CXX)), g++) GLOBAL_CXXFLAGS_PCH += -include $(buildprefix)precompiled-headers.h -Winvalid-pch
GLOBAL_CXXFLAGS_PCH += -include $(buildprefix)precompiled-headers.h -Winvalid-pch GLOBAL_ORDER_AFTER += $(GCH)
GLOBAL_ORDER_AFTER += $(GCH)
else ifeq ($(findstring clang++,$(CXX)), clang++)
GLOBAL_CXXFLAGS_PCH += -include-pch $(PCH) -Winvalid-pch
GLOBAL_ORDER_AFTER += $(PCH)
else
$(error Don't know how to precompile headers on $(CXX))
endif
endif endif

View file

@ -1,3 +1,4 @@
#[allow(improper_ctypes_definitions)]
#[cfg(not(test))] #[cfg(not(test))]
mod c; mod c;
mod error; mod error;

View file

@ -19,9 +19,9 @@ impl StorePath {
} }
Self::new_from_base_name( Self::new_from_base_name(
path.file_name() path.file_name()
.ok_or(Error::BadStorePath(path.into()))? .ok_or_else(|| Error::BadStorePath(path.into()))?
.to_str() .to_str()
.ok_or(Error::BadStorePath(path.into()))?, .ok_or_else(|| Error::BadStorePath(path.into()))?,
) )
} }
@ -34,7 +34,7 @@ impl StorePath {
pub fn new_from_base_name(base_name: &str) -> Result<Self, Error> { pub fn new_from_base_name(base_name: &str) -> Result<Self, Error> {
if base_name.len() < STORE_PATH_HASH_CHARS + 1 if base_name.len() < STORE_PATH_HASH_CHARS + 1
|| base_name.as_bytes()[STORE_PATH_HASH_CHARS] != '-' as u8 || base_name.as_bytes()[STORE_PATH_HASH_CHARS] != b'-'
{ {
return Err(Error::BadStorePath(base_name.into())); return Err(Error::BadStorePath(base_name.into()));
} }
@ -65,7 +65,7 @@ impl StorePathHash {
Ok(Self(bytes)) Ok(Self(bytes))
} }
pub fn hash<'a>(&'a self) -> &'a [u8; STORE_PATH_HASH_BYTES] { pub fn hash(&self) -> &[u8; STORE_PATH_HASH_BYTES] {
&self.0 &self.0
} }
} }
@ -98,7 +98,7 @@ pub struct StorePathName(String);
impl StorePathName { impl StorePathName {
pub fn new(s: &str) -> Result<Self, Error> { pub fn new(s: &str) -> Result<Self, Error> {
if s.len() == 0 { if s.is_empty() {
return Err(Error::StorePathNameEmpty); return Err(Error::StorePathNameEmpty);
} }
@ -106,25 +106,24 @@ impl StorePathName {
return Err(Error::StorePathNameTooLong); return Err(Error::StorePathNameTooLong);
} }
if s.starts_with('.') let is_good_path_name = s.chars().all(|c| {
|| !s.chars().all(|c| { c.is_ascii_alphabetic()
c.is_ascii_alphabetic() || c.is_ascii_digit()
|| c.is_ascii_digit() || c == '+'
|| c == '+' || c == '-'
|| c == '-' || c == '.'
|| c == '.' || c == '_'
|| c == '_' || c == '?'
|| c == '?' || c == '='
|| c == '=' });
}) if s.starts_with('.') || !is_good_path_name {
{
return Err(Error::BadStorePathName); return Err(Error::BadStorePathName);
} }
Ok(Self(s.to_string())) Ok(Self(s.to_string()))
} }
pub fn name<'a>(&'a self) -> &'a str { pub fn name(&self) -> &str {
&self.0 &self.0
} }
} }

View file

@ -13,7 +13,7 @@ pub fn decoded_len(input_len: usize) -> usize {
input_len * 5 / 8 input_len * 5 / 8
} }
static BASE32_CHARS: &'static [u8; 32] = &b"0123456789abcdfghijklmnpqrsvwxyz"; static BASE32_CHARS: &[u8; 32] = &b"0123456789abcdfghijklmnpqrsvwxyz";
lazy_static! { lazy_static! {
static ref BASE32_CHARS_REVERSE: Box<[u8; 256]> = { static ref BASE32_CHARS_REVERSE: Box<[u8; 256]> = {

View file

@ -44,7 +44,7 @@ static bool allSupportedLocally(Store & store, const std::set<std::string>& requ
return true; return true;
} }
static int _main(int argc, char * * argv) static int main_build_remote(int argc, char * * argv)
{ {
{ {
logger = makeJSONLogger(*logger); logger = makeJSONLogger(*logger);
@ -297,4 +297,4 @@ connected:
} }
} }
static RegisterLegacyCommand s1("build-remote", _main); static RegisterLegacyCommand r_build_remote("build-remote", main_build_remote);

View file

@ -11,7 +11,7 @@ namespace nix::eval_cache {
MakeError(CachedEvalError, EvalError); MakeError(CachedEvalError, EvalError);
class AttrDb; struct AttrDb;
class AttrCursor; class AttrCursor;
class EvalCache : public std::enable_shared_from_this<EvalCache> class EvalCache : public std::enable_shared_from_this<EvalCache>

View file

@ -2081,7 +2081,7 @@ Strings EvalSettings::getDefaultNixPath()
EvalSettings evalSettings; EvalSettings evalSettings;
static GlobalConfig::Register r1(&evalSettings); static GlobalConfig::Register rEvalSettings(&evalSettings);
} }

View file

@ -12,7 +12,7 @@ using namespace flake;
namespace flake { namespace flake {
typedef std::pair<Tree, FlakeRef> FetchedFlake; typedef std::pair<fetchers::Tree, FlakeRef> FetchedFlake;
typedef std::vector<std::pair<FlakeRef, FetchedFlake>> FlakeCache; typedef std::vector<std::pair<FlakeRef, FetchedFlake>> FlakeCache;
static std::optional<FetchedFlake> lookupInFlakeCache( static std::optional<FetchedFlake> lookupInFlakeCache(

View file

@ -13,12 +13,12 @@ FlakeRef getFlakeRef(
{ {
auto i = json.find(attr); auto i = json.find(attr);
if (i != json.end()) { if (i != json.end()) {
auto attrs = jsonToAttrs(*i); auto attrs = fetchers::jsonToAttrs(*i);
// FIXME: remove when we drop support for version 5. // FIXME: remove when we drop support for version 5.
if (info) { if (info) {
auto j = json.find(info); auto j = json.find(info);
if (j != json.end()) { if (j != json.end()) {
for (auto k : jsonToAttrs(*j)) for (auto k : fetchers::jsonToAttrs(*j))
attrs.insert_or_assign(k.first, k.second); attrs.insert_or_assign(k.first, k.second);
} }
} }

View file

@ -11,8 +11,6 @@ class StorePath;
namespace nix::flake { namespace nix::flake {
using namespace fetchers;
typedef std::vector<FlakeId> InputPath; typedef std::vector<FlakeId> InputPath;
struct LockedNode; struct LockedNode;

View file

@ -1,3 +1,5 @@
#pragma once
#include "eval.hh" #include "eval.hh"
#include <tuple> #include <tuple>

View file

@ -11,7 +11,7 @@ static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos,
mkString(v, s, PathSet()); mkString(v, s, PathSet());
} }
static RegisterPrimOp r1("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext); static RegisterPrimOp primop_unsafeDiscardStringContext("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
static void prim_hasContext(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_hasContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
@ -21,7 +21,7 @@ static void prim_hasContext(EvalState & state, const Pos & pos, Value * * args,
mkBool(v, !context.empty()); mkBool(v, !context.empty());
} }
static RegisterPrimOp r2("__hasContext", 1, prim_hasContext); static RegisterPrimOp primop_hasContext("__hasContext", 1, prim_hasContext);
/* Sometimes we want to pass a derivation path (i.e. pkg.drvPath) to a /* Sometimes we want to pass a derivation path (i.e. pkg.drvPath) to a
@ -42,7 +42,7 @@ static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & po
mkString(v, s, context2); mkString(v, s, context2);
} }
static RegisterPrimOp r3("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency); static RegisterPrimOp primop_unsafeDiscardOutputDependency("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
/* Extract the context of a string as a structured Nix value. /* Extract the context of a string as a structured Nix value.
@ -127,7 +127,7 @@ static void prim_getContext(EvalState & state, const Pos & pos, Value * * args,
v.attrs->sort(); v.attrs->sort();
} }
static RegisterPrimOp r4("__getContext", 1, prim_getContext); static RegisterPrimOp primop_getContext("__getContext", 1, prim_getContext);
/* Append the given context to a given string. /* Append the given context to a given string.
@ -191,6 +191,6 @@ static void prim_appendContext(EvalState & state, const Pos & pos, Value * * arg
mkString(v, orig, context); mkString(v, orig, context);
} }
static RegisterPrimOp r5("__appendContext", 2, prim_appendContext); static RegisterPrimOp primop_appendContext("__appendContext", 2, prim_appendContext);
} }

View file

@ -87,6 +87,6 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
state.allowedPaths->insert(tree.actualPath); state.allowedPaths->insert(tree.actualPath);
} }
static RegisterPrimOp r("fetchMercurial", 1, prim_fetchMercurial); static RegisterPrimOp r_fetchMercurial("fetchMercurial", 1, prim_fetchMercurial);
} }

View file

@ -152,7 +152,7 @@ static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, V
fetchTree(state, pos, args, v, std::nullopt); fetchTree(state, pos, args, v, std::nullopt);
} }
static RegisterPrimOp r("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 string & who, bool unpack, std::string name)

View file

@ -88,6 +88,6 @@ static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Va
} }
} }
static RegisterPrimOp r("fromTOML", 1, prim_fromTOML); static RegisterPrimOp primop_fromTOML("fromTOML", 1, prim_fromTOML);
} }

View file

@ -86,6 +86,9 @@ public:
struct InputScheme struct InputScheme
{ {
virtual ~InputScheme()
{ }
virtual std::optional<Input> inputFromURL(const ParsedURL & url) = 0; virtual std::optional<Input> inputFromURL(const ParsedURL & url) = 0;
virtual std::optional<Input> inputFromAttrs(const Attrs & attrs) = 0; virtual std::optional<Input> inputFromAttrs(const Attrs & attrs) = 0;

View file

@ -452,6 +452,6 @@ struct GitInputScheme : InputScheme
} }
}; };
static auto r1 = OnStartup([] { registerInputScheme(std::make_unique<GitInputScheme>()); }); static auto rGitInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitInputScheme>()); });
} }

View file

@ -25,7 +25,7 @@ struct GitArchiveInputScheme : InputScheme
{ {
virtual std::string type() = 0; virtual std::string type() = 0;
virtual std::optional<std::pair<std::string, std::string> > accessHeaderFromToken(const std::string & token) const = 0; virtual std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const = 0;
std::optional<Input> inputFromURL(const ParsedURL & url) override std::optional<Input> inputFromURL(const ParsedURL & url) override
{ {
@ -215,7 +215,7 @@ struct GitHubInputScheme : GitArchiveInputScheme
{ {
std::string type() override { return "github"; } std::string type() override { return "github"; }
std::optional<std::pair<std::string, std::string> > accessHeaderFromToken(const std::string & token) const std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
{ {
// Github supports PAT/OAuth2 tokens and HTTP Basic // Github supports PAT/OAuth2 tokens and HTTP Basic
// Authentication. The former simply specifies the token, the // Authentication. The former simply specifies the token, the
@ -270,7 +270,7 @@ struct GitLabInputScheme : GitArchiveInputScheme
{ {
std::string type() override { return "gitlab"; } std::string type() override { return "gitlab"; }
std::optional<std::pair<std::string, std::string> > accessHeaderFromToken(const std::string & token) const std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
{ {
// Gitlab supports 4 kinds of authorization, two of which are // Gitlab supports 4 kinds of authorization, two of which are
// relevant here: OAuth2 and PAT (Private Access Token). The // relevant here: OAuth2 and PAT (Private Access Token). The
@ -334,7 +334,7 @@ struct GitLabInputScheme : GitArchiveInputScheme
} }
}; };
static auto r1 = OnStartup([] { registerInputScheme(std::make_unique<GitHubInputScheme>()); }); static auto rGitHubInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitHubInputScheme>()); });
static auto r2 = OnStartup([] { registerInputScheme(std::make_unique<GitLabInputScheme>()); }); static auto rGitLabInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitLabInputScheme>()); });
} }

View file

@ -100,6 +100,6 @@ struct IndirectInputScheme : InputScheme
} }
}; };
static auto r1 = OnStartup([] { registerInputScheme(std::make_unique<IndirectInputScheme>()); }); static auto rIndirectInputScheme = OnStartup([] { registerInputScheme(std::make_unique<IndirectInputScheme>()); });
} }

View file

@ -293,6 +293,6 @@ struct MercurialInputScheme : InputScheme
} }
}; };
static auto r1 = OnStartup([] { registerInputScheme(std::make_unique<MercurialInputScheme>()); }); static auto rMercurialInputScheme = OnStartup([] { registerInputScheme(std::make_unique<MercurialInputScheme>()); });
} }

View file

@ -102,6 +102,6 @@ struct PathInputScheme : InputScheme
} }
}; };
static auto r1 = OnStartup([] { registerInputScheme(std::make_unique<PathInputScheme>()); }); static auto rPathInputScheme = OnStartup([] { registerInputScheme(std::make_unique<PathInputScheme>()); });
} }

View file

@ -3,6 +3,7 @@
#include "util.hh" #include "util.hh"
#include "globals.hh" #include "globals.hh"
#include "store-api.hh" #include "store-api.hh"
#include "local-fs-store.hh"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>

View file

@ -237,6 +237,6 @@ struct TarballInputScheme : InputScheme
} }
}; };
static auto r1 = OnStartup([] { registerInputScheme(std::make_unique<TarballInputScheme>()); }); static auto rTarballInputScheme = OnStartup([] { registerInputScheme(std::make_unique<TarballInputScheme>()); });
} }

View file

@ -44,7 +44,7 @@ MixCommonArgs::MixCommonArgs(const string & programName)
globalConfig.getSettings(settings); globalConfig.getSettings(settings);
for (auto & s : settings) for (auto & s : settings)
if (hasPrefix(s.first, prefix)) if (hasPrefix(s.first, prefix))
completions->insert(s.first); completions->add(s.first, s.second.description);
} }
} }
}); });

View file

@ -386,18 +386,12 @@ RunPager::~RunPager()
} }
string showBytes(uint64_t bytes)
{
return (format("%.2f MiB") % (bytes / (1024.0 * 1024.0))).str();
}
PrintFreed::~PrintFreed() PrintFreed::~PrintFreed()
{ {
if (show) if (show)
std::cout << format("%1% store paths deleted, %2% freed\n") std::cout << fmt("%d store paths deleted, %s freed\n",
% results.paths.size() results.paths.size(),
% showBytes(results.bytesFreed); showBytes(results.bytesFreed));
} }
Exit::~Exit() { } Exit::~Exit() { }

View file

@ -831,6 +831,10 @@ private:
paths to the sandbox as a result of recursive Nix calls. */ paths to the sandbox as a result of recursive Nix calls. */
AutoCloseFD sandboxMountNamespace; AutoCloseFD sandboxMountNamespace;
/* On Linux, whether we're doing the build in its own user
namespace. */
bool usingUserNamespace = true;
/* The build hook. */ /* The build hook. */
std::unique_ptr<HookInstance> hook; std::unique_ptr<HookInstance> hook;
@ -920,8 +924,8 @@ private:
result. */ result. */
std::map<Path, ValidPathInfo> prevInfos; std::map<Path, ValidPathInfo> prevInfos;
const uid_t sandboxUid = 1000; uid_t sandboxUid() { return usingUserNamespace ? 1000 : buildUser->getUID(); }
const gid_t sandboxGid = 100; gid_t sandboxGid() { return usingUserNamespace ? 100 : buildUser->getGID(); }
const static Path homeDir; const static Path homeDir;
@ -2355,7 +2359,8 @@ void DerivationGoal::startBuilder()
worker.store.computeFSClosure(worker.store.toStorePath(i.second.source).first, closure); worker.store.computeFSClosure(worker.store.toStorePath(i.second.source).first, closure);
} catch (InvalidPath & e) { } catch (InvalidPath & e) {
} catch (Error & e) { } catch (Error & e) {
throw Error("while processing 'sandbox-paths': %s", e.what()); e.addTrace({}, "while processing 'sandbox-paths'");
throw;
} }
for (auto & i : closure) { for (auto & i : closure) {
auto p = worker.store.printStorePath(i); auto p = worker.store.printStorePath(i);
@ -2423,15 +2428,14 @@ void DerivationGoal::startBuilder()
"root:x:0:0:Nix build user:%3%:/noshell\n" "root:x:0:0:Nix build user:%3%:/noshell\n"
"nixbld:x:%1%:%2%:Nix build user:%3%:/noshell\n" "nixbld:x:%1%:%2%:Nix build user:%3%:/noshell\n"
"nobody:x:65534:65534:Nobody:/:/noshell\n", "nobody:x:65534:65534:Nobody:/:/noshell\n",
sandboxUid, sandboxGid, settings.sandboxBuildDir)); sandboxUid(), sandboxGid(), settings.sandboxBuildDir));
/* Declare the build user's group so that programs get a consistent /* Declare the build user's group so that programs get a consistent
view of the system (e.g., "id -gn"). */ view of the system (e.g., "id -gn"). */
writeFile(chrootRootDir + "/etc/group", writeFile(chrootRootDir + "/etc/group",
(format( fmt("root:x:0:\n"
"root:x:0:\n"
"nixbld:!:%1%:\n" "nixbld:!:%1%:\n"
"nogroup:x:65534:\n") % sandboxGid).str()); "nogroup:x:65534:\n", sandboxGid()));
/* Create /etc/hosts with localhost entry. */ /* Create /etc/hosts with localhost entry. */
if (!(derivationIsImpure(derivationType))) if (!(derivationIsImpure(derivationType)))
@ -2628,6 +2632,13 @@ void DerivationGoal::startBuilder()
options.allowVfork = false; options.allowVfork = false;
Path maxUserNamespaces = "/proc/sys/user/max_user_namespaces";
static bool userNamespacesEnabled =
pathExists(maxUserNamespaces)
&& trim(readFile(maxUserNamespaces)) != "0";
usingUserNamespace = userNamespacesEnabled;
Pid helper = startProcess([&]() { Pid helper = startProcess([&]() {
/* Drop additional groups here because we can't do it /* Drop additional groups here because we can't do it
@ -2646,9 +2657,11 @@ void DerivationGoal::startBuilder()
PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
if (stack == MAP_FAILED) throw SysError("allocating stack"); if (stack == MAP_FAILED) throw SysError("allocating stack");
int flags = CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD; int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD;
if (privateNetwork) if (privateNetwork)
flags |= CLONE_NEWNET; flags |= CLONE_NEWNET;
if (usingUserNamespace)
flags |= CLONE_NEWUSER;
pid_t child = clone(childEntry, stack + stackSize, flags, this); pid_t child = clone(childEntry, stack + stackSize, flags, this);
if (child == -1 && errno == EINVAL) { if (child == -1 && errno == EINVAL) {
@ -2657,11 +2670,12 @@ void DerivationGoal::startBuilder()
flags &= ~CLONE_NEWPID; flags &= ~CLONE_NEWPID;
child = clone(childEntry, stack + stackSize, flags, this); child = clone(childEntry, stack + stackSize, flags, this);
} }
if (child == -1 && (errno == EPERM || errno == EINVAL)) { if (usingUserNamespace && child == -1 && (errno == EPERM || errno == EINVAL)) {
/* Some distros patch Linux to not allow unprivileged /* Some distros patch Linux to not allow unprivileged
* user namespaces. If we get EPERM or EINVAL, try * user namespaces. If we get EPERM or EINVAL, try
* without CLONE_NEWUSER and see if that works. * without CLONE_NEWUSER and see if that works.
*/ */
usingUserNamespace = false;
flags &= ~CLONE_NEWUSER; flags &= ~CLONE_NEWUSER;
child = clone(childEntry, stack + stackSize, flags, this); child = clone(childEntry, stack + stackSize, flags, this);
} }
@ -2672,7 +2686,8 @@ void DerivationGoal::startBuilder()
_exit(1); _exit(1);
if (child == -1) throw SysError("cloning builder process"); if (child == -1) throw SysError("cloning builder process");
writeFull(builderOut.writeSide.get(), std::to_string(child) + "\n"); writeFull(builderOut.writeSide.get(),
fmt("%d %d\n", usingUserNamespace, child));
_exit(0); _exit(0);
}, options); }, options);
@ -2686,23 +2701,38 @@ void DerivationGoal::startBuilder()
userNamespaceSync.readSide = -1; userNamespaceSync.readSide = -1;
/* Close the write side to prevent runChild() from hanging
reading from this. */
Finally cleanup([&]() {
userNamespaceSync.writeSide = -1;
});
pid_t tmp; pid_t tmp;
if (!string2Int<pid_t>(readLine(builderOut.readSide.get()), tmp)) abort(); auto ss = tokenizeString<std::vector<std::string>>(readLine(builderOut.readSide.get()));
assert(ss.size() == 2);
usingUserNamespace = ss[0] == "1";
if (!string2Int<pid_t>(ss[1], tmp)) abort();
pid = tmp; pid = tmp;
/* Set the UID/GID mapping of the builder's user namespace if (usingUserNamespace) {
such that the sandbox user maps to the build user, or to /* Set the UID/GID mapping of the builder's user namespace
the calling user (if build users are disabled). */ such that the sandbox user maps to the build user, or to
uid_t hostUid = buildUser ? buildUser->getUID() : getuid(); the calling user (if build users are disabled). */
uid_t hostGid = buildUser ? buildUser->getGID() : getgid(); uid_t hostUid = buildUser ? buildUser->getUID() : getuid();
uid_t hostGid = buildUser ? buildUser->getGID() : getgid();
writeFile("/proc/" + std::to_string(pid) + "/uid_map", writeFile("/proc/" + std::to_string(pid) + "/uid_map",
(format("%d %d 1") % sandboxUid % hostUid).str()); fmt("%d %d 1", sandboxUid(), hostUid));
writeFile("/proc/" + std::to_string(pid) + "/setgroups", "deny"); writeFile("/proc/" + std::to_string(pid) + "/setgroups", "deny");
writeFile("/proc/" + std::to_string(pid) + "/gid_map", writeFile("/proc/" + std::to_string(pid) + "/gid_map",
(format("%d %d 1") % sandboxGid % hostGid).str()); fmt("%d %d 1", sandboxGid(), hostGid));
} else {
debug("note: not using a user namespace");
if (!buildUser)
throw Error("cannot perform a sandboxed build because user namespaces are not enabled; check /proc/sys/user/max_user_namespaces");
}
/* Save the mount namespace of the child. We have to do this /* Save the mount namespace of the child. We have to do this
*before* the child does a chroot. */ *before* the child does a chroot. */
@ -2712,7 +2742,6 @@ void DerivationGoal::startBuilder()
/* Signal the builder that we've updated its user namespace. */ /* Signal the builder that we've updated its user namespace. */
writeFull(userNamespaceSync.writeSide.get(), "1"); writeFull(userNamespaceSync.writeSide.get(), "1");
userNamespaceSync.writeSide = -1;
} else } else
#endif #endif
@ -2732,11 +2761,14 @@ void DerivationGoal::startBuilder()
/* Check if setting up the build environment failed. */ /* Check if setting up the build environment failed. */
while (true) { while (true) {
string msg = readLine(builderOut.readSide.get()); string msg = readLine(builderOut.readSide.get());
if (string(msg, 0, 1) == "\2") break;
if (string(msg, 0, 1) == "\1") { if (string(msg, 0, 1) == "\1") {
if (msg.size() == 1) break; FdSource source(builderOut.readSide.get());
throw Error(string(msg, 1)); auto ex = readError(source);
ex.addTrace({}, "while setting up the build environment");
throw ex;
} }
debug(msg); debug("sandbox setup: " + msg);
} }
} }
@ -3560,9 +3592,9 @@ void DerivationGoal::runChild()
/* Switch to the sandbox uid/gid in the user namespace, /* Switch to the sandbox uid/gid in the user namespace,
which corresponds to the build user or calling user in which corresponds to the build user or calling user in
the parent namespace. */ the parent namespace. */
if (setgid(sandboxGid) == -1) if (setgid(sandboxGid()) == -1)
throw SysError("setgid failed"); throw SysError("setgid failed");
if (setuid(sandboxUid) == -1) if (setuid(sandboxUid()) == -1)
throw SysError("setuid failed"); throw SysError("setuid failed");
setUser = false; setUser = false;
@ -3780,7 +3812,7 @@ void DerivationGoal::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("\1\n")); writeFull(STDERR_FILENO, string("\2\n"));
/* Execute the program. This should not return. */ /* Execute the program. This should not return. */
if (drv->isBuiltin()) { if (drv->isBuiltin()) {
@ -3801,7 +3833,7 @@ void DerivationGoal::runChild()
throw Error("unsupported builtin function '%1%'", string(drv->builder, 8)); throw Error("unsupported builtin function '%1%'", string(drv->builder, 8));
_exit(0); _exit(0);
} catch (std::exception & e) { } catch (std::exception & e) {
writeFull(STDERR_FILENO, "error: " + string(e.what()) + "\n"); writeFull(STDERR_FILENO, e.what() + std::string("\n"));
_exit(1); _exit(1);
} }
} }
@ -3810,8 +3842,11 @@ void DerivationGoal::runChild()
throw SysError("executing '%1%'", drv->builder); throw SysError("executing '%1%'", drv->builder);
} catch (std::exception & e) { } catch (Error & e) {
writeFull(STDERR_FILENO, "\1while setting up the build environment: " + string(e.what()) + "\n"); writeFull(STDERR_FILENO, "\1\n");
FdSink sink(STDERR_FILENO);
sink << e;
sink.flush();
_exit(1); _exit(1);
} }
} }

View file

@ -101,17 +101,20 @@ struct TunnelLogger : public Logger
/* stopWork() means that we're done; stop sending stderr to the /* stopWork() means that we're done; stop sending stderr to the
client. */ client. */
void stopWork(bool success = true, const string & msg = "", unsigned int status = 0) void stopWork(const Error * ex = nullptr)
{ {
auto state(state_.lock()); auto state(state_.lock());
state->canSendStderr = false; state->canSendStderr = false;
if (success) if (!ex)
to << STDERR_LAST; to << STDERR_LAST;
else { else {
to << STDERR_ERROR << msg; if (GET_PROTOCOL_MINOR(clientVersion) >= 26) {
if (status != 0) to << status; to << STDERR_ERROR << *ex;
} else {
to << STDERR_ERROR << ex->what() << ex->status;
}
} }
} }
@ -935,10 +938,11 @@ void processConnection(
during addTextToStore() / importPath(). If that during addTextToStore() / importPath(). If that
happens, just send the error message and exit. */ happens, just send the error message and exit. */
bool errorAllowed = tunnelLogger->state_.lock()->canSendStderr; bool errorAllowed = tunnelLogger->state_.lock()->canSendStderr;
tunnelLogger->stopWork(false, e.msg(), e.status); tunnelLogger->stopWork(&e);
if (!errorAllowed) throw; if (!errorAllowed) throw;
} catch (std::bad_alloc & e) { } catch (std::bad_alloc & e) {
tunnelLogger->stopWork(false, "Nix daemon out of memory", 1); auto ex = Error("Nix daemon out of memory");
tunnelLogger->stopWork(&ex);
throw; throw;
} }
@ -947,8 +951,13 @@ void processConnection(
assert(!tunnelLogger->state_.lock()->canSendStderr); assert(!tunnelLogger->state_.lock()->canSendStderr);
}; };
} catch (Error & e) {
tunnelLogger->stopWork(&e);
to.flush();
return;
} catch (std::exception & e) { } catch (std::exception & e) {
tunnelLogger->stopWork(false, e.what(), 1); auto ex = Error(e.what());
tunnelLogger->stopWork(&ex);
to.flush(); to.flush();
return; return;
} }

View file

@ -1,3 +1,5 @@
#pragma once
#include "serialise.hh" #include "serialise.hh"
#include "store-api.hh" #include "store-api.hh"

View file

@ -61,8 +61,6 @@ typedef std::map<string, DerivationOutput> DerivationOutputs;
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, StorePath>>
DerivationOutputsAndPaths;
typedef std::map<string, std::pair<DerivationOutput, std::optional<StorePath>>> typedef std::map<string, std::pair<DerivationOutput, std::optional<StorePath>>>
DerivationOutputsAndOptPaths; DerivationOutputsAndOptPaths;

View file

@ -18,8 +18,7 @@ struct DummyStore : public Store, public virtual DummyStoreConfig
DummyStore(const Params & params) DummyStore(const Params & params)
: StoreConfig(params) : StoreConfig(params)
, Store(params) , Store(params)
{ { }
}
string getUri() override string getUri() override
{ {
@ -63,6 +62,6 @@ struct DummyStore : public Store, public virtual DummyStoreConfig
{ unsupported("buildDerivation"); } { unsupported("buildDerivation"); }
}; };
static RegisterStoreImplementation<DummyStore, DummyStoreConfig> regStore; static RegisterStoreImplementation<DummyStore, DummyStoreConfig> regDummyStore;
} }

View file

@ -31,7 +31,7 @@ namespace nix {
FileTransferSettings fileTransferSettings; FileTransferSettings fileTransferSettings;
static GlobalConfig::Register r1(&fileTransferSettings); static GlobalConfig::Register rFileTransferSettings(&fileTransferSettings);
std::string resolveUri(const std::string & uri) std::string resolveUri(const std::string & uri)
{ {

View file

@ -1,6 +1,7 @@
#include "derivations.hh" #include "derivations.hh"
#include "globals.hh" #include "globals.hh"
#include "local-store.hh" #include "local-store.hh"
#include "local-fs-store.hh"
#include "finally.hh" #include "finally.hh"
#include <functional> #include <functional>

View file

@ -25,7 +25,7 @@ namespace nix {
Settings settings; Settings settings;
static GlobalConfig::Register r1(&settings); static GlobalConfig::Register rSettings(&settings);
Settings::Settings() Settings::Settings()
: nixPrefix(NIX_PREFIX) : nixPrefix(NIX_PREFIX)

View file

@ -181,6 +181,6 @@ protected:
}; };
static RegisterStoreImplementation<HttpBinaryCacheStore, HttpBinaryCacheStoreConfig> regStore; static RegisterStoreImplementation<HttpBinaryCacheStore, HttpBinaryCacheStoreConfig> regHttpBinaryCacheStore;
} }

View file

@ -334,6 +334,6 @@ public:
} }
}; };
static RegisterStoreImplementation<LegacySSHStore, LegacySSHStoreConfig> regStore; static RegisterStoreImplementation<LegacySSHStore, LegacySSHStoreConfig> regLegacySSHStore;
} }

View file

@ -105,6 +105,6 @@ std::set<std::string> LocalBinaryCacheStore::uriSchemes()
return {"file"}; return {"file"};
} }
static RegisterStoreImplementation<LocalBinaryCacheStore, LocalBinaryCacheStoreConfig> regStore; static RegisterStoreImplementation<LocalBinaryCacheStore, LocalBinaryCacheStoreConfig> regLocalBinaryCacheStore;
} }

View file

@ -1,6 +1,7 @@
#include "archive.hh" #include "archive.hh"
#include "fs-accessor.hh" #include "fs-accessor.hh"
#include "store-api.hh" #include "store-api.hh"
#include "local-fs-store.hh"
#include "globals.hh" #include "globals.hh"
#include "compression.hh" #include "compression.hh"
#include "derivations.hh" #include "derivations.hh"

View file

@ -0,0 +1,48 @@
#pragma once
#include "store-api.hh"
namespace nix {
struct LocalFSStoreConfig : virtual StoreConfig
{
using StoreConfig::StoreConfig;
// FIXME: the (StoreConfig*) cast works around a bug in gcc that causes
// it to omit the call to the Setting constructor. Clang works fine
// either way.
const PathSetting rootDir{(StoreConfig*) this, true, "",
"root", "directory prefixed to all other paths"};
const PathSetting stateDir{(StoreConfig*) this, false,
rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir,
"state", "directory where Nix will store state"};
const PathSetting logDir{(StoreConfig*) this, false,
rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir,
"log", "directory where Nix will store state"};
};
class LocalFSStore : public virtual Store, public virtual LocalFSStoreConfig
{
public:
const static string drvsLogDir;
LocalFSStore(const Params & params);
void narFromPath(const StorePath & path, Sink & sink) override;
ref<FSAccessor> getFSAccessor() override;
/* Register a permanent GC root. */
Path addPermRoot(const StorePath & storePath, const Path & gcRoot);
virtual Path getRealStoreDir() { return storeDir; }
Path toRealPath(const Path & storePath) override
{
assert(isInStore(storePath));
return getRealStoreDir() + "/" + std::string(storePath, storeDir.size() + 1);
}
std::shared_ptr<std::string> getBuildLog(const StorePath & path) override;
};
}

View file

@ -4,6 +4,7 @@
#include "pathlocks.hh" #include "pathlocks.hh"
#include "store-api.hh" #include "store-api.hh"
#include "local-fs-store.hh"
#include "sync.hh" #include "sync.hh"
#include "util.hh" #include "util.hh"

View file

@ -276,21 +276,15 @@ void LocalStore::optimiseStore(OptimiseStats & stats)
} }
} }
static string showBytes(uint64_t bytes)
{
return (format("%.2f MiB") % (bytes / (1024.0 * 1024.0))).str();
}
void LocalStore::optimiseStore() void LocalStore::optimiseStore()
{ {
OptimiseStats stats; OptimiseStats stats;
optimiseStore(stats); optimiseStore(stats);
printInfo( printInfo("%s freed by hard-linking %d files",
format("%1% freed by hard-linking %2% files") showBytes(stats.bytesFreed),
% showBytes(stats.bytesFreed) stats.filesLinked);
% stats.filesLinked);
} }
void LocalStore::optimisePath(const Path & path) void LocalStore::optimisePath(const Path & path)

View file

@ -1,3 +1,5 @@
#pragma once
#include "store-api.hh" #include "store-api.hh"
#include <nlohmann/json_fwd.hpp> #include <nlohmann/json_fwd.hpp>

View file

@ -1,5 +1,6 @@
#include "profiles.hh" #include "profiles.hh"
#include "store-api.hh" #include "store-api.hh"
#include "local-fs-store.hh"
#include "util.hh" #include "util.hh"
#include <sys/types.h> #include <sys/types.h>

View file

@ -12,16 +12,6 @@
#include "logging.hh" #include "logging.hh"
#include "callback.hh" #include "callback.hh"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
namespace nix { namespace nix {
namespace worker_proto { namespace worker_proto {
@ -125,69 +115,6 @@ ref<RemoteStore::Connection> RemoteStore::openConnectionWrapper()
} }
UDSRemoteStore::UDSRemoteStore(const Params & params)
: StoreConfig(params)
, Store(params)
, LocalFSStore(params)
, RemoteStore(params)
{
}
UDSRemoteStore::UDSRemoteStore(
const std::string scheme,
std::string socket_path,
const Params & params)
: UDSRemoteStore(params)
{
path.emplace(socket_path);
}
std::string UDSRemoteStore::getUri()
{
if (path) {
return std::string("unix://") + *path;
} else {
return "daemon";
}
}
ref<RemoteStore::Connection> UDSRemoteStore::openConnection()
{
auto conn = make_ref<Connection>();
/* Connect to a daemon that does the privileged work for us. */
conn->fd = socket(PF_UNIX, SOCK_STREAM
#ifdef SOCK_CLOEXEC
| SOCK_CLOEXEC
#endif
, 0);
if (!conn->fd)
throw SysError("cannot create Unix domain socket");
closeOnExec(conn->fd.get());
string socketPath = path ? *path : settings.nixDaemonSocketFile;
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
if (socketPath.size() + 1 >= sizeof(addr.sun_path))
throw Error("socket path '%1%' is too long", socketPath);
strcpy(addr.sun_path, socketPath.c_str());
if (::connect(conn->fd.get(), (struct sockaddr *) &addr, sizeof(addr)) == -1)
throw SysError("cannot connect to daemon at '%1%'", socketPath);
conn->from.fd = conn->fd.get();
conn->to.fd = conn->fd.get();
conn->startTime = std::chrono::steady_clock::now();
return conn;
}
void RemoteStore::initConnection(Connection & conn) void RemoteStore::initConnection(Connection & conn)
{ {
/* Send the magic greeting, check for the reply. */ /* Send the magic greeting, check for the reply. */
@ -926,9 +853,13 @@ std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source *
} }
else if (msg == STDERR_ERROR) { else if (msg == STDERR_ERROR) {
string error = readString(from); if (GET_PROTOCOL_MINOR(daemonVersion) >= 26) {
unsigned int status = readInt(from); return std::make_exception_ptr(readError(from));
return std::make_exception_ptr(Error(status, error)); } else {
string error = readString(from);
unsigned int status = readInt(from);
return std::make_exception_ptr(Error(status, error));
}
} }
else if (msg == STDERR_NEXT) else if (msg == STDERR_NEXT)
@ -1009,6 +940,4 @@ void ConnectionHandle::withFramedSink(std::function<void(Sink &sink)> fun)
} }
static RegisterStoreImplementation<UDSRemoteStore, UDSRemoteStoreConfig> regStore;
} }

View file

@ -155,49 +155,5 @@ private:
}; };
struct UDSRemoteStoreConfig : virtual LocalFSStoreConfig, virtual RemoteStoreConfig
{
UDSRemoteStoreConfig(const Store::Params & params)
: StoreConfig(params)
, LocalFSStoreConfig(params)
, RemoteStoreConfig(params)
{
}
UDSRemoteStoreConfig()
: UDSRemoteStoreConfig(Store::Params({}))
{
}
const std::string name() override { return "Local Daemon Store"; }
};
class UDSRemoteStore : public LocalFSStore, public RemoteStore, public virtual UDSRemoteStoreConfig
{
public:
UDSRemoteStore(const Params & params);
UDSRemoteStore(const std::string scheme, std::string path, const Params & params);
std::string getUri() override;
static std::set<std::string> uriSchemes()
{ return {"unix"}; }
bool sameMachine() override
{ return true; }
ref<FSAccessor> getFSAccessor() override
{ return LocalFSStore::getFSAccessor(); }
void narFromPath(const StorePath & path, Sink & sink) override
{ LocalFSStore::narFromPath(path, sink); }
private:
ref<RemoteStore::Connection> openConnection() override;
std::optional<std::string> path;
};
} }

View file

@ -439,7 +439,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore, virtual S3BinaryCache
}; };
static RegisterStoreImplementation<S3BinaryCacheStoreImpl, S3BinaryCacheStoreConfig> regStore; static RegisterStoreImplementation<S3BinaryCacheStoreImpl, S3BinaryCacheStoreConfig> regS3BinaryCacheStore;
} }

View file

@ -83,6 +83,6 @@ ref<RemoteStore::Connection> SSHStore::openConnection()
return conn; return conn;
} }
static RegisterStoreImplementation<SSHStore, SSHStoreConfig> regStore; static RegisterStoreImplementation<SSHStore, SSHStoreConfig> regSSHStore;
} }

View file

@ -1077,7 +1077,7 @@ Derivation Store::readDerivation(const StorePath & drvPath)
#include "local-store.hh" #include "local-store.hh"
#include "remote-store.hh" #include "uds-remote-store.hh"
namespace nix { namespace nix {

View file

@ -196,6 +196,8 @@ struct StoreConfig : public Config
*/ */
StoreConfig() { assert(false); } StoreConfig() { assert(false); }
virtual ~StoreConfig() { }
virtual const std::string name() = 0; virtual const std::string name() = 0;
const PathSetting storeDir_{this, false, settings.nixStore, const PathSetting storeDir_{this, false, settings.nixStore,
@ -709,47 +711,6 @@ protected:
}; };
struct LocalFSStoreConfig : virtual StoreConfig
{
using StoreConfig::StoreConfig;
// FIXME: the (StoreConfig*) cast works around a bug in gcc that causes
// it to omit the call to the Setting constructor. Clang works fine
// either way.
const PathSetting rootDir{(StoreConfig*) this, true, "",
"root", "directory prefixed to all other paths"};
const PathSetting stateDir{(StoreConfig*) this, false,
rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir,
"state", "directory where Nix will store state"};
const PathSetting logDir{(StoreConfig*) this, false,
rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir,
"log", "directory where Nix will store state"};
};
class LocalFSStore : public virtual Store, public virtual LocalFSStoreConfig
{
public:
const static string drvsLogDir;
LocalFSStore(const Params & params);
void narFromPath(const StorePath & path, Sink & sink) override;
ref<FSAccessor> getFSAccessor() override;
/* Register a permanent GC root. */
Path addPermRoot(const StorePath & storePath, const Path & gcRoot);
virtual Path getRealStoreDir() { return storeDir; }
Path toRealPath(const Path & storePath) override
{
assert(isInStore(storePath));
return getRealStoreDir() + "/" + std::string(storePath, storeDir.size() + 1);
}
std::shared_ptr<std::string> getBuildLog(const StorePath & path) override;
};
/* Copy a path from one store to another. */ /* Copy a path from one store to another. */
void copyStorePath(ref<Store> srcStore, ref<Store> dstStore, void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,

View file

@ -0,0 +1,81 @@
#include "uds-remote-store.hh"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
namespace nix {
UDSRemoteStore::UDSRemoteStore(const Params & params)
: StoreConfig(params)
, Store(params)
, LocalFSStore(params)
, RemoteStore(params)
{
}
UDSRemoteStore::UDSRemoteStore(
const std::string scheme,
std::string socket_path,
const Params & params)
: UDSRemoteStore(params)
{
path.emplace(socket_path);
}
std::string UDSRemoteStore::getUri()
{
if (path) {
return std::string("unix://") + *path;
} else {
return "daemon";
}
}
ref<RemoteStore::Connection> UDSRemoteStore::openConnection()
{
auto conn = make_ref<Connection>();
/* Connect to a daemon that does the privileged work for us. */
conn->fd = socket(PF_UNIX, SOCK_STREAM
#ifdef SOCK_CLOEXEC
| SOCK_CLOEXEC
#endif
, 0);
if (!conn->fd)
throw SysError("cannot create Unix domain socket");
closeOnExec(conn->fd.get());
string socketPath = path ? *path : settings.nixDaemonSocketFile;
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
if (socketPath.size() + 1 >= sizeof(addr.sun_path))
throw Error("socket path '%1%' is too long", socketPath);
strcpy(addr.sun_path, socketPath.c_str());
if (::connect(conn->fd.get(), (struct sockaddr *) &addr, sizeof(addr)) == -1)
throw SysError("cannot connect to daemon at '%1%'", socketPath);
conn->from.fd = conn->fd.get();
conn->to.fd = conn->fd.get();
conn->startTime = std::chrono::steady_clock::now();
return conn;
}
static RegisterStoreImplementation<UDSRemoteStore, UDSRemoteStoreConfig> regUDSRemoteStore;
}

View file

@ -0,0 +1,52 @@
#pragma once
#include "remote-store.hh"
#include "local-fs-store.hh"
namespace nix {
struct UDSRemoteStoreConfig : virtual LocalFSStoreConfig, virtual RemoteStoreConfig
{
UDSRemoteStoreConfig(const Store::Params & params)
: StoreConfig(params)
, LocalFSStoreConfig(params)
, RemoteStoreConfig(params)
{
}
UDSRemoteStoreConfig()
: UDSRemoteStoreConfig(Store::Params({}))
{
}
const std::string name() override { return "Local Daemon Store"; }
};
class UDSRemoteStore : public LocalFSStore, public RemoteStore, public virtual UDSRemoteStoreConfig
{
public:
UDSRemoteStore(const Params & params);
UDSRemoteStore(const std::string scheme, std::string path, const Params & params);
std::string getUri() override;
static std::set<std::string> uriSchemes()
{ return {"unix"}; }
bool sameMachine() override
{ return true; }
ref<FSAccessor> getFSAccessor() override
{ return LocalFSStore::getFSAccessor(); }
void narFromPath(const StorePath & path, Sink & sink) override
{ LocalFSStore::narFromPath(path, sink); }
private:
ref<RemoteStore::Connection> openConnection() override;
std::optional<std::string> path;
};
}

View file

@ -6,7 +6,7 @@ namespace nix {
#define WORKER_MAGIC_1 0x6e697863 #define WORKER_MAGIC_1 0x6e697863
#define WORKER_MAGIC_2 0x6478696f #define WORKER_MAGIC_2 0x6478696f
#define PROTOCOL_VERSION 0x119 #define PROTOCOL_VERSION 0x11a
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00) #define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff) #define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
@ -83,7 +83,6 @@ MAKE_WORKER_PROTO(, StorePath);
MAKE_WORKER_PROTO(, ContentAddress); MAKE_WORKER_PROTO(, ContentAddress);
MAKE_WORKER_PROTO(template<typename T>, std::set<T>); MAKE_WORKER_PROTO(template<typename T>, std::set<T>);
MAKE_WORKER_PROTO(template<typename T>, std::optional<T>);
#define X_ template<typename K, typename V> #define X_ template<typename K, typename V>
#define Y_ std::map<K, V> #define Y_ std::map<K, V>
@ -91,6 +90,22 @@ MAKE_WORKER_PROTO(X_, Y_);
#undef X_ #undef X_
#undef Y_ #undef Y_
/* These use the empty string for the null case, relying on the fact
that the underlying types never serialize to the empty string.
We do this instead of a generic std::optional<T> instance because
ordinal tags (0 or 1, here) are a bit of a compatability hazard. For
the same reason, we don't have a std::variant<T..> instances (ordinal
tags 0...n).
We could the generic instances and then these as specializations for
compatability, but that's proven a bit finnicky, and also makes the
worker protocol harder to implement in other languages where such
specializations may not be allowed.
*/
MAKE_WORKER_PROTO(, std::optional<StorePath>);
MAKE_WORKER_PROTO(, std::optional<ContentAddress>);
template<typename T> template<typename T>
std::set<T> read(const Store & store, Source & from, Phantom<std::set<T>> _) std::set<T> read(const Store & store, Source & from, Phantom<std::set<T>> _)
{ {
@ -134,37 +149,6 @@ void write(const Store & store, Sink & out, const std::map<K, V> & resMap)
} }
} }
template<typename T>
std::optional<T> read(const Store & store, Source & from, Phantom<std::optional<T>> _)
{
auto tag = readNum<uint8_t>(from);
switch (tag) {
case 0:
return std::nullopt;
case 1:
return read(store, from, Phantom<T> {});
default:
throw Error("got an invalid tag bit for std::optional: %#04x", (size_t)tag);
}
}
template<typename T>
void write(const Store & store, Sink & out, const std::optional<T> & optVal)
{
out << (uint64_t) (optVal ? 1 : 0);
if (optVal)
worker_proto::write(store, out, *optVal);
}
/* Specialization which uses and empty string for the empty case, taking
advantage of the fact these types always serialize to non-empty strings.
This is done primarily for backwards compatability, so that T <=
std::optional<T>, where <= is the compatability partial order, T is one of
the types below.
*/
MAKE_WORKER_PROTO(, std::optional<StorePath>);
MAKE_WORKER_PROTO(, std::optional<ContentAddress>);
} }
} }

View file

@ -33,7 +33,7 @@ struct ArchiveSettings : Config
static ArchiveSettings archiveSettings; static ArchiveSettings archiveSettings;
static GlobalConfig::Register r1(&archiveSettings); static GlobalConfig::Register rArchiveSettings(&archiveSettings);
const std::string narVersionMagic1 = "nix-archive-1"; const std::string narVersionMagic1 = "nix-archive-1";

View file

@ -17,8 +17,20 @@ void Args::addFlag(Flag && flag_)
if (flag->shortName) shortFlags[flag->shortName] = flag; if (flag->shortName) shortFlags[flag->shortName] = flag;
} }
void Completions::add(std::string completion, std::string description)
{
assert(description.find('\n') == std::string::npos);
insert(Completion {
.completion = completion,
.description = description
});
}
bool Completion::operator<(const Completion & other) const
{ return completion < other.completion || (completion == other.completion && description < other.description); }
bool pathCompletions = false; bool pathCompletions = false;
std::shared_ptr<std::set<std::string>> completions; std::shared_ptr<Completions> completions;
std::string completionMarker = "___COMPLETE___"; std::string completionMarker = "___COMPLETE___";
@ -148,7 +160,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
for (auto & [name, flag] : longFlags) { for (auto & [name, flag] : longFlags) {
if (!hiddenCategories.count(flag->category) if (!hiddenCategories.count(flag->category)
&& hasPrefix(name, std::string(*prefix, 2))) && hasPrefix(name, std::string(*prefix, 2)))
completions->insert("--" + name); completions->add("--" + name, flag->description);
} }
} }
auto i = longFlags.find(string(*pos, 2)); auto i = longFlags.find(string(*pos, 2));
@ -165,9 +177,9 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
if (auto prefix = needsCompletion(*pos)) { if (auto prefix = needsCompletion(*pos)) {
if (prefix == "-") { if (prefix == "-") {
completions->insert("--"); completions->add("--");
for (auto & [flag, _] : shortFlags) for (auto & [flagName, flag] : shortFlags)
completions->insert(std::string("-") + flag); completions->add(std::string("-") + flagName, flag->description);
} }
} }
@ -248,7 +260,7 @@ static void hashTypeCompleter(size_t index, std::string_view prefix)
{ {
for (auto & type : hashTypes) for (auto & type : hashTypes)
if (hasPrefix(type, prefix)) if (hasPrefix(type, prefix))
completions->insert(type); completions->add(type);
} }
Args::Flag Args::Flag::mkHashTypeFlag(std::string && longName, HashType * ht) Args::Flag Args::Flag::mkHashTypeFlag(std::string && longName, HashType * ht)
@ -277,7 +289,7 @@ Args::Flag Args::Flag::mkHashTypeOptFlag(std::string && longName, std::optional<
}; };
} }
static void completePath(std::string_view prefix, bool onlyDirs) static void _completePath(std::string_view prefix, bool onlyDirs)
{ {
pathCompletions = true; pathCompletions = true;
glob_t globbuf; glob_t globbuf;
@ -292,7 +304,7 @@ static void completePath(std::string_view prefix, bool onlyDirs)
auto st = lstat(globbuf.gl_pathv[i]); auto st = lstat(globbuf.gl_pathv[i]);
if (!S_ISDIR(st.st_mode)) continue; if (!S_ISDIR(st.st_mode)) continue;
} }
completions->insert(globbuf.gl_pathv[i]); completions->add(globbuf.gl_pathv[i]);
} }
globfree(&globbuf); globfree(&globbuf);
} }
@ -300,12 +312,12 @@ static void completePath(std::string_view prefix, bool onlyDirs)
void completePath(size_t, std::string_view prefix) void completePath(size_t, std::string_view prefix)
{ {
completePath(prefix, false); _completePath(prefix, false);
} }
void completeDir(size_t, std::string_view prefix) void completeDir(size_t, std::string_view prefix)
{ {
completePath(prefix, true); _completePath(prefix, true);
} }
Strings argvToStrings(int argc, char * * argv) Strings argvToStrings(int argc, char * * argv)
@ -385,7 +397,7 @@ MultiCommand::MultiCommand(const Commands & commands)
if (auto prefix = needsCompletion(s)) { if (auto prefix = needsCompletion(s)) {
for (auto & [name, command] : commands) for (auto & [name, command] : commands)
if (hasPrefix(name, *prefix)) if (hasPrefix(name, *prefix))
completions->insert(name); completions->add(name);
} }
auto i = commands.find(s); auto i = commands.find(s);
if (i == commands.end()) if (i == commands.end())

View file

@ -283,7 +283,17 @@ typedef std::vector<std::pair<std::string, std::string>> Table2;
void printTable(std::ostream & out, const Table2 & table); void printTable(std::ostream & out, const Table2 & table);
extern std::shared_ptr<std::set<std::string>> completions; struct Completion {
std::string completion;
std::string description;
bool operator<(const Completion & other) const;
};
class Completions : public std::set<Completion> {
public:
void add(std::string completion, std::string description = "");
};
extern std::shared_ptr<Completions> completions;
extern bool pathCompletions; extern bool pathCompletions;
std::optional<std::string> needsCompletion(std::string_view s); std::optional<std::string> needsCompletion(std::string_view s);

View file

@ -11,13 +11,13 @@ const std::string nativeSystem = SYSTEM;
BaseError & BaseError::addTrace(std::optional<ErrPos> e, hintformat hint) BaseError & BaseError::addTrace(std::optional<ErrPos> e, hintformat hint)
{ {
err.traces.push_front(Trace { .pos = e, .hint = hint}); err.traces.push_front(Trace { .pos = e, .hint = hint });
return *this; return *this;
} }
// c++ std::exception descendants must have a 'const char* what()' function. // c++ std::exception descendants must have a 'const char* what()' function.
// This stringifies the error and caches it for use by what(), or similarly by msg(). // This stringifies the error and caches it for use by what(), or similarly by msg().
const string& BaseError::calcWhat() const const string & BaseError::calcWhat() const
{ {
if (what_.has_value()) if (what_.has_value())
return *what_; return *what_;
@ -34,12 +34,12 @@ const string& BaseError::calcWhat() const
std::optional<string> ErrorInfo::programName = std::nullopt; std::optional<string> ErrorInfo::programName = std::nullopt;
std::ostream& operator<<(std::ostream &os, const hintformat &hf) std::ostream & operator<<(std::ostream & os, const hintformat & hf)
{ {
return os << hf.str(); return os << hf.str();
} }
string showErrPos(const ErrPos &errPos) string showErrPos(const ErrPos & errPos)
{ {
if (errPos.line > 0) { if (errPos.line > 0) {
if (errPos.column > 0) { if (errPos.column > 0) {
@ -53,7 +53,7 @@ string showErrPos(const ErrPos &errPos)
} }
} }
std::optional<LinesOfCode> getCodeLines(const ErrPos &errPos) std::optional<LinesOfCode> getCodeLines(const ErrPos & errPos)
{ {
if (errPos.line <= 0) if (errPos.line <= 0)
return std::nullopt; return std::nullopt;
@ -92,13 +92,13 @@ std::optional<LinesOfCode> getCodeLines(const ErrPos &errPos)
return loc; return loc;
} }
} }
catch (EndOfFile &eof) { catch (EndOfFile & eof) {
if (loc.errLineOfCode.has_value()) if (loc.errLineOfCode.has_value())
return loc; return loc;
else else
return std::nullopt; return std::nullopt;
} }
catch (std::exception &e) { catch (std::exception & e) {
printError("error reading nix file: %s\n%s", errPos.file, e.what()); printError("error reading nix file: %s\n%s", errPos.file, e.what());
return std::nullopt; return std::nullopt;
} }
@ -137,10 +137,10 @@ std::optional<LinesOfCode> getCodeLines(const ErrPos &errPos)
} }
// print lines of code to the ostream, indicating the error column. // print lines of code to the ostream, indicating the error column.
void printCodeLines(std::ostream &out, void printCodeLines(std::ostream & out,
const string &prefix, const string & prefix,
const ErrPos &errPos, const ErrPos & errPos,
const LinesOfCode &loc) const LinesOfCode & loc)
{ {
// previous line of code. // previous line of code.
if (loc.prevLineOfCode.has_value()) { if (loc.prevLineOfCode.has_value()) {
@ -186,7 +186,7 @@ void printCodeLines(std::ostream &out,
} }
} }
void printAtPos(const string &prefix, const ErrPos &pos, std::ostream &out) void printAtPos(const string & prefix, const ErrPos & pos, std::ostream & out)
{ {
if (pos) if (pos)
{ {
@ -212,7 +212,7 @@ void printAtPos(const string &prefix, const ErrPos &pos, std::ostream &out)
} }
} }
std::ostream& showErrorInfo(std::ostream &out, const ErrorInfo &einfo, bool showTrace) std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace)
{ {
auto errwidth = std::max<size_t>(getWindowSize().second, 20); auto errwidth = std::max<size_t>(getWindowSize().second, 20);
string prefix = ""; string prefix = "";

View file

@ -107,7 +107,7 @@ struct Trace {
struct ErrorInfo { struct ErrorInfo {
Verbosity level; Verbosity level;
string name; string name;
string description; string description; // FIXME: remove? it seems to be barely used
std::optional<hintformat> hint; std::optional<hintformat> hint;
std::optional<ErrPos> errPos; std::optional<ErrPos> errPos;
std::list<Trace> traces; std::list<Trace> traces;
@ -169,7 +169,7 @@ public:
#endif #endif
const string & msg() const { return calcWhat(); } const string & msg() const { return calcWhat(); }
const ErrorInfo & info() { calcWhat(); return err; } const ErrorInfo & info() const { calcWhat(); return err; }
template<typename... Args> template<typename... Args>
BaseError & addTrace(std::optional<ErrPos> e, const string &fs, const Args & ... args) BaseError & addTrace(std::optional<ErrPos> e, const string &fs, const Args & ... args)

View file

@ -76,11 +76,11 @@ template <class T>
struct yellowtxt struct yellowtxt
{ {
yellowtxt(const T &s) : value(s) {} yellowtxt(const T &s) : value(s) {}
const T &value; const T & value;
}; };
template <class T> template <class T>
std::ostream& operator<<(std::ostream &out, const yellowtxt<T> &y) std::ostream & operator<<(std::ostream & out, const yellowtxt<T> & y)
{ {
return out << ANSI_YELLOW << y.value << ANSI_NORMAL; return out << ANSI_YELLOW << y.value << ANSI_NORMAL;
} }
@ -88,12 +88,12 @@ std::ostream& operator<<(std::ostream &out, const yellowtxt<T> &y)
template <class T> template <class T>
struct normaltxt struct normaltxt
{ {
normaltxt(const T &s) : value(s) {} normaltxt(const T & s) : value(s) {}
const T &value; const T & value;
}; };
template <class T> template <class T>
std::ostream& operator<<(std::ostream &out, const normaltxt<T> &y) std::ostream & operator<<(std::ostream & out, const normaltxt<T> & y)
{ {
return out << ANSI_NORMAL << y.value; return out << ANSI_NORMAL << y.value;
} }
@ -101,26 +101,30 @@ std::ostream& operator<<(std::ostream &out, const normaltxt<T> &y)
class hintformat class hintformat
{ {
public: public:
hintformat(const string &format) :fmt(format) hintformat(const string & format) : fmt(format)
{ {
fmt.exceptions(boost::io::all_error_bits ^ fmt.exceptions(boost::io::all_error_bits ^
boost::io::too_many_args_bit ^ boost::io::too_many_args_bit ^
boost::io::too_few_args_bit); boost::io::too_few_args_bit);
} }
hintformat(const hintformat &hf) hintformat(const hintformat & hf)
: fmt(hf.fmt) : fmt(hf.fmt)
{} { }
hintformat(format && fmt)
: fmt(std::move(fmt))
{ }
template<class T> template<class T>
hintformat& operator%(const T &value) hintformat & operator%(const T & value)
{ {
fmt % yellowtxt(value); fmt % yellowtxt(value);
return *this; return *this;
} }
template<class T> template<class T>
hintformat& operator%(const normaltxt<T> &value) hintformat & operator%(const normaltxt<T> & value)
{ {
fmt % value.value; fmt % value.value;
return *this; return *this;
@ -135,7 +139,7 @@ private:
format fmt; format fmt;
}; };
std::ostream& operator<<(std::ostream &os, const hintformat &hf); std::ostream & operator<<(std::ostream & os, const hintformat & hf);
template<typename... Args> template<typename... Args>
inline hintformat hintfmt(const std::string & fs, const Args & ... args) inline hintformat hintfmt(const std::string & fs, const Args & ... args)

View file

@ -1,48 +0,0 @@
#include <exception>
#include <functional>
#include <mutex>
namespace nix {
/* A helper class for lazily-initialized variables.
Lazy<T> var([]() { return value; });
declares a variable of type T that is initialized to 'value' (in a
thread-safe way) on first use, that is, when var() is first
called. If the initialiser code throws an exception, then all
subsequent calls to var() will rethrow that exception. */
template<typename T>
class Lazy
{
typedef std::function<T()> Init;
Init init;
std::once_flag done;
T value;
std::exception_ptr ex;
public:
Lazy(Init init) : init(init)
{ }
const T & operator () ()
{
std::call_once(done, [&]() {
try {
value = init();
} catch (...) {
ex = std::current_exception();
}
});
if (ex) std::rethrow_exception(ex);
return value;
}
};
}

View file

@ -10,7 +10,7 @@ namespace nix {
LoggerSettings loggerSettings; LoggerSettings loggerSettings;
static GlobalConfig::Register r1(&loggerSettings); static GlobalConfig::Register rLoggerSettings(&loggerSettings);
static thread_local ActivityId curActivity = 0; static thread_local ActivityId curActivity = 0;

View file

@ -266,6 +266,24 @@ Sink & operator << (Sink & sink, const StringSet & s)
return sink; return sink;
} }
Sink & operator << (Sink & sink, const Error & ex)
{
auto info = ex.info();
sink
<< "Error"
<< info.level
<< info.name
<< info.description
<< (info.hint ? info.hint->str() : "")
<< 0 // FIXME: info.errPos
<< info.traces.size();
for (auto & trace : info.traces) {
sink << 0; // FIXME: trace.pos
sink << trace.hint.str();
}
return sink;
}
void readPadding(size_t len, Source & source) void readPadding(size_t len, Source & source)
{ {
@ -319,6 +337,30 @@ template Paths readStrings(Source & source);
template PathSet readStrings(Source & source); template PathSet readStrings(Source & source);
Error readError(Source & source)
{
auto type = readString(source);
assert(type == "Error");
ErrorInfo info;
info.level = (Verbosity) readInt(source);
info.name = readString(source);
info.description = readString(source);
auto hint = readString(source);
if (hint != "") info.hint = hintformat(std::move(format("%s") % hint));
auto havePos = readNum<size_t>(source);
assert(havePos == 0);
auto nrTraces = readNum<size_t>(source);
for (size_t i = 0; i < nrTraces; ++i) {
havePos = readNum<size_t>(source);
assert(havePos == 0);
info.traces.push_back(Trace {
.hint = hintformat(std::move(format("%s") % readString(source)))
});
}
return Error(std::move(info));
}
void StringSink::operator () (const unsigned char * data, size_t len) void StringSink::operator () (const unsigned char * data, size_t len)
{ {
static bool warned = false; static bool warned = false;

View file

@ -321,6 +321,7 @@ inline Sink & operator << (Sink & sink, uint64_t n)
Sink & operator << (Sink & sink, const string & s); Sink & operator << (Sink & sink, const string & s);
Sink & operator << (Sink & sink, const Strings & s); Sink & operator << (Sink & sink, const Strings & s);
Sink & operator << (Sink & sink, const StringSet & s); Sink & operator << (Sink & sink, const StringSet & s);
Sink & operator << (Sink & in, const Error & ex);
MakeError(SerialisationError, Error); MakeError(SerialisationError, Error);
@ -382,6 +383,8 @@ Source & operator >> (Source & in, bool & b)
return in; return in;
} }
Error readError(Source & source);
/* An adapter that converts a std::basic_istream into a source. */ /* An adapter that converts a std::basic_istream into a source. */
struct StreamToSourceAdapter : Source struct StreamToSourceAdapter : Source

View file

@ -1,3 +1,5 @@
#pragma once
#include "error.hh" #include "error.hh"
namespace nix { namespace nix {

View file

@ -1,4 +1,3 @@
#include "lazy.hh"
#include "util.hh" #include "util.hh"
#include "affinity.hh" #include "affinity.hh"
#include "sync.hh" #include "sync.hh"
@ -326,7 +325,12 @@ void writeFile(const Path & path, const string & s, mode_t mode)
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode); AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
if (!fd) if (!fd)
throw SysError("opening file '%1%'", path); throw SysError("opening file '%1%'", path);
writeFull(fd.get(), s); try {
writeFull(fd.get(), s);
} catch (Error & e) {
e.addTrace({}, "writing file '%1%'", path);
throw;
}
} }
@ -338,11 +342,16 @@ void writeFile(const Path & path, Source & source, mode_t mode)
std::vector<unsigned char> buf(64 * 1024); std::vector<unsigned char> buf(64 * 1024);
while (true) { try {
try { while (true) {
auto n = source.read(buf.data(), buf.size()); try {
writeFull(fd.get(), (unsigned char *) buf.data(), n); auto n = source.read(buf.data(), buf.size());
} catch (EndOfFile &) { break; } writeFull(fd.get(), (unsigned char *) buf.data(), n);
} catch (EndOfFile &) { break; }
}
} catch (Error & e) {
e.addTrace({}, "writing file '%1%'", path);
throw;
} }
} }
@ -512,21 +521,24 @@ std::string getUserName()
} }
static Lazy<Path> getHome2([]() { Path getHome()
auto homeDir = getEnv("HOME"); {
if (!homeDir) { static Path homeDir = []()
std::vector<char> buf(16384); {
struct passwd pwbuf; auto homeDir = getEnv("HOME");
struct passwd * pw; if (!homeDir) {
if (getpwuid_r(geteuid(), &pwbuf, buf.data(), buf.size(), &pw) != 0 std::vector<char> buf(16384);
|| !pw || !pw->pw_dir || !pw->pw_dir[0]) struct passwd pwbuf;
throw Error("cannot determine user's home directory"); struct passwd * pw;
homeDir = pw->pw_dir; if (getpwuid_r(geteuid(), &pwbuf, buf.data(), buf.size(), &pw) != 0
} || !pw || !pw->pw_dir || !pw->pw_dir[0])
return *homeDir; throw Error("cannot determine user's home directory");
}); homeDir = pw->pw_dir;
}
Path getHome() { return getHome2(); } return *homeDir;
}();
return homeDir;
}
Path getCacheDir() Path getCacheDir()
@ -1641,4 +1653,11 @@ AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode)
return fdSocket; return fdSocket;
} }
string showBytes(uint64_t bytes)
{
return fmt("%.2f MiB", bytes / (1024.0 * 1024.0));
}
} }

View file

@ -573,4 +573,7 @@ template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
std::string showBytes(uint64_t bytes);
} }

View file

@ -6,6 +6,7 @@
#include <vector> #include <vector>
#include "store-api.hh" #include "store-api.hh"
#include "local-fs-store.hh"
#include "globals.hh" #include "globals.hh"
#include "derivations.hh" #include "derivations.hh"
#include "affinity.hh" #include "affinity.hh"
@ -67,7 +68,7 @@ std::vector<string> shellwords(const string & s)
return res; return res;
} }
static void _main(int argc, char * * argv) static void main_nix_build(int argc, char * * argv)
{ {
auto dryRun = false; auto dryRun = false;
auto runEnv = std::regex_search(argv[0], std::regex("nix-shell$")); auto runEnv = std::regex_search(argv[0], std::regex("nix-shell$"));
@ -540,5 +541,5 @@ static void _main(int argc, char * * argv)
} }
} }
static RegisterLegacyCommand s1("nix-build", _main); static RegisterLegacyCommand r_nix_build("nix-build", main_nix_build);
static RegisterLegacyCommand s2("nix-shell", _main); static RegisterLegacyCommand r_nix_shell("nix-shell", main_nix_build);

View file

@ -153,7 +153,7 @@ static void update(const StringSet & channelNames)
replaceSymlink(profile, channelLink); replaceSymlink(profile, channelLink);
} }
static int _main(int argc, char ** argv) static int main_nix_channel(int argc, char ** argv)
{ {
{ {
// Figure out the name of the `.nix-channels' file to use // Figure out the name of the `.nix-channels' file to use
@ -250,4 +250,4 @@ static int _main(int argc, char ** argv)
} }
} }
static RegisterLegacyCommand s1("nix-channel", _main); static RegisterLegacyCommand r_nix_channel("nix-channel", main_nix_channel);

View file

@ -49,7 +49,7 @@ void removeOldGenerations(std::string dir)
} }
} }
static int _main(int argc, char * * argv) static int main_nix_collect_garbage(int argc, char * * argv)
{ {
{ {
bool removeOld = false; bool removeOld = false;
@ -92,4 +92,4 @@ static int _main(int argc, char * * argv)
} }
} }
static RegisterLegacyCommand s1("nix-collect-garbage", _main); static RegisterLegacyCommand r_nix_collect_garbage("nix-collect-garbage", main_nix_collect_garbage);

View file

@ -4,7 +4,7 @@
using namespace nix; using namespace nix;
static int _main(int argc, char ** argv) static int main_nix_copy_closure(int argc, char ** argv)
{ {
{ {
auto gzip = false; auto gzip = false;
@ -65,4 +65,4 @@ static int _main(int argc, char ** argv)
} }
} }
static RegisterLegacyCommand s1("nix-copy-closure", _main); static RegisterLegacyCommand r_nix_copy_closure("nix-copy-closure", main_nix_copy_closure);

View file

@ -265,7 +265,7 @@ static void daemonLoop(char * * argv)
} }
static int _main(int argc, char * * argv) static int main_nix_daemon(int argc, char * * argv)
{ {
{ {
auto stdio = false; auto stdio = false;
@ -330,4 +330,4 @@ static int _main(int argc, char * * argv)
} }
} }
static RegisterLegacyCommand s1("nix-daemon", _main); static RegisterLegacyCommand r_nix_daemon("nix-daemon", main_nix_daemon);

View file

@ -8,6 +8,7 @@
#include "profiles.hh" #include "profiles.hh"
#include "shared.hh" #include "shared.hh"
#include "store-api.hh" #include "store-api.hh"
#include "local-fs-store.hh"
#include "user-env.hh" #include "user-env.hh"
#include "util.hh" #include "util.hh"
#include "json.hh" #include "json.hh"
@ -1330,7 +1331,7 @@ static void opVersion(Globals & globals, Strings opFlags, Strings opArgs)
} }
static int _main(int argc, char * * argv) static int main_nix_env(int argc, char * * argv)
{ {
{ {
Strings opFlags, opArgs; Strings opFlags, opArgs;
@ -1460,4 +1461,4 @@ static int _main(int argc, char * * argv)
} }
} }
static RegisterLegacyCommand s1("nix-env", _main); static RegisterLegacyCommand r_nix_env("nix-env", main_nix_env);

View file

@ -2,6 +2,7 @@
#include "util.hh" #include "util.hh"
#include "derivations.hh" #include "derivations.hh"
#include "store-api.hh" #include "store-api.hh"
#include "local-fs-store.hh"
#include "globals.hh" #include "globals.hh"
#include "shared.hh" #include "shared.hh"
#include "eval.hh" #include "eval.hh"

View file

@ -8,6 +8,7 @@
#include "value-to-json.hh" #include "value-to-json.hh"
#include "util.hh" #include "util.hh"
#include "store-api.hh" #include "store-api.hh"
#include "local-fs-store.hh"
#include "common-eval-args.hh" #include "common-eval-args.hh"
#include "../nix/legacy.hh" #include "../nix/legacy.hh"
@ -83,7 +84,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
} }
static int _main(int argc, char * * argv) static int main_nix_instantiate(int argc, char * * argv)
{ {
{ {
Strings files; Strings files;
@ -192,4 +193,4 @@ static int _main(int argc, char * * argv)
} }
} }
static RegisterLegacyCommand s1("nix-instantiate", _main); static RegisterLegacyCommand r_nix_instantiate("nix-instantiate", main_nix_instantiate);

View file

@ -48,7 +48,7 @@ string resolveMirrorUri(EvalState & state, string uri)
} }
static int _main(int argc, char * * argv) static int main_nix_prefetch_url(int argc, char * * argv)
{ {
{ {
HashType ht = htSHA256; HashType ht = htSHA256;
@ -235,4 +235,4 @@ static int _main(int argc, char * * argv)
} }
} }
static RegisterLegacyCommand s1("nix-prefetch-url", _main); static RegisterLegacyCommand r_nix_prefetch_url("nix-prefetch-url", main_nix_prefetch_url);

View file

@ -24,6 +24,9 @@
#endif #endif
namespace nix_store {
using namespace nix; using namespace nix;
using std::cin; using std::cin;
using std::cout; using std::cout;
@ -1031,7 +1034,7 @@ static void opVersion(Strings opFlags, Strings opArgs)
/* Scan the arguments; find the operation, set global flags, put all /* Scan the arguments; find the operation, set global flags, put all
other flags in a list, and put all other arguments in another other flags in a list, and put all other arguments in another
list. */ list. */
static int _main(int argc, char * * argv) static int main_nix_store(int argc, char * * argv)
{ {
{ {
Strings opFlags, opArgs; Strings opFlags, opArgs;
@ -1127,4 +1130,6 @@ static int _main(int argc, char * * argv)
} }
} }
static RegisterLegacyCommand s1("nix-store", _main); static RegisterLegacyCommand r_nix_store("nix-store", main_nix_store);
}

View file

@ -93,4 +93,4 @@ struct CmdAddToStore : MixDryRun, StoreCommand
} }
}; };
static auto r1 = registerCommand<CmdAddToStore>("add-to-store"); static auto rCmdAddToStore = registerCommand<CmdAddToStore>("add-to-store");

View file

@ -3,6 +3,7 @@
#include "common-args.hh" #include "common-args.hh"
#include "shared.hh" #include "shared.hh"
#include "store-api.hh" #include "store-api.hh"
#include "local-fs-store.hh"
using namespace nix; using namespace nix;
@ -88,4 +89,4 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixProfile
} }
}; };
static auto r1 = registerCommand<CmdBuild>("build"); static auto rCmdBuild = registerCommand<CmdBuild>("build");

View file

@ -2,6 +2,7 @@
#include "common-args.hh" #include "common-args.hh"
#include "shared.hh" #include "shared.hh"
#include "store-api.hh" #include "store-api.hh"
#include "local-fs-store.hh"
#include "fs-accessor.hh" #include "fs-accessor.hh"
using namespace nix; using namespace nix;

View file

@ -72,5 +72,5 @@ struct CmdCatNar : StoreCommand, MixCat
} }
}; };
static auto r1 = registerCommand<CmdCatStore>("cat-store"); static auto rCmdCatStore = registerCommand<CmdCatStore>("cat-store");
static auto r2 = registerCommand<CmdCatNar>("cat-nar"); static auto rCmdCatNar = registerCommand<CmdCatNar>("cat-nar");

View file

@ -1,5 +1,6 @@
#include "command.hh" #include "command.hh"
#include "store-api.hh" #include "store-api.hh"
#include "local-fs-store.hh"
#include "derivations.hh" #include "derivations.hh"
#include "nixexpr.hh" #include "nixexpr.hh"
#include "profiles.hh" #include "profiles.hh"

View file

@ -106,4 +106,4 @@ struct CmdCopy : StorePathsCommand
} }
}; };
static auto r1 = registerCommand<CmdCopy>("copy"); static auto rCmdCopy = registerCommand<CmdCopy>("copy");

View file

@ -41,4 +41,4 @@ struct CmdDescribeStores : Command, MixJSON
} }
}; };
static auto r1 = registerCommand<CmdDescribeStores>("describe-stores"); static auto rDescribeStore = registerCommand<CmdDescribeStores>("describe-stores");

View file

@ -164,6 +164,7 @@ struct Common : InstallableCommand, MixProfile
"BASHOPTS", "BASHOPTS",
"EUID", "EUID",
"HOME", // FIXME: don't ignore in pure mode? "HOME", // FIXME: don't ignore in pure mode?
"HOSTNAME",
"NIX_BUILD_TOP", "NIX_BUILD_TOP",
"NIX_ENFORCE_PURITY", "NIX_ENFORCE_PURITY",
"NIX_LOG_FD", "NIX_LOG_FD",
@ -377,6 +378,10 @@ struct CmdDevelop : Common, MixEnvironment
script += fmt("exec %s\n", concatStringsSep(" ", args)); script += fmt("exec %s\n", concatStringsSep(" ", args));
} }
else {
script += "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc;\n";
}
writeFull(rcFileFd.get(), script); writeFull(rcFileFd.get(), script);
stopProgressBar(); stopProgressBar();
@ -443,5 +448,5 @@ struct CmdPrintDevEnv : Common
} }
}; };
static auto r1 = registerCommand<CmdPrintDevEnv>("print-dev-env"); static auto rCmdPrintDevEnv = registerCommand<CmdPrintDevEnv>("print-dev-env");
static auto r2 = registerCommand<CmdDevelop>("develop"); static auto rCmdDevelop = registerCommand<CmdDevelop>("develop");

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