Make the Store API more type-safe

Most functions now take a StorePath argument rather than a Path (which
is just an alias for std::string). The StorePath constructor ensures
that the path is syntactically correct (i.e. it looks like
<store-dir>/<base32-hash>-<name>). Similarly, functions like
buildPaths() now take a StorePathWithOutputs, rather than abusing Path
by adding a '!<outputs>' suffix.

Note that the StorePath type is implemented in Rust. This involves
some hackery to allow Rust values to be used directly in C++, via a
helper type whose destructor calls the Rust type's drop()
function. The main issue is the dynamic nature of C++ move semantics:
after we have moved a Rust value, we should not call the drop function
on the original value. So when we move a value, we set the original
value to bitwise zero, and the destructor only calls drop() if the
value is not bitwise zero. This should be sufficient for most types.

Also lots of minor cleanups to the C++ API to make it more modern
(e.g. using std::optional and std::string_view in some places).
This commit is contained in:
Eelco Dolstra 2019-12-05 19:11:09 +01:00
parent ebd89999c2
commit bbe97dff8b
98 changed files with 2638 additions and 2880 deletions

760
nix-rust/Cargo.lock generated
View file

@ -33,15 +33,6 @@ name = "byteorder"
version = "1.3.2" version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bytes"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "c2-chacha" name = "c2-chacha"
version = "0.2.3" version = "0.2.3"
@ -63,63 +54,6 @@ dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "crossbeam-channel"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-deque"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-epoch"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-queue"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-utils"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-utils"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "filetime" name = "filetime"
version = "0.2.8" version = "0.2.8"
@ -141,81 +75,6 @@ name = "fuchsia-cprng"
version = "0.1.1" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-channel-preview"
version = "0.3.0-alpha.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-core-preview"
version = "0.3.0-alpha.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-executor-preview"
version = "0.3.0-alpha.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-io-preview"
version = "0.3.0-alpha.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-preview"
version = "0.3.0-alpha.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-executor-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-sink-preview"
version = "0.3.0-alpha.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-util-preview"
version = "0.3.0-alpha.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.1.13" version = "0.1.13"
@ -226,234 +85,31 @@ dependencies = [
"wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "h2"
version = "0.2.0-alpha.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hermit-abi"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "hex" name = "hex"
version = "0.3.2" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "http"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "http-body"
version = "0.2.0-alpha.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "httparse"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "hyper"
version = "0.13.0-alpha.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"h2 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"http-body 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-project 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-net 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-timer 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tower-make 0.3.0-alpha.2a (registry+https://github.com/rust-lang/crates.io-index)",
"tower-service 0.3.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)",
"want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "indexmap"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "iovec"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.66" version = "0.2.66"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lock_api"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "maybe-uninit"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memoffset"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio"
version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio-uds"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "miow"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "net2"
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "nix-rust" name = "nix-rust"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.13.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tar 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -464,75 +120,11 @@ dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "num_cpus"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parking_lot"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parking_lot_core"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pin-project"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"pin-project-internal 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pin-project-internal"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pin-utils"
version = "0.1.0-alpha.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.6" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "proptest" name = "proptest"
version = "0.9.4" version = "0.9.4"
@ -557,14 +149,6 @@ name = "quick-error"
version = "1.2.2" version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.6.5" version = "0.6.5"
@ -724,14 +308,6 @@ dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "rusty-fork" name = "rusty-fork"
version = "0.2.2" version = "0.2.2"
@ -743,60 +319,6 @@ dependencies = [
"wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "scopeguard"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slab"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smallvec"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "string"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "tar" name = "tar"
version = "0.4.26" version = "0.4.26"
@ -821,188 +343,6 @@ dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "time"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio"
version = "0.2.0-alpha.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-macros 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-net 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-timer 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tracing-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-codec"
version = "0.2.0-alpha.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-executor"
version = "0.2.0-alpha.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tracing 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-io"
version = "0.2.0-alpha.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-project 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-macros"
version = "0.2.0-alpha.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-net"
version = "0.2.0-alpha.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tracing 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-sync"
version = "0.2.0-alpha.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-timer"
version = "0.3.0-alpha.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tower-make"
version = "0.3.0-alpha.2a"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tower-service 0.3.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tower-service"
version = "0.3.0-alpha.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "tracing"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tracing-attributes 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"tracing-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tracing-attributes"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tracing-core"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "try-lock"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "wait-timeout" name = "wait-timeout"
version = "0.2.0" version = "0.2.0"
@ -1011,25 +351,11 @@ dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "want"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.7.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.8" version = "0.3.8"
@ -1039,11 +365,6 @@ dependencies = [
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "winapi-i686-pc-windows-gnu" name = "winapi-i686-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
@ -1054,15 +375,6 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "xattr" name = "xattr"
version = "0.2.2" version = "0.2.2"
@ -1078,63 +390,20 @@ dependencies = [
"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb" "checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa"
"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
"checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" "checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e5f4df964fa9c1c2f8bddeb5c3611631cacd93baf810fc8bb2fb4b495c263a"
"checksum futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "b35b6263fb1ef523c3056565fa67b1d16f0a8604ff12b11b08c25f28a734c60a"
"checksum futures-executor-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "75236e88bd9fe88e5e8bfcd175b665d0528fe03ca4c5207fabc028c8f9d93e98"
"checksum futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "f4914ae450db1921a56c91bde97a27846287d062087d4a652efc09bb3a01ebda"
"checksum futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "3b1dce2a0267ada5c6ff75a8ba864b4e679a9e2aa44262af7a3b5516d530d76e"
"checksum futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "86f148ef6b69f75bb610d4f9a2336d4fc88c4b5b67129d1a340dd0fd362efeec"
"checksum futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce968633c17e5f97936bd2797b6e38fb56cf16a7422319f7ec2e30d3c470e8d"
"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407"
"checksum h2 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0f107db1419ef8271686187b1a5d47c6431af4a7f4d98b495e7b7fc249bb0a78"
"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120"
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
"checksum http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0"
"checksum http-body 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f3aef6f3de2bd8585f5b366f3f550b5774500b4764d00cf00f903c95749eec3"
"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
"checksum hyper 0.13.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2d05aa523087ac0b9d8b93dd80d5d482a697308ed3b0dca7b0667511a7fa7cdc"
"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2"
"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
"checksum lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
"checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f"
"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" "checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72"
"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
"checksum pin-project 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "94b90146c7216e4cb534069fb91366de4ea0ea353105ee45ed297e2d1619e469"
"checksum pin-project-internal 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "44ca92f893f0656d3cba8158dd0f2b99b94de256a4a54e870bd6922fcc6c8355"
"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" "checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
@ -1153,41 +422,12 @@ dependencies = [
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae" "checksum rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d"
"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
"checksum tar 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "b3196bfbffbba3e57481b6ea32249fbaf590396a52505a2615adbb79d9d826d3" "checksum tar 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "b3196bfbffbba3e57481b6ea32249fbaf590396a52505a2615adbb79d9d826d3"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1f17f5d6ab0f35c1506678b28fb1798bdf74fcb737e9843c7b17b73e426eba38"
"checksum tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9f5d22fd1e84bd4045d28813491cb7d7caae34d45c80517c2213f09a85e8787a"
"checksum tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee9ceecf69145923834ea73f32ba40c790fd877b74a7817dd0b089f1eb9c7c8"
"checksum tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "112784d5543df30660b04a72ca423bfbd90e8bb32f94dcf610f15401218b22c5"
"checksum tokio-macros 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "86b616374bcdadd95974e1f0dfca07dc913f1163c53840c0d664aca35114964e"
"checksum tokio-net 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a441682cd32f3559383112c4a7f372f5c9fa1950c5cf8c8dd05274a2ce8c2654"
"checksum tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f1aaeb685540f7407ea0e27f1c9757d258c7c6bf4e3eb19da6fc59b747239d2"
"checksum tokio-timer 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b97c1587fe71018eb245a4a9daa13a5a3b681bbc1f7fdadfe24720e141472c13"
"checksum tower-make 0.3.0-alpha.2a (registry+https://github.com/rust-lang/crates.io-index)" = "316d47dd40cde4ac5d88110eaf9a10a4e2a68612d9c056cd2aa24e37dcb484cd"
"checksum tower-service 0.3.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "63ff37396cd966ce43bea418bfa339f802857495f797dafa00bea5b7221ebdfa"
"checksum tracing 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ff4e4f59e752cb3beb5b61c6d5e11191c7946231ba84faec2902c9efdd8691c5"
"checksum tracing-attributes 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a4263b12c3d3c403274493eb805966093b53214124796552d674ca1dd5d27c2b"
"checksum tracing-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bc913647c520c959b6d21e35ed8fa6984971deca9f0a2fcb8c51207e0c56af1d"
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
"checksum want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
"checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" "checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c"

View file

@ -11,12 +11,12 @@ crate-type = ["cdylib"]
[dependencies] [dependencies]
tar = "0.4" tar = "0.4"
libc = "0.2" libc = "0.2"
futures-preview = { version = "=0.3.0-alpha.19" } #futures-preview = { version = "=0.3.0-alpha.19" }
hyper = "0.13.0-alpha.4" #hyper = "0.13.0-alpha.4"
http = "0.1" #http = "0.1"
tokio = { version = "0.2.0-alpha.6", default-features = false, features = ["rt-full"] } #tokio = { version = "0.2.0-alpha.6", default-features = false, features = ["rt-full"] }
lazy_static = "1.4" lazy_static = "1.4"
byteorder = "1.3" #byteorder = "1.3"
[dev-dependencies] [dev-dependencies]
hex = "0.3" hex = "0.3"

View file

@ -37,7 +37,9 @@ clean: clean-rust
clean-rust: clean-rust:
$(suppress) rm -rfv nix-rust/target $(suppress) rm -rfv nix-rust/target
ifneq ($(OS), Darwin)
check: rust-tests check: rust-tests
rust-tests: rust-tests:
cd nix-rust && CARGO_HOME=$$(if [[ -d vendor ]]; then echo vendor; fi) RUSTC_BOOTSTRAP=1 cargo test --release $$(if [[ -d vendor ]]; then echo -Z offline; fi) cd nix-rust && CARGO_HOME=$$(if [[ -d vendor ]]; then echo vendor; fi) cargo test --release $$(if [[ -d vendor ]]; then echo --offline; fi)
endif

View file

@ -1,6 +1,7 @@
use super::{ use super::{
error, error,
foreign::{self, CBox}, foreign::{self, CBox},
store::StorePath,
util, util,
}; };
@ -13,43 +14,72 @@ pub extern "C" fn unpack_tarfile(
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rust_test() { pub unsafe extern "C" fn ffi_String_new(s: &str, out: *mut String) {
use crate::store::{self, Store}; // FIXME: check whether 's' is valid UTF-8?
use std::path::Path; out.write(s.to_string())
use tokio::runtime::Runtime; }
let fut = async move { #[no_mangle]
let store: Box<dyn Store> = Box::new(store::BinaryCacheStore::new( pub unsafe extern "C" fn ffi_String_drop(self_: *mut String) {
"http://cache.nixos.org".to_string(), std::ptr::drop_in_place(self_);
)); }
let path = store #[no_mangle]
.parse_store_path(&Path::new( pub extern "C" fn ffi_StorePath_new(
"/nix/store/7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3", path: &str,
)) store_dir: &str,
.unwrap(); ) -> Result<StorePath, error::CppException> {
StorePath::new(std::path::Path::new(path), store_dir).map_err(|err| err.into())
/* }
let info = store.query_path_info(&path).await.unwrap();
#[no_mangle]
eprintln!("INFO = {:?}", info); pub extern "C" fn ffi_StorePath_new2(
*/ hash: &[u8; crate::store::path::STORE_PATH_HASH_BYTES],
name: &str,
let closure = store ) -> Result<StorePath, error::CppException> {
.compute_path_closure(vec![path].into_iter().collect()) StorePath::from_parts(*hash, name).map_err(|err| err.into())
.await }
.unwrap();
#[no_mangle]
eprintln!("CLOSURE = {:?}", closure.len()); pub extern "C" fn ffi_StorePath_fromBaseName(
}; base_name: &str,
) -> Result<StorePath, error::CppException> {
let rt = Runtime::new().unwrap(); StorePath::new_from_base_name(base_name).map_err(|err| err.into())
}
rt.block_on(fut);
#[no_mangle]
/* pub unsafe extern "C" fn ffi_StorePath_drop(self_: *mut StorePath) {
let file = std::fs::File::open("test.nar").unwrap(); std::ptr::drop_in_place(self_);
}
crate::nar::parse(&mut std::io::BufReader::new(file)).unwrap();
*/ #[no_mangle]
pub extern "C" fn ffi_StorePath_to_string(self_: &StorePath) -> String {
format!("{}", self_)
}
#[no_mangle]
pub extern "C" fn ffi_StorePath_less_than(a: &StorePath, b: &StorePath) -> bool {
a < b
}
#[no_mangle]
pub extern "C" fn ffi_StorePath_eq(a: &StorePath, b: &StorePath) -> bool {
a == b
}
#[no_mangle]
pub extern "C" fn ffi_StorePath_clone(self_: &StorePath) -> StorePath {
self_.clone()
}
#[no_mangle]
pub extern "C" fn ffi_StorePath_name(self_: &StorePath) -> &str {
self_.name.name()
}
#[no_mangle]
pub extern "C" fn ffi_StorePath_hash_data(
self_: &StorePath,
) -> &[u8; crate::store::path::STORE_PATH_HASH_BYTES] {
self_.hash.hash()
} }

View file

@ -19,6 +19,7 @@ pub enum Error {
BadNarField(String), BadNarField(String),
BadExecutableField, BadExecutableField,
IOError(std::io::Error), IOError(std::io::Error),
#[cfg(unused)]
HttpError(hyper::error::Error), HttpError(hyper::error::Error),
Misc(String), Misc(String),
Foreign(CppException), Foreign(CppException),
@ -30,6 +31,7 @@ impl From<std::io::Error> for Error {
} }
} }
#[cfg(unused)]
impl From<hyper::error::Error> for Error { impl From<hyper::error::Error> for Error {
fn from(err: hyper::error::Error) -> Self { fn from(err: hyper::error::Error) -> Self {
Error::HttpError(err) Error::HttpError(err)
@ -58,6 +60,7 @@ impl fmt::Display for Error {
Error::BadNarField(s) => write!(f, "unrecognized NAR field '{}'", s), Error::BadNarField(s) => write!(f, "unrecognized NAR field '{}'", s),
Error::BadExecutableField => write!(f, "bad 'executable' field in NAR"), Error::BadExecutableField => write!(f, "bad 'executable' field in NAR"),
Error::IOError(err) => write!(f, "I/O error: {}", err), Error::IOError(err) => write!(f, "I/O error: {}", err),
#[cfg(unused)]
Error::HttpError(err) => write!(f, "HTTP error: {}", err), Error::HttpError(err) => write!(f, "HTTP error: {}", err),
Error::Foreign(_) => write!(f, "<C++ exception>"), // FIXME Error::Foreign(_) => write!(f, "<C++ exception>"), // FIXME
Error::Misc(s) => write!(f, "{}", s), Error::Misc(s) => write!(f, "{}", s),

View file

@ -12,6 +12,7 @@ extern crate proptest;
mod c; mod c;
mod error; mod error;
mod foreign; mod foreign;
#[cfg(unused)]
mod nar; mod nar;
mod store; mod store;
mod util; mod util;

View file

@ -1,9 +1,17 @@
pub mod path;
#[cfg(unused)]
mod binary_cache_store; mod binary_cache_store;
mod path; #[cfg(unused)]
mod path_info; mod path_info;
#[cfg(unused)]
mod store; mod store;
pub use binary_cache_store::BinaryCacheStore;
pub use path::{StorePath, StorePathHash, StorePathName}; pub use path::{StorePath, StorePathHash, StorePathName};
#[cfg(unused)]
pub use binary_cache_store::BinaryCacheStore;
#[cfg(unused)]
pub use path_info::PathInfo; pub use path_info::PathInfo;
#[cfg(unused)]
pub use store::Store; pub use store::Store;

View file

@ -23,6 +23,13 @@ impl StorePath {
) )
} }
pub fn from_parts(hash: [u8; STORE_PATH_HASH_BYTES], name: &str) -> Result<Self, Error> {
Ok(StorePath {
hash: StorePathHash(hash),
name: StorePathName::new(name)?,
})
}
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] != '-' as u8
@ -43,7 +50,7 @@ impl fmt::Display for StorePath {
} }
} }
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub struct StorePathHash([u8; STORE_PATH_HASH_BYTES]); pub struct StorePathHash([u8; STORE_PATH_HASH_BYTES]);
impl StorePathHash { impl StorePathHash {
@ -55,6 +62,10 @@ impl StorePathHash {
bytes.copy_from_slice(&v[0..STORE_PATH_HASH_BYTES]); bytes.copy_from_slice(&v[0..STORE_PATH_HASH_BYTES]);
Ok(Self(bytes)) Ok(Self(bytes))
} }
pub fn hash<'a>(&'a self) -> &'a [u8; STORE_PATH_HASH_BYTES] {
&self.0
}
} }
impl fmt::Display for StorePathHash { impl fmt::Display for StorePathHash {
@ -63,6 +74,21 @@ impl fmt::Display for StorePathHash {
} }
} }
impl Ord for StorePathHash {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
// Historically we've sorted store paths by their base32
// serialization, but our base32 encodes bytes in reverse
// order. So compare them in reverse order as well.
self.0.iter().rev().cmp(other.0.iter().rev())
}
}
impl PartialOrd for StorePathHash {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct StorePathName(String); pub struct StorePathName(String);
@ -93,6 +119,10 @@ impl StorePathName {
Ok(Self(s.to_string())) Ok(Self(s.to_string()))
} }
pub fn name<'a>(&'a self) -> &'a str {
&self.0
}
} }
impl fmt::Display for StorePathName { impl fmt::Display for StorePathName {

View file

@ -59,7 +59,7 @@ void setVerbosity(int level)
int isValidPath(char * path) int isValidPath(char * path)
CODE: CODE:
try { try {
RETVAL = store()->isValidPath(path); RETVAL = store()->isValidPath(store()->parseStorePath(path));
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());
} }
@ -70,9 +70,8 @@ int isValidPath(char * path)
SV * queryReferences(char * path) SV * queryReferences(char * path)
PPCODE: PPCODE:
try { try {
PathSet paths = store()->queryPathInfo(path)->references; for (auto & i : store()->queryPathInfo(store()->parseStorePath(path))->references)
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(i).c_str(), 0)));
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());
} }
@ -81,7 +80,7 @@ SV * queryReferences(char * path)
SV * queryPathHash(char * path) SV * queryPathHash(char * path)
PPCODE: PPCODE:
try { try {
auto s = store()->queryPathInfo(path)->narHash.to_string(); auto s = store()->queryPathInfo(store()->parseStorePath(path))->narHash.to_string();
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());
@ -91,9 +90,9 @@ SV * queryPathHash(char * path)
SV * queryDeriver(char * path) SV * queryDeriver(char * path)
PPCODE: PPCODE:
try { try {
auto deriver = store()->queryPathInfo(path)->deriver; auto info = store()->queryPathInfo(store()->parseStorePath(path));
if (deriver == "") XSRETURN_UNDEF; if (!info->deriver) XSRETURN_UNDEF;
XPUSHs(sv_2mortal(newSVpv(deriver.c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(*info->deriver).c_str(), 0)));
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());
} }
@ -102,18 +101,18 @@ SV * queryDeriver(char * path)
SV * queryPathInfo(char * path, int base32) SV * queryPathInfo(char * path, int base32)
PPCODE: PPCODE:
try { try {
auto info = store()->queryPathInfo(path); auto info = store()->queryPathInfo(store()->parseStorePath(path));
if (info->deriver == "") if (info->deriver)
XPUSHs(&PL_sv_undef); XPUSHs(&PL_sv_undef);
else else
XPUSHs(sv_2mortal(newSVpv(info->deriver.c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(*info->deriver).c_str(), 0)));
auto s = info->narHash.to_string(base32 ? Base32 : Base16); auto s = info->narHash.to_string(base32 ? Base32 : Base16);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
mXPUSHi(info->registrationTime); mXPUSHi(info->registrationTime);
mXPUSHi(info->narSize); mXPUSHi(info->narSize);
AV * arr = newAV(); AV * arr = newAV();
for (PathSet::iterator i = info->references.begin(); i != info->references.end(); ++i) for (auto & i : info->references)
av_push(arr, newSVpv(i->c_str(), 0)); av_push(arr, newSVpv(store()->printStorePath(i).c_str(), 0));
XPUSHs(sv_2mortal(newRV((SV *) arr))); XPUSHs(sv_2mortal(newRV((SV *) arr)));
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());
@ -123,8 +122,8 @@ SV * queryPathInfo(char * path, int base32)
SV * queryPathFromHashPart(char * hashPart) SV * queryPathFromHashPart(char * hashPart)
PPCODE: PPCODE:
try { try {
Path path = store()->queryPathFromHashPart(hashPart); auto path = store()->queryPathFromHashPart(hashPart);
XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(path ? store()->printStorePath(*path).c_str() : "", 0)));
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());
} }
@ -133,11 +132,11 @@ SV * queryPathFromHashPart(char * hashPart)
SV * computeFSClosure(int flipDirection, int includeOutputs, ...) SV * computeFSClosure(int flipDirection, int includeOutputs, ...)
PPCODE: PPCODE:
try { try {
PathSet paths; StorePathSet paths;
for (int n = 2; n < items; ++n) for (int n = 2; n < items; ++n)
store()->computeFSClosure(SvPV_nolen(ST(n)), paths, flipDirection, includeOutputs); store()->computeFSClosure(store()->parseStorePath(SvPV_nolen(ST(n))), paths, flipDirection, includeOutputs);
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) for (auto & i : paths)
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(i).c_str(), 0)));
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());
} }
@ -146,11 +145,11 @@ SV * computeFSClosure(int flipDirection, int includeOutputs, ...)
SV * topoSortPaths(...) SV * topoSortPaths(...)
PPCODE: PPCODE:
try { try {
PathSet paths; StorePathSet paths;
for (int n = 0; n < items; ++n) paths.insert(SvPV_nolen(ST(n))); for (int n = 0; n < items; ++n) paths.insert(store()->parseStorePath(SvPV_nolen(ST(n))));
Paths sorted = store()->topoSortPaths(paths); auto sorted = store()->topoSortPaths(paths);
for (Paths::iterator i = sorted.begin(); i != sorted.end(); ++i) for (auto & i : sorted)
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(i).c_str(), 0)));
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());
} }
@ -159,7 +158,7 @@ SV * topoSortPaths(...)
SV * followLinksToStorePath(char * path) SV * followLinksToStorePath(char * path)
CODE: CODE:
try { try {
RETVAL = newSVpv(store()->followLinksToStorePath(path).c_str(), 0); RETVAL = newSVpv(store()->printStorePath(store()->followLinksToStorePath(path)).c_str(), 0);
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());
} }
@ -170,8 +169,8 @@ SV * followLinksToStorePath(char * path)
void exportPaths(int fd, ...) void exportPaths(int fd, ...)
PPCODE: PPCODE:
try { try {
Paths paths; StorePathSet paths;
for (int n = 1; n < items; ++n) paths.push_back(SvPV_nolen(ST(n))); for (int n = 1; n < items; ++n) paths.insert(store()->parseStorePath(SvPV_nolen(ST(n))));
FdSink sink(fd); FdSink sink(fd);
store()->exportPaths(paths, sink); store()->exportPaths(paths, sink);
} catch (Error & e) { } catch (Error & e) {
@ -275,8 +274,8 @@ int checkSignature(SV * publicKey_, SV * sig_, char * msg)
SV * addToStore(char * srcPath, int recursive, char * algo) SV * addToStore(char * srcPath, int recursive, char * algo)
PPCODE: PPCODE:
try { try {
Path path = store()->addToStore(baseNameOf(srcPath), srcPath, recursive, parseHashType(algo)); auto path = store()->addToStore(std::string(baseNameOf(srcPath)), srcPath, recursive, parseHashType(algo));
XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(path).c_str(), 0)));
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());
} }
@ -286,8 +285,8 @@ SV * makeFixedOutputPath(int recursive, char * algo, char * hash, char * name)
PPCODE: PPCODE:
try { try {
Hash h(hash, parseHashType(algo)); Hash h(hash, parseHashType(algo));
Path path = store()->makeFixedOutputPath(recursive, h, name); auto path = store()->makeFixedOutputPath(recursive, h, name);
XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(path).c_str(), 0)));
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());
} }
@ -298,35 +297,35 @@ SV * derivationFromPath(char * drvPath)
HV *hash; HV *hash;
CODE: CODE:
try { try {
Derivation drv = store()->derivationFromPath(drvPath); Derivation drv = store()->derivationFromPath(store()->parseStorePath(drvPath));
hash = newHV(); hash = newHV();
HV * outputs = newHV(); HV * outputs = newHV();
for (DerivationOutputs::iterator i = drv.outputs.begin(); i != drv.outputs.end(); ++i) for (auto & i : drv.outputs)
hv_store(outputs, i->first.c_str(), i->first.size(), newSVpv(i->second.path.c_str(), 0), 0); hv_store(outputs, i.first.c_str(), i.first.size(), newSVpv(store()->printStorePath(i.second.path).c_str(), 0), 0);
hv_stores(hash, "outputs", newRV((SV *) outputs)); hv_stores(hash, "outputs", newRV((SV *) outputs));
AV * inputDrvs = newAV(); AV * inputDrvs = newAV();
for (DerivationInputs::iterator i = drv.inputDrvs.begin(); i != drv.inputDrvs.end(); ++i) for (auto & i : drv.inputDrvs)
av_push(inputDrvs, newSVpv(i->first.c_str(), 0)); // !!! ignores i->second av_push(inputDrvs, newSVpv(store()->printStorePath(i.first).c_str(), 0)); // !!! ignores i->second
hv_stores(hash, "inputDrvs", newRV((SV *) inputDrvs)); hv_stores(hash, "inputDrvs", newRV((SV *) inputDrvs));
AV * inputSrcs = newAV(); AV * inputSrcs = newAV();
for (PathSet::iterator i = drv.inputSrcs.begin(); i != drv.inputSrcs.end(); ++i) for (auto & i : drv.inputSrcs)
av_push(inputSrcs, newSVpv(i->c_str(), 0)); av_push(inputSrcs, newSVpv(store()->printStorePath(i).c_str(), 0));
hv_stores(hash, "inputSrcs", newRV((SV *) inputSrcs)); hv_stores(hash, "inputSrcs", newRV((SV *) inputSrcs));
hv_stores(hash, "platform", newSVpv(drv.platform.c_str(), 0)); hv_stores(hash, "platform", newSVpv(drv.platform.c_str(), 0));
hv_stores(hash, "builder", newSVpv(drv.builder.c_str(), 0)); hv_stores(hash, "builder", newSVpv(drv.builder.c_str(), 0));
AV * args = newAV(); AV * args = newAV();
for (Strings::iterator i = drv.args.begin(); i != drv.args.end(); ++i) for (auto & i : drv.args)
av_push(args, newSVpv(i->c_str(), 0)); av_push(args, newSVpv(i.c_str(), 0));
hv_stores(hash, "args", newRV((SV *) args)); hv_stores(hash, "args", newRV((SV *) args));
HV * env = newHV(); HV * env = newHV();
for (StringPairs::iterator i = drv.env.begin(); i != drv.env.end(); ++i) for (auto & i : drv.env)
hv_store(env, i->first.c_str(), i->first.size(), newSVpv(i->second.c_str(), 0), 0); hv_store(env, i.first.c_str(), i.first.size(), newSVpv(i.second.c_str(), 0), 0);
hv_stores(hash, "env", newRV((SV *) env)); hv_stores(hash, "env", newRV((SV *) env));
RETVAL = newRV_noinc((SV *)hash); RETVAL = newRV_noinc((SV *)hash);
@ -340,7 +339,7 @@ SV * derivationFromPath(char * drvPath)
void addTempRoot(char * storePath) void addTempRoot(char * storePath)
PPCODE: PPCODE:
try { try {
store()->addTempRoot(storePath); store()->addTempRoot(store()->parseStorePath(storePath));
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());
} }

View file

@ -88,7 +88,7 @@ static int _main(int argc, char * * argv)
return 0; return 0;
} }
string drvPath; std::optional<StorePath> drvPath;
string storeUri; string storeUri;
while (true) { while (true) {
@ -100,7 +100,7 @@ static int _main(int argc, char * * argv)
auto amWilling = readInt(source); auto amWilling = readInt(source);
auto neededSystem = readString(source); auto neededSystem = readString(source);
source >> drvPath; drvPath = store->parseStorePath(readString(source));
auto requiredFeatures = readStrings<std::set<std::string>>(source); auto requiredFeatures = readStrings<std::set<std::string>>(source);
auto canBuildLocally = amWilling auto canBuildLocally = amWilling
@ -236,26 +236,27 @@ connected:
{ {
Activity act(*logger, lvlTalkative, actUnknown, fmt("copying dependencies to '%s'", storeUri)); Activity act(*logger, lvlTalkative, actUnknown, fmt("copying dependencies to '%s'", storeUri));
copyPaths(store, ref<Store>(sshStore), inputs, NoRepair, NoCheckSigs, substitute); copyPaths(store, ref<Store>(sshStore), store->parseStorePathSet(inputs), NoRepair, NoCheckSigs, substitute);
} }
uploadLock = -1; uploadLock = -1;
BasicDerivation drv(readDerivation(store->realStoreDir + "/" + baseNameOf(drvPath))); BasicDerivation drv(readDerivation(*store, store->realStoreDir + "/" + std::string(drvPath->to_string())));
drv.inputSrcs = inputs; drv.inputSrcs = store->parseStorePathSet(inputs);
auto result = sshStore->buildDerivation(drvPath, drv); auto result = sshStore->buildDerivation(*drvPath, drv);
if (!result.success()) if (!result.success())
throw Error("build of '%s' on '%s' failed: %s", drvPath, storeUri, result.errorMsg); throw Error("build of '%s' on '%s' failed: %s", store->printStorePath(*drvPath), storeUri, result.errorMsg);
PathSet missing; StorePathSet missing;
for (auto & path : outputs) for (auto & path : outputs)
if (!store->isValidPath(path)) missing.insert(path); if (!store->isValidPath(store->parseStorePath(path))) missing.insert(store->parseStorePath(path));
if (!missing.empty()) { if (!missing.empty()) {
Activity act(*logger, lvlTalkative, actUnknown, fmt("copying outputs from '%s'", storeUri)); Activity act(*logger, lvlTalkative, actUnknown, fmt("copying outputs from '%s'", storeUri));
store->locksHeld.insert(missing.begin(), missing.end()); /* FIXME: ugly */ for (auto & i : missing)
store->locksHeld.insert(store->printStorePath(i)); /* FIXME: ugly */
copyPaths(ref<Store>(sshStore), store, missing, NoRepair, NoCheckSigs, NoSubstitute); copyPaths(ref<Store>(sshStore), store, missing, NoRepair, NoCheckSigs, NoSubstitute);
} }

View file

@ -43,6 +43,19 @@ static char * dupString(const char * s)
} }
static char * dupStringWithLen(const char * s, size_t size)
{
char * t;
#if HAVE_BOEHMGC
t = GC_STRNDUP(s, size);
#else
t = strndup(s, size);
#endif
if (!t) throw std::bad_alloc();
return t;
}
static void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v) static void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v)
{ {
checkInterrupt(); checkInterrupt();
@ -330,10 +343,10 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store)
auto path = r.second; auto path = r.second;
if (store->isInStore(r.second)) { if (store->isInStore(r.second)) {
PathSet closure; StorePathSet closure;
store->computeFSClosure(store->toStorePath(r.second), closure); store->computeFSClosure(store->parseStorePath(store->toStorePath(r.second)), closure);
for (auto & path : closure) for (auto & path : closure)
allowedPaths->insert(path); allowedPaths->insert(store->printStorePath(path));
} else } else
allowedPaths->insert(r.second); allowedPaths->insert(r.second);
} }
@ -550,9 +563,11 @@ void mkString(Value & v, const char * s)
} }
Value & mkString(Value & v, const string & s, const PathSet & context) Value & mkString(Value & v, std::string_view s, const PathSet & context)
{ {
mkString(v, s.c_str()); v.type = tString;
v.string.s = dupStringWithLen(s.data(), s.size());
v.string.context = 0;
if (!context.empty()) { if (!context.empty()) {
size_t n = 0; size_t n = 0;
v.string.context = (const char * *) v.string.context = (const char * *)
@ -1639,15 +1654,16 @@ string EvalState::copyPathToStore(PathSet & context, const Path & path)
throwEvalError("file names are not allowed to end in '%1%'", drvExtension); throwEvalError("file names are not allowed to end in '%1%'", drvExtension);
Path dstPath; Path dstPath;
if (srcToStore[path] != "") auto i = srcToStore.find(path);
dstPath = srcToStore[path]; if (i != srcToStore.end())
dstPath = store->printStorePath(i->second);
else { else {
dstPath = settings.readOnlyMode auto p = settings.readOnlyMode
? store->computeStorePathForPath(baseNameOf(path), checkSourcePath(path)).first ? store->computeStorePathForPath(std::string(baseNameOf(path)), checkSourcePath(path)).first
: store->addToStore(baseNameOf(path), checkSourcePath(path), true, htSHA256, defaultPathFilter, repair); : store->addToStore(std::string(baseNameOf(path)), checkSourcePath(path), true, htSHA256, defaultPathFilter, repair);
srcToStore[path] = dstPath; dstPath = store->printStorePath(p);
printMsg(lvlChatty, format("copied source '%1%' -> '%2%'") srcToStore.insert_or_assign(path, std::move(p));
% path % dstPath); printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, dstPath);
} }
context.insert(dstPath); context.insert(dstPath);

View file

@ -17,6 +17,7 @@ namespace nix {
class Store; class Store;
class EvalState; class EvalState;
struct StorePath;
enum RepairFlag : bool; enum RepairFlag : bool;
@ -42,14 +43,14 @@ struct Env
}; };
Value & mkString(Value & v, const string & s, const PathSet & context = PathSet()); Value & mkString(Value & v, std::string_view s, const PathSet & context = PathSet());
void copyContext(const Value & v, PathSet & context); void copyContext(const Value & v, PathSet & context);
/* Cache for calls to addToStore(); maps source paths to the store /* Cache for calls to addToStore(); maps source paths to the store
paths. */ paths. */
typedef std::map<Path, Path> SrcToStore; typedef std::map<Path, StorePath> SrcToStore;
std::ostream & operator << (std::ostream & str, const Value & v); std::ostream & operator << (std::ostream & str, const Value & v);

View file

@ -19,27 +19,27 @@ DrvInfo::DrvInfo(EvalState & state, const string & attrPath, Bindings * attrs)
DrvInfo::DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPathWithOutputs) DrvInfo::DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPathWithOutputs)
: state(&state), attrs(nullptr), attrPath("") : state(&state), attrs(nullptr), attrPath("")
{ {
auto spec = parseDrvPathWithOutputs(drvPathWithOutputs); auto [drvPath, selectedOutputs] = store->parseDrvPathWithOutputs(drvPathWithOutputs);
drvPath = spec.first; this->drvPath = store->printStorePath(drvPath);
auto drv = store->derivationFromPath(drvPath); auto drv = store->derivationFromPath(drvPath);
name = storePathToName(drvPath); name = drvPath.name();
if (spec.second.size() > 1) if (selectedOutputs.size() > 1)
throw Error("building more than one derivation output is not supported, in '%s'", drvPathWithOutputs); throw Error("building more than one derivation output is not supported, in '%s'", drvPathWithOutputs);
outputName = outputName =
spec.second.empty() selectedOutputs.empty()
? get(drv.env, "outputName", "out") ? get(drv.env, "outputName").value_or("out")
: *spec.second.begin(); : *selectedOutputs.begin();
auto i = drv.outputs.find(outputName); auto i = drv.outputs.find(outputName);
if (i == drv.outputs.end()) if (i == drv.outputs.end())
throw Error("derivation '%s' does not have output '%s'", drvPath, outputName); throw Error("derivation '%s' does not have output '%s'", store->printStorePath(drvPath), outputName);
outPath = i->second.path; outPath = store->printStorePath(i->second.path);
} }

View file

@ -6,7 +6,7 @@ libexpr_DIR := $(d)
libexpr_SOURCES := $(wildcard $(d)/*.cc) $(wildcard $(d)/primops/*.cc) $(d)/lexer-tab.cc $(d)/parser-tab.cc libexpr_SOURCES := $(wildcard $(d)/*.cc) $(wildcard $(d)/primops/*.cc) $(d)/lexer-tab.cc $(d)/parser-tab.cc
libexpr_LIBS = libutil libstore libexpr_LIBS = libutil libstore libnixrust
libexpr_LDFLAGS = libexpr_LDFLAGS =
ifneq ($(OS), FreeBSD) ifneq ($(OS), FreeBSD)

View file

@ -16,14 +16,14 @@ DrvName::DrvName()
a letter. The `version' part is the rest (excluding the separating a letter. The `version' part is the rest (excluding the separating
dash). E.g., `apache-httpd-2.0.48' is parsed to (`apache-httpd', dash). E.g., `apache-httpd-2.0.48' is parsed to (`apache-httpd',
'2.0.48'). */ '2.0.48'). */
DrvName::DrvName(const string & s) : hits(0) DrvName::DrvName(std::string_view s) : hits(0)
{ {
name = fullName = s; name = fullName = std::string(s);
for (unsigned int i = 0; i < s.size(); ++i) { for (unsigned int i = 0; i < s.size(); ++i) {
/* !!! isalpha/isdigit are affected by the locale. */ /* !!! isalpha/isdigit are affected by the locale. */
if (s[i] == '-' && i + 1 < s.size() && !isalpha(s[i + 1])) { if (s[i] == '-' && i + 1 < s.size() && !isalpha(s[i + 1])) {
name = string(s, 0, i); name = s.substr(0, i);
version = string(s, i + 1); version = s.substr(i + 1);
break; break;
} }
} }

View file

@ -15,7 +15,7 @@ struct DrvName
unsigned int hits; unsigned int hits;
DrvName(); DrvName();
DrvName(const string & s); DrvName(std::string_view s);
bool matches(DrvName & n); bool matches(DrvName & n);
private: private:

View file

@ -44,29 +44,28 @@ std::pair<string, string> decodeContext(const string & s)
InvalidPathError::InvalidPathError(const Path & path) : InvalidPathError::InvalidPathError(const Path & path) :
EvalError(format("path '%1%' is not valid") % path), path(path) {} EvalError("path '%s' is not valid", path), path(path) {}
void EvalState::realiseContext(const PathSet & context) void EvalState::realiseContext(const PathSet & context)
{ {
PathSet drvs; std::vector<StorePathWithOutputs> drvs;
for (auto & i : context) { for (auto & i : context) {
std::pair<string, string> decoded = decodeContext(i); std::pair<string, string> decoded = decodeContext(i);
Path ctx = decoded.first; auto ctx = store->parseStorePath(decoded.first);
assert(store->isStorePath(ctx));
if (!store->isValidPath(ctx)) if (!store->isValidPath(ctx))
throw InvalidPathError(ctx); throw InvalidPathError(store->printStorePath(ctx));
if (!decoded.second.empty() && nix::isDerivation(ctx)) { if (!decoded.second.empty() && ctx.isDerivation()) {
drvs.insert(decoded.first + "!" + decoded.second); drvs.push_back(StorePathWithOutputs{ctx.clone(), {decoded.second}});
/* Add the output of this derivation to the allowed /* Add the output of this derivation to the allowed
paths. */ paths. */
if (allowedPaths) { if (allowedPaths) {
auto drv = store->derivationFromPath(decoded.first); auto drv = store->derivationFromPath(store->parseStorePath(decoded.first));
DerivationOutputs::iterator i = drv.outputs.find(decoded.second); DerivationOutputs::iterator i = drv.outputs.find(decoded.second);
if (i == drv.outputs.end()) if (i == drv.outputs.end())
throw Error("derivation '%s' does not have an output named '%s'", decoded.first, decoded.second); throw Error("derivation '%s' does not have an output named '%s'", decoded.first, decoded.second);
allowedPaths->insert(i->second.path); allowedPaths->insert(store->printStorePath(i->second.path));
} }
} }
} }
@ -74,10 +73,11 @@ void EvalState::realiseContext(const PathSet & context)
if (drvs.empty()) return; if (drvs.empty()) return;
if (!evalSettings.enableImportFromDerivation) if (!evalSettings.enableImportFromDerivation)
throw EvalError(format("attempted to realize '%1%' during evaluation but 'allow-import-from-derivation' is false") % *(drvs.begin())); throw EvalError("attempted to realize '%1%' during evaluation but 'allow-import-from-derivation' is false",
store->printStorePath(drvs.begin()->path));
/* For performance, prefetch all substitute info. */ /* For performance, prefetch all substitute info. */
PathSet willBuild, willSubstitute, unknown; StorePathSet willBuild, willSubstitute, unknown;
unsigned long long downloadSize, narSize; unsigned long long downloadSize, narSize;
store->queryMissing(drvs, willBuild, willSubstitute, unknown, downloadSize, narSize); store->queryMissing(drvs, willBuild, willSubstitute, unknown, downloadSize, narSize);
store->buildPaths(drvs); store->buildPaths(drvs);
@ -100,8 +100,9 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
Path realPath = state.checkSourcePath(state.toRealPath(path, context)); Path realPath = state.checkSourcePath(state.toRealPath(path, context));
if (state.store->isStorePath(path) && state.store->isValidPath(path) && isDerivation(path)) { // FIXME
Derivation drv = readDerivation(realPath); if (state.store->isStorePath(path) && state.store->isValidPath(state.store->parseStorePath(path)) && isDerivation(path)) {
Derivation drv = readDerivation(*state.store, realPath);
Value & w = *state.allocValue(); Value & w = *state.allocValue();
state.mkAttrs(w, 3 + drv.outputs.size()); state.mkAttrs(w, 3 + drv.outputs.size());
Value * v2 = state.allocAttr(w, state.sDrvPath); Value * v2 = state.allocAttr(w, state.sDrvPath);
@ -115,7 +116,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
for (const auto & o : drv.outputs) { for (const auto & o : drv.outputs) {
v2 = state.allocAttr(w, state.symbols.create(o.first)); v2 = state.allocAttr(w, state.symbols.create(o.first));
mkString(*v2, o.second.path, {"!" + o.first + "!" + path}); mkString(*v2, state.store->printStorePath(o.second.path), {"!" + o.first + "!" + path});
outputsVal->listElems()[outputs_index] = state.allocValue(); outputsVal->listElems()[outputs_index] = state.allocValue();
mkString(*(outputsVal->listElems()[outputs_index++]), o.first); mkString(*(outputsVal->listElems()[outputs_index++]), o.first);
} }
@ -676,24 +677,24 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
runs. */ runs. */
if (path.at(0) == '=') { if (path.at(0) == '=') {
/* !!! This doesn't work if readOnlyMode is set. */ /* !!! This doesn't work if readOnlyMode is set. */
PathSet refs; StorePathSet refs;
state.store->computeFSClosure(string(path, 1), refs); state.store->computeFSClosure(state.store->parseStorePath(std::string_view(path).substr(1)), refs);
for (auto & j : refs) { for (auto & j : refs) {
drv.inputSrcs.insert(j); drv.inputSrcs.insert(j.clone());
if (isDerivation(j)) if (j.isDerivation())
drv.inputDrvs[j] = state.store->queryDerivationOutputNames(j); drv.inputDrvs[j.clone()] = state.store->queryDerivationOutputNames(j);
} }
} }
/* 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); std::pair<string, string> ctx = decodeContext(path);
drv.inputDrvs[ctx.first].insert(ctx.second); drv.inputDrvs[state.store->parseStorePath(ctx.first)].insert(ctx.second);
} }
/* Otherwise it's a source file. */ /* Otherwise it's a source file. */
else else
drv.inputSrcs.insert(path); drv.inputSrcs.insert(state.store->parseStorePath(path));
} }
/* Do we have all required attributes? */ /* Do we have all required attributes? */
@ -703,10 +704,8 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
throw EvalError(format("required attribute 'system' missing, at %1%") % posDrvName); throw EvalError(format("required attribute 'system' missing, at %1%") % posDrvName);
/* Check whether the derivation name is valid. */ /* Check whether the derivation name is valid. */
checkStoreName(drvName);
if (isDerivation(drvName)) if (isDerivation(drvName))
throw EvalError(format("derivation names are not allowed to end in '%1%', at %2%") throw EvalError("derivation names are not allowed to end in '%s', at %s", drvExtension, posDrvName);
% drvExtension % posDrvName);
if (outputHash) { if (outputHash) {
/* Handle fixed-output derivations. */ /* Handle fixed-output derivations. */
@ -716,52 +715,51 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
HashType ht = outputHashAlgo.empty() ? htUnknown : parseHashType(outputHashAlgo); HashType ht = outputHashAlgo.empty() ? htUnknown : parseHashType(outputHashAlgo);
Hash h(*outputHash, ht); Hash h(*outputHash, ht);
Path outPath = state.store->makeFixedOutputPath(outputHashRecursive, h, drvName); auto outPath = state.store->makeFixedOutputPath(outputHashRecursive, h, drvName);
if (!jsonObject) drv.env["out"] = outPath; if (!jsonObject) drv.env["out"] = state.store->printStorePath(outPath);
drv.outputs["out"] = DerivationOutput(outPath, drv.outputs.insert_or_assign("out", DerivationOutput(std::move(outPath),
(outputHashRecursive ? "r:" : "") + printHashType(h.type), (outputHashRecursive ? "r:" : "") + printHashType(h.type),
h.to_string(Base16, false)); h.to_string(Base16, false)));
} }
else { else {
/* Construct the "masked" store derivation, which is the final /* Compute a hash over the "masked" store derivation, which is
one except that in the list of outputs, the output paths the final one except that in the list of outputs, the
are empty, and the corresponding environment variables have output paths are empty strings, and the corresponding
an empty value. This ensures that changes in the set of environment variables have an empty value. This ensures
output names do get reflected in the hash. */ that changes in the set of output names do get reflected in
the hash. */
for (auto & i : outputs) { for (auto & i : outputs) {
if (!jsonObject) drv.env[i] = ""; if (!jsonObject) drv.env[i] = "";
drv.outputs[i] = DerivationOutput("", "", "");
} }
/* Use the masked derivation expression to compute the output Hash h = hashDerivationModulo(*state.store, Derivation(drv), true);
path. */
Hash h = hashDerivationModulo(*state.store, drv);
for (auto & i : drv.outputs) for (auto & i : outputs) {
if (i.second.path == "") { auto outPath = state.store->makeOutputPath(i, h, drvName);
Path outPath = state.store->makeOutputPath(i.first, h, drvName); if (!jsonObject) drv.env[i] = state.store->printStorePath(outPath);
if (!jsonObject) drv.env[i.first] = outPath; drv.outputs.insert_or_assign(i,
i.second.path = outPath; DerivationOutput(std::move(outPath), "", ""));
} }
} }
/* Write the resulting term into the Nix store directory. */ /* Write the resulting term into the Nix store directory. */
Path drvPath = writeDerivation(state.store, drv, drvName, state.repair); auto drvPath = writeDerivation(state.store, drv, drvName, state.repair);
auto drvPathS = state.store->printStorePath(drvPath);
printMsg(lvlChatty, format("instantiated '%1%' -> '%2%'") printMsg(lvlChatty, "instantiated '%1%' -> '%2%'", drvName, drvPathS);
% drvName % drvPath);
/* Optimisation, but required in read-only mode! because in that /* Optimisation, but required in read-only mode! because in that
case we don't actually write store derivations, so we can't case we don't actually write store derivations, so we can't
read them later. */ read them later. */
drvHashes[drvPath] = hashDerivationModulo(*state.store, drv); drvHashes.insert_or_assign(drvPath.clone(),
hashDerivationModulo(*state.store, Derivation(drv), false));
state.mkAttrs(v, 1 + drv.outputs.size()); state.mkAttrs(v, 1 + drv.outputs.size());
mkString(*state.allocAttr(v, state.sDrvPath), drvPath, {"=" + drvPath}); mkString(*state.allocAttr(v, state.sDrvPath), drvPathS, {"=" + drvPathS});
for (auto & i : drv.outputs) { for (auto & i : drv.outputs) {
mkString(*state.allocAttr(v, state.symbols.create(i.first)), mkString(*state.allocAttr(v, state.symbols.create(i.first)),
i.second.path, {"!" + i.first + "!" + drvPath}); state.store->printStorePath(i.second.path), {"!" + i.first + "!" + drvPathS});
} }
v.attrs->sort(); v.attrs->sort();
} }
@ -814,7 +812,7 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V
throw EvalError(format("path '%1%' is not in the Nix store, at %2%") % path % pos); throw EvalError(format("path '%1%' is not in the Nix store, at %2%") % path % pos);
Path path2 = state.store->toStorePath(path); Path path2 = state.store->toStorePath(path);
if (!settings.readOnlyMode) if (!settings.readOnlyMode)
state.store->ensurePath(path2); state.store->ensurePath(state.store->parseStorePath(path2));
context.insert(path2); context.insert(path2);
mkString(v, path, context); mkString(v, path, context);
} }
@ -1010,17 +1008,17 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
string name = state.forceStringNoCtx(*args[0], pos); string name = state.forceStringNoCtx(*args[0], pos);
string contents = state.forceString(*args[1], context, pos); string contents = state.forceString(*args[1], context, pos);
PathSet refs; StorePathSet refs;
for (auto path : context) { for (auto path : context) {
if (path.at(0) != '/') if (path.at(0) != '/')
throw EvalError(format("in 'toFile': the file '%1%' cannot refer to derivation outputs, at %2%") % name % pos); throw EvalError(format("in 'toFile': the file '%1%' cannot refer to derivation outputs, at %2%") % name % pos);
refs.insert(path); refs.insert(state.store->parseStorePath(path));
} }
Path storePath = settings.readOnlyMode auto storePath = state.store->printStorePath(settings.readOnlyMode
? state.store->computeStorePathForText(name, contents, refs) ? state.store->computeStorePathForText(name, contents, refs)
: state.store->addTextToStore(name, contents, refs, state.repair); : state.store->addTextToStore(name, contents, refs, state.repair));
/* Note: we don't need to add `context' to the context of the /* Note: we don't need to add `context' to the context of the
result, since `storePath' itself has references to the paths result, since `storePath' itself has references to the paths
@ -1060,21 +1058,18 @@ static void addPath(EvalState & state, const Pos & pos, const string & name, con
return state.forceBool(res, pos); return state.forceBool(res, pos);
}) : defaultPathFilter; }) : defaultPathFilter;
Path expectedStorePath; std::optional<StorePath> expectedStorePath;
if (expectedHash) { if (expectedHash)
expectedStorePath = expectedStorePath = state.store->makeFixedOutputPath(recursive, expectedHash, name);
state.store->makeFixedOutputPath(recursive, expectedHash, name);
}
Path dstPath; Path dstPath;
if (!expectedHash || !state.store->isValidPath(expectedStorePath)) { if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
dstPath = settings.readOnlyMode dstPath = state.store->printStorePath(settings.readOnlyMode
? state.store->computeStorePathForPath(name, path, recursive, htSHA256, filter).first ? state.store->computeStorePathForPath(name, path, recursive, htSHA256, filter).first
: state.store->addToStore(name, path, recursive, htSHA256, filter, state.repair); : state.store->addToStore(name, path, recursive, htSHA256, filter, state.repair));
if (expectedHash && expectedStorePath != dstPath) { if (expectedHash && expectedStorePath != state.store->parseStorePath(dstPath))
throw Error(format("store path mismatch in (possibly filtered) path added from '%1%'") % path); throw Error("store path mismatch in (possibly filtered) path added from '%s'", path);
}
} else } else
dstPath = expectedStorePath; dstPath = state.store->printStorePath(*expectedStorePath);
mkString(v, dstPath, {dstPath}); mkString(v, dstPath, {dstPath});
} }
@ -1091,7 +1086,7 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args
if (args[0]->type != tLambda) if (args[0]->type != tLambda)
throw TypeError(format("first argument in call to 'filterSource' is not a function but %1%, at %2%") % showType(*args[0]) % pos); throw TypeError(format("first argument in call to 'filterSource' is not a function but %1%, at %2%") % showType(*args[0]) % pos);
addPath(state, pos, baseNameOf(path), path, args[0], true, Hash(), v); addPath(state, pos, std::string(baseNameOf(path)), path, args[0], true, Hash(), v);
} }
static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value & v)
@ -2151,7 +2146,7 @@ void EvalState::createBaseEnv()
} }
if (!evalSettings.pureEval) { if (!evalSettings.pureEval) {
mkString(v, settings.thisSystem); mkString(v, settings.thisSystem.get());
addConstant("__currentSystem", v); addConstant("__currentSystem", v);
} }

View file

@ -148,7 +148,7 @@ static void prim_appendContext(EvalState & state, const Pos & pos, Value * * arg
if (!state.store->isStorePath(i.name)) if (!state.store->isStorePath(i.name))
throw EvalError("Context key '%s' is not a store path, at %s", i.name, i.pos); throw EvalError("Context key '%s' is not a store path, at %s", i.name, i.pos);
if (!settings.readOnlyMode) if (!settings.readOnlyMode)
state.store->ensurePath(i.name); state.store->ensurePath(state.store->parseStorePath(i.name));
state.forceAttrs(*i.value, *i.pos); state.forceAttrs(*i.value, *i.pos);
auto iter = i.value->attrs->find(sPath); auto iter = i.value->attrs->find(sPath);
if (iter != i.value->attrs->end()) { if (iter != i.value->attrs->end()) {

View file

@ -69,7 +69,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
return files.count(file); return files.count(file);
}; };
gitInfo.storePath = store->addToStore("source", uri, true, htSHA256, filter); gitInfo.storePath = store->printStorePath(store->addToStore("source", uri, true, htSHA256, filter));
return gitInfo; return gitInfo;
} }
@ -156,7 +156,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
gitInfo.storePath = json["storePath"]; gitInfo.storePath = json["storePath"];
if (store->isValidPath(gitInfo.storePath)) { if (store->isValidPath(store->parseStorePath(gitInfo.storePath))) {
gitInfo.revCount = json["revCount"]; gitInfo.revCount = json["revCount"];
return gitInfo; return gitInfo;
} }
@ -176,7 +176,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
unpackTarfile(*source, tmpDir); unpackTarfile(*source, tmpDir);
gitInfo.storePath = store->addToStore(name, tmpDir); gitInfo.storePath = store->printStorePath(store->addToStore(name, tmpDir));
gitInfo.revCount = std::stoull(runProgram("git", true, { "-C", cacheDir, "rev-list", "--count", gitInfo.rev })); gitInfo.revCount = std::stoull(runProgram("git", true, { "-C", cacheDir, "rev-list", "--count", gitInfo.rev }));

View file

@ -63,7 +63,7 @@ HgInfo exportMercurial(ref<Store> store, const std::string & uri,
return files.count(file); return files.count(file);
}; };
hgInfo.storePath = store->addToStore("source", uri, true, htSHA256, filter); hgInfo.storePath = store->printStorePath(store->addToStore("source", uri, true, htSHA256, filter));
return hgInfo; return hgInfo;
} }
@ -134,7 +134,7 @@ HgInfo exportMercurial(ref<Store> store, const std::string & uri,
hgInfo.storePath = json["storePath"]; hgInfo.storePath = json["storePath"];
if (store->isValidPath(hgInfo.storePath)) { if (store->isValidPath(store->parseStorePath(hgInfo.storePath))) {
printTalkative("using cached Mercurial store path '%s'", hgInfo.storePath); printTalkative("using cached Mercurial store path '%s'", hgInfo.storePath);
return hgInfo; return hgInfo;
} }
@ -150,7 +150,7 @@ HgInfo exportMercurial(ref<Store> store, const std::string & uri,
deletePath(tmpDir + "/.hg_archival.txt"); deletePath(tmpDir + "/.hg_archival.txt");
hgInfo.storePath = store->addToStore(name, tmpDir); hgInfo.storePath = store->printStorePath(store->addToStore(name, tmpDir));
nlohmann::json json; nlohmann::json json;
json["storePath"] = hgInfo.storePath; json["storePath"] = hgInfo.storePath;

View file

@ -38,7 +38,12 @@ public:
return s < s2.s; return s < s2.s;
} }
operator const string & () const operator const std::string & () const
{
return *s;
}
operator const std::string_view () const
{ {
return *s; return *s;
} }

View file

@ -33,25 +33,25 @@ void printGCWarning()
} }
void printMissing(ref<Store> store, const PathSet & paths, Verbosity lvl) void printMissing(ref<Store> store, const std::vector<StorePathWithOutputs> & paths, Verbosity lvl)
{ {
unsigned long long downloadSize, narSize; unsigned long long downloadSize, narSize;
PathSet willBuild, willSubstitute, unknown; StorePathSet willBuild, willSubstitute, unknown;
store->queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize); store->queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
printMissing(store, willBuild, willSubstitute, unknown, downloadSize, narSize, lvl); printMissing(store, willBuild, willSubstitute, unknown, downloadSize, narSize, lvl);
} }
void printMissing(ref<Store> store, const PathSet & willBuild, void printMissing(ref<Store> store, const StorePathSet & willBuild,
const PathSet & willSubstitute, const PathSet & unknown, const StorePathSet & willSubstitute, const StorePathSet & unknown,
unsigned long long downloadSize, unsigned long long narSize, Verbosity lvl) unsigned long long downloadSize, unsigned long long narSize, Verbosity lvl)
{ {
if (!willBuild.empty()) { if (!willBuild.empty()) {
printMsg(lvl, "these derivations will be built:"); printMsg(lvl, "these derivations will be built:");
Paths sorted = store->topoSortPaths(willBuild); auto sorted = store->topoSortPaths(willBuild);
reverse(sorted.begin(), sorted.end()); reverse(sorted.begin(), sorted.end());
for (auto & i : sorted) for (auto & i : sorted)
printMsg(lvl, fmt(" %s", i)); printMsg(lvl, fmt(" %s", store->printStorePath(i)));
} }
if (!willSubstitute.empty()) { if (!willSubstitute.empty()) {
@ -59,14 +59,14 @@ void printMissing(ref<Store> store, const PathSet & willBuild,
downloadSize / (1024.0 * 1024.0), downloadSize / (1024.0 * 1024.0),
narSize / (1024.0 * 1024.0))); narSize / (1024.0 * 1024.0)));
for (auto & i : willSubstitute) for (auto & i : willSubstitute)
printMsg(lvl, fmt(" %s", i)); printMsg(lvl, fmt(" %s", store->printStorePath(i)));
} }
if (!unknown.empty()) { if (!unknown.empty()) {
printMsg(lvl, fmt("don't know how to build these paths%s:", printMsg(lvl, fmt("don't know how to build these paths%s:",
(settings.readOnlyMode ? " (may be caused by read-only store access)" : ""))); (settings.readOnlyMode ? " (may be caused by read-only store access)" : "")));
for (auto & i : unknown) for (auto & i : unknown)
printMsg(lvl, fmt(" %s", i)); printMsg(lvl, fmt(" %s", store->printStorePath(i)));
} }
} }
@ -237,7 +237,7 @@ bool LegacyArgs::processArgs(const Strings & args, bool finish)
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)
{ {
parseCmdLine(baseNameOf(argv[0]), argvToStrings(argc, argv), parseArg); parseCmdLine(std::string(baseNameOf(argv[0])), argvToStrings(argc, argv), parseArg);
} }

View file

@ -3,6 +3,7 @@
#include "util.hh" #include "util.hh"
#include "args.hh" #include "args.hh"
#include "common-args.hh" #include "common-args.hh"
#include "path.hh"
#include <signal.h> #include <signal.h>
@ -37,11 +38,15 @@ void printVersion(const string & programName);
void printGCWarning(); void printGCWarning();
class Store; class Store;
struct StorePathWithOutputs;
void printMissing(ref<Store> store, const PathSet & paths, Verbosity lvl = lvlInfo); void printMissing(
ref<Store> store,
const std::vector<StorePathWithOutputs> & paths,
Verbosity lvl = lvlInfo);
void printMissing(ref<Store> store, const PathSet & willBuild, void printMissing(ref<Store> store, const StorePathSet & willBuild,
const PathSet & willSubstitute, const PathSet & unknown, const StorePathSet & willSubstitute, const StorePathSet & unknown,
unsigned long long downloadSize, unsigned long long narSize, Verbosity lvl = lvlInfo); unsigned long long downloadSize, unsigned long long narSize, Verbosity lvl = lvlInfo);
string getArg(const string & opt, string getArg(const string & opt,

View file

@ -91,19 +91,18 @@ std::shared_ptr<std::string> BinaryCacheStore::getFile(const std::string & path)
return sink.s; return sink.s;
} }
Path BinaryCacheStore::narInfoFileFor(const Path & storePath) std::string BinaryCacheStore::narInfoFileFor(const StorePath & storePath)
{ {
assertStorePath(storePath); return storePathToHash(printStorePath(storePath)) + ".narinfo";
return storePathToHash(storePath) + ".narinfo";
} }
void BinaryCacheStore::writeNarInfo(ref<NarInfo> narInfo) void BinaryCacheStore::writeNarInfo(ref<NarInfo> narInfo)
{ {
auto narInfoFile = narInfoFileFor(narInfo->path); auto narInfoFile = narInfoFileFor(narInfo->path);
upsertFile(narInfoFile, narInfo->to_string(), "text/x-nix-narinfo"); upsertFile(narInfoFile, narInfo->to_string(*this), "text/x-nix-narinfo");
auto hashPart = storePathToHash(narInfo->path); auto hashPart = storePathToHash(printStorePath(narInfo->path));
{ {
auto state_(state.lock()); auto state_(state.lock());
@ -126,8 +125,8 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, const ref<std::str
if (ref != info.path) if (ref != info.path)
queryPathInfo(ref); queryPathInfo(ref);
} catch (InvalidPath &) { } catch (InvalidPath &) {
throw Error(format("cannot add '%s' to the binary cache because the reference '%s' is not valid") throw Error("cannot add '%s' to the binary cache because the reference '%s' is not valid",
% info.path % ref); printStorePath(info.path), printStorePath(ref));
} }
assert(nar->compare(0, narMagic.size(), narMagic) == 0); assert(nar->compare(0, narMagic.size(), narMagic) == 0);
@ -138,14 +137,14 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, const ref<std::str
narInfo->narHash = hashString(htSHA256, *nar); narInfo->narHash = hashString(htSHA256, *nar);
if (info.narHash && info.narHash != narInfo->narHash) if (info.narHash && info.narHash != narInfo->narHash)
throw Error(format("refusing to copy corrupted path '%1%' to binary cache") % info.path); throw Error("refusing to copy corrupted path '%1%' to binary cache", printStorePath(info.path));
auto accessor_ = std::dynamic_pointer_cast<RemoteFSAccessor>(accessor); auto accessor_ = std::dynamic_pointer_cast<RemoteFSAccessor>(accessor);
auto narAccessor = makeNarAccessor(nar); auto narAccessor = makeNarAccessor(nar);
if (accessor_) if (accessor_)
accessor_->addToCache(info.path, *nar, narAccessor); accessor_->addToCache(printStorePath(info.path), *nar, narAccessor);
/* Optionally write a JSON file containing a listing of the /* Optionally write a JSON file containing a listing of the
contents of the NAR. */ contents of the NAR. */
@ -162,7 +161,7 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, const ref<std::str
} }
} }
upsertFile(storePathToHash(info.path) + ".ls", jsonOut.str(), "application/json"); upsertFile(storePathToHash(printStorePath(info.path)) + ".ls", jsonOut.str(), "application/json");
} }
/* Compress the NAR. */ /* Compress the NAR. */
@ -174,10 +173,10 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, const ref<std::str
narInfo->fileSize = narCompressed->size(); narInfo->fileSize = narCompressed->size();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now2 - now1).count(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now2 - now1).count();
printMsg(lvlTalkative, format("copying path '%1%' (%2% bytes, compressed %3$.1f%% in %4% ms) to binary cache") printMsg(lvlTalkative, "copying path '%1%' (%2% bytes, compressed %3$.1f%% in %4% ms) to binary cache",
% narInfo->path % narInfo->narSize printStorePath(narInfo->path), narInfo->narSize,
% ((1.0 - (double) narCompressed->size() / nar->size()) * 100.0) ((1.0 - (double) narCompressed->size() / nar->size()) * 100.0),
% duration); duration);
narInfo->url = "nar/" + narInfo->fileHash.to_string(Base32, false) + ".nar" narInfo->url = "nar/" + narInfo->fileHash.to_string(Base32, false) + ".nar"
+ (compression == "xz" ? ".xz" : + (compression == "xz" ? ".xz" :
@ -254,14 +253,14 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, const ref<std::str
stats.narWriteCompressionTimeMs += duration; stats.narWriteCompressionTimeMs += duration;
/* Atomically write the NAR info file.*/ /* Atomically write the NAR info file.*/
if (secretKey) narInfo->sign(*secretKey); if (secretKey) narInfo->sign(*this, *secretKey);
writeNarInfo(narInfo); writeNarInfo(narInfo);
stats.narInfoWrite++; stats.narInfoWrite++;
} }
bool BinaryCacheStore::isValidPathUncached(const Path & storePath) bool BinaryCacheStore::isValidPathUncached(const StorePath & storePath)
{ {
// FIXME: this only checks whether a .narinfo with a matching hash // FIXME: this only checks whether a .narinfo with a matching hash
// part exists. So f4kb...-foo matches f4kb...-bar, even // part exists. So f4kb...-foo matches f4kb...-bar, even
@ -269,7 +268,7 @@ bool BinaryCacheStore::isValidPathUncached(const Path & storePath)
return fileExists(narInfoFileFor(storePath)); return fileExists(narInfoFileFor(storePath));
} }
void BinaryCacheStore::narFromPath(const Path & storePath, Sink & sink) void BinaryCacheStore::narFromPath(const StorePath & storePath, Sink & sink)
{ {
auto info = queryPathInfo(storePath).cast<const NarInfo>(); auto info = queryPathInfo(storePath).cast<const NarInfo>();
@ -295,12 +294,13 @@ void BinaryCacheStore::narFromPath(const Path & storePath, Sink & sink)
stats.narReadBytes += narSize; stats.narReadBytes += narSize;
} }
void BinaryCacheStore::queryPathInfoUncached(const Path & storePath, void BinaryCacheStore::queryPathInfoUncached(const StorePath & storePath,
Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept
{ {
auto uri = getUri(); auto uri = getUri();
auto storePathS = printStorePath(storePath);
auto act = std::make_shared<Activity>(*logger, lvlTalkative, actQueryPathInfo, auto act = std::make_shared<Activity>(*logger, lvlTalkative, actQueryPathInfo,
fmt("querying info about '%s' on '%s'", storePath, uri), Logger::Fields{storePath, uri}); fmt("querying info about '%s' on '%s'", storePathS, uri), Logger::Fields{storePathS, uri});
PushActivity pact(act->id); PushActivity pact(act->id);
auto narInfoFile = narInfoFileFor(storePath); auto narInfoFile = narInfoFileFor(storePath);
@ -326,7 +326,7 @@ void BinaryCacheStore::queryPathInfoUncached(const Path & storePath,
}}); }});
} }
Path BinaryCacheStore::addToStore(const string & name, const Path & srcPath, StorePath BinaryCacheStore::addToStore(const string & name, const Path & srcPath,
bool recursive, HashType hashAlgo, PathFilter & filter, RepairFlag repair) bool recursive, HashType hashAlgo, PathFilter & filter, RepairFlag repair)
{ {
// FIXME: some cut&paste from LocalStore::addToStore(). // FIXME: some cut&paste from LocalStore::addToStore().
@ -345,20 +345,18 @@ Path BinaryCacheStore::addToStore(const string & name, const Path & srcPath,
h = hashString(hashAlgo, s); h = hashString(hashAlgo, s);
} }
ValidPathInfo info; ValidPathInfo info(makeFixedOutputPath(recursive, h, name));
info.path = makeFixedOutputPath(recursive, h, name);
addToStore(info, sink.s, repair, CheckSigs, nullptr); addToStore(info, sink.s, repair, CheckSigs, nullptr);
return info.path; return std::move(info.path);
} }
Path BinaryCacheStore::addTextToStore(const string & name, const string & s, StorePath BinaryCacheStore::addTextToStore(const string & name, const string & s,
const PathSet & references, RepairFlag repair) const StorePathSet & references, RepairFlag repair)
{ {
ValidPathInfo info; ValidPathInfo info(computeStorePathForText(name, s, references));
info.path = computeStorePathForText(name, s, references); info.references = cloneStorePathSet(references);
info.references = references;
if (repair || !isValidPath(info.path)) { if (repair || !isValidPath(info.path)) {
StringSink sink; StringSink sink;
@ -366,7 +364,7 @@ Path BinaryCacheStore::addTextToStore(const string & name, const string & s,
addToStore(info, sink.s, repair, CheckSigs, nullptr); addToStore(info, sink.s, repair, CheckSigs, nullptr);
} }
return info.path; return std::move(info.path);
} }
ref<FSAccessor> BinaryCacheStore::getFSAccessor() ref<FSAccessor> BinaryCacheStore::getFSAccessor()
@ -374,7 +372,7 @@ ref<FSAccessor> BinaryCacheStore::getFSAccessor()
return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this()), localNarCache); return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this()), localNarCache);
} }
void BinaryCacheStore::addSignatures(const Path & storePath, const StringSet & sigs) void BinaryCacheStore::addSignatures(const StorePath & storePath, const StringSet & sigs)
{ {
/* Note: this is inherently racy since there is no locking on /* Note: this is inherently racy since there is no locking on
binary caches. In particular, with S3 this unreliable, even binary caches. In particular, with S3 this unreliable, even
@ -390,24 +388,22 @@ void BinaryCacheStore::addSignatures(const Path & storePath, const StringSet & s
writeNarInfo(narInfo); writeNarInfo(narInfo);
} }
std::shared_ptr<std::string> BinaryCacheStore::getBuildLog(const Path & path) std::shared_ptr<std::string> BinaryCacheStore::getBuildLog(const StorePath & path)
{ {
Path drvPath; auto drvPath = path.clone();
if (isDerivation(path)) if (!path.isDerivation()) {
drvPath = path;
else {
try { try {
auto info = queryPathInfo(path); auto info = queryPathInfo(path);
// FIXME: add a "Log" field to .narinfo // FIXME: add a "Log" field to .narinfo
if (info->deriver == "") return nullptr; if (!info->deriver) return nullptr;
drvPath = info->deriver; drvPath = info->deriver->clone();
} catch (InvalidPath &) { } catch (InvalidPath &) {
return nullptr; return nullptr;
} }
} }
auto logPath = "log/" + baseNameOf(drvPath); auto logPath = "log/" + std::string(baseNameOf(printStorePath(drvPath)));
debug("fetching build log from binary cache '%s/%s'", getUri(), logPath); debug("fetching build log from binary cache '%s/%s'", getUri(), logPath);

View file

@ -65,18 +65,18 @@ private:
std::string narMagic; std::string narMagic;
std::string narInfoFileFor(const Path & storePath); std::string narInfoFileFor(const StorePath & storePath);
void writeNarInfo(ref<NarInfo> narInfo); void writeNarInfo(ref<NarInfo> narInfo);
public: public:
bool isValidPathUncached(const Path & path) override; bool isValidPathUncached(const StorePath & path) override;
void queryPathInfoUncached(const Path & path, void queryPathInfoUncached(const StorePath & path,
Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override; Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override;
Path queryPathFromHashPart(const string & hashPart) override std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
{ unsupported("queryPathFromHashPart"); } { unsupported("queryPathFromHashPart"); }
bool wantMassQuery() override { return wantMassQuery_; } bool wantMassQuery() override { return wantMassQuery_; }
@ -85,27 +85,27 @@ public:
RepairFlag repair, CheckSigsFlag checkSigs, RepairFlag repair, CheckSigsFlag checkSigs,
std::shared_ptr<FSAccessor> accessor) override; std::shared_ptr<FSAccessor> accessor) override;
Path addToStore(const string & name, const Path & srcPath, StorePath addToStore(const string & name, const Path & srcPath,
bool recursive, HashType hashAlgo, bool recursive, HashType hashAlgo,
PathFilter & filter, RepairFlag repair) override; PathFilter & filter, RepairFlag repair) override;
Path addTextToStore(const string & name, const string & s, StorePath addTextToStore(const string & name, const string & s,
const PathSet & references, RepairFlag repair) override; const StorePathSet & references, RepairFlag repair) override;
void narFromPath(const Path & path, Sink & sink) override; void narFromPath(const StorePath & path, Sink & sink) override;
BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv, BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode) override BuildMode buildMode) override
{ unsupported("buildDerivation"); } { unsupported("buildDerivation"); }
void ensurePath(const Path & path) override void ensurePath(const StorePath & path) override
{ unsupported("ensurePath"); } { unsupported("ensurePath"); }
ref<FSAccessor> getFSAccessor() override; ref<FSAccessor> getFSAccessor() override;
void addSignatures(const Path & storePath, const StringSet & sigs) override; void addSignatures(const StorePath & storePath, const StringSet & sigs) override;
std::shared_ptr<std::string> getBuildLog(const Path & path) override; std::shared_ptr<std::string> getBuildLog(const StorePath & path) override;
int getPriority() override { return priority; } int getPriority() override { return priority; }

File diff suppressed because it is too large Load diff

View file

@ -24,7 +24,7 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
Path storePath = getAttr("out"); Path storePath = getAttr("out");
auto mainUrl = getAttr("url"); auto mainUrl = getAttr("url");
bool unpack = get(drv.env, "unpack", "") == "1"; bool unpack = get(drv.env, "unpack").value_or("") == "1";
/* Note: have to use a fresh downloader here because we're in /* Note: have to use a fresh downloader here because we're in
a forked process. */ a forked process. */

View file

@ -260,14 +260,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
switch (op) { switch (op) {
case wopIsValidPath: { case wopIsValidPath: {
/* 'readStorePath' could raise an error leading to the connection auto path = store->parseStorePath(readString(from));
being closed. To be able to recover from an invalid path error,
call 'startWork' early, and do 'assertStorePath' afterwards so
that the 'Error' exception handler doesn't close the
connection. */
Path path = readString(from);
logger->startWork(); logger->startWork();
store->assertStorePath(path);
bool result = store->isValidPath(path); bool result = store->isValidPath(path);
logger->stopWork(); logger->stopWork();
to << result; to << result;
@ -275,34 +269,36 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
} }
case wopQueryValidPaths: { case wopQueryValidPaths: {
PathSet paths = readStorePaths<PathSet>(*store, from); auto paths = readStorePaths<StorePathSet>(*store, from);
logger->startWork(); logger->startWork();
PathSet res = store->queryValidPaths(paths); auto res = store->queryValidPaths(paths);
logger->stopWork(); logger->stopWork();
to << res; writeStorePaths(*store, to, res);
break; break;
} }
case wopHasSubstitutes: { case wopHasSubstitutes: {
Path path = readStorePath(*store, from); auto path = store->parseStorePath(readString(from));
logger->startWork(); logger->startWork();
PathSet res = store->querySubstitutablePaths({path}); StorePathSet paths; // FIXME
paths.insert(path.clone());
auto res = store->querySubstitutablePaths(paths);
logger->stopWork(); logger->stopWork();
to << (res.find(path) != res.end()); to << (res.count(path) != 0);
break; break;
} }
case wopQuerySubstitutablePaths: { case wopQuerySubstitutablePaths: {
PathSet paths = readStorePaths<PathSet>(*store, from); auto paths = readStorePaths<StorePathSet>(*store, from);
logger->startWork(); logger->startWork();
PathSet res = store->querySubstitutablePaths(paths); auto res = store->querySubstitutablePaths(paths);
logger->stopWork(); logger->stopWork();
to << res; writeStorePaths(*store, to, res);
break; break;
} }
case wopQueryPathHash: { case wopQueryPathHash: {
Path path = readStorePath(*store, from); auto path = store->parseStorePath(readString(from));
logger->startWork(); logger->startWork();
auto hash = store->queryPathInfo(path)->narHash; auto hash = store->queryPathInfo(path)->narHash;
logger->stopWork(); logger->stopWork();
@ -314,23 +310,24 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
case wopQueryReferrers: case wopQueryReferrers:
case wopQueryValidDerivers: case wopQueryValidDerivers:
case wopQueryDerivationOutputs: { case wopQueryDerivationOutputs: {
Path path = readStorePath(*store, from); auto path = store->parseStorePath(readString(from));
logger->startWork(); logger->startWork();
PathSet paths; StorePathSet paths;
if (op == wopQueryReferences) if (op == wopQueryReferences)
paths = store->queryPathInfo(path)->references; for (auto & i : store->queryPathInfo(path)->references)
paths.insert(i.clone());
else if (op == wopQueryReferrers) else if (op == wopQueryReferrers)
store->queryReferrers(path, paths); store->queryReferrers(path, paths);
else if (op == wopQueryValidDerivers) else if (op == wopQueryValidDerivers)
paths = store->queryValidDerivers(path); paths = store->queryValidDerivers(path);
else paths = store->queryDerivationOutputs(path); else paths = store->queryDerivationOutputs(path);
logger->stopWork(); logger->stopWork();
to << paths; writeStorePaths(*store, to, paths);
break; break;
} }
case wopQueryDerivationOutputNames: { case wopQueryDerivationOutputNames: {
Path path = readStorePath(*store, from); auto path = store->parseStorePath(readString(from));
logger->startWork(); logger->startWork();
StringSet names; StringSet names;
names = store->queryDerivationOutputNames(path); names = store->queryDerivationOutputNames(path);
@ -340,20 +337,20 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
} }
case wopQueryDeriver: { case wopQueryDeriver: {
Path path = readStorePath(*store, from); auto path = store->parseStorePath(readString(from));
logger->startWork(); logger->startWork();
auto deriver = store->queryPathInfo(path)->deriver; auto info = store->queryPathInfo(path);
logger->stopWork(); logger->stopWork();
to << deriver; to << (info->deriver ? store->printStorePath(*info->deriver) : "");
break; break;
} }
case wopQueryPathFromHashPart: { case wopQueryPathFromHashPart: {
string hashPart = readString(from); auto hashPart = readString(from);
logger->startWork(); logger->startWork();
Path path = store->queryPathFromHashPart(hashPart); auto path = store->queryPathFromHashPart(hashPart);
logger->stopWork(); logger->stopWork();
to << path; to << (path ? store->printStorePath(*path) : "");
break; break;
} }
@ -383,26 +380,26 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
logger->startWork(); logger->startWork();
if (!savedRegular.regular) throw Error("regular file expected"); if (!savedRegular.regular) throw Error("regular file expected");
Path path = store->addToStoreFromDump(recursive ? *savedNAR.data : savedRegular.s, baseName, recursive, hashAlgo); auto path = store->addToStoreFromDump(recursive ? *savedNAR.data : savedRegular.s, baseName, recursive, hashAlgo);
logger->stopWork(); logger->stopWork();
to << path; to << store->printStorePath(path);
break; break;
} }
case wopAddTextToStore: { case wopAddTextToStore: {
string suffix = readString(from); string suffix = readString(from);
string s = readString(from); string s = readString(from);
PathSet refs = readStorePaths<PathSet>(*store, from); auto refs = readStorePaths<StorePathSet>(*store, from);
logger->startWork(); logger->startWork();
Path path = store->addTextToStore(suffix, s, refs, NoRepair); auto path = store->addTextToStore(suffix, s, refs, NoRepair);
logger->stopWork(); logger->stopWork();
to << path; to << store->printStorePath(path);
break; break;
} }
case wopExportPath: { case wopExportPath: {
Path path = readStorePath(*store, from); auto path = store->parseStorePath(readString(from));
readInt(from); // obsolete readInt(from); // obsolete
logger->startWork(); logger->startWork();
TunnelSink sink(to); TunnelSink sink(to);
@ -415,15 +412,19 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
case wopImportPaths: { case wopImportPaths: {
logger->startWork(); logger->startWork();
TunnelSource source(from, to); TunnelSource source(from, to);
Paths paths = store->importPaths(source, nullptr, auto paths = store->importPaths(source, nullptr,
trusted ? NoCheckSigs : CheckSigs); trusted ? NoCheckSigs : CheckSigs);
logger->stopWork(); logger->stopWork();
to << paths; Strings paths2;
for (auto & i : paths) paths2.push_back(store->printStorePath(i));
to << paths2;
break; break;
} }
case wopBuildPaths: { case wopBuildPaths: {
PathSet drvs = readStorePaths<PathSet>(*store, from); std::vector<StorePathWithOutputs> drvs;
for (auto & s : readStrings<Strings>(from))
drvs.push_back(store->parseDrvPathWithOutputs(s));
BuildMode mode = bmNormal; BuildMode mode = bmNormal;
if (GET_PROTOCOL_MINOR(clientVersion) >= 15) { if (GET_PROTOCOL_MINOR(clientVersion) >= 15) {
mode = (BuildMode) readInt(from); mode = (BuildMode) readInt(from);
@ -441,7 +442,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
} }
case wopBuildDerivation: { case wopBuildDerivation: {
Path drvPath = readStorePath(*store, from); auto drvPath = store->parseStorePath(readString(from));
BasicDerivation drv; BasicDerivation drv;
readDerivation(from, *store, drv); readDerivation(from, *store, drv);
BuildMode buildMode = (BuildMode) readInt(from); BuildMode buildMode = (BuildMode) readInt(from);
@ -455,7 +456,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
} }
case wopEnsurePath: { case wopEnsurePath: {
Path path = readStorePath(*store, from); auto path = store->parseStorePath(readString(from));
logger->startWork(); logger->startWork();
store->ensurePath(path); store->ensurePath(path);
logger->stopWork(); logger->stopWork();
@ -464,7 +465,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
} }
case wopAddTempRoot: { case wopAddTempRoot: {
Path path = readStorePath(*store, from); auto path = store->parseStorePath(readString(from));
logger->startWork(); logger->startWork();
store->addTempRoot(path); store->addTempRoot(path);
logger->stopWork(); logger->stopWork();
@ -502,7 +503,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
for (auto & [target, links] : roots) for (auto & [target, links] : roots)
for (auto & link : links) for (auto & link : links)
to << link << target; to << link << store->printStorePath(target);
break; break;
} }
@ -510,7 +511,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
case wopCollectGarbage: { case wopCollectGarbage: {
GCOptions options; GCOptions options;
options.action = (GCOptions::GCAction) readInt(from); options.action = (GCOptions::GCAction) readInt(from);
options.pathsToDelete = readStorePaths<PathSet>(*store, from); options.pathsToDelete = readStorePaths<StorePathSet>(*store, from);
from >> options.ignoreLiveness >> options.maxFreed; from >> options.ignoreLiveness >> options.maxFreed;
// obsolete fields // obsolete fields
readInt(from); readInt(from);
@ -568,44 +569,52 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
} }
case wopQuerySubstitutablePathInfo: { case wopQuerySubstitutablePathInfo: {
Path path = absPath(readString(from)); auto path = store->parseStorePath(readString(from));
logger->startWork(); logger->startWork();
SubstitutablePathInfos infos; SubstitutablePathInfos infos;
store->querySubstitutablePathInfos({path}, infos); StorePathSet paths;
paths.insert(path.clone()); // FIXME
store->querySubstitutablePathInfos(paths, infos);
logger->stopWork(); logger->stopWork();
SubstitutablePathInfos::iterator i = infos.find(path); auto i = infos.find(path);
if (i == infos.end()) if (i == infos.end())
to << 0; to << 0;
else { else {
to << 1 << i->second.deriver << i->second.references << i->second.downloadSize << i->second.narSize; to << 1
<< (i->second.deriver ? store->printStorePath(*i->second.deriver) : "");
writeStorePaths(*store, to, i->second.references);
to << i->second.downloadSize
<< i->second.narSize;
} }
break; break;
} }
case wopQuerySubstitutablePathInfos: { case wopQuerySubstitutablePathInfos: {
PathSet paths = readStorePaths<PathSet>(*store, from); auto paths = readStorePaths<StorePathSet>(*store, from);
logger->startWork(); logger->startWork();
SubstitutablePathInfos infos; SubstitutablePathInfos infos;
store->querySubstitutablePathInfos(paths, infos); store->querySubstitutablePathInfos(paths, infos);
logger->stopWork(); logger->stopWork();
to << infos.size(); to << infos.size();
for (auto & i : infos) { for (auto & i : infos) {
to << i.first << i.second.deriver << i.second.references to << store->printStorePath(i.first)
<< i.second.downloadSize << i.second.narSize; << (i.second.deriver ? store->printStorePath(*i.second.deriver) : "");
writeStorePaths(*store, to, i.second.references);
to << i.second.downloadSize << i.second.narSize;
} }
break; break;
} }
case wopQueryAllValidPaths: { case wopQueryAllValidPaths: {
logger->startWork(); logger->startWork();
PathSet paths = store->queryAllValidPaths(); auto paths = store->queryAllValidPaths();
logger->stopWork(); logger->stopWork();
to << paths; writeStorePaths(*store, to, paths);
break; break;
} }
case wopQueryPathInfo: { case wopQueryPathInfo: {
Path path = readStorePath(*store, from); auto path = store->parseStorePath(readString(from));
std::shared_ptr<const ValidPathInfo> info; std::shared_ptr<const ValidPathInfo> info;
logger->startWork(); logger->startWork();
try { try {
@ -617,8 +626,10 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
if (info) { if (info) {
if (GET_PROTOCOL_MINOR(clientVersion) >= 17) if (GET_PROTOCOL_MINOR(clientVersion) >= 17)
to << 1; to << 1;
to << info->deriver << info->narHash.to_string(Base16, false) << info->references to << (info->deriver ? store->printStorePath(*info->deriver) : "")
<< info->registrationTime << info->narSize; << info->narHash.to_string(Base16, false);
writeStorePaths(*store, to, info->references);
to << info->registrationTime << info->narSize;
if (GET_PROTOCOL_MINOR(clientVersion) >= 16) { if (GET_PROTOCOL_MINOR(clientVersion) >= 16) {
to << info->ultimate to << info->ultimate
<< info->sigs << info->sigs
@ -651,7 +662,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
} }
case wopAddSignatures: { case wopAddSignatures: {
Path path = readStorePath(*store, from); auto path = store->parseStorePath(readString(from));
StringSet sigs = readStrings<StringSet>(from); StringSet sigs = readStrings<StringSet>(from);
logger->startWork(); logger->startWork();
if (!trusted) if (!trusted)
@ -663,22 +674,21 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
} }
case wopNarFromPath: { case wopNarFromPath: {
auto path = readStorePath(*store, from); auto path = store->parseStorePath(readString(from));
logger->startWork(); logger->startWork();
logger->stopWork(); logger->stopWork();
dumpPath(path, to); dumpPath(store->printStorePath(path), to);
break; break;
} }
case wopAddToStoreNar: { case wopAddToStoreNar: {
bool repair, dontCheckSigs; bool repair, dontCheckSigs;
ValidPathInfo info; ValidPathInfo info(store->parseStorePath(readString(from)));
info.path = readStorePath(*store, from); auto deriver = readString(from);
from >> info.deriver; if (deriver != "")
if (!info.deriver.empty()) info.deriver = store->parseStorePath(deriver);
store->assertStorePath(info.deriver);
info.narHash = Hash(readString(from), htSHA256); info.narHash = Hash(readString(from), htSHA256);
info.references = readStorePaths<PathSet>(*store, from); info.references = readStorePaths<StorePathSet>(*store, from);
from >> info.registrationTime >> info.narSize >> info.ultimate; from >> info.registrationTime >> info.narSize >> info.ultimate;
info.sigs = readStrings<StringSet>(from); info.sigs = readStrings<StringSet>(from);
from >> info.ca >> repair >> dontCheckSigs; from >> info.ca >> repair >> dontCheckSigs;
@ -709,13 +719,18 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
} }
case wopQueryMissing: { case wopQueryMissing: {
PathSet targets = readStorePaths<PathSet>(*store, from); std::vector<StorePathWithOutputs> targets;
for (auto & s : readStrings<Strings>(from))
targets.push_back(store->parseDrvPathWithOutputs(s));
logger->startWork(); logger->startWork();
PathSet willBuild, willSubstitute, unknown; StorePathSet willBuild, willSubstitute, unknown;
unsigned long long downloadSize, narSize; unsigned long long downloadSize, narSize;
store->queryMissing(targets, willBuild, willSubstitute, unknown, downloadSize, narSize); store->queryMissing(targets, willBuild, willSubstitute, unknown, downloadSize, narSize);
logger->stopWork(); logger->stopWork();
to << willBuild << willSubstitute << unknown << downloadSize << narSize; writeStorePaths(*store, to, willBuild);
writeStorePaths(*store, to, willSubstitute);
writeStorePaths(*store, to, unknown);
to << downloadSize << narSize;
break; break;
} }

View file

@ -21,17 +21,39 @@ void DerivationOutput::parseHashInfo(bool & recursive, Hash & hash) const
HashType hashType = parseHashType(algo); HashType hashType = parseHashType(algo);
if (hashType == htUnknown) if (hashType == htUnknown)
throw Error(format("unknown hash algorithm '%1%'") % algo); throw Error("unknown hash algorithm '%s'", algo);
hash = Hash(this->hash, hashType); hash = Hash(this->hash, hashType);
} }
Path BasicDerivation::findOutput(const string & id) const BasicDerivation::BasicDerivation(const BasicDerivation & other)
: platform(other.platform)
, builder(other.builder)
, args(other.args)
, env(other.env)
{
for (auto & i : other.outputs)
outputs.insert_or_assign(i.first,
DerivationOutput(i.second.path.clone(), std::string(i.second.hashAlgo), std::string(i.second.hash)));
for (auto & i : other.inputSrcs)
inputSrcs.insert(i.clone());
}
Derivation::Derivation(const Derivation & other)
: BasicDerivation(other)
{
for (auto & i : other.inputDrvs)
inputDrvs.insert_or_assign(i.first.clone(), i.second);
}
const StorePath & BasicDerivation::findOutput(const string & id) const
{ {
auto i = outputs.find(id); auto i = outputs.find(id);
if (i == outputs.end()) if (i == outputs.end())
throw Error(format("derivation has no output '%1%'") % id); throw Error("derivation has no output '%s'", id);
return i->second.path; return i->second.path;
} }
@ -42,18 +64,17 @@ bool BasicDerivation::isBuiltin() const
} }
Path writeDerivation(ref<Store> store, StorePath writeDerivation(ref<Store> store,
const Derivation & drv, const string & name, RepairFlag repair) const Derivation & drv, const string & name, RepairFlag repair)
{ {
PathSet references; auto references = cloneStorePathSet(drv.inputSrcs);
references.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
for (auto & i : drv.inputDrvs) for (auto & i : drv.inputDrvs)
references.insert(i.first); references.insert(i.first.clone());
/* Note that the outputs of a derivation are *not* references /* Note that the outputs of a derivation are *not* references
(that can be missing (of course) and should not necessarily be (that can be missing (of course) and should not necessarily be
held during a garbage collection). */ held during a garbage collection). */
string suffix = name + drvExtension; string suffix = name + drvExtension;
string contents = drv.unparse(); string contents = drv.unparse(*store, false);
return settings.readOnlyMode return settings.readOnlyMode
? store->computeStorePathForText(suffix, contents, references) ? store->computeStorePathForText(suffix, contents, references)
: store->addTextToStore(suffix, contents, references, repair); : store->addTextToStore(suffix, contents, references, repair);
@ -121,7 +142,7 @@ static StringSet parseStrings(std::istream & str, bool arePaths)
} }
static Derivation parseDerivation(const string & s) static Derivation parseDerivation(const Store & store, const string & s)
{ {
Derivation drv; Derivation drv;
istringstream_nocopy str(s); istringstream_nocopy str(s);
@ -129,13 +150,12 @@ static Derivation parseDerivation(const string & s)
/* Parse the list of outputs. */ /* Parse the list of outputs. */
while (!endOfList(str)) { while (!endOfList(str)) {
DerivationOutput out; expect(str, "("); std::string id = parseString(str);
expect(str, "("); string id = parseString(str); expect(str, ","); auto path = store.parseStorePath(parsePath(str));
expect(str, ","); out.path = parsePath(str); expect(str, ","); auto hashAlgo = parseString(str);
expect(str, ","); out.hashAlgo = parseString(str); expect(str, ","); auto hash = parseString(str);
expect(str, ","); out.hash = parseString(str);
expect(str, ")"); expect(str, ")");
drv.outputs[id] = out; drv.outputs.emplace(id, DerivationOutput(std::move(path), std::move(hashAlgo), std::move(hash)));
} }
/* Parse the list of input derivations. */ /* Parse the list of input derivations. */
@ -144,11 +164,11 @@ static Derivation parseDerivation(const string & s)
expect(str, "("); expect(str, "(");
Path drvPath = parsePath(str); Path drvPath = parsePath(str);
expect(str, ",["); expect(str, ",[");
drv.inputDrvs[drvPath] = parseStrings(str, false); drv.inputDrvs.insert_or_assign(store.parseStorePath(drvPath), parseStrings(str, false));
expect(str, ")"); expect(str, ")");
} }
expect(str, ",["); drv.inputSrcs = parseStrings(str, true); expect(str, ",["); drv.inputSrcs = store.parseStorePathSet(parseStrings(str, true));
expect(str, ","); drv.platform = parseString(str); expect(str, ","); drv.platform = parseString(str);
expect(str, ","); drv.builder = parseString(str); expect(str, ","); drv.builder = parseString(str);
@ -171,25 +191,24 @@ static Derivation parseDerivation(const string & s)
} }
Derivation readDerivation(const Path & drvPath) Derivation readDerivation(const Store & store, const Path & drvPath)
{ {
try { try {
return parseDerivation(readFile(drvPath)); return parseDerivation(store, readFile(drvPath));
} catch (FormatError & e) { } catch (FormatError & e) {
throw Error(format("error parsing derivation '%1%': %2%") % drvPath % e.msg()); throw Error(format("error parsing derivation '%1%': %2%") % drvPath % e.msg());
} }
} }
Derivation Store::derivationFromPath(const Path & drvPath) Derivation Store::derivationFromPath(const StorePath & drvPath)
{ {
assertStorePath(drvPath);
ensurePath(drvPath); ensurePath(drvPath);
auto accessor = getFSAccessor(); auto accessor = getFSAccessor();
try { try {
return parseDerivation(accessor->readFile(drvPath)); return parseDerivation(*this, accessor->readFile(printStorePath(drvPath)));
} catch (FormatError & e) { } catch (FormatError & e) {
throw Error(format("error parsing derivation '%1%': %2%") % drvPath % e.msg()); throw Error("error parsing derivation '%s': %s", printStorePath(drvPath), e.msg());
} }
} }
@ -220,33 +239,56 @@ static void printStrings(string & res, ForwardIterator i, ForwardIterator j)
} }
string Derivation::unparse() const string Derivation::unparse(const Store & store, bool maskOutputs,
std::map<std::string, StringSet> * actualInputs) const
{ {
string s; string s;
s.reserve(65536); s.reserve(65536);
s += "Derive(["; s += "Derive([";
bool first = true; StringSet maskedOutputs;
for (auto & i : outputs) {
if (first) first = false; else s += ','; if (maskOutputs) {
s += '('; printString(s, i.first); bool first = true;
s += ','; printString(s, i.second.path); maskedOutputs = tokenizeString<StringSet>(get(env, "outputs").value_or("out"), " ");
s += ','; printString(s, i.second.hashAlgo); for (auto & i : maskedOutputs) {
s += ','; printString(s, i.second.hash); if (first) first = false; else s += ',';
s += ')'; s += '('; printString(s, i);
s += ",\"\",\"\",\"\")";
}
} else {
bool first = true;
for (auto & i : outputs) {
if (first) first = false; else s += ',';
s += '('; printString(s, i.first);
s += ','; printString(s, store.printStorePath(i.second.path));
s += ','; printString(s, i.second.hashAlgo);
s += ','; printString(s, i.second.hash);
s += ')';
}
} }
s += "],["; s += "],[";
first = true; bool first = true;
for (auto & i : inputDrvs) { if (actualInputs) {
if (first) first = false; else s += ','; for (auto & i : *actualInputs) {
s += '('; printString(s, i.first); if (first) first = false; else s += ',';
s += ','; printStrings(s, i.second.begin(), i.second.end()); s += '('; printString(s, i.first);
s += ')'; s += ','; printStrings(s, i.second.begin(), i.second.end());
s += ')';
}
} else {
for (auto & i : inputDrvs) {
if (first) first = false; else s += ',';
s += '('; printString(s, store.printStorePath(i.first));
s += ','; printStrings(s, i.second.begin(), i.second.end());
s += ')';
}
} }
s += "],"; s += "],";
printStrings(s, inputSrcs.begin(), inputSrcs.end()); auto paths = store.printStorePathSet(inputSrcs); // FIXME: slow
printStrings(s, paths.begin(), paths.end());
s += ','; printString(s, platform); s += ','; printString(s, platform);
s += ','; printString(s, builder); s += ','; printString(s, builder);
@ -257,7 +299,7 @@ string Derivation::unparse() const
for (auto & i : env) { for (auto & i : env) {
if (first) first = false; else s += ','; if (first) first = false; else s += ',';
s += '('; printString(s, i.first); s += '('; printString(s, i.first);
s += ','; printString(s, i.second); s += ','; printString(s, maskOutputs && maskedOutputs.count(i.first) ? "" : i.second);
s += ')'; s += ')';
} }
@ -267,6 +309,7 @@ string Derivation::unparse() const
} }
// FIXME: remove
bool isDerivation(const string & fileName) bool isDerivation(const string & fileName)
{ {
return hasSuffix(fileName, drvExtension); return hasSuffix(fileName, drvExtension);
@ -304,7 +347,7 @@ DrvHashes drvHashes;
paths have been replaced by the result of a recursive call to this paths have been replaced by the result of a recursive call to this
function, and that for fixed-output derivations we return a hash of function, and that for fixed-output derivations we return a hash of
its output path. */ its output path. */
Hash hashDerivationModulo(Store & store, Derivation drv) Hash hashDerivationModulo(Store & store, const Derivation & drv, bool maskOutputs)
{ {
/* Return a fixed hash for fixed-output derivations. */ /* Return a fixed hash for fixed-output derivations. */
if (drv.isFixedOutput()) { if (drv.isFixedOutput()) {
@ -312,42 +355,41 @@ Hash hashDerivationModulo(Store & store, Derivation drv)
return hashString(htSHA256, "fixed:out:" return hashString(htSHA256, "fixed:out:"
+ i->second.hashAlgo + ":" + i->second.hashAlgo + ":"
+ i->second.hash + ":" + i->second.hash + ":"
+ i->second.path); + store.printStorePath(i->second.path));
} }
/* For other derivations, replace the inputs paths with recursive /* For other derivations, replace the inputs paths with recursive
calls to this function.*/ calls to this function.*/
DerivationInputs inputs2; std::map<std::string, StringSet> inputs2;
for (auto & i : drv.inputDrvs) { for (auto & i : drv.inputDrvs) {
Hash h = drvHashes[i.first]; auto h = drvHashes.find(i.first);
if (!h) { if (h == drvHashes.end()) {
assert(store.isValidPath(i.first)); assert(store.isValidPath(i.first));
Derivation drv2 = readDerivation(store.toRealPath(i.first)); h = drvHashes.insert_or_assign(i.first.clone(), hashDerivationModulo(store,
h = hashDerivationModulo(store, drv2); readDerivation(store, store.toRealPath(store.printStorePath(i.first))), false)).first;
drvHashes[i.first] = h;
} }
inputs2[h.to_string(Base16, false)] = i.second; inputs2.insert_or_assign(h->second.to_string(Base16, false), i.second);
} }
drv.inputDrvs = inputs2;
return hashString(htSHA256, drv.unparse()); return hashString(htSHA256, drv.unparse(store, maskOutputs, &inputs2));
} }
DrvPathWithOutputs parseDrvPathWithOutputs(const string & s) StorePathWithOutputs Store::parseDrvPathWithOutputs(const std::string & s)
{ {
size_t n = s.find("!"); size_t n = s.find("!");
return n == s.npos return n == s.npos
? DrvPathWithOutputs(s, std::set<string>()) ? StorePathWithOutputs{parseStorePath(s), std::set<string>()}
: DrvPathWithOutputs(string(s, 0, n), tokenizeString<std::set<string> >(string(s, n + 1), ",")); : StorePathWithOutputs{parseStorePath(std::string_view(s.data(), n)),
tokenizeString<std::set<string>>(string(s, n + 1), ",")};
} }
Path makeDrvPathWithOutputs(const Path & drvPath, const std::set<string> & outputs) std::string StorePathWithOutputs::to_string(const Store & store) const
{ {
return outputs.empty() return outputs.empty()
? drvPath ? store.printStorePath(path)
: drvPath + "!" + concatStringsSep(",", outputs); : store.printStorePath(path) + "!" + concatStringsSep(",", outputs);
} }
@ -357,28 +399,28 @@ bool wantOutput(const string & output, const std::set<string> & wanted)
} }
PathSet BasicDerivation::outputPaths() const StorePathSet BasicDerivation::outputPaths() const
{ {
PathSet paths; StorePathSet paths;
for (auto & i : outputs) for (auto & i : outputs)
paths.insert(i.second.path); paths.insert(i.second.path.clone());
return paths; return paths;
} }
Source & readDerivation(Source & in, Store & store, BasicDerivation & drv) Source & readDerivation(Source & in, const Store & store, BasicDerivation & drv)
{ {
drv.outputs.clear(); drv.outputs.clear();
auto nr = readNum<size_t>(in); auto nr = readNum<size_t>(in);
for (size_t n = 0; n < nr; n++) { for (size_t n = 0; n < nr; n++) {
auto name = readString(in); auto name = readString(in);
DerivationOutput o; auto path = store.parseStorePath(readString(in));
in >> o.path >> o.hashAlgo >> o.hash; auto hashAlgo = readString(in);
store.assertStorePath(o.path); auto hash = readString(in);
drv.outputs[name] = o; drv.outputs.emplace(name, DerivationOutput(std::move(path), std::move(hashAlgo), std::move(hash)));
} }
drv.inputSrcs = readStorePaths<PathSet>(store, in); drv.inputSrcs = readStorePaths<StorePathSet>(store, in);
in >> drv.platform >> drv.builder; in >> drv.platform >> drv.builder;
drv.args = readStrings<Strings>(in); drv.args = readStrings<Strings>(in);
@ -393,16 +435,16 @@ Source & readDerivation(Source & in, Store & store, BasicDerivation & drv)
} }
Sink & operator << (Sink & out, const BasicDerivation & drv) void writeDerivation(Sink & out, const Store & store, const BasicDerivation & drv)
{ {
out << drv.outputs.size(); out << drv.outputs.size();
for (auto & i : drv.outputs) for (auto & i : drv.outputs)
out << i.first << i.second.path << i.second.hashAlgo << i.second.hash; out << i.first << store.printStorePath(i.second.path) << i.second.hashAlgo << i.second.hash;
out << drv.inputSrcs << drv.platform << drv.builder << drv.args; writeStorePaths(store, out, drv.inputSrcs);
out << drv.platform << drv.builder << drv.args;
out << drv.env.size(); out << drv.env.size();
for (auto & i : drv.env) for (auto & i : drv.env)
out << i.first << i.second; out << i.first << i.second;
return out;
} }

View file

@ -10,26 +10,18 @@
namespace nix { namespace nix {
/* Extension of derivations in the Nix store. */
const string drvExtension = ".drv";
/* Abstract syntax of derivations. */ /* Abstract syntax of derivations. */
struct DerivationOutput struct DerivationOutput
{ {
Path path; StorePath path;
string hashAlgo; /* hash used for expected hash computation */ std::string hashAlgo; /* hash used for expected hash computation */
string hash; /* expected hash, may be null */ std::string hash; /* expected hash, may be null */
DerivationOutput() DerivationOutput(StorePath && path, std::string && hashAlgo, std::string && hash)
{ : path(std::move(path))
} , hashAlgo(std::move(hashAlgo))
DerivationOutput(Path path, string hashAlgo, string hash) , hash(std::move(hash))
{ { }
this->path = path;
this->hashAlgo = hashAlgo;
this->hash = hash;
}
void parseHashInfo(bool & recursive, Hash & hash) const; void parseHashInfo(bool & recursive, Hash & hash) const;
}; };
@ -37,24 +29,26 @@ typedef std::map<string, DerivationOutput> DerivationOutputs;
/* 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<Path, StringSet> DerivationInputs; typedef std::map<StorePath, StringSet> DerivationInputs;
typedef std::map<string, string> StringPairs; typedef std::map<string, string> StringPairs;
struct BasicDerivation struct BasicDerivation
{ {
DerivationOutputs outputs; /* keyed on symbolic IDs */ DerivationOutputs outputs; /* keyed on symbolic IDs */
PathSet inputSrcs; /* inputs that are sources */ StorePathSet inputSrcs; /* inputs that are sources */
string platform; string platform;
Path builder; Path builder;
Strings args; Strings args;
StringPairs env; StringPairs env;
BasicDerivation() { }
explicit BasicDerivation(const BasicDerivation & other);
virtual ~BasicDerivation() { }; virtual ~BasicDerivation() { };
/* Return the path corresponding to the output identifier `id' in /* Return the path corresponding to the output identifier `id' in
the given derivation. */ the given derivation. */
Path findOutput(const string & id) const; const StorePath & findOutput(const std::string & id) const;
bool isBuiltin() const; bool isBuiltin() const;
@ -62,7 +56,7 @@ struct BasicDerivation
bool isFixedOutput() const; bool isFixedOutput() const;
/* Return the output paths of a derivation. */ /* Return the output paths of a derivation. */
PathSet outputPaths() const; StorePathSet outputPaths() const;
}; };
@ -71,7 +65,12 @@ struct Derivation : BasicDerivation
DerivationInputs inputDrvs; /* inputs that are sub-derivations */ DerivationInputs inputDrvs; /* inputs that are sub-derivations */
/* Print a derivation. */ /* Print a derivation. */
std::string unparse() const; std::string unparse(const Store & store, bool maskOutputs,
std::map<std::string, StringSet> * actualInputs = nullptr) const;
Derivation() { }
Derivation(Derivation && other) = default;
explicit Derivation(const Derivation & other);
}; };
@ -79,38 +78,29 @@ class Store;
/* Write a derivation to the Nix store, and return its path. */ /* Write a derivation to the Nix store, and return its path. */
Path writeDerivation(ref<Store> store, StorePath writeDerivation(ref<Store> store,
const Derivation & drv, const string & name, RepairFlag repair = NoRepair); const Derivation & drv, const string & name, RepairFlag repair = NoRepair);
/* Read a derivation from a file. */ /* Read a derivation from a file. */
Derivation readDerivation(const Path & drvPath); Derivation readDerivation(const Store & store, const Path & drvPath);
/* Check whether a file name ends with the extension for // FIXME: remove
derivations. */
bool isDerivation(const string & fileName); bool isDerivation(const string & fileName);
Hash hashDerivationModulo(Store & store, Derivation drv); Hash hashDerivationModulo(Store & store, const Derivation & drv, bool maskOutputs);
/* Memoisation of hashDerivationModulo(). */ /* Memoisation of hashDerivationModulo(). */
typedef std::map<Path, Hash> DrvHashes; typedef std::map<StorePath, Hash> DrvHashes;
extern DrvHashes drvHashes; // FIXME: global, not thread-safe extern DrvHashes drvHashes; // FIXME: global, not thread-safe
/* Split a string specifying a derivation and a set of outputs
(/nix/store/hash-foo!out1,out2,...) into the derivation path and
the outputs. */
typedef std::pair<string, std::set<string> > DrvPathWithOutputs;
DrvPathWithOutputs parseDrvPathWithOutputs(const string & s);
Path makeDrvPathWithOutputs(const Path & drvPath, const std::set<string> & outputs);
bool wantOutput(const string & output, const std::set<string> & wanted); bool wantOutput(const string & output, const std::set<string> & wanted);
struct Source; struct Source;
struct Sink; struct Sink;
Source & readDerivation(Source & in, Store & store, BasicDerivation & drv); Source & readDerivation(Source & in, const Store & store, BasicDerivation & drv);
Sink & operator << (Sink & out, const BasicDerivation & drv); void writeDerivation(Sink & out, const Store & store, const BasicDerivation & drv);
std::string hashPlaceholder(const std::string & outputName); std::string hashPlaceholder(const std::string & outputName);

View file

@ -650,10 +650,10 @@ struct CurlDownloader : public Downloader
#ifdef ENABLE_S3 #ifdef ENABLE_S3
auto [bucketName, key, params] = parseS3Uri(request.uri); auto [bucketName, key, params] = parseS3Uri(request.uri);
std::string profile = get(params, "profile", ""); std::string profile = get(params, "profile").value_or("");
std::string region = get(params, "region", Aws::Region::US_EAST_1); std::string region = get(params, "region").value_or(Aws::Region::US_EAST_1);
std::string scheme = get(params, "scheme", ""); std::string scheme = get(params, "scheme").value_or("");
std::string endpoint = get(params, "endpoint", ""); std::string endpoint = get(params, "endpoint").value_or("");
S3Helper s3Helper(profile, region, scheme, endpoint); S3Helper s3Helper(profile, region, scheme, endpoint);
@ -811,13 +811,13 @@ CachedDownloadResult Downloader::downloadCached(
if (p != string::npos) name = string(url, p + 1); if (p != string::npos) name = string(url, p + 1);
} }
Path expectedStorePath; std::optional<StorePath> expectedStorePath;
if (request.expectedHash) { if (request.expectedHash) {
expectedStorePath = store->makeFixedOutputPath(request.unpack, request.expectedHash, name); expectedStorePath = store->makeFixedOutputPath(request.unpack, request.expectedHash, name);
if (store->isValidPath(expectedStorePath)) { if (store->isValidPath(*expectedStorePath)) {
CachedDownloadResult result; CachedDownloadResult result;
result.storePath = expectedStorePath; result.storePath = store->printStorePath(*expectedStorePath);
result.path = store->toRealPath(expectedStorePath); result.path = store->toRealPath(result.storePath);
return result; return result;
} }
} }
@ -832,7 +832,7 @@ CachedDownloadResult Downloader::downloadCached(
PathLocks lock({fileLink}, fmt("waiting for lock on '%1%'...", fileLink)); PathLocks lock({fileLink}, fmt("waiting for lock on '%1%'...", fileLink));
Path storePath; std::optional<StorePath> storePath;
string expectedETag; string expectedETag;
@ -841,9 +841,10 @@ CachedDownloadResult Downloader::downloadCached(
CachedDownloadResult result; CachedDownloadResult result;
if (pathExists(fileLink) && pathExists(dataFile)) { if (pathExists(fileLink) && pathExists(dataFile)) {
storePath = readLink(fileLink); storePath = store->parseStorePath(readLink(fileLink));
store->addTempRoot(storePath); // FIXME
if (store->isValidPath(storePath)) { store->addTempRoot(*storePath);
if (store->isValidPath(*storePath)) {
auto ss = tokenizeString<vector<string>>(readFile(dataFile), "\n"); auto ss = tokenizeString<vector<string>>(readFile(dataFile), "\n");
if (ss.size() >= 3 && ss[0] == url) { if (ss.size() >= 3 && ss[0] == url) {
time_t lastChecked; time_t lastChecked;
@ -857,7 +858,7 @@ CachedDownloadResult Downloader::downloadCached(
} }
} }
} else } else
storePath = ""; storePath.reset();
} }
if (!skip) { if (!skip) {
@ -870,65 +871,65 @@ CachedDownloadResult Downloader::downloadCached(
result.etag = res.etag; result.etag = res.etag;
if (!res.cached) { if (!res.cached) {
ValidPathInfo info;
StringSink sink; StringSink sink;
dumpString(*res.data, sink); dumpString(*res.data, sink);
Hash hash = hashString(request.expectedHash ? request.expectedHash.type : htSHA256, *res.data); Hash hash = hashString(request.expectedHash ? request.expectedHash.type : htSHA256, *res.data);
info.path = store->makeFixedOutputPath(false, hash, name); ValidPathInfo info(store->makeFixedOutputPath(false, hash, name));
info.narHash = hashString(htSHA256, *sink.s); info.narHash = hashString(htSHA256, *sink.s);
info.narSize = sink.s->size(); info.narSize = sink.s->size();
info.ca = makeFixedOutputCA(false, hash); info.ca = makeFixedOutputCA(false, hash);
store->addToStore(info, sink.s, NoRepair, NoCheckSigs); store->addToStore(info, sink.s, NoRepair, NoCheckSigs);
storePath = info.path; storePath = info.path.clone();
} }
assert(!storePath.empty()); assert(storePath);
replaceSymlink(storePath, fileLink); replaceSymlink(store->printStorePath(*storePath), fileLink);
writeFile(dataFile, url + "\n" + res.etag + "\n" + std::to_string(time(0)) + "\n"); writeFile(dataFile, url + "\n" + res.etag + "\n" + std::to_string(time(0)) + "\n");
} catch (DownloadError & e) { } catch (DownloadError & e) {
if (storePath.empty()) throw; if (!storePath) throw;
warn("warning: %s; using cached result", e.msg()); warn("warning: %s; using cached result", e.msg());
result.etag = expectedETag; result.etag = expectedETag;
} }
} }
if (request.unpack) { if (request.unpack) {
Path unpackedLink = cacheDir + "/" + baseNameOf(storePath) + "-unpacked"; Path unpackedLink = cacheDir + "/" + ((std::string) storePath->to_string()) + "-unpacked";
PathLocks lock2({unpackedLink}, fmt("waiting for lock on '%1%'...", unpackedLink)); PathLocks lock2({unpackedLink}, fmt("waiting for lock on '%1%'...", unpackedLink));
Path unpackedStorePath; std::optional<StorePath> unpackedStorePath;
if (pathExists(unpackedLink)) { if (pathExists(unpackedLink)) {
unpackedStorePath = readLink(unpackedLink); unpackedStorePath = store->parseStorePath(readLink(unpackedLink));
store->addTempRoot(unpackedStorePath); // FIXME
if (!store->isValidPath(unpackedStorePath)) store->addTempRoot(*unpackedStorePath);
unpackedStorePath = ""; if (!store->isValidPath(*unpackedStorePath))
unpackedStorePath.reset();
} }
if (unpackedStorePath.empty()) { if (!unpackedStorePath) {
printInfo("unpacking '%s'...", url); printInfo("unpacking '%s'...", url);
Path tmpDir = createTempDir(); Path tmpDir = createTempDir();
AutoDelete autoDelete(tmpDir, true); AutoDelete autoDelete(tmpDir, true);
unpackTarfile(store->toRealPath(storePath), tmpDir, baseNameOf(url)); unpackTarfile(store->toRealPath(store->printStorePath(*storePath)), tmpDir, std::string(baseNameOf(url)));
auto members = readDirectory(tmpDir); auto members = readDirectory(tmpDir);
if (members.size() != 1) if (members.size() != 1)
throw nix::Error("tarball '%s' contains an unexpected number of top-level files", url); throw nix::Error("tarball '%s' contains an unexpected number of top-level files", url);
auto topDir = tmpDir + "/" + members.begin()->name; auto topDir = tmpDir + "/" + members.begin()->name;
unpackedStorePath = store->addToStore(name, topDir, true, htSHA256, defaultPathFilter, NoRepair); unpackedStorePath = store->addToStore(name, topDir, true, htSHA256, defaultPathFilter, NoRepair);
} }
replaceSymlink(unpackedStorePath, unpackedLink); replaceSymlink(store->printStorePath(*unpackedStorePath), unpackedLink);
storePath = unpackedStorePath; storePath = std::move(*unpackedStorePath);
} }
if (expectedStorePath != "" && storePath != expectedStorePath) { if (expectedStorePath && *storePath != *expectedStorePath) {
unsigned int statusCode = 102; unsigned int statusCode = 102;
Hash gotHash = request.unpack Hash gotHash = request.unpack
? hashPath(request.expectedHash.type, store->toRealPath(storePath)).first ? hashPath(request.expectedHash.type, store->toRealPath(store->printStorePath(*storePath))).first
: hashFile(request.expectedHash.type, store->toRealPath(storePath)); : hashFile(request.expectedHash.type, store->toRealPath(store->printStorePath(*storePath)));
throw nix::Error(statusCode, "hash mismatch in file downloaded from '%s':\n wanted: %s\n got: %s", throw nix::Error(statusCode, "hash mismatch in file downloaded from '%s':\n wanted: %s\n got: %s",
url, request.expectedHash.to_string(), gotHash.to_string()); url, request.expectedHash.to_string(), gotHash.to_string());
} }
result.storePath = storePath; result.storePath = store->printStorePath(*storePath);
result.path = store->toRealPath(storePath); result.path = store->toRealPath(result.storePath);
return result; return result;
} }

View file

@ -24,9 +24,9 @@ struct HashAndWriteSink : Sink
} }
}; };
void Store::exportPaths(const Paths & paths, Sink & sink) void Store::exportPaths(const StorePathSet & paths, Sink & sink)
{ {
Paths sorted = topoSortPaths(PathSet(paths.begin(), paths.end())); auto sorted = topoSortPaths(paths);
std::reverse(sorted.begin(), sorted.end()); std::reverse(sorted.begin(), sorted.end());
std::string doneLabel("paths exported"); std::string doneLabel("paths exported");
@ -42,7 +42,7 @@ void Store::exportPaths(const Paths & paths, Sink & sink)
sink << 0; sink << 0;
} }
void Store::exportPath(const Path & path, Sink & sink) void Store::exportPath(const StorePath & path, Sink & sink)
{ {
auto info = queryPathInfo(path); auto info = queryPathInfo(path);
@ -55,15 +55,21 @@ void Store::exportPath(const Path & path, Sink & sink)
Don't complain if the stored hash is zero (unknown). */ Don't complain if the stored hash is zero (unknown). */
Hash hash = hashAndWriteSink.currentHash(); Hash hash = hashAndWriteSink.currentHash();
if (hash != info->narHash && info->narHash != Hash(info->narHash.type)) if (hash != info->narHash && info->narHash != Hash(info->narHash.type))
throw Error(format("hash of path '%1%' has changed from '%2%' to '%3%'!") % path throw Error("hash of path '%s' has changed from '%s' to '%s'!",
% info->narHash.to_string() % hash.to_string()); printStorePath(path), info->narHash.to_string(), hash.to_string());
hashAndWriteSink << exportMagic << path << info->references << info->deriver << 0; hashAndWriteSink
<< exportMagic
<< printStorePath(path);
writeStorePaths(*this, hashAndWriteSink, info->references);
hashAndWriteSink
<< (info->deriver ? printStorePath(*info->deriver) : "")
<< 0;
} }
Paths Store::importPaths(Source & source, std::shared_ptr<FSAccessor> accessor, CheckSigsFlag checkSigs) StorePaths Store::importPaths(Source & source, std::shared_ptr<FSAccessor> accessor, CheckSigsFlag checkSigs)
{ {
Paths res; StorePaths res;
while (true) { while (true) {
auto n = readNum<uint64_t>(source); auto n = readNum<uint64_t>(source);
if (n == 0) break; if (n == 0) break;
@ -77,16 +83,15 @@ Paths Store::importPaths(Source & source, std::shared_ptr<FSAccessor> accessor,
if (magic != exportMagic) if (magic != exportMagic)
throw Error("Nix archive cannot be imported; wrong format"); throw Error("Nix archive cannot be imported; wrong format");
ValidPathInfo info; ValidPathInfo info(parseStorePath(readString(source)));
info.path = readStorePath(*this, source);
//Activity act(*logger, lvlInfo, format("importing path '%s'") % info.path); //Activity act(*logger, lvlInfo, format("importing path '%s'") % info.path);
info.references = readStorePaths<PathSet>(*this, source); info.references = readStorePaths<StorePathSet>(*this, source);
info.deriver = readString(source); auto deriver = readString(source);
if (info.deriver != "") assertStorePath(info.deriver); if (deriver != "")
info.deriver = parseStorePath(deriver);
info.narHash = hashString(htSHA256, *tee.source.data); info.narHash = hashString(htSHA256, *tee.source.data);
info.narSize = tee.source.data->size(); info.narSize = tee.source.data->size();
@ -97,7 +102,7 @@ Paths Store::importPaths(Source & source, std::shared_ptr<FSAccessor> accessor,
addToStore(info, tee.source.data, NoRepair, checkSigs, accessor); addToStore(info, tee.source.data, NoRepair, checkSigs, accessor);
res.push_back(info.path); res.push_back(info.path.clone());
} }
return res; return res;

View file

@ -85,12 +85,10 @@ void LocalStore::addIndirectRoot(const Path & path)
} }
Path LocalFSStore::addPermRoot(const Path & _storePath, Path LocalFSStore::addPermRoot(const StorePath & storePath,
const Path & _gcRoot, bool indirect, bool allowOutsideRootsDir) const Path & _gcRoot, bool indirect, bool allowOutsideRootsDir)
{ {
Path storePath(canonPath(_storePath));
Path gcRoot(canonPath(_gcRoot)); Path gcRoot(canonPath(_gcRoot));
assertStorePath(storePath);
if (isInStore(gcRoot)) if (isInStore(gcRoot))
throw Error(format( throw Error(format(
@ -102,7 +100,7 @@ Path LocalFSStore::addPermRoot(const Path & _storePath,
point to the Nix store. */ point to the Nix store. */
if (pathExists(gcRoot) && (!isLink(gcRoot) || !isInStore(readLink(gcRoot)))) if (pathExists(gcRoot) && (!isLink(gcRoot) || !isInStore(readLink(gcRoot))))
throw Error(format("cannot create symlink '%1%'; already exists") % gcRoot); throw Error(format("cannot create symlink '%1%'; already exists") % gcRoot);
makeSymlink(gcRoot, storePath); makeSymlink(gcRoot, printStorePath(storePath));
addIndirectRoot(gcRoot); addIndirectRoot(gcRoot);
} }
@ -117,10 +115,10 @@ Path LocalFSStore::addPermRoot(const Path & _storePath,
% gcRoot % rootsDir); % gcRoot % rootsDir);
} }
if (baseNameOf(gcRoot) == baseNameOf(storePath)) if (baseNameOf(gcRoot) == std::string(storePath.to_string()))
writeFile(gcRoot, ""); writeFile(gcRoot, "");
else else
makeSymlink(gcRoot, storePath); makeSymlink(gcRoot, printStorePath(storePath));
} }
/* Check that the root can be found by the garbage collector. /* Check that the root can be found by the garbage collector.
@ -129,13 +127,12 @@ Path LocalFSStore::addPermRoot(const Path & _storePath,
check if the root is in a directory in or linked from the check if the root is in a directory in or linked from the
gcroots directory. */ gcroots directory. */
if (settings.checkRootReachability) { if (settings.checkRootReachability) {
Roots roots = findRoots(false); auto roots = findRoots(false);
if (roots[storePath].count(gcRoot) == 0) if (roots[storePath.clone()].count(gcRoot) == 0)
printError( printError(
format( "warning: '%1%' is not in a directory where the garbage collector looks for roots; "
"warning: '%1%' is not in a directory where the garbage collector looks for roots; " "therefore, '%2%' might be removed by the garbage collector",
"therefore, '%2%' might be removed by the garbage collector") gcRoot, printStorePath(storePath));
% gcRoot % storePath);
} }
/* Grab the global GC root, causing us to block while a GC is in /* Grab the global GC root, causing us to block while a GC is in
@ -147,7 +144,7 @@ Path LocalFSStore::addPermRoot(const Path & _storePath,
} }
void LocalStore::addTempRoot(const Path & path) void LocalStore::addTempRoot(const StorePath & path)
{ {
auto state(_state.lock()); auto state(_state.lock());
@ -188,7 +185,7 @@ void LocalStore::addTempRoot(const Path & path)
debug(format("acquiring write lock on '%1%'") % fnTempRoots); debug(format("acquiring write lock on '%1%'") % fnTempRoots);
lockFile(state->fdTempRoots.get(), ltWrite, true); lockFile(state->fdTempRoots.get(), ltWrite, true);
string s = path + '\0'; string s = printStorePath(path) + '\0';
writeFull(state->fdTempRoots.get(), s); writeFull(state->fdTempRoots.get(), s);
/* Downgrade to a read lock. */ /* Downgrade to a read lock. */
@ -246,8 +243,7 @@ void LocalStore::findTempRoots(FDs & fds, Roots & tempRoots, bool censor)
while ((end = contents.find((char) 0, pos)) != string::npos) { while ((end = contents.find((char) 0, pos)) != 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);
assertStorePath(root); tempRoots[parseStorePath(root)].emplace(censor ? censored : fmt("{temp:%d}", pid));
tempRoots[root].emplace(censor ? censored : fmt("{temp:%d}", pid));
pos = end + 1; pos = end + 1;
} }
@ -260,10 +256,11 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
{ {
auto foundRoot = [&](const Path & path, const Path & target) { auto foundRoot = [&](const Path & path, const Path & target) {
Path storePath = toStorePath(target); Path storePath = toStorePath(target);
if (isStorePath(storePath) && isValidPath(storePath)) // FIXME
roots[storePath].emplace(path); if (isStorePath(storePath) && isValidPath(parseStorePath(storePath)))
roots[parseStorePath(storePath)].emplace(path);
else else
printInfo(format("skipping invalid root from '%1%' to '%2%'") % path % storePath); printInfo("skipping invalid root from '%1%' to '%2%'", path, storePath);
}; };
try { try {
@ -299,9 +296,10 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
} }
else if (type == DT_REG) { else if (type == DT_REG) {
Path storePath = storeDir + "/" + baseNameOf(path); Path storePath = storeDir + "/" + std::string(baseNameOf(path));
if (isStorePath(storePath) && isValidPath(storePath)) // FIXME
roots[storePath].emplace(path); if (isStorePath(storePath) && isValidPath(parseStorePath(storePath)))
roots[parseStorePath(storePath)].emplace(path);
} }
} }
@ -309,7 +307,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
catch (SysError & e) { catch (SysError & e) {
/* We only ignore permanent failures. */ /* We only ignore permanent failures. */
if (e.errNo == EACCES || e.errNo == ENOENT || e.errNo == ENOTDIR) if (e.errNo == EACCES || e.errNo == ENOENT || e.errNo == ENOTDIR)
printInfo(format("cannot read potential root '%1%'") % path); printInfo("cannot read potential root '%1%'", path);
else else
throw; throw;
} }
@ -340,7 +338,9 @@ Roots LocalStore::findRoots(bool censor)
return roots; return roots;
} }
static void readProcLink(const string & file, Roots & roots) typedef std::unordered_map<Path, std::unordered_set<std::string>> UncheckedRoots;
static void readProcLink(const 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};
@ -369,7 +369,7 @@ static string quoteRegexChars(const string & raw)
return std::regex_replace(raw, specialRegex, R"(\$&)"); return std::regex_replace(raw, specialRegex, R"(\$&)");
} }
static void readFileRoots(const char * path, Roots & roots) static void readFileRoots(const char * path, UncheckedRoots & roots)
{ {
try { try {
roots[readFile(path)].emplace(path); roots[readFile(path)].emplace(path);
@ -381,7 +381,7 @@ static void readFileRoots(const char * path, Roots & roots)
void LocalStore::findRuntimeRoots(Roots & roots, bool censor) void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
{ {
Roots unchecked; UncheckedRoots unchecked;
auto procDir = AutoCloseDir{opendir("/proc")}; auto procDir = AutoCloseDir{opendir("/proc")};
if (procDir) { if (procDir) {
@ -466,16 +466,16 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
#endif #endif
for (auto & [target, links] : unchecked) { for (auto & [target, links] : unchecked) {
if (isInStore(target)) { if (!isInStore(target)) continue;
Path path = toStorePath(target); Path pathS = toStorePath(target);
if (isStorePath(path) && isValidPath(path)) { if (!isStorePath(pathS)) continue;
debug(format("got additional root '%1%'") % path); auto path = parseStorePath(pathS);
if (censor) if (!isValidPath(path)) continue;
roots[path].insert(censored); debug("got additional root '%1%'", pathS);
else if (censor)
roots[path].insert(links.begin(), links.end()); roots[path.clone()].insert(censored);
} else
} roots[path.clone()].insert(links.begin(), links.end());
} }
} }
@ -485,18 +485,19 @@ struct GCLimitReached { };
struct LocalStore::GCState struct LocalStore::GCState
{ {
GCOptions options; const GCOptions & options;
GCResults & results; GCResults & results;
PathSet roots; StorePathSet roots;
PathSet tempRoots; StorePathSet tempRoots;
PathSet dead; StorePathSet dead;
PathSet alive; StorePathSet alive;
bool gcKeepOutputs; bool gcKeepOutputs;
bool gcKeepDerivations; bool gcKeepDerivations;
unsigned long long bytesInvalidated; unsigned long long bytesInvalidated;
bool moveToTrash = true; bool moveToTrash = true;
bool shouldDelete; bool shouldDelete;
GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { } GCState(const GCOptions & options, GCResults & results)
: options(options), results(results), bytesInvalidated(0) { }
}; };
@ -504,7 +505,7 @@ bool LocalStore::isActiveTempFile(const GCState & state,
const Path & path, const string & suffix) const Path & path, const string & suffix)
{ {
return hasSuffix(path, suffix) return hasSuffix(path, suffix)
&& state.tempRoots.find(string(path, 0, path.size() - suffix.size())) != state.tempRoots.end(); && state.tempRoots.count(parseStorePath(string(path, 0, path.size() - suffix.size())));
} }
@ -522,16 +523,17 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
unsigned long long size = 0; unsigned long long size = 0;
if (isStorePath(path) && isValidPath(path)) { // FIXME
PathSet referrers; if (isStorePath(path) && isValidPath(parseStorePath(path))) {
queryReferrers(path, referrers); StorePathSet referrers;
queryReferrers(parseStorePath(path), referrers);
for (auto & i : referrers) for (auto & i : referrers)
if (i != path) deletePathRecursive(state, i); if (printStorePath(i) != path) deletePathRecursive(state, printStorePath(i));
size = queryPathInfo(path)->narSize; size = queryPathInfo(parseStorePath(path))->narSize;
invalidatePathChecked(path); invalidatePathChecked(parseStorePath(path));
} }
Path realPath = realStoreDir + "/" + baseNameOf(path); Path realPath = realStoreDir + "/" + std::string(baseNameOf(path));
struct stat st; struct stat st;
if (lstat(realPath.c_str(), &st)) { if (lstat(realPath.c_str(), &st)) {
@ -555,7 +557,7 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
try { try {
if (chmod(realPath.c_str(), st.st_mode | S_IWUSR) == -1) if (chmod(realPath.c_str(), st.st_mode | S_IWUSR) == -1)
throw SysError(format("making '%1%' writable") % realPath); throw SysError(format("making '%1%' writable") % realPath);
Path tmp = trashDir + "/" + baseNameOf(path); Path tmp = trashDir + "/" + std::string(baseNameOf(path));
if (rename(realPath.c_str(), tmp.c_str())) if (rename(realPath.c_str(), tmp.c_str()))
throw SysError(format("unable to rename '%1%' to '%2%'") % realPath % tmp); throw SysError(format("unable to rename '%1%' to '%2%'") % realPath % tmp);
state.bytesInvalidated += size; state.bytesInvalidated += size;
@ -575,7 +577,7 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
} }
bool LocalStore::canReachRoot(GCState & state, PathSet & visited, const Path & path) bool LocalStore::canReachRoot(GCState & state, StorePathSet & visited, const StorePath & path)
{ {
if (visited.count(path)) return false; if (visited.count(path)) return false;
@ -584,41 +586,41 @@ bool LocalStore::canReachRoot(GCState & state, PathSet & visited, const Path & p
if (state.dead.count(path)) return false; if (state.dead.count(path)) return false;
if (state.roots.count(path)) { if (state.roots.count(path)) {
debug(format("cannot delete '%1%' because it's a root") % path); debug("cannot delete '%1%' because it's a root", printStorePath(path));
state.alive.insert(path); state.alive.insert(path.clone());
return true; return true;
} }
visited.insert(path); visited.insert(path.clone());
if (!isStorePath(path) || !isValidPath(path)) return false; //FIXME
if (!isStorePath(printStorePath(path)) || !isValidPath(path)) return false;
PathSet incoming; StorePathSet incoming;
/* Don't delete this path if any of its referrers are alive. */ /* Don't delete this path if any of its referrers are alive. */
queryReferrers(path, incoming); queryReferrers(path, incoming);
/* If keep-derivations is set and this is a derivation, then /* If keep-derivations is set and this is a derivation, then
don't delete the derivation if any of the outputs are alive. */ don't delete the derivation if any of the outputs are alive. */
if (state.gcKeepDerivations && isDerivation(path)) { if (state.gcKeepDerivations && path.isDerivation()) {
PathSet outputs = queryDerivationOutputs(path); for (auto & i : queryDerivationOutputs(path))
for (auto & i : outputs)
if (isValidPath(i) && queryPathInfo(i)->deriver == path) if (isValidPath(i) && queryPathInfo(i)->deriver == path)
incoming.insert(i); incoming.insert(i.clone());
} }
/* If keep-outputs is set, then don't delete this path if there /* If keep-outputs is set, then don't delete this path if there
are derivers of this path that are not garbage. */ are derivers of this path that are not garbage. */
if (state.gcKeepOutputs) { if (state.gcKeepOutputs) {
PathSet derivers = queryValidDerivers(path); auto derivers = queryValidDerivers(path);
for (auto & i : derivers) for (auto & i : derivers)
incoming.insert(i); incoming.insert(i.clone());
} }
for (auto & i : incoming) for (auto & i : incoming)
if (i != path) if (i != path)
if (canReachRoot(state, visited, i)) { if (canReachRoot(state, visited, i)) {
state.alive.insert(path); state.alive.insert(path.clone());
return true; return true;
} }
@ -630,12 +632,13 @@ void LocalStore::tryToDelete(GCState & state, const Path & path)
{ {
checkInterrupt(); checkInterrupt();
auto realPath = realStoreDir + "/" + baseNameOf(path); auto realPath = realStoreDir + "/" + std::string(baseNameOf(path));
if (realPath == linksDir || realPath == trashDir) return; if (realPath == linksDir || realPath == trashDir) return;
//Activity act(*logger, lvlDebug, format("considering whether to delete '%1%'") % path); //Activity act(*logger, lvlDebug, format("considering whether to delete '%1%'") % path);
if (!isStorePath(path) || !isValidPath(path)) { // FIXME
if (!isStorePath(path) || !isValidPath(parseStorePath(path))) {
/* A lock file belonging to a path that we're building right /* A lock file belonging to a path that we're building right
now isn't garbage. */ now isn't garbage. */
if (isActiveTempFile(state, path, ".lock")) return; if (isActiveTempFile(state, path, ".lock")) return;
@ -650,16 +653,17 @@ void LocalStore::tryToDelete(GCState & state, const Path & path)
if (isActiveTempFile(state, path, ".check")) return; if (isActiveTempFile(state, path, ".check")) return;
} }
PathSet visited; StorePathSet visited;
if (canReachRoot(state, visited, path)) { if (canReachRoot(state, visited, parseStorePath(path))) {
debug(format("cannot delete '%1%' because it's still reachable") % path); debug("cannot delete '%s' because it's still reachable", path);
} else { } else {
/* No path we visited was a root, so everything is garbage. /* No path we visited was a root, so everything is garbage.
But we only delete path and its referrers here so that But we only delete path and its referrers here so that
nix-store --delete doesn't have the unexpected effect of nix-store --delete doesn't have the unexpected effect of
recursing into derivations and outputs. */ recursing into derivations and outputs. */
state.dead.insert(visited.begin(), visited.end()); for (auto & i : visited)
state.dead.insert(i.clone());
if (state.shouldDelete) if (state.shouldDelete)
deletePathRecursive(state, path); deletePathRecursive(state, path);
} }
@ -715,8 +719,7 @@ void LocalStore::removeUnusedLinks(const GCState & state)
void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
{ {
GCState state(results); GCState state(options, results);
state.options = options;
state.gcKeepOutputs = settings.gcKeepOutputs; state.gcKeepOutputs = settings.gcKeepOutputs;
state.gcKeepDerivations = settings.gcKeepDerivations; state.gcKeepDerivations = settings.gcKeepDerivations;
@ -741,12 +744,12 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
/* Find the roots. Since we've grabbed the GC lock, the set of /* Find the roots. Since we've grabbed the GC lock, the set of
permanent roots cannot increase now. */ permanent roots cannot increase now. */
printError(format("finding garbage collector roots...")); printError("finding garbage collector roots...");
Roots rootMap; Roots rootMap;
if (!options.ignoreLiveness) if (!options.ignoreLiveness)
findRootsNoTemp(rootMap, true); findRootsNoTemp(rootMap, true);
for (auto & i : rootMap) state.roots.insert(i.first); for (auto & i : rootMap) state.roots.insert(i.first.clone());
/* Read the temporary roots. This acquires read locks on all /* Read the temporary roots. This acquires read locks on all
per-process temporary root files. So after this point no paths per-process temporary root files. So after this point no paths
@ -754,9 +757,10 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
FDs fds; FDs fds;
Roots tempRoots; Roots tempRoots;
findTempRoots(fds, tempRoots, true); findTempRoots(fds, tempRoots, true);
for (auto & root : tempRoots) for (auto & root : tempRoots) {
state.tempRoots.insert(root.first); state.tempRoots.insert(root.first.clone());
state.roots.insert(state.tempRoots.begin(), state.tempRoots.end()); state.roots.insert(root.first.clone());
}
/* After this point the set of roots or temporary roots cannot /* After this point the set of roots or temporary roots cannot
increase, since we hold locks on everything. So everything increase, since we hold locks on everything. So everything
@ -768,7 +772,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
createDirs(trashDir); createDirs(trashDir);
} catch (SysError & e) { } catch (SysError & e) {
if (e.errNo == ENOSPC) { if (e.errNo == ENOSPC) {
printInfo(format("note: can't create trash directory: %1%") % e.msg()); printInfo("note: can't create trash directory: %s", e.msg());
state.moveToTrash = false; state.moveToTrash = false;
} }
} }
@ -780,22 +784,21 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
if (options.action == GCOptions::gcDeleteSpecific) { if (options.action == GCOptions::gcDeleteSpecific) {
for (auto & i : options.pathsToDelete) { for (auto & i : options.pathsToDelete) {
assertStorePath(i); tryToDelete(state, printStorePath(i));
tryToDelete(state, i);
if (state.dead.find(i) == state.dead.end()) if (state.dead.find(i) == state.dead.end())
throw Error(format( throw Error(
"cannot delete path '%1%' since it is still alive. " "cannot delete path '%1%' since it is still alive. "
"To find out why use: " "To find out why use: "
"nix-store --query --roots" "nix-store --query --roots",
) % i); printStorePath(i));
} }
} else if (options.maxFreed > 0) { } else if (options.maxFreed > 0) {
if (state.shouldDelete) if (state.shouldDelete)
printError(format("deleting garbage...")); printError("deleting garbage...");
else else
printError(format("determining live/dead paths...")); printError("determining live/dead paths...");
try { try {
@ -815,7 +818,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
string name = dirent->d_name; string name = dirent->d_name;
if (name == "." || name == "..") continue; if (name == "." || name == "..") continue;
Path path = storeDir + "/" + name; Path path = storeDir + "/" + name;
if (isStorePath(path) && isValidPath(path)) // FIXME
if (isStorePath(path) && isValidPath(parseStorePath(path)))
entries.push_back(path); entries.push_back(path);
else else
tryToDelete(state, path); tryToDelete(state, path);
@ -840,12 +844,14 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
} }
if (state.options.action == GCOptions::gcReturnLive) { if (state.options.action == GCOptions::gcReturnLive) {
state.results.paths = state.alive; for (auto & i : state.alive)
state.results.paths.insert(printStorePath(i));
return; return;
} }
if (state.options.action == GCOptions::gcReturnDead) { if (state.options.action == GCOptions::gcReturnDead) {
state.results.paths = state.dead; for (auto & i : state.dead)
state.results.paths.insert(printStorePath(i));
return; return;
} }
@ -859,7 +865,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
/* Clean up the links directory. */ /* Clean up the links directory. */
if (options.action == GCOptions::gcDeleteDead || options.action == GCOptions::gcDeleteSpecific) { if (options.action == GCOptions::gcDeleteDead || options.action == GCOptions::gcDeleteSpecific) {
printError(format("deleting unused links...")); printError("deleting unused links...");
removeUnusedLinks(state); removeUnusedLinks(state);
} }

View file

@ -87,25 +87,27 @@ struct LegacySSHStore : public Store
return uriScheme + host; return uriScheme + host;
} }
void queryPathInfoUncached(const Path & path, void queryPathInfoUncached(const StorePath & path,
Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override
{ {
try { try {
auto conn(connections->get()); auto conn(connections->get());
debug("querying remote host '%s' for info on '%s'", host, path); debug("querying remote host '%s' for info on '%s'", host, printStorePath(path));
conn->to << cmdQueryPathInfos << PathSet{path}; conn->to << cmdQueryPathInfos << PathSet{printStorePath(path)};
conn->to.flush(); conn->to.flush();
auto info = std::make_shared<ValidPathInfo>(); auto p = readString(conn->from);
conn->from >> info->path; if (p.empty()) return callback(nullptr);
if (info->path.empty()) return callback(nullptr); auto info = std::make_shared<ValidPathInfo>(parseStorePath(p));
assert(path == info->path); assert(path == info->path);
PathSet references; PathSet references;
conn->from >> info->deriver; auto deriver = readString(conn->from);
info->references = readStorePaths<PathSet>(*this, conn->from); if (deriver != "")
info->deriver = parseStorePath(deriver);
info->references = readStorePaths<StorePathSet>(*this, conn->from);
readLongLong(conn->from); // download size readLongLong(conn->from); // download size
info->narSize = readLongLong(conn->from); info->narSize = readLongLong(conn->from);
@ -127,7 +129,7 @@ struct LegacySSHStore : public Store
RepairFlag repair, CheckSigsFlag checkSigs, RepairFlag repair, CheckSigsFlag checkSigs,
std::shared_ptr<FSAccessor> accessor) override std::shared_ptr<FSAccessor> accessor) override
{ {
debug("adding path '%s' to remote host '%s'", info.path, host); debug("adding path '%s' to remote host '%s'", printStorePath(info.path), host);
auto conn(connections->get()); auto conn(connections->get());
@ -135,10 +137,11 @@ struct LegacySSHStore : public Store
conn->to conn->to
<< cmdAddToStoreNar << cmdAddToStoreNar
<< info.path << printStorePath(info.path)
<< info.deriver << (info.deriver ? printStorePath(*info.deriver) : "")
<< info.narHash.to_string(Base16, false) << info.narHash.to_string(Base16, false);
<< info.references writeStorePaths(*this, conn->to, info.references);
conn->to
<< info.registrationTime << info.registrationTime
<< info.narSize << info.narSize
<< info.ultimate << info.ultimate
@ -165,9 +168,10 @@ struct LegacySSHStore : public Store
} }
conn->to conn->to
<< exportMagic << exportMagic
<< info.path << printStorePath(info.path);
<< info.references writeStorePaths(*this, conn->to, info.references);
<< info.deriver conn->to
<< (info.deriver ? printStorePath(*info.deriver) : "")
<< 0 << 0
<< 0; << 0;
conn->to.flush(); conn->to.flush();
@ -175,39 +179,40 @@ struct LegacySSHStore : public Store
} }
if (readInt(conn->from) != 1) if (readInt(conn->from) != 1)
throw Error("failed to add path '%s' to remote host '%s', info.path, host"); throw Error("failed to add path '%s' to remote host '%s'", printStorePath(info.path), host);
} }
void narFromPath(const Path & path, Sink & sink) override void narFromPath(const StorePath & path, Sink & sink) override
{ {
auto conn(connections->get()); auto conn(connections->get());
conn->to << cmdDumpStorePath << path; conn->to << cmdDumpStorePath << printStorePath(path);
conn->to.flush(); conn->to.flush();
copyNAR(conn->from, sink); copyNAR(conn->from, sink);
} }
Path queryPathFromHashPart(const string & hashPart) override std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
{ unsupported("queryPathFromHashPart"); } { unsupported("queryPathFromHashPart"); }
Path addToStore(const string & name, const Path & srcPath, StorePath addToStore(const string & name, const Path & srcPath,
bool recursive, HashType hashAlgo, bool recursive, HashType hashAlgo,
PathFilter & filter, RepairFlag repair) override PathFilter & filter, RepairFlag repair) override
{ unsupported("addToStore"); } { unsupported("addToStore"); }
Path addTextToStore(const string & name, const string & s, StorePath addTextToStore(const string & name, const string & s,
const PathSet & references, RepairFlag repair) override const StorePathSet & references, RepairFlag repair) override
{ unsupported("addTextToStore"); } { unsupported("addTextToStore"); }
BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv, BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode) override BuildMode buildMode) override
{ {
auto conn(connections->get()); auto conn(connections->get());
conn->to conn->to
<< cmdBuildDerivation << cmdBuildDerivation
<< drvPath << printStorePath(drvPath);
<< drv writeDerivation(conn->to, *this, drv);
conn->to
<< settings.maxSilentTime << settings.maxSilentTime
<< settings.buildTimeout; << settings.buildTimeout;
if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 2) if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 2)
@ -230,11 +235,11 @@ struct LegacySSHStore : public Store
return status; return status;
} }
void ensurePath(const Path & path) override void ensurePath(const StorePath & path) override
{ unsupported("ensurePath"); } { unsupported("ensurePath"); }
void computeFSClosure(const PathSet & paths, void computeFSClosure(const StorePathSet & paths,
PathSet & out, bool flipDirection = false, StorePathSet & out, bool flipDirection = false,
bool includeOutputs = false, bool includeDerivers = false) override bool includeOutputs = false, bool includeDerivers = false) override
{ {
if (flipDirection || includeDerivers) { if (flipDirection || includeDerivers) {
@ -246,16 +251,15 @@ struct LegacySSHStore : public Store
conn->to conn->to
<< cmdQueryClosure << cmdQueryClosure
<< includeOutputs << includeOutputs;
<< paths; writeStorePaths(*this, conn->to, paths);
conn->to.flush(); conn->to.flush();
auto res = readStorePaths<PathSet>(*this, conn->from); for (auto & i : readStorePaths<StorePathSet>(*this, conn->from))
out.insert(i.clone());
out.insert(res.begin(), res.end());
} }
PathSet queryValidPaths(const PathSet & paths, StorePathSet queryValidPaths(const StorePathSet & paths,
SubstituteFlag maybeSubstitute = NoSubstitute) override SubstituteFlag maybeSubstitute = NoSubstitute) override
{ {
auto conn(connections->get()); auto conn(connections->get());
@ -263,11 +267,11 @@ struct LegacySSHStore : public Store
conn->to conn->to
<< cmdQueryValidPaths << cmdQueryValidPaths
<< false // lock << false // lock
<< maybeSubstitute << maybeSubstitute;
<< paths; writeStorePaths(*this, conn->to, paths);
conn->to.flush(); conn->to.flush();
return readStorePaths<PathSet>(*this, conn->from); return readStorePaths<StorePathSet>(*this, conn->from);
} }
void connect() override void connect() override

View file

@ -44,15 +44,15 @@ protected:
} }
} }
PathSet queryAllValidPaths() override StorePathSet queryAllValidPaths() override
{ {
PathSet paths; StorePathSet paths;
for (auto & entry : readDirectory(binaryCacheDir)) { for (auto & entry : readDirectory(binaryCacheDir)) {
if (entry.name.size() != 40 || if (entry.name.size() != 40 ||
!hasSuffix(entry.name, ".narinfo")) !hasSuffix(entry.name, ".narinfo"))
continue; continue;
paths.insert(storeDir + "/" + entry.name.substr(0, entry.name.size() - 8)); paths.insert(parseStorePath(storeDir + "/" + entry.name.substr(0, entry.name.size() - 8)));
} }
return paths; return paths;

View file

@ -21,7 +21,7 @@ struct LocalStoreAccessor : public FSAccessor
Path toRealPath(const Path & path) Path toRealPath(const Path & path)
{ {
Path storePath = store->toStorePath(path); Path storePath = store->toStorePath(path);
if (!store->isValidPath(storePath)) if (!store->isValidPath(store->parseStorePath(storePath)))
throw InvalidPath(format("path '%1%' is not a valid store path") % storePath); throw InvalidPath(format("path '%1%' is not a valid store path") % storePath);
return store->getRealStoreDir() + std::string(path, store->storeDir.size()); return store->getRealStoreDir() + std::string(path, store->storeDir.size());
} }
@ -77,34 +77,32 @@ ref<FSAccessor> LocalFSStore::getFSAccessor()
std::dynamic_pointer_cast<LocalFSStore>(shared_from_this()))); std::dynamic_pointer_cast<LocalFSStore>(shared_from_this())));
} }
void LocalFSStore::narFromPath(const Path & path, Sink & sink) void LocalFSStore::narFromPath(const StorePath & path, Sink & sink)
{ {
if (!isValidPath(path)) if (!isValidPath(path))
throw Error(format("path '%s' is not valid") % path); throw Error("path '%s' is not valid", printStorePath(path));
dumpPath(getRealStoreDir() + std::string(path, storeDir.size()), sink); dumpPath(getRealStoreDir() + std::string(printStorePath(path), storeDir.size()), sink);
} }
const string LocalFSStore::drvsLogDir = "drvs"; const string LocalFSStore::drvsLogDir = "drvs";
std::shared_ptr<std::string> LocalFSStore::getBuildLog(const Path & path_) std::shared_ptr<std::string> LocalFSStore::getBuildLog(const StorePath & path_)
{ {
auto path(path_); auto path = path_.clone();
assertStorePath(path); if (!path.isDerivation()) {
if (!isDerivation(path)) {
try { try {
path = queryPathInfo(path)->deriver; auto info = queryPathInfo(path);
if (!info->deriver) return nullptr;
path = info->deriver->clone();
} catch (InvalidPath &) { } catch (InvalidPath &) {
return nullptr; return nullptr;
} }
if (path == "") return nullptr;
} }
string baseName = baseNameOf(path); auto baseName = std::string(baseNameOf(printStorePath(path)));
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {

View file

@ -541,42 +541,36 @@ void canonicalisePathMetaData(const Path & path, uid_t fromUid)
} }
void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation & drv) void LocalStore::checkDerivationOutputs(const StorePath & drvPath, const Derivation & drv)
{ {
string drvName = storePathToName(drvPath); assert(drvPath.isDerivation());
assert(isDerivation(drvName)); std::string drvName(drvPath.name());
drvName = string(drvName, 0, drvName.size() - drvExtension.size()); drvName = string(drvName, 0, drvName.size() - drvExtension.size());
if (drv.isFixedOutput()) { if (drv.isFixedOutput()) {
DerivationOutputs::const_iterator out = drv.outputs.find("out"); DerivationOutputs::const_iterator out = drv.outputs.find("out");
if (out == drv.outputs.end()) if (out == drv.outputs.end())
throw Error(format("derivation '%1%' does not have an output named 'out'") % drvPath); throw Error("derivation '%s' does not have an output named 'out'", printStorePath(drvPath));
bool recursive; Hash h; bool recursive; Hash h;
out->second.parseHashInfo(recursive, h); out->second.parseHashInfo(recursive, h);
Path outPath = makeFixedOutputPath(recursive, h, drvName); auto outPath = makeFixedOutputPath(recursive, h, drvName);
StringPairs::const_iterator j = drv.env.find("out"); StringPairs::const_iterator j = drv.env.find("out");
if (out->second.path != outPath || j == drv.env.end() || j->second != outPath) if (out->second.path != outPath || j == drv.env.end() || parseStorePath(j->second) != outPath)
throw Error(format("derivation '%1%' has incorrect output '%2%', should be '%3%'") throw Error("derivation '%s' has incorrect output '%s', should be '%s'",
% drvPath % out->second.path % outPath); printStorePath(drvPath), printStorePath(out->second.path), printStorePath(outPath));
} }
else { else {
Derivation drvCopy(drv); Hash h = hashDerivationModulo(*this, drv, true);
for (auto & i : drvCopy.outputs) {
i.second.path = "";
drvCopy.env[i.first] = "";
}
Hash h = hashDerivationModulo(*this, drvCopy);
for (auto & i : drv.outputs) { for (auto & i : drv.outputs) {
Path outPath = makeOutputPath(i.first, h, drvName); auto outPath = makeOutputPath(i.first, h, drvName);
StringPairs::const_iterator j = drv.env.find(i.first); StringPairs::const_iterator j = drv.env.find(i.first);
if (i.second.path != outPath || j == drv.env.end() || j->second != outPath) if (i.second.path != outPath || j == drv.env.end() || parseStorePath(j->second) != outPath)
throw Error(format("derivation '%1%' has incorrect output '%2%', should be '%3%'") throw Error("derivation '%s' has incorrect output '%s', should be '%s'",
% drvPath % i.second.path % outPath); printStorePath(drvPath), printStorePath(i.second.path), printStorePath(outPath));
} }
} }
} }
@ -585,16 +579,15 @@ void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation &
uint64_t LocalStore::addValidPath(State & state, uint64_t LocalStore::addValidPath(State & state,
const ValidPathInfo & info, bool checkOutputs) const ValidPathInfo & info, bool checkOutputs)
{ {
checkStoreName(storePathToName(info.path));
if (info.ca != "" && !info.isContentAddressed(*this)) if (info.ca != "" && !info.isContentAddressed(*this))
throw Error("cannot add path '%s' to the Nix store because it claims to be content-addressed but isn't", info.path); throw Error("cannot add path '%s' to the Nix store because it claims to be content-addressed but isn't",
printStorePath(info.path));
state.stmtRegisterValidPath.use() state.stmtRegisterValidPath.use()
(info.path) (printStorePath(info.path))
(info.narHash.to_string(Base16)) (info.narHash.to_string(Base16))
(info.registrationTime == 0 ? time(0) : info.registrationTime) (info.registrationTime == 0 ? time(0) : info.registrationTime)
(info.deriver, info.deriver != "") (info.deriver ? printStorePath(*info.deriver) : "", (bool) info.deriver)
(info.narSize, info.narSize != 0) (info.narSize, info.narSize != 0)
(info.ultimate ? 1 : 0, info.ultimate) (info.ultimate ? 1 : 0, info.ultimate)
(concatStringsSep(" ", info.sigs), !info.sigs.empty()) (concatStringsSep(" ", info.sigs), !info.sigs.empty())
@ -606,8 +599,8 @@ uint64_t LocalStore::addValidPath(State & state,
the database. This is useful for the garbage collector: it can the database. This is useful for the garbage collector: it can
efficiently query whether a path is an output of some efficiently query whether a path is an output of some
derivation. */ derivation. */
if (isDerivation(info.path)) { if (info.path.isDerivation()) {
Derivation drv = readDerivation(realStoreDir + "/" + baseNameOf(info.path)); auto drv = readDerivation(*this, realStoreDir + "/" + std::string(info.path.to_string()));
/* Verify that the output paths in the derivation are correct /* Verify that the output paths in the derivation are correct
(i.e., follow the scheme for computing output paths from (i.e., follow the scheme for computing output paths from
@ -620,34 +613,31 @@ uint64_t LocalStore::addValidPath(State & state,
state.stmtAddDerivationOutput.use() state.stmtAddDerivationOutput.use()
(id) (id)
(i.first) (i.first)
(i.second.path) (printStorePath(i.second.path))
.exec(); .exec();
} }
} }
{ {
auto state_(Store::state.lock()); auto state_(Store::state.lock());
state_->pathInfoCache.upsert(storePathToHash(info.path), std::make_shared<ValidPathInfo>(info)); state_->pathInfoCache.upsert(storePathToHash(printStorePath(info.path)), std::make_shared<ValidPathInfo>(info));
} }
return id; return id;
} }
void LocalStore::queryPathInfoUncached(const Path & path, void LocalStore::queryPathInfoUncached(const StorePath & path,
Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept
{ {
try { try {
auto info = std::make_shared<ValidPathInfo>(); auto info = std::make_shared<ValidPathInfo>(path.clone());
info->path = path;
assertStorePath(path);
callback(retrySQLite<std::shared_ptr<ValidPathInfo>>([&]() { callback(retrySQLite<std::shared_ptr<ValidPathInfo>>([&]() {
auto state(_state.lock()); auto state(_state.lock());
/* Get the path info. */ /* Get the path info. */
auto useQueryPathInfo(state->stmtQueryPathInfo.use()(path)); auto useQueryPathInfo(state->stmtQueryPathInfo.use()(printStorePath(info->path)));
if (!useQueryPathInfo.next()) if (!useQueryPathInfo.next())
return std::shared_ptr<ValidPathInfo>(); return std::shared_ptr<ValidPathInfo>();
@ -657,13 +647,13 @@ void LocalStore::queryPathInfoUncached(const Path & path,
try { try {
info->narHash = Hash(useQueryPathInfo.getStr(1)); info->narHash = Hash(useQueryPathInfo.getStr(1));
} catch (BadHash & e) { } catch (BadHash & e) {
throw Error("in valid-path entry for '%s': %s", path, e.what()); throw Error("in valid-path entry for '%s': %s", printStorePath(path), e.what());
} }
info->registrationTime = useQueryPathInfo.getInt(2); info->registrationTime = useQueryPathInfo.getInt(2);
auto s = (const char *) sqlite3_column_text(state->stmtQueryPathInfo, 3); auto s = (const char *) sqlite3_column_text(state->stmtQueryPathInfo, 3);
if (s) info->deriver = s; if (s) info->deriver = parseStorePath(s);
/* Note that narSize = NULL yields 0. */ /* Note that narSize = NULL yields 0. */
info->narSize = useQueryPathInfo.getInt(4); info->narSize = useQueryPathInfo.getInt(4);
@ -680,7 +670,7 @@ void LocalStore::queryPathInfoUncached(const Path & path,
auto useQueryReferences(state->stmtQueryReferences.use()(info->id)); auto useQueryReferences(state->stmtQueryReferences.use()(info->id));
while (useQueryReferences.next()) while (useQueryReferences.next())
info->references.insert(useQueryReferences.getStr(0)); info->references.insert(parseStorePath(useQueryReferences.getStr(0)));
return info; return info;
})); }));
@ -698,27 +688,27 @@ void LocalStore::updatePathInfo(State & state, const ValidPathInfo & info)
(info.ultimate ? 1 : 0, info.ultimate) (info.ultimate ? 1 : 0, info.ultimate)
(concatStringsSep(" ", info.sigs), !info.sigs.empty()) (concatStringsSep(" ", info.sigs), !info.sigs.empty())
(info.ca, !info.ca.empty()) (info.ca, !info.ca.empty())
(info.path) (printStorePath(info.path))
.exec(); .exec();
} }
uint64_t LocalStore::queryValidPathId(State & state, const Path & path) uint64_t LocalStore::queryValidPathId(State & state, const StorePath & path)
{ {
auto use(state.stmtQueryPathInfo.use()(path)); auto use(state.stmtQueryPathInfo.use()(printStorePath(path)));
if (!use.next()) if (!use.next())
throw Error(format("path '%1%' is not valid") % path); throw Error("path '%s' is not valid", printStorePath(path));
return use.getInt(0); return use.getInt(0);
} }
bool LocalStore::isValidPath_(State & state, const Path & path) bool LocalStore::isValidPath_(State & state, const StorePath & path)
{ {
return state.stmtQueryPathInfo.use()(path).next(); return state.stmtQueryPathInfo.use()(printStorePath(path)).next();
} }
bool LocalStore::isValidPathUncached(const Path & path) bool LocalStore::isValidPathUncached(const StorePath & path)
{ {
return retrySQLite<bool>([&]() { return retrySQLite<bool>([&]() {
auto state(_state.lock()); auto state(_state.lock());
@ -727,39 +717,38 @@ bool LocalStore::isValidPathUncached(const Path & path)
} }
PathSet LocalStore::queryValidPaths(const PathSet & paths, SubstituteFlag maybeSubstitute) StorePathSet LocalStore::queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute)
{ {
PathSet res; StorePathSet res;
for (auto & i : paths) for (auto & i : paths)
if (isValidPath(i)) res.insert(i); if (isValidPath(i)) res.insert(i.clone());
return res; return res;
} }
PathSet LocalStore::queryAllValidPaths() StorePathSet LocalStore::queryAllValidPaths()
{ {
return retrySQLite<PathSet>([&]() { return retrySQLite<StorePathSet>([&]() {
auto state(_state.lock()); auto state(_state.lock());
auto use(state->stmtQueryValidPaths.use()); auto use(state->stmtQueryValidPaths.use());
PathSet res; StorePathSet res;
while (use.next()) res.insert(use.getStr(0)); while (use.next()) res.insert(parseStorePath(use.getStr(0)));
return res; return res;
}); });
} }
void LocalStore::queryReferrers(State & state, const Path & path, PathSet & referrers) void LocalStore::queryReferrers(State & state, const StorePath & path, StorePathSet & referrers)
{ {
auto useQueryReferrers(state.stmtQueryReferrers.use()(path)); auto useQueryReferrers(state.stmtQueryReferrers.use()(printStorePath(path)));
while (useQueryReferrers.next()) while (useQueryReferrers.next())
referrers.insert(useQueryReferrers.getStr(0)); referrers.insert(parseStorePath(useQueryReferrers.getStr(0)));
} }
void LocalStore::queryReferrers(const Path & path, PathSet & referrers) void LocalStore::queryReferrers(const StorePath & path, StorePathSet & referrers)
{ {
assertStorePath(path);
return retrySQLite<void>([&]() { return retrySQLite<void>([&]() {
auto state(_state.lock()); auto state(_state.lock());
queryReferrers(*state, path, referrers); queryReferrers(*state, path, referrers);
@ -767,42 +756,40 @@ void LocalStore::queryReferrers(const Path & path, PathSet & referrers)
} }
PathSet LocalStore::queryValidDerivers(const Path & path) StorePathSet LocalStore::queryValidDerivers(const StorePath & path)
{ {
assertStorePath(path); return retrySQLite<StorePathSet>([&]() {
return retrySQLite<PathSet>([&]() {
auto state(_state.lock()); auto state(_state.lock());
auto useQueryValidDerivers(state->stmtQueryValidDerivers.use()(path)); auto useQueryValidDerivers(state->stmtQueryValidDerivers.use()(printStorePath(path)));
PathSet derivers; StorePathSet derivers;
while (useQueryValidDerivers.next()) while (useQueryValidDerivers.next())
derivers.insert(useQueryValidDerivers.getStr(1)); derivers.insert(parseStorePath(useQueryValidDerivers.getStr(1)));
return derivers; return derivers;
}); });
} }
PathSet LocalStore::queryDerivationOutputs(const Path & path) StorePathSet LocalStore::queryDerivationOutputs(const StorePath & path)
{ {
return retrySQLite<PathSet>([&]() { return retrySQLite<StorePathSet>([&]() {
auto state(_state.lock()); auto state(_state.lock());
auto useQueryDerivationOutputs(state->stmtQueryDerivationOutputs.use() auto useQueryDerivationOutputs(state->stmtQueryDerivationOutputs.use()
(queryValidPathId(*state, path))); (queryValidPathId(*state, path)));
PathSet outputs; StorePathSet outputs;
while (useQueryDerivationOutputs.next()) while (useQueryDerivationOutputs.next())
outputs.insert(useQueryDerivationOutputs.getStr(1)); outputs.insert(parseStorePath(useQueryDerivationOutputs.getStr(1)));
return outputs; return outputs;
}); });
} }
StringSet LocalStore::queryDerivationOutputNames(const Path & path) StringSet LocalStore::queryDerivationOutputNames(const StorePath & path)
{ {
return retrySQLite<StringSet>([&]() { return retrySQLite<StringSet>([&]() {
auto state(_state.lock()); auto state(_state.lock());
@ -819,31 +806,36 @@ StringSet LocalStore::queryDerivationOutputNames(const Path & path)
} }
Path LocalStore::queryPathFromHashPart(const string & hashPart) std::optional<StorePath> LocalStore::queryPathFromHashPart(const std::string & hashPart)
{ {
if (hashPart.size() != storePathHashLen) throw Error("invalid hash part"); if (hashPart.size() != storePathHashLen) throw Error("invalid hash part");
Path prefix = storeDir + "/" + hashPart; Path prefix = storeDir + "/" + hashPart;
return retrySQLite<Path>([&]() -> std::string { return retrySQLite<std::optional<StorePath>>([&]() -> std::optional<StorePath> {
auto state(_state.lock()); auto state(_state.lock());
auto useQueryPathFromHashPart(state->stmtQueryPathFromHashPart.use()(prefix)); auto useQueryPathFromHashPart(state->stmtQueryPathFromHashPart.use()(prefix));
if (!useQueryPathFromHashPart.next()) return ""; if (!useQueryPathFromHashPart.next()) return {};
const char * s = (const char *) sqlite3_column_text(state->stmtQueryPathFromHashPart, 0); const char * s = (const char *) sqlite3_column_text(state->stmtQueryPathFromHashPart, 0);
return s && prefix.compare(0, prefix.size(), s, prefix.size()) == 0 ? s : ""; if (s && prefix.compare(0, prefix.size(), s, prefix.size()) == 0)
return parseStorePath(s);
return {};
}); });
} }
PathSet LocalStore::querySubstitutablePaths(const PathSet & paths) StorePathSet LocalStore::querySubstitutablePaths(const StorePathSet & paths)
{ {
if (!settings.useSubstitutes) return PathSet(); if (!settings.useSubstitutes) return StorePathSet();
auto remaining = paths; StorePathSet remaining;
PathSet res; for (auto & i : paths)
remaining.insert(i.clone());
StorePathSet res;
for (auto & sub : getDefaultSubstituters()) { for (auto & sub : getDefaultSubstituters()) {
if (remaining.empty()) break; if (remaining.empty()) break;
@ -852,12 +844,12 @@ PathSet LocalStore::querySubstitutablePaths(const PathSet & paths)
auto valid = sub->queryValidPaths(remaining); auto valid = sub->queryValidPaths(remaining);
PathSet remaining2; StorePathSet remaining2;
for (auto & path : remaining) for (auto & path : remaining)
if (valid.count(path)) if (valid.count(path))
res.insert(path); res.insert(path.clone());
else else
remaining2.insert(path); remaining2.insert(path.clone());
std::swap(remaining, remaining2); std::swap(remaining, remaining2);
} }
@ -866,7 +858,7 @@ PathSet LocalStore::querySubstitutablePaths(const PathSet & paths)
} }
void LocalStore::querySubstitutablePathInfos(const PathSet & paths, void LocalStore::querySubstitutablePathInfos(const StorePathSet & paths,
SubstitutablePathInfos & infos) SubstitutablePathInfos & infos)
{ {
if (!settings.useSubstitutes) return; if (!settings.useSubstitutes) return;
@ -874,17 +866,16 @@ void LocalStore::querySubstitutablePathInfos(const PathSet & paths,
if (sub->storeDir != storeDir) continue; if (sub->storeDir != storeDir) continue;
for (auto & path : paths) { for (auto & path : paths) {
if (infos.count(path)) continue; if (infos.count(path)) continue;
debug(format("checking substituter '%s' for path '%s'") debug("checking substituter '%s' for path '%s'", sub->getUri(), printStorePath(path));
% sub->getUri() % path);
try { try {
auto info = sub->queryPathInfo(path); auto info = sub->queryPathInfo(path);
auto narInfo = std::dynamic_pointer_cast<const NarInfo>( auto narInfo = std::dynamic_pointer_cast<const NarInfo>(
std::shared_ptr<const ValidPathInfo>(info)); std::shared_ptr<const ValidPathInfo>(info));
infos[path] = SubstitutablePathInfo{ infos.insert_or_assign(path.clone(), SubstitutablePathInfo{
info->deriver, info->deriver ? info->deriver->clone() : std::optional<StorePath>(),
info->references, cloneStorePathSet(info->references),
narInfo ? narInfo->fileSize : 0, narInfo ? narInfo->fileSize : 0,
info->narSize}; info->narSize});
} catch (InvalidPath &) { } catch (InvalidPath &) {
} catch (SubstituterDisabled &) { } catch (SubstituterDisabled &) {
} catch (Error & e) { } catch (Error & e) {
@ -918,7 +909,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
auto state(_state.lock()); auto state(_state.lock());
SQLiteTxn txn(state->db); SQLiteTxn txn(state->db);
PathSet paths; StorePathSet paths;
for (auto & i : infos) { for (auto & i : infos) {
assert(i.narHash.type == htSHA256); assert(i.narHash.type == htSHA256);
@ -926,7 +917,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
updatePathInfo(*state, i); updatePathInfo(*state, i);
else else
addValidPath(*state, i, false); addValidPath(*state, i, false);
paths.insert(i.path); paths.insert(i.path.clone());
} }
for (auto & i : infos) { for (auto & i : infos) {
@ -939,10 +930,10 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
this in addValidPath() above, because the references might this in addValidPath() above, because the references might
not be valid yet. */ not be valid yet. */
for (auto & i : infos) for (auto & i : infos)
if (isDerivation(i.path)) { if (i.path.isDerivation()) {
// FIXME: inefficient; we already loaded the derivation in addValidPath(). // FIXME: inefficient; we already loaded the derivation in addValidPath().
Derivation drv = readDerivation(realStoreDir + "/" + baseNameOf(i.path)); checkDerivationOutputs(i.path,
checkDerivationOutputs(i.path, drv); readDerivation(*this, realStoreDir + "/" + std::string(i.path.to_string())));
} }
/* Do a topological sort of the paths. This will throw an /* Do a topological sort of the paths. This will throw an
@ -958,18 +949,18 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
/* Invalidate a path. The caller is responsible for checking that /* Invalidate a path. The caller is responsible for checking that
there are no referrers. */ there are no referrers. */
void LocalStore::invalidatePath(State & state, const Path & path) void LocalStore::invalidatePath(State & state, const StorePath & path)
{ {
debug(format("invalidating path '%1%'") % path); debug("invalidating path '%s'", printStorePath(path));
state.stmtInvalidatePath.use()(path).exec(); state.stmtInvalidatePath.use()(printStorePath(path)).exec();
/* Note that the foreign key constraints on the Refs table take /* Note that the foreign key constraints on the Refs table take
care of deleting the references entries for `path'. */ care of deleting the references entries for `path'. */
{ {
auto state_(Store::state.lock()); auto state_(Store::state.lock());
state_->pathInfoCache.erase(storePathToHash(path)); state_->pathInfoCache.erase(storePathToHash(printStorePath(path)));
} }
} }
@ -987,10 +978,10 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
RepairFlag repair, CheckSigsFlag checkSigs, std::shared_ptr<FSAccessor> accessor) RepairFlag repair, CheckSigsFlag checkSigs, std::shared_ptr<FSAccessor> accessor)
{ {
if (!info.narHash) if (!info.narHash)
throw Error("cannot add path '%s' because it lacks a hash", info.path); throw Error("cannot add path '%s' because it lacks a hash", printStorePath(info.path));
if (requireSigs && checkSigs && !info.checkSignatures(*this, getPublicKeys())) if (requireSigs && checkSigs && !info.checkSignatures(*this, getPublicKeys()))
throw Error("cannot add path '%s' because it lacks a valid signature", info.path); throw Error("cannot add path '%s' because it lacks a valid signature", printStorePath(info.path));
addTempRoot(info.path); addTempRoot(info.path);
@ -998,12 +989,12 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
PathLocks outputLock; PathLocks outputLock;
Path realPath = realStoreDir + "/" + baseNameOf(info.path); Path realPath = realStoreDir + "/" + std::string(info.path.to_string());
/* Lock the output path. But don't lock if we're being called /* Lock the output path. But don't lock if we're being called
from a build hook (whose parent process already acquired a from a build hook (whose parent process already acquired a
lock on this path). */ lock on this path). */
if (!locksHeld.count(info.path)) if (!locksHeld.count(printStorePath(info.path)))
outputLock.lockPaths({realPath}); outputLock.lockPaths({realPath});
if (repair || !isValidPath(info.path)) { if (repair || !isValidPath(info.path)) {
@ -1018,7 +1009,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
else { else {
if (!info.references.empty()) if (!info.references.empty())
settings.requireExperimentalFeature("ca-references"); settings.requireExperimentalFeature("ca-references");
hashSink = std::make_unique<HashModuloSink>(htSHA256, storePathToHash(info.path)); hashSink = std::make_unique<HashModuloSink>(htSHA256, storePathToHash(printStorePath(info.path)));
} }
LambdaSource wrapperSource([&](unsigned char * data, size_t len) -> size_t { LambdaSource wrapperSource([&](unsigned char * data, size_t len) -> size_t {
@ -1033,11 +1024,11 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
if (hashResult.first != info.narHash) if (hashResult.first != info.narHash)
throw Error("hash mismatch importing path '%s';\n wanted: %s\n got: %s", throw Error("hash mismatch importing path '%s';\n wanted: %s\n got: %s",
info.path, info.narHash.to_string(), hashResult.first.to_string()); printStorePath(info.path), info.narHash.to_string(), hashResult.first.to_string());
if (hashResult.second != info.narSize) if (hashResult.second != info.narSize)
throw Error("size mismatch importing path '%s';\n wanted: %s\n got: %s", throw Error("size mismatch importing path '%s';\n wanted: %s\n got: %s",
info.path, info.narSize, hashResult.second); printStorePath(info.path), info.narSize, hashResult.second);
autoGC(); autoGC();
@ -1053,12 +1044,12 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
} }
Path LocalStore::addToStoreFromDump(const string & dump, const string & name, StorePath LocalStore::addToStoreFromDump(const string & dump, const string & name,
bool recursive, HashType hashAlgo, RepairFlag repair) bool recursive, HashType hashAlgo, RepairFlag repair)
{ {
Hash h = hashString(hashAlgo, dump); Hash h = hashString(hashAlgo, dump);
Path dstPath = makeFixedOutputPath(recursive, h, name); auto dstPath = makeFixedOutputPath(recursive, h, name);
addTempRoot(dstPath); addTempRoot(dstPath);
@ -1067,7 +1058,8 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name,
/* The first check above is an optimisation to prevent /* The first check above is an optimisation to prevent
unnecessary lock acquisition. */ unnecessary lock acquisition. */
Path realPath = realStoreDir + "/" + baseNameOf(dstPath); Path realPath = realStoreDir + "/";
realPath += dstPath.to_string();
PathLocks outputLock({realPath}); PathLocks outputLock({realPath});
@ -1098,8 +1090,7 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name,
optimisePath(realPath); // FIXME: combine with hashPath() optimisePath(realPath); // FIXME: combine with hashPath()
ValidPathInfo info; ValidPathInfo info(dstPath.clone());
info.path = dstPath;
info.narHash = hash.first; info.narHash = hash.first;
info.narSize = hash.second; info.narSize = hash.second;
info.ca = makeFixedOutputCA(recursive, h); info.ca = makeFixedOutputCA(recursive, h);
@ -1113,7 +1104,7 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name,
} }
Path LocalStore::addToStore(const string & name, const Path & _srcPath, StorePath LocalStore::addToStore(const string & name, const Path & _srcPath,
bool recursive, HashType hashAlgo, PathFilter & filter, RepairFlag repair) bool recursive, HashType hashAlgo, PathFilter & filter, RepairFlag repair)
{ {
Path srcPath(absPath(_srcPath)); Path srcPath(absPath(_srcPath));
@ -1131,8 +1122,8 @@ Path LocalStore::addToStore(const string & name, const Path & _srcPath,
} }
Path LocalStore::addTextToStore(const string & name, const string & s, StorePath LocalStore::addTextToStore(const string & name, const string & s,
const PathSet & references, RepairFlag repair) const StorePathSet & references, RepairFlag repair)
{ {
auto hash = hashString(htSHA256, s); auto hash = hashString(htSHA256, s);
auto dstPath = makeTextPath(name, hash, references); auto dstPath = makeTextPath(name, hash, references);
@ -1141,7 +1132,8 @@ Path LocalStore::addTextToStore(const string & name, const string & s,
if (repair || !isValidPath(dstPath)) { if (repair || !isValidPath(dstPath)) {
Path realPath = realStoreDir + "/" + baseNameOf(dstPath); Path realPath = realStoreDir + "/";
realPath += dstPath.to_string();
PathLocks outputLock({realPath}); PathLocks outputLock({realPath});
@ -1161,11 +1153,10 @@ Path LocalStore::addTextToStore(const string & name, const string & s,
optimisePath(realPath); optimisePath(realPath);
ValidPathInfo info; ValidPathInfo info(dstPath.clone());
info.path = dstPath;
info.narHash = narHash; info.narHash = narHash;
info.narSize = sink.s->size(); info.narSize = sink.s->size();
info.references = references; info.references = cloneStorePathSet(references);
info.ca = "text:" + hash.to_string(); info.ca = "text:" + hash.to_string();
registerValidPath(info); registerValidPath(info);
} }
@ -1187,27 +1178,25 @@ Path LocalStore::createTempDirInStore()
the GC between createTempDir() and addTempRoot(), so repeat the GC between createTempDir() and addTempRoot(), so repeat
until `tmpDir' exists. */ until `tmpDir' exists. */
tmpDir = createTempDir(realStoreDir); tmpDir = createTempDir(realStoreDir);
addTempRoot(tmpDir); addTempRoot(parseStorePath(tmpDir));
} while (!pathExists(tmpDir)); } while (!pathExists(tmpDir));
return tmpDir; return tmpDir;
} }
void LocalStore::invalidatePathChecked(const Path & path) void LocalStore::invalidatePathChecked(const StorePath & path)
{ {
assertStorePath(path);
retrySQLite<void>([&]() { retrySQLite<void>([&]() {
auto state(_state.lock()); auto state(_state.lock());
SQLiteTxn txn(state->db); SQLiteTxn txn(state->db);
if (isValidPath_(*state, path)) { if (isValidPath_(*state, path)) {
PathSet referrers; queryReferrers(*state, path, referrers); StorePathSet referrers; queryReferrers(*state, path, referrers);
referrers.erase(path); /* ignore self-references */ referrers.erase(path); /* ignore self-references */
if (!referrers.empty()) if (!referrers.empty())
throw PathInUse(format("cannot delete path '%1%' because it is in use by %2%") throw PathInUse("cannot delete path '%s' because it is in use by %s",
% path % showPaths(referrers)); printStorePath(path), showPaths(referrers));
invalidatePath(*state, path); invalidatePath(*state, path);
} }
@ -1226,18 +1215,19 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
existing and valid paths. */ existing and valid paths. */
AutoCloseFD fdGCLock = openGCLock(ltWrite); AutoCloseFD fdGCLock = openGCLock(ltWrite);
PathSet store; StringSet store;
for (auto & i : readDirectory(realStoreDir)) store.insert(i.name); for (auto & i : readDirectory(realStoreDir)) store.insert(i.name);
/* Check whether all valid paths actually exist. */ /* Check whether all valid paths actually exist. */
printInfo("checking path existence..."); printInfo("checking path existence...");
PathSet validPaths2 = queryAllValidPaths(), validPaths, done; StorePathSet validPaths;
PathSet done;
fdGCLock = -1; fdGCLock = -1;
for (auto & i : validPaths2) for (auto & i : queryAllValidPaths())
verifyPath(i, store, done, validPaths, repair, errors); verifyPath(printStorePath(i), store, done, validPaths, repair, errors);
/* Optionally, check the content hashes (slow). */ /* Optionally, check the content hashes (slow). */
if (checkContents) { if (checkContents) {
@ -1272,21 +1262,20 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
auto info = std::const_pointer_cast<ValidPathInfo>(std::shared_ptr<const ValidPathInfo>(queryPathInfo(i))); auto info = std::const_pointer_cast<ValidPathInfo>(std::shared_ptr<const ValidPathInfo>(queryPathInfo(i)));
/* Check the content hash (optionally - slow). */ /* Check the content hash (optionally - slow). */
printMsg(lvlTalkative, format("checking contents of '%1%'") % i); printMsg(lvlTalkative, "checking contents of '%s'", printStorePath(i));
std::unique_ptr<AbstractHashSink> hashSink; std::unique_ptr<AbstractHashSink> hashSink;
if (info->ca == "") if (info->ca == "")
hashSink = std::make_unique<HashSink>(info->narHash.type); hashSink = std::make_unique<HashSink>(info->narHash.type);
else else
hashSink = std::make_unique<HashModuloSink>(info->narHash.type, storePathToHash(info->path)); hashSink = std::make_unique<HashModuloSink>(info->narHash.type, storePathToHash(printStorePath(info->path)));
dumpPath(toRealPath(i), *hashSink); dumpPath(toRealPath(printStorePath(i)), *hashSink);
auto current = hashSink->finish(); auto current = hashSink->finish();
if (info->narHash != nullHash && info->narHash != current.first) { if (info->narHash != nullHash && info->narHash != current.first) {
printError(format("path '%1%' was modified! " printError("path '%s' was modified! expected hash '%s', got '%s'",
"expected hash '%2%', got '%3%'") printStorePath(i), info->narHash.to_string(), current.first.to_string());
% i % info->narHash.to_string() % current.first.to_string());
if (repair) repairPath(i); else errors = true; if (repair) repairPath(i); else errors = true;
} else { } else {
@ -1294,14 +1283,14 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
/* Fill in missing hashes. */ /* Fill in missing hashes. */
if (info->narHash == nullHash) { if (info->narHash == nullHash) {
printError(format("fixing missing hash on '%1%'") % i); printError("fixing missing hash on '%s'", printStorePath(i));
info->narHash = current.first; info->narHash = current.first;
update = true; update = true;
} }
/* Fill in missing narSize fields (from old stores). */ /* Fill in missing narSize fields (from old stores). */
if (info->narSize == 0) { if (info->narSize == 0) {
printError(format("updating size field on '%1%' to %2%") % i % current.second); printError("updating size field on '%s' to %s", printStorePath(i), current.second);
info->narSize = current.second; info->narSize = current.second;
update = true; update = true;
} }
@ -1317,9 +1306,9 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
/* It's possible that the path got GC'ed, so ignore /* It's possible that the path got GC'ed, so ignore
errors on invalid paths. */ errors on invalid paths. */
if (isValidPath(i)) if (isValidPath(i))
printError(format("error: %1%") % e.msg()); printError("error: %s", e.msg());
else else
printError(format("warning: %1%") % e.msg()); warn(e.msg());
errors = true; errors = true;
} }
} }
@ -1329,43 +1318,43 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
} }
void LocalStore::verifyPath(const Path & path, const PathSet & store, void LocalStore::verifyPath(const Path & pathS, const StringSet & store,
PathSet & done, PathSet & validPaths, RepairFlag repair, bool & errors) PathSet & done, StorePathSet & validPaths, RepairFlag repair, bool & errors)
{ {
checkInterrupt(); checkInterrupt();
if (!done.insert(path).second) return; if (!done.insert(pathS).second) return;
if (!isStorePath(path)) { if (!isStorePath(pathS)) {
printError(format("path '%1%' is not in the Nix store") % path); printError("path '%s' is not in the Nix store", pathS);
auto state(_state.lock());
invalidatePath(*state, path);
return; return;
} }
if (store.find(baseNameOf(path)) == store.end()) { auto path = parseStorePath(pathS);
if (!store.count(std::string(path.to_string()))) {
/* Check any referrers first. If we can invalidate them /* Check any referrers first. If we can invalidate them
first, then we can invalidate this path as well. */ first, then we can invalidate this path as well. */
bool canInvalidate = true; bool canInvalidate = true;
PathSet referrers; queryReferrers(path, referrers); StorePathSet referrers; queryReferrers(path, referrers);
for (auto & i : referrers) for (auto & i : referrers)
if (i != path) { if (i != path) {
verifyPath(i, store, done, validPaths, repair, errors); verifyPath(printStorePath(i), store, done, validPaths, repair, errors);
if (validPaths.find(i) != validPaths.end()) if (validPaths.count(i))
canInvalidate = false; canInvalidate = false;
} }
if (canInvalidate) { if (canInvalidate) {
printError(format("path '%1%' disappeared, removing from database...") % path); printError("path '%s' disappeared, removing from database...", pathS);
auto state(_state.lock()); auto state(_state.lock());
invalidatePath(*state, path); invalidatePath(*state, path);
} else { } else {
printError(format("path '%1%' disappeared, but it still has valid referrers!") % path); printError("path '%s' disappeared, but it still has valid referrers!", pathS);
if (repair) if (repair)
try { try {
repairPath(path); repairPath(path);
} catch (Error & e) { } catch (Error & e) {
printError(format("warning: %1%") % e.msg()); warn(e.msg());
errors = true; errors = true;
} }
else errors = true; else errors = true;
@ -1374,7 +1363,7 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
return; return;
} }
validPaths.insert(path); validPaths.insert(std::move(path));
} }
@ -1443,7 +1432,7 @@ void LocalStore::vacuumDB()
} }
void LocalStore::addSignatures(const Path & storePath, const StringSet & sigs) void LocalStore::addSignatures(const StorePath & storePath, const StringSet & sigs)
{ {
retrySQLite<void>([&]() { retrySQLite<void>([&]() {
auto state(_state.lock()); auto state(_state.lock());
@ -1469,7 +1458,7 @@ void LocalStore::signPathInfo(ValidPathInfo & info)
for (auto & secretKeyFile : secretKeyFiles.get()) { for (auto & secretKeyFile : secretKeyFiles.get()) {
SecretKey secretKey(readFile(secretKeyFile)); SecretKey secretKey(readFile(secretKeyFile));
info.sign(secretKey); info.sign(*this, secretKey);
} }
} }

View file

@ -119,36 +119,36 @@ public:
std::string getUri() override; std::string getUri() override;
bool isValidPathUncached(const Path & path) override; bool isValidPathUncached(const StorePath & path) override;
PathSet queryValidPaths(const PathSet & paths, StorePathSet queryValidPaths(const StorePathSet & paths,
SubstituteFlag maybeSubstitute = NoSubstitute) override; SubstituteFlag maybeSubstitute = NoSubstitute) override;
PathSet queryAllValidPaths() override; StorePathSet queryAllValidPaths() override;
void queryPathInfoUncached(const Path & path, void queryPathInfoUncached(const StorePath & path,
Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override; Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override;
void queryReferrers(const Path & path, PathSet & referrers) override; void queryReferrers(const StorePath & path, StorePathSet & referrers) override;
PathSet queryValidDerivers(const Path & path) override; StorePathSet queryValidDerivers(const StorePath & path) override;
PathSet queryDerivationOutputs(const Path & path) override; StorePathSet queryDerivationOutputs(const StorePath & path) override;
StringSet queryDerivationOutputNames(const Path & path) override; StringSet queryDerivationOutputNames(const StorePath & path) override;
Path queryPathFromHashPart(const string & hashPart) override; std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override;
PathSet querySubstitutablePaths(const PathSet & paths) override; StorePathSet querySubstitutablePaths(const StorePathSet & paths) override;
void querySubstitutablePathInfos(const PathSet & paths, void querySubstitutablePathInfos(const StorePathSet & paths,
SubstitutablePathInfos & infos) override; SubstitutablePathInfos & infos) override;
void addToStore(const ValidPathInfo & info, Source & source, void addToStore(const ValidPathInfo & info, Source & source,
RepairFlag repair, CheckSigsFlag checkSigs, RepairFlag repair, CheckSigsFlag checkSigs,
std::shared_ptr<FSAccessor> accessor) override; std::shared_ptr<FSAccessor> accessor) override;
Path addToStore(const string & name, const Path & srcPath, StorePath addToStore(const string & name, const Path & srcPath,
bool recursive, HashType hashAlgo, bool recursive, HashType hashAlgo,
PathFilter & filter, RepairFlag repair) override; PathFilter & filter, RepairFlag repair) override;
@ -156,20 +156,22 @@ public:
in `dump', which is either a NAR serialisation (if recursive == in `dump', which is either a NAR serialisation (if recursive ==
true) or simply the contents of a regular file (if recursive == true) or simply the contents of a regular file (if recursive ==
false). */ false). */
Path addToStoreFromDump(const string & dump, const string & name, StorePath addToStoreFromDump(const string & dump, const string & name,
bool recursive = true, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair) override; bool recursive = true, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair) override;
Path addTextToStore(const string & name, const string & s, StorePath addTextToStore(const string & name, const string & s,
const PathSet & references, RepairFlag repair) override; const StorePathSet & references, RepairFlag repair) override;
void buildPaths(const PathSet & paths, BuildMode buildMode) override; void buildPaths(
const std::vector<StorePathWithOutputs> & paths,
BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv,
BuildMode buildMode) override; BuildMode buildMode) override;
void ensurePath(const Path & path) override; BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode) override;
void addTempRoot(const Path & path) override; void ensurePath(const StorePath & path) override;
void addTempRoot(const StorePath & path) override;
void addIndirectRoot(const Path & path) override; void addIndirectRoot(const Path & path) override;
@ -215,9 +217,9 @@ public:
/* Repair the contents of the given path by redownloading it using /* Repair the contents of the given path by redownloading it using
a substituter (if available). */ a substituter (if available). */
void repairPath(const Path & path); void repairPath(const StorePath & path);
void addSignatures(const Path & storePath, const StringSet & sigs) override; void addSignatures(const StorePath & storePath, const StringSet & sigs) override;
/* If free disk space in /nix/store if below minFree, delete /* If free disk space in /nix/store if below minFree, delete
garbage until it exceeds maxFree. */ garbage until it exceeds maxFree. */
@ -231,17 +233,17 @@ private:
void makeStoreWritable(); void makeStoreWritable();
uint64_t queryValidPathId(State & state, const Path & path); uint64_t queryValidPathId(State & state, const StorePath & path);
uint64_t addValidPath(State & state, const ValidPathInfo & info, bool checkOutputs = true); uint64_t addValidPath(State & state, const ValidPathInfo & info, bool checkOutputs = true);
void invalidatePath(State & state, const Path & path); void invalidatePath(State & state, const StorePath & path);
/* Delete a path from the Nix store. */ /* Delete a path from the Nix store. */
void invalidatePathChecked(const Path & path); void invalidatePathChecked(const StorePath & path);
void verifyPath(const Path & path, const PathSet & store, void verifyPath(const Path & path, const StringSet & store,
PathSet & done, PathSet & validPaths, RepairFlag repair, bool & errors); PathSet & done, StorePathSet & validPaths, RepairFlag repair, bool & errors);
void updatePathInfo(State & state, const ValidPathInfo & info); void updatePathInfo(State & state, const ValidPathInfo & info);
@ -256,7 +258,7 @@ private:
void tryToDelete(GCState & state, const Path & path); void tryToDelete(GCState & state, const Path & path);
bool canReachRoot(GCState & state, PathSet & visited, const Path & path); bool canReachRoot(GCState & state, StorePathSet & visited, const StorePath & path);
void deletePathRecursive(GCState & state, const Path & path); void deletePathRecursive(GCState & state, const Path & path);
@ -275,7 +277,7 @@ private:
Path createTempDirInStore(); Path createTempDirInStore();
void checkDerivationOutputs(const Path & drvPath, const Derivation & drv); void checkDerivationOutputs(const StorePath & drvPath, const Derivation & drv);
typedef std::unordered_set<ino_t> InodeHash; typedef std::unordered_set<ino_t> InodeHash;
@ -284,8 +286,8 @@ private:
void optimisePath_(Activity * act, OptimiseStats & stats, const Path & path, InodeHash & inodeHash); void optimisePath_(Activity * act, OptimiseStats & stats, const Path & path, InodeHash & inodeHash);
// Internal versions that are not wrapped in retry_sqlite. // Internal versions that are not wrapped in retry_sqlite.
bool isValidPath_(State & state, const Path & path); bool isValidPath_(State & state, const StorePath & path);
void queryReferrers(State & state, const Path & path, PathSet & referrers); void queryReferrers(State & state, const StorePath & path, StorePathSet & referrers);
/* Add signatures to a ValidPathInfo using the secret keys /* Add signatures to a ValidPathInfo using the secret keys
specified by the secret-key-files option. */ specified by the secret-key-files option. */

View file

@ -6,7 +6,7 @@ libstore_DIR := $(d)
libstore_SOURCES := $(wildcard $(d)/*.cc $(d)/builtins/*.cc) libstore_SOURCES := $(wildcard $(d)/*.cc $(d)/builtins/*.cc)
libstore_LIBS = libutil libstore_LIBS = libutil libnixrust
libstore_LDFLAGS = $(SQLITE3_LIBS) -lbz2 $(LIBCURL_LIBS) $(SODIUM_LIBS) -pthread libstore_LDFLAGS = $(SQLITE3_LIBS) -lbz2 $(LIBCURL_LIBS) $(SODIUM_LIBS) -pthread
ifneq ($(OS), FreeBSD) ifneq ($(OS), FreeBSD)

View file

@ -9,13 +9,13 @@
namespace nix { namespace nix {
void Store::computeFSClosure(const PathSet & startPaths, void Store::computeFSClosure(const StorePathSet & startPaths,
PathSet & paths_, bool flipDirection, bool includeOutputs, bool includeDerivers) StorePathSet & paths_, bool flipDirection, bool includeOutputs, bool includeDerivers)
{ {
struct State struct State
{ {
size_t pending; size_t pending;
PathSet & paths; StorePathSet & paths;
std::exception_ptr exc; std::exception_ptr exc;
}; };
@ -29,45 +29,47 @@ void Store::computeFSClosure(const PathSet & startPaths,
{ {
auto state(state_.lock()); auto state(state_.lock());
if (state->exc) return; if (state->exc) return;
if (!state->paths.insert(path).second) return; if (!state->paths.insert(parseStorePath(path)).second) return;
state->pending++; state->pending++;
} }
queryPathInfo(path, {[&, path](std::future<ref<const ValidPathInfo>> fut) { queryPathInfo(parseStorePath(path), {[&, pathS(path)](std::future<ref<const ValidPathInfo>> fut) {
// FIXME: calls to isValidPath() should be async // FIXME: calls to isValidPath() should be async
try { try {
auto info = fut.get(); auto info = fut.get();
auto path = parseStorePath(pathS);
if (flipDirection) { if (flipDirection) {
PathSet referrers; StorePathSet referrers;
queryReferrers(path, referrers); queryReferrers(path, referrers);
for (auto & ref : referrers) for (auto & ref : referrers)
if (ref != path) if (ref != path)
enqueue(ref); enqueue(printStorePath(ref));
if (includeOutputs) if (includeOutputs)
for (auto & i : queryValidDerivers(path)) for (auto & i : queryValidDerivers(path))
enqueue(i); enqueue(printStorePath(i));
if (includeDerivers && isDerivation(path)) if (includeDerivers && path.isDerivation())
for (auto & i : queryDerivationOutputs(path)) for (auto & i : queryDerivationOutputs(path))
if (isValidPath(i) && queryPathInfo(i)->deriver == path) if (isValidPath(i) && queryPathInfo(i)->deriver == path)
enqueue(i); enqueue(printStorePath(i));
} else { } else {
for (auto & ref : info->references) for (auto & ref : info->references)
if (ref != path) if (ref != path)
enqueue(ref); enqueue(printStorePath(ref));
if (includeOutputs && isDerivation(path)) if (includeOutputs && path.isDerivation())
for (auto & i : queryDerivationOutputs(path)) for (auto & i : queryDerivationOutputs(path))
if (isValidPath(i)) enqueue(i); if (isValidPath(i)) enqueue(printStorePath(i));
if (includeDerivers && isValidPath(info->deriver)) if (includeDerivers && info->deriver && isValidPath(*info->deriver))
enqueue(info->deriver); enqueue(printStorePath(*info->deriver));
} }
@ -87,7 +89,7 @@ void Store::computeFSClosure(const PathSet & startPaths,
}; };
for (auto & startPath : startPaths) for (auto & startPath : startPaths)
enqueue(startPath); enqueue(printStorePath(startPath));
{ {
auto state(state_.lock()); auto state(state_.lock());
@ -97,15 +99,17 @@ void Store::computeFSClosure(const PathSet & startPaths,
} }
void Store::computeFSClosure(const Path & startPath, void Store::computeFSClosure(const StorePath & startPath,
PathSet & paths_, bool flipDirection, bool includeOutputs, bool includeDerivers) StorePathSet & paths_, bool flipDirection, bool includeOutputs, bool includeDerivers)
{ {
computeFSClosure(PathSet{startPath}, paths_, flipDirection, includeOutputs, includeDerivers); StorePathSet paths;
paths.insert(startPath.clone());
computeFSClosure(paths, paths_, flipDirection, includeOutputs, includeDerivers);
} }
void Store::queryMissing(const PathSet & targets, void Store::queryMissing(const std::vector<StorePathWithOutputs> & targets,
PathSet & willBuild_, PathSet & willSubstitute_, PathSet & unknown_, StorePathSet & willBuild_, StorePathSet & willSubstitute_, StorePathSet & unknown_,
unsigned long long & downloadSize_, unsigned long long & narSize_) unsigned long long & downloadSize_, unsigned long long & narSize_)
{ {
Activity act(*logger, lvlDebug, actUnknown, "querying info about missing paths"); Activity act(*logger, lvlDebug, actUnknown, "querying info about missing paths");
@ -116,8 +120,8 @@ void Store::queryMissing(const PathSet & targets,
struct State struct State
{ {
PathSet done; std::unordered_set<std::string> done;
PathSet & unknown, & willSubstitute, & willBuild; StorePathSet & unknown, & willSubstitute, & willBuild;
unsigned long long & downloadSize; unsigned long long & downloadSize;
unsigned long long & narSize; unsigned long long & narSize;
}; };
@ -126,31 +130,36 @@ void Store::queryMissing(const PathSet & targets,
{ {
size_t left; size_t left;
bool done = false; bool done = false;
PathSet outPaths; StorePathSet outPaths;
DrvState(size_t left) : left(left) { } DrvState(size_t left) : left(left) { }
}; };
Sync<State> state_(State{PathSet(), unknown_, willSubstitute_, willBuild_, downloadSize_, narSize_}); Sync<State> state_(State{{}, unknown_, willSubstitute_, willBuild_, downloadSize_, narSize_});
std::function<void(Path)> doPath; std::function<void(StorePathWithOutputs)> doPath;
auto mustBuildDrv = [&](const Path & drvPath, const Derivation & drv) { auto mustBuildDrv = [&](const StorePath & drvPath, const Derivation & drv) {
{ {
auto state(state_.lock()); auto state(state_.lock());
state->willBuild.insert(drvPath); state->willBuild.insert(drvPath.clone());
} }
for (auto & i : drv.inputDrvs) for (auto & i : drv.inputDrvs)
pool.enqueue(std::bind(doPath, makeDrvPathWithOutputs(i.first, i.second))); pool.enqueue(std::bind(doPath, StorePathWithOutputs(i.first, i.second)));
}; };
auto checkOutput = [&]( auto checkOutput = [&](
const Path & drvPath, ref<Derivation> drv, const Path & outPath, ref<Sync<DrvState>> drvState_) const Path & drvPathS, ref<Derivation> drv, const Path & outPathS, ref<Sync<DrvState>> drvState_)
{ {
if (drvState_->lock()->done) return; if (drvState_->lock()->done) return;
auto drvPath = parseStorePath(drvPathS);
auto outPath = parseStorePath(outPathS);
SubstitutablePathInfos infos; SubstitutablePathInfos infos;
querySubstitutablePathInfos({outPath}, infos); StorePathSet paths; // FIXME
paths.insert(outPath.clone());
querySubstitutablePathInfos(paths, infos);
if (infos.empty()) { if (infos.empty()) {
drvState_->lock()->done = true; drvState_->lock()->done = true;
@ -161,74 +170,74 @@ void Store::queryMissing(const PathSet & targets,
if (drvState->done) return; if (drvState->done) return;
assert(drvState->left); assert(drvState->left);
drvState->left--; drvState->left--;
drvState->outPaths.insert(outPath); drvState->outPaths.insert(outPath.clone());
if (!drvState->left) { if (!drvState->left) {
for (auto & path : drvState->outPaths) for (auto & path : drvState->outPaths)
pool.enqueue(std::bind(doPath, path)); pool.enqueue(std::bind(doPath, StorePathWithOutputs(path.clone())));
} }
} }
} }
}; };
doPath = [&](const Path & path) { doPath = [&](const StorePathWithOutputs & path) {
{ {
auto state(state_.lock()); auto state(state_.lock());
if (!state->done.insert(path).second) return; if (!state->done.insert(path.to_string(*this)).second) return;
} }
DrvPathWithOutputs i2 = parseDrvPathWithOutputs(path); if (path.path.isDerivation()) {
if (!isValidPath(path.path)) {
if (isDerivation(i2.first)) {
if (!isValidPath(i2.first)) {
// FIXME: we could try to substitute the derivation. // FIXME: we could try to substitute the derivation.
auto state(state_.lock()); auto state(state_.lock());
state->unknown.insert(path); state->unknown.insert(path.path.clone());
return; return;
} }
Derivation drv = derivationFromPath(i2.first); auto drv = make_ref<Derivation>(derivationFromPath(path.path));
ParsedDerivation parsedDrv(i2.first, drv); ParsedDerivation parsedDrv(path.path.clone(), *drv);
PathSet invalid; PathSet invalid;
for (auto & j : drv.outputs) for (auto & j : drv->outputs)
if (wantOutput(j.first, i2.second) if (wantOutput(j.first, path.outputs)
&& !isValidPath(j.second.path)) && !isValidPath(j.second.path))
invalid.insert(j.second.path); invalid.insert(printStorePath(j.second.path));
if (invalid.empty()) return; if (invalid.empty()) return;
if (settings.useSubstitutes && parsedDrv.substitutesAllowed()) { if (settings.useSubstitutes && parsedDrv.substitutesAllowed()) {
auto drvState = make_ref<Sync<DrvState>>(DrvState(invalid.size())); auto drvState = make_ref<Sync<DrvState>>(DrvState(invalid.size()));
for (auto & output : invalid) for (auto & output : invalid)
pool.enqueue(std::bind(checkOutput, i2.first, make_ref<Derivation>(drv), output, drvState)); pool.enqueue(std::bind(checkOutput, printStorePath(path.path), drv, output, drvState));
} else } else
mustBuildDrv(i2.first, drv); mustBuildDrv(path.path, *drv);
} else { } else {
if (isValidPath(path)) return; if (isValidPath(path.path)) return;
SubstitutablePathInfos infos; SubstitutablePathInfos infos;
querySubstitutablePathInfos({path}, infos); StorePathSet paths; // FIXME
paths.insert(path.path.clone());
querySubstitutablePathInfos(paths, infos);
if (infos.empty()) { if (infos.empty()) {
auto state(state_.lock()); auto state(state_.lock());
state->unknown.insert(path); state->unknown.insert(path.path.clone());
return; return;
} }
auto info = infos.find(path); auto info = infos.find(path.path);
assert(info != infos.end()); assert(info != infos.end());
{ {
auto state(state_.lock()); auto state(state_.lock());
state->willSubstitute.insert(path); state->willSubstitute.insert(path.path.clone());
state->downloadSize += info->second.downloadSize; state->downloadSize += info->second.downloadSize;
state->narSize += info->second.narSize; state->narSize += info->second.narSize;
} }
for (auto & ref : info->second.references) for (auto & ref : info->second.references)
pool.enqueue(std::bind(doPath, ref)); pool.enqueue(std::bind(doPath, StorePathWithOutputs(ref)));
} }
}; };
@ -239,39 +248,42 @@ void Store::queryMissing(const PathSet & targets,
} }
Paths Store::topoSortPaths(const PathSet & paths) StorePaths Store::topoSortPaths(const StorePathSet & paths)
{ {
Paths sorted; StorePaths sorted;
PathSet visited, parents; StorePathSet visited, parents;
std::function<void(const Path & path, const Path * parent)> dfsVisit; std::function<void(const StorePath & path, const StorePath * parent)> dfsVisit;
dfsVisit = [&](const Path & path, const Path * parent) { dfsVisit = [&](const StorePath & path, const StorePath * parent) {
if (parents.find(path) != parents.end()) if (parents.count(path))
throw BuildError(format("cycle detected in the references of '%1%' from '%2%'") % path % *parent); throw BuildError("cycle detected in the references of '%s' from '%s'",
printStorePath(path), printStorePath(*parent));
if (!visited.insert(path).second) return; if (!visited.insert(path.clone()).second) return;
parents.insert(path); parents.insert(path.clone());
PathSet references; StorePathSet references;
try { try {
references = queryPathInfo(path)->references; references = cloneStorePathSet(queryPathInfo(path)->references);
} catch (InvalidPath &) { } catch (InvalidPath &) {
} }
for (auto & i : references) for (auto & i : references)
/* Don't traverse into paths that don't exist. That can /* Don't traverse into paths that don't exist. That can
happen due to substitutes for non-existent paths. */ happen due to substitutes for non-existent paths. */
if (i != path && paths.find(i) != paths.end()) if (i != path && paths.count(i))
dfsVisit(i, &path); dfsVisit(i, &path);
sorted.push_front(path); sorted.push_back(path.clone());
parents.erase(path); parents.erase(path);
}; };
for (auto & i : paths) for (auto & i : paths)
dfsVisit(i, nullptr); dfsVisit(i, nullptr);
std::reverse(sorted.begin(), sorted.end());
return sorted; return sorted;
} }

View file

@ -193,11 +193,8 @@ public:
if (!queryNAR.getInt(0)) if (!queryNAR.getInt(0))
return {oInvalid, 0}; return {oInvalid, 0};
auto narInfo = make_ref<NarInfo>();
auto namePart = queryNAR.getStr(1); auto namePart = queryNAR.getStr(1);
narInfo->path = cache.storeDir + "/" + auto narInfo = make_ref<NarInfo>(StorePath::fromBaseName(hashPart + "-" + namePart));
hashPart + (namePart.empty() ? "" : "-" + namePart);
narInfo->url = queryNAR.getStr(2); narInfo->url = queryNAR.getStr(2);
narInfo->compression = queryNAR.getStr(3); narInfo->compression = queryNAR.getStr(3);
if (!queryNAR.isNull(4)) if (!queryNAR.isNull(4))
@ -206,9 +203,9 @@ public:
narInfo->narHash = Hash(queryNAR.getStr(6)); narInfo->narHash = Hash(queryNAR.getStr(6));
narInfo->narSize = queryNAR.getInt(7); narInfo->narSize = queryNAR.getInt(7);
for (auto & r : tokenizeString<Strings>(queryNAR.getStr(8), " ")) for (auto & r : tokenizeString<Strings>(queryNAR.getStr(8), " "))
narInfo->references.insert(cache.storeDir + "/" + r); narInfo->references.insert(StorePath::fromBaseName(r));
if (!queryNAR.isNull(9)) if (!queryNAR.isNull(9))
narInfo->deriver = cache.storeDir + "/" + queryNAR.getStr(9); narInfo->deriver = StorePath::fromBaseName(queryNAR.getStr(9));
for (auto & sig : tokenizeString<Strings>(queryNAR.getStr(10), " ")) for (auto & sig : tokenizeString<Strings>(queryNAR.getStr(10), " "))
narInfo->sigs.insert(sig); narInfo->sigs.insert(sig);
narInfo->ca = queryNAR.getStr(11); narInfo->ca = queryNAR.getStr(11);
@ -230,12 +227,12 @@ public:
auto narInfo = std::dynamic_pointer_cast<const NarInfo>(info); auto narInfo = std::dynamic_pointer_cast<const NarInfo>(info);
assert(hashPart == storePathToHash(info->path)); //assert(hashPart == storePathToHash(info->path));
state->insertNAR.use() state->insertNAR.use()
(cache.id) (cache.id)
(hashPart) (hashPart)
(storePathToName(info->path)) (std::string(info->path.name()))
(narInfo ? narInfo->url : "", narInfo != 0) (narInfo ? narInfo->url : "", narInfo != 0)
(narInfo ? narInfo->compression : "", narInfo != 0) (narInfo ? narInfo->compression : "", narInfo != 0)
(narInfo && narInfo->fileHash ? narInfo->fileHash.to_string() : "", narInfo && narInfo->fileHash) (narInfo && narInfo->fileHash ? narInfo->fileHash.to_string() : "", narInfo && narInfo->fileHash)
@ -243,7 +240,7 @@ public:
(info->narHash.to_string()) (info->narHash.to_string())
(info->narSize) (info->narSize)
(concatStringsSep(" ", info->shortRefs())) (concatStringsSep(" ", info->shortRefs()))
(info->deriver != "" ? baseNameOf(info->deriver) : "", info->deriver != "") (info->deriver ? std::string(info->deriver->to_string()) : "", (bool) info->deriver)
(concatStringsSep(" ", info->sigs)) (concatStringsSep(" ", info->sigs))
(info->ca) (info->ca)
(time(0)).exec(); (time(0)).exec();

View file

@ -4,6 +4,7 @@
namespace nix { namespace nix {
NarInfo::NarInfo(const Store & store, const std::string & s, const std::string & whence) NarInfo::NarInfo(const Store & store, const std::string & s, const std::string & whence)
: ValidPathInfo(StorePath::make((unsigned char *) "xxxxxxxxxxxxxxxxxxxx", "x")) // FIXME: hack
{ {
auto corrupt = [&]() { auto corrupt = [&]() {
throw Error(format("NAR info file '%1%' is corrupt") % whence); throw Error(format("NAR info file '%1%' is corrupt") % whence);
@ -18,6 +19,8 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
} }
}; };
bool havePath = false;
size_t pos = 0; size_t pos = 0;
while (pos < s.size()) { while (pos < s.size()) {
@ -32,8 +35,8 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
std::string value(s, colon + 2, eol - colon - 2); std::string value(s, colon + 2, eol - colon - 2);
if (name == "StorePath") { if (name == "StorePath") {
if (!store.isStorePath(value)) corrupt(); path = store.parseStorePath(value);
path = value; havePath = true;
} }
else if (name == "URL") else if (name == "URL")
url = value; url = value;
@ -52,18 +55,12 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
else if (name == "References") { else if (name == "References") {
auto refs = tokenizeString<Strings>(value, " "); auto refs = tokenizeString<Strings>(value, " ");
if (!references.empty()) corrupt(); if (!references.empty()) corrupt();
for (auto & r : refs) { for (auto & r : refs)
auto r2 = store.storeDir + "/" + r; references.insert(StorePath::fromBaseName(r));
if (!store.isStorePath(r2)) corrupt();
references.insert(r2);
}
} }
else if (name == "Deriver") { else if (name == "Deriver") {
if (value != "unknown-deriver") { if (value != "unknown-deriver")
auto p = store.storeDir + "/" + value; deriver = StorePath::fromBaseName(value);
if (!store.isStorePath(p)) corrupt();
deriver = p;
}
} }
else if (name == "System") else if (name == "System")
system = value; system = value;
@ -79,13 +76,13 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
if (compression == "") compression = "bzip2"; if (compression == "") compression = "bzip2";
if (path.empty() || url.empty() || narSize == 0 || !narHash) corrupt(); if (!havePath || url.empty() || narSize == 0 || !narHash) corrupt();
} }
std::string NarInfo::to_string() const std::string NarInfo::to_string(const Store & store) const
{ {
std::string res; std::string res;
res += "StorePath: " + path + "\n"; res += "StorePath: " + store.printStorePath(path) + "\n";
res += "URL: " + url + "\n"; res += "URL: " + url + "\n";
assert(compression != ""); assert(compression != "");
res += "Compression: " + compression + "\n"; res += "Compression: " + compression + "\n";
@ -98,8 +95,8 @@ std::string NarInfo::to_string() const
res += "References: " + concatStringsSep(" ", shortRefs()) + "\n"; res += "References: " + concatStringsSep(" ", shortRefs()) + "\n";
if (!deriver.empty()) if (deriver)
res += "Deriver: " + baseNameOf(deriver) + "\n"; res += "Deriver: " + std::string(deriver->to_string()) + "\n";
if (!system.empty()) if (!system.empty())
res += "System: " + system + "\n"; res += "System: " + system + "\n";

View file

@ -14,11 +14,12 @@ struct NarInfo : ValidPathInfo
uint64_t fileSize = 0; uint64_t fileSize = 0;
std::string system; std::string system;
NarInfo() { } NarInfo() = delete;
NarInfo(StorePath && path) : ValidPathInfo(std::move(path)) { }
NarInfo(const ValidPathInfo & info) : ValidPathInfo(info) { } NarInfo(const ValidPathInfo & info) : ValidPathInfo(info) { }
NarInfo(const Store & store, const std::string & s, const std::string & whence); NarInfo(const Store & store, const std::string & s, const std::string & whence);
std::string to_string() const; std::string to_string(const Store & store) const;
}; };
} }

View file

@ -254,7 +254,7 @@ void LocalStore::optimiseStore(OptimiseStats & stats)
{ {
Activity act(*logger, actOptimiseStore); Activity act(*logger, actOptimiseStore);
PathSet paths = queryAllValidPaths(); auto paths = queryAllValidPaths();
InodeHash inodeHash = loadInodeHash(); InodeHash inodeHash = loadInodeHash();
act.progress(0, paths.size()); act.progress(0, paths.size());
@ -265,8 +265,8 @@ void LocalStore::optimiseStore(OptimiseStats & stats)
addTempRoot(i); addTempRoot(i);
if (!isValidPath(i)) continue; /* path was GC'ed, probably */ if (!isValidPath(i)) continue; /* path was GC'ed, probably */
{ {
Activity act(*logger, lvlTalkative, actUnknown, fmt("optimising path '%s'", i)); Activity act(*logger, lvlTalkative, actUnknown, fmt("optimising path '%s'", printStorePath(i)));
optimisePath_(&act, stats, realStoreDir + "/" + baseNameOf(i), inodeHash); optimisePath_(&act, stats, realStoreDir + "/" + std::string(i.to_string()), inodeHash);
} }
done++; done++;
act.progress(done, paths.size()); act.progress(done, paths.size());

View file

@ -2,8 +2,8 @@
namespace nix { namespace nix {
ParsedDerivation::ParsedDerivation(const Path & drvPath, BasicDerivation & drv) ParsedDerivation::ParsedDerivation(StorePath && drvPath, BasicDerivation & drv)
: drvPath(drvPath), drv(drv) : drvPath(std::move(drvPath)), drv(drv)
{ {
/* Parse the __json attribute, if any. */ /* Parse the __json attribute, if any. */
auto jsonAttr = drv.env.find("__json"); auto jsonAttr = drv.env.find("__json");
@ -11,7 +11,7 @@ ParsedDerivation::ParsedDerivation(const Path & drvPath, BasicDerivation & drv)
try { try {
structuredAttrs = nlohmann::json::parse(jsonAttr->second); structuredAttrs = nlohmann::json::parse(jsonAttr->second);
} catch (std::exception & e) { } catch (std::exception & e) {
throw Error("cannot process __json attribute of '%s': %s", drvPath, e.what()); throw Error("cannot process __json attribute of '%s': %s", drvPath.to_string(), e.what());
} }
} }
} }
@ -24,7 +24,7 @@ std::optional<std::string> ParsedDerivation::getStringAttr(const std::string & n
return {}; return {};
else { else {
if (!i->is_string()) if (!i->is_string())
throw Error("attribute '%s' of derivation '%s' must be a string", name, drvPath); throw Error("attribute '%s' of derivation '%s' must be a string", name, drvPath.to_string());
return i->get<std::string>(); return i->get<std::string>();
} }
} else { } else {
@ -44,7 +44,7 @@ bool ParsedDerivation::getBoolAttr(const std::string & name, bool def) const
return def; return def;
else { else {
if (!i->is_boolean()) if (!i->is_boolean())
throw Error("attribute '%s' of derivation '%s' must be a Boolean", name, drvPath); throw Error("attribute '%s' of derivation '%s' must be a Boolean", name, drvPath.to_string());
return i->get<bool>(); return i->get<bool>();
} }
} else { } else {
@ -64,11 +64,11 @@ std::optional<Strings> ParsedDerivation::getStringsAttr(const std::string & name
return {}; return {};
else { else {
if (!i->is_array()) if (!i->is_array())
throw Error("attribute '%s' of derivation '%s' must be a list of strings", name, drvPath); throw Error("attribute '%s' of derivation '%s' must be a list of strings", name, drvPath.to_string());
Strings res; Strings res;
for (auto j = i->begin(); j != i->end(); ++j) { for (auto j = i->begin(); j != i->end(); ++j) {
if (!j->is_string()) if (!j->is_string())
throw Error("attribute '%s' of derivation '%s' must be a list of strings", name, drvPath); throw Error("attribute '%s' of derivation '%s' must be a list of strings", name, drvPath.to_string());
res.push_back(j->get<std::string>()); res.push_back(j->get<std::string>());
} }
return res; return res;

View file

@ -6,13 +6,13 @@ namespace nix {
class ParsedDerivation class ParsedDerivation
{ {
Path drvPath; StorePath drvPath;
BasicDerivation & drv; BasicDerivation & drv;
std::optional<nlohmann::json> structuredAttrs; std::optional<nlohmann::json> structuredAttrs;
public: public:
ParsedDerivation(const Path & drvPath, BasicDerivation & drv); ParsedDerivation(StorePath && drvPath, BasicDerivation & drv);
const std::optional<nlohmann::json> & getStructuredAttrs() const const std::optional<nlohmann::json> & getStructuredAttrs() const
{ {

99
src/libstore/path.cc Normal file
View file

@ -0,0 +1,99 @@
#include "store-api.hh"
namespace nix {
extern "C" {
rust::Result<StorePath> ffi_StorePath_new(rust::StringSlice path, rust::StringSlice storeDir);
rust::Result<StorePath> ffi_StorePath_new2(unsigned char hash[20], rust::StringSlice storeDir);
rust::Result<StorePath> ffi_StorePath_fromBaseName(rust::StringSlice baseName);
rust::String ffi_StorePath_to_string(const StorePath & _this);
StorePath ffi_StorePath_clone(const StorePath & _this);
rust::StringSlice ffi_StorePath_name(const StorePath & _this);
}
StorePath StorePath::make(std::string_view path, std::string_view storeDir)
{
return ffi_StorePath_new((rust::StringSlice) path, (rust::StringSlice) storeDir).unwrap();
}
StorePath StorePath::make(unsigned char hash[20], std::string_view name)
{
return ffi_StorePath_new2(hash, (rust::StringSlice) name).unwrap();
}
StorePath StorePath::fromBaseName(std::string_view baseName)
{
return ffi_StorePath_fromBaseName((rust::StringSlice) baseName).unwrap();
}
rust::String StorePath::to_string() const
{
return ffi_StorePath_to_string(*this);
}
StorePath StorePath::clone() const
{
return ffi_StorePath_clone(*this);
}
bool StorePath::isDerivation() const
{
return hasSuffix(name(), drvExtension);
}
std::string_view StorePath::name() const
{
return ffi_StorePath_name(*this);
}
StorePath Store::parseStorePath(std::string_view path) const
{
return StorePath::make(path, storeDir);
}
StorePathSet Store::parseStorePathSet(const PathSet & paths) const
{
StorePathSet res;
for (auto & i : paths) res.insert(parseStorePath(i));
return res;
}
std::string Store::printStorePath(const StorePath & path) const
{
auto s = storeDir + "/";
s += (std::string_view) path.to_string();
return s;
}
PathSet Store::printStorePathSet(const StorePathSet & paths) const
{
PathSet res;
for (auto & i : paths) res.insert(printStorePath(i));
return res;
}
StorePathSet cloneStorePathSet(const StorePathSet & paths)
{
StorePathSet res;
for (auto & p : paths)
res.insert(p.clone());
return res;
}
StorePathSet storePathsToSet(const StorePaths & paths)
{
StorePathSet res;
for (auto & p : paths)
res.insert(p.clone());
return res;
}
StorePathSet singleton(const StorePath & path)
{
StorePathSet res;
res.insert(path.clone());
return res;
}
}

81
src/libstore/path.hh Normal file
View file

@ -0,0 +1,81 @@
#pragma once
#include "rust-ffi.hh"
namespace nix {
/* See path.rs. */
struct StorePath;
extern "C" {
void ffi_StorePath_drop(void *);
bool ffi_StorePath_less_than(const StorePath & a, const StorePath & b);
bool ffi_StorePath_eq(const StorePath & a, const StorePath & b);
unsigned char * ffi_StorePath_hash_data(const StorePath & p);
}
struct StorePath : rust::Value<3 * sizeof(void *) + 24, ffi_StorePath_drop>
{
static StorePath make(std::string_view path, std::string_view storeDir);
static StorePath make(unsigned char hash[20], std::string_view name);
static StorePath fromBaseName(std::string_view baseName);
rust::String to_string() const;
bool operator < (const StorePath & other) const
{
return ffi_StorePath_less_than(*this, other);
}
bool operator == (const StorePath & other) const
{
return ffi_StorePath_eq(*this, other);
}
bool operator != (const StorePath & other) const
{
return !(*this == other);
}
StorePath clone() const;
/* Check whether a file name ends with the extension for
derivations. */
bool isDerivation() const;
std::string_view name() const;
unsigned char * hashData() const
{
return ffi_StorePath_hash_data(*this);
}
};
typedef std::set<StorePath> StorePathSet;
typedef std::vector<StorePath> StorePaths;
StorePathSet cloneStorePathSet(const StorePathSet & paths);
StorePathSet storePathsToSet(const StorePaths & paths);
StorePathSet singleton(const StorePath & path);
/* Size of the hash part of store paths, in base-32 characters. */
const size_t storePathHashLen = 32; // i.e. 160 bits
/* Extension of derivations in the Nix store. */
const std::string drvExtension = ".drv";
}
namespace std {
template<> struct hash<nix::StorePath> {
std::size_t operator()(const nix::StorePath & path) const noexcept
{
return * (std::size_t *) path.hashData();
}
};
}

View file

@ -40,7 +40,7 @@ Generations findGenerations(Path profile, int & curGen)
Generations gens; Generations gens;
Path profileDir = dirOf(profile); Path profileDir = dirOf(profile);
string profileName = baseNameOf(profile); auto profileName = std::string(baseNameOf(profile));
for (auto & i : readDirectory(profileDir)) { for (auto & i : readDirectory(profileDir)) {
int n; int n;
@ -108,7 +108,7 @@ Path createGeneration(ref<LocalFSStore> store, Path profile, Path outPath)
user environment etc. we've just built. */ user environment etc. we've just built. */
Path generation; Path generation;
makeName(profile, num + 1, generation); makeName(profile, num + 1, generation);
store->addPermRoot(outPath, generation, false, true); store->addPermRoot(store->parseStorePath(outPath), generation, false, true);
return generation; return generation;
} }

View file

@ -89,7 +89,7 @@ PathSet scanForReferences(const string & path,
hash part of the file name. (This assumes that all references hash part of the file name. (This assumes that all references
have the form `HASH-bla'). */ have the form `HASH-bla'). */
for (auto & i : refs) { for (auto & i : refs) {
string baseName = baseNameOf(i); auto baseName = std::string(baseNameOf(i));
string::size_type pos = baseName.find('-'); string::size_type pos = baseName.find('-');
if (pos == string::npos) if (pos == string::npos)
throw Error(format("bad reference '%1%'") % i); throw Error(format("bad reference '%1%'") % i);

View file

@ -50,7 +50,7 @@ std::pair<ref<FSAccessor>, Path> RemoteFSAccessor::fetch(const Path & path_)
auto storePath = store->toStorePath(path); auto storePath = store->toStorePath(path);
std::string restPath = std::string(path, storePath.size()); std::string restPath = std::string(path, storePath.size());
if (!store->isValidPath(storePath)) if (!store->isValidPath(store->parseStorePath(storePath)))
throw InvalidPath(format("path '%1%' is not a valid store path") % storePath); throw InvalidPath(format("path '%1%' is not a valid store path") % storePath);
auto i = nars.find(storePath); auto i = nars.find(storePath);
@ -96,7 +96,7 @@ std::pair<ref<FSAccessor>, Path> RemoteFSAccessor::fetch(const Path & path_)
} catch (SysError &) { } } catch (SysError &) { }
} }
store->narFromPath(storePath, sink); store->narFromPath(store->parseStorePath(storePath), sink);
auto narAccessor = makeNarAccessor(sink.s); auto narAccessor = makeNarAccessor(sink.s);
addToCache(storePath, *sink.s, narAccessor); addToCache(storePath, *sink.s, narAccessor);
return {narAccessor, restPath}; return {narAccessor, restPath};

View file

@ -22,23 +22,22 @@
namespace nix { namespace nix {
Path readStorePath(Store & store, Source & from) template<> StorePathSet readStorePaths(const Store & store, Source & from)
{ {
Path path = readString(from); StorePathSet paths;
store.assertStorePath(path); for (auto & i : readStrings<Strings>(from))
return path; paths.insert(store.parseStorePath(i));
}
template<class T> T readStorePaths(Store & store, Source & from)
{
T paths = readStrings<T>(from);
for (auto & i : paths) store.assertStorePath(i);
return paths; return paths;
} }
template PathSet readStorePaths(Store & store, Source & from);
template Paths readStorePaths(Store & store, Source & from); void writeStorePaths(const Store & store, Sink & out, const StorePathSet & paths)
{
out << paths.size();
for (auto & i : paths)
out << store.printStorePath(i);
}
/* TODO: Separate these store impls into different files, give them better names */ /* TODO: Separate these store impls into different files, give them better names */
RemoteStore::RemoteStore(const Params & params) RemoteStore::RemoteStore(const Params & params)
@ -254,60 +253,62 @@ ConnectionHandle RemoteStore::getConnection()
} }
bool RemoteStore::isValidPathUncached(const Path & path) bool RemoteStore::isValidPathUncached(const StorePath & path)
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopIsValidPath << path; conn->to << wopIsValidPath << printStorePath(path);
conn.processStderr(); conn.processStderr();
return readInt(conn->from); return readInt(conn->from);
} }
PathSet RemoteStore::queryValidPaths(const PathSet & paths, SubstituteFlag maybeSubstitute) StorePathSet RemoteStore::queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute)
{ {
auto conn(getConnection()); auto conn(getConnection());
if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 12) { if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 12) {
PathSet res; StorePathSet res;
for (auto & i : paths) for (auto & i : paths)
if (isValidPath(i)) res.insert(i); if (isValidPath(i)) res.insert(i.clone());
return res; return res;
} else { } else {
conn->to << wopQueryValidPaths << paths; conn->to << wopQueryValidPaths;
writeStorePaths(*this, conn->to, paths);
conn.processStderr(); conn.processStderr();
return readStorePaths<PathSet>(*this, conn->from); return readStorePaths<StorePathSet>(*this, conn->from);
} }
} }
PathSet RemoteStore::queryAllValidPaths() StorePathSet RemoteStore::queryAllValidPaths()
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopQueryAllValidPaths; conn->to << wopQueryAllValidPaths;
conn.processStderr(); conn.processStderr();
return readStorePaths<PathSet>(*this, conn->from); return readStorePaths<StorePathSet>(*this, conn->from);
} }
PathSet RemoteStore::querySubstitutablePaths(const PathSet & paths) StorePathSet RemoteStore::querySubstitutablePaths(const StorePathSet & paths)
{ {
auto conn(getConnection()); auto conn(getConnection());
if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 12) { if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 12) {
PathSet res; StorePathSet res;
for (auto & i : paths) { for (auto & i : paths) {
conn->to << wopHasSubstitutes << i; conn->to << wopHasSubstitutes << printStorePath(i);
conn.processStderr(); conn.processStderr();
if (readInt(conn->from)) res.insert(i); if (readInt(conn->from)) res.insert(i.clone());
} }
return res; return res;
} else { } else {
conn->to << wopQuerySubstitutablePaths << paths; conn->to << wopQuerySubstitutablePaths;
writeStorePaths(*this, conn->to, paths);
conn.processStderr(); conn.processStderr();
return readStorePaths<PathSet>(*this, conn->from); return readStorePaths<StorePathSet>(*this, conn->from);
} }
} }
void RemoteStore::querySubstitutablePathInfos(const PathSet & paths, void RemoteStore::querySubstitutablePathInfos(const StorePathSet & paths,
SubstitutablePathInfos & infos) SubstitutablePathInfos & infos)
{ {
if (paths.empty()) return; if (paths.empty()) return;
@ -318,29 +319,31 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
for (auto & i : paths) { for (auto & i : paths) {
SubstitutablePathInfo info; SubstitutablePathInfo info;
conn->to << wopQuerySubstitutablePathInfo << i; conn->to << wopQuerySubstitutablePathInfo << printStorePath(i);
conn.processStderr(); conn.processStderr();
unsigned int reply = readInt(conn->from); unsigned int reply = readInt(conn->from);
if (reply == 0) continue; if (reply == 0) continue;
info.deriver = readString(conn->from); auto deriver = readString(conn->from);
if (info.deriver != "") assertStorePath(info.deriver); if (deriver != "")
info.references = readStorePaths<PathSet>(*this, conn->from); info.deriver = parseStorePath(deriver);
info.references = readStorePaths<StorePathSet>(*this, conn->from);
info.downloadSize = readLongLong(conn->from); info.downloadSize = readLongLong(conn->from);
info.narSize = readLongLong(conn->from); info.narSize = readLongLong(conn->from);
infos[i] = info; infos.insert_or_assign(i.clone(), std::move(info));
} }
} else { } else {
conn->to << wopQuerySubstitutablePathInfos << paths; conn->to << wopQuerySubstitutablePathInfos;
writeStorePaths(*this, conn->to, paths);
conn.processStderr(); conn.processStderr();
size_t count = readNum<size_t>(conn->from); size_t count = readNum<size_t>(conn->from);
for (size_t n = 0; n < count; n++) { for (size_t n = 0; n < count; n++) {
Path path = readStorePath(*this, conn->from); SubstitutablePathInfo & info(infos[parseStorePath(readString(conn->from))]);
SubstitutablePathInfo & info(infos[path]); auto deriver = readString(conn->from);
info.deriver = readString(conn->from); if (deriver != "")
if (info.deriver != "") assertStorePath(info.deriver); info.deriver = parseStorePath(deriver);
info.references = readStorePaths<PathSet>(*this, conn->from); info.references = readStorePaths<StorePathSet>(*this, conn->from);
info.downloadSize = readLongLong(conn->from); info.downloadSize = readLongLong(conn->from);
info.narSize = readLongLong(conn->from); info.narSize = readLongLong(conn->from);
} }
@ -349,14 +352,14 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
} }
void RemoteStore::queryPathInfoUncached(const Path & path, void RemoteStore::queryPathInfoUncached(const StorePath & path,
Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept
{ {
try { try {
std::shared_ptr<ValidPathInfo> info; std::shared_ptr<ValidPathInfo> info;
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopQueryPathInfo << path; conn->to << wopQueryPathInfo << printStorePath(path);
try { try {
conn.processStderr(); conn.processStderr();
} catch (Error & e) { } catch (Error & e) {
@ -367,14 +370,13 @@ void RemoteStore::queryPathInfoUncached(const Path & path,
} }
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 17) { if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 17) {
bool valid; conn->from >> valid; bool valid; conn->from >> valid;
if (!valid) throw InvalidPath(format("path '%s' is not valid") % path); if (!valid) throw InvalidPath("path '%s' is not valid", printStorePath(path));
} }
info = std::make_shared<ValidPathInfo>(); info = std::make_shared<ValidPathInfo>(path.clone());
info->path = path; auto deriver = readString(conn->from);
info->deriver = readString(conn->from); if (deriver != "") info->deriver = parseStorePath(deriver);
if (info->deriver != "") assertStorePath(info->deriver);
info->narHash = Hash(readString(conn->from), htSHA256); info->narHash = Hash(readString(conn->from), htSHA256);
info->references = readStorePaths<PathSet>(*this, conn->from); info->references = readStorePaths<StorePathSet>(*this, conn->from);
conn->from >> info->registrationTime >> info->narSize; conn->from >> info->registrationTime >> info->narSize;
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 16) { if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 16) {
conn->from >> info->ultimate; conn->from >> info->ultimate;
@ -387,52 +389,52 @@ void RemoteStore::queryPathInfoUncached(const Path & path,
} }
void RemoteStore::queryReferrers(const Path & path, void RemoteStore::queryReferrers(const StorePath & path,
PathSet & referrers) StorePathSet & referrers)
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopQueryReferrers << path; conn->to << wopQueryReferrers << printStorePath(path);
conn.processStderr(); conn.processStderr();
PathSet referrers2 = readStorePaths<PathSet>(*this, conn->from); for (auto & i : readStorePaths<StorePathSet>(*this, conn->from))
referrers.insert(referrers2.begin(), referrers2.end()); referrers.insert(i.clone());
} }
PathSet RemoteStore::queryValidDerivers(const Path & path) StorePathSet RemoteStore::queryValidDerivers(const StorePath & path)
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopQueryValidDerivers << path; conn->to << wopQueryValidDerivers << printStorePath(path);
conn.processStderr(); conn.processStderr();
return readStorePaths<PathSet>(*this, conn->from); return readStorePaths<StorePathSet>(*this, conn->from);
} }
PathSet RemoteStore::queryDerivationOutputs(const Path & path) StorePathSet RemoteStore::queryDerivationOutputs(const StorePath & path)
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopQueryDerivationOutputs << path; conn->to << wopQueryDerivationOutputs << printStorePath(path);
conn.processStderr(); conn.processStderr();
return readStorePaths<PathSet>(*this, conn->from); return readStorePaths<StorePathSet>(*this, conn->from);
} }
PathSet RemoteStore::queryDerivationOutputNames(const Path & path) PathSet RemoteStore::queryDerivationOutputNames(const StorePath & path)
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopQueryDerivationOutputNames << path; conn->to << wopQueryDerivationOutputNames << printStorePath(path);
conn.processStderr(); conn.processStderr();
return readStrings<PathSet>(conn->from); return readStrings<PathSet>(conn->from);
} }
Path RemoteStore::queryPathFromHashPart(const string & hashPart) std::optional<StorePath> RemoteStore::queryPathFromHashPart(const std::string & hashPart)
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopQueryPathFromHashPart << hashPart; conn->to << wopQueryPathFromHashPart << hashPart;
conn.processStderr(); conn.processStderr();
Path path = readString(conn->from); Path path = readString(conn->from);
if (!path.empty()) assertStorePath(path); if (path.empty()) return {};
return path; return parseStorePath(path);
} }
@ -450,9 +452,10 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
copyNAR(source, sink); copyNAR(source, sink);
sink sink
<< exportMagic << exportMagic
<< info.path << printStorePath(info.path);
<< info.references writeStorePaths(*this, sink, info.references);
<< info.deriver sink
<< (info.deriver ? printStorePath(*info.deriver) : "")
<< 0 // == no legacy signature << 0 // == no legacy signature
<< 0 // == no path follows << 0 // == no path follows
; ;
@ -460,14 +463,17 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
conn.processStderr(0, source2.get()); conn.processStderr(0, source2.get());
auto importedPaths = readStorePaths<PathSet>(*this, conn->from); auto importedPaths = readStorePaths<StorePathSet>(*this, conn->from);
assert(importedPaths.size() <= 1); assert(importedPaths.size() <= 1);
} }
else { else {
conn->to << wopAddToStoreNar conn->to << wopAddToStoreNar
<< info.path << info.deriver << info.narHash.to_string(Base16, false) << printStorePath(info.path)
<< info.references << info.registrationTime << info.narSize << (info.deriver ? printStorePath(*info.deriver) : "")
<< info.narHash.to_string(Base16, false);
writeStorePaths(*this, conn->to, info.references);
conn->to << info.registrationTime << info.narSize
<< info.ultimate << info.sigs << info.ca << info.ultimate << info.sigs << info.ca
<< repair << !checkSigs; << repair << !checkSigs;
bool tunnel = GET_PROTOCOL_MINOR(conn->daemonVersion) >= 21; bool tunnel = GET_PROTOCOL_MINOR(conn->daemonVersion) >= 21;
@ -477,7 +483,7 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
} }
Path RemoteStore::addToStore(const string & name, const Path & _srcPath, StorePath RemoteStore::addToStore(const string & name, const Path & _srcPath,
bool recursive, HashType hashAlgo, PathFilter & filter, RepairFlag repair) bool recursive, HashType hashAlgo, PathFilter & filter, RepairFlag repair)
{ {
if (repair) throw Error("repairing is not supported when building through the Nix daemon"); if (repair) throw Error("repairing is not supported when building through the Nix daemon");
@ -511,54 +517,52 @@ Path RemoteStore::addToStore(const string & name, const Path & _srcPath,
throw; throw;
} }
return readStorePath(*this, conn->from); return parseStorePath(readString(conn->from));
} }
Path RemoteStore::addTextToStore(const string & name, const string & s, StorePath RemoteStore::addTextToStore(const string & name, const string & s,
const PathSet & references, RepairFlag repair) const StorePathSet & references, RepairFlag repair)
{ {
if (repair) throw Error("repairing is not supported when building through the Nix daemon"); if (repair) throw Error("repairing is not supported when building through the Nix daemon");
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopAddTextToStore << name << s << references; conn->to << wopAddTextToStore << name << s;
writeStorePaths(*this, conn->to, references);
conn.processStderr(); conn.processStderr();
return readStorePath(*this, conn->from); return parseStorePath(readString(conn->from));
} }
void RemoteStore::buildPaths(const PathSet & drvPaths, BuildMode buildMode) void RemoteStore::buildPaths(const std::vector<StorePathWithOutputs> & drvPaths, BuildMode buildMode)
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopBuildPaths; conn->to << wopBuildPaths;
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 13) { assert(GET_PROTOCOL_MINOR(conn->daemonVersion) >= 13);
conn->to << drvPaths; Strings ss;
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 15) for (auto & p : drvPaths)
conn->to << buildMode; ss.push_back(p.to_string(*this));
else conn->to << ss;
/* Old daemons did not take a 'buildMode' parameter, so we if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 15)
need to validate it here on the client side. */ conn->to << buildMode;
if (buildMode != bmNormal) else
throw Error("repairing or checking is not supported when building through the Nix daemon"); /* Old daemons did not take a 'buildMode' parameter, so we
} else { need to validate it here on the client side. */
/* For backwards compatibility with old daemons, strip output if (buildMode != bmNormal)
identifiers. */ throw Error("repairing or checking is not supported when building through the Nix daemon");
PathSet drvPaths2;
for (auto & i : drvPaths)
drvPaths2.insert(string(i, 0, i.find('!')));
conn->to << drvPaths2;
}
conn.processStderr(); conn.processStderr();
readInt(conn->from); readInt(conn->from);
} }
BuildResult RemoteStore::buildDerivation(const Path & drvPath, const BasicDerivation & drv, BuildResult RemoteStore::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode) BuildMode buildMode)
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopBuildDerivation << drvPath << drv << buildMode; conn->to << wopBuildDerivation << printStorePath(drvPath);
writeDerivation(conn->to, *this, drv);
conn->to << buildMode;
conn.processStderr(); conn.processStderr();
BuildResult res; BuildResult res;
unsigned int status; unsigned int status;
@ -568,19 +572,19 @@ BuildResult RemoteStore::buildDerivation(const Path & drvPath, const BasicDeriva
} }
void RemoteStore::ensurePath(const Path & path) void RemoteStore::ensurePath(const StorePath & path)
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopEnsurePath << path; conn->to << wopEnsurePath << printStorePath(path);
conn.processStderr(); conn.processStderr();
readInt(conn->from); readInt(conn->from);
} }
void RemoteStore::addTempRoot(const Path & path) void RemoteStore::addTempRoot(const StorePath & path)
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopAddTempRoot << path; conn->to << wopAddTempRoot << printStorePath(path);
conn.processStderr(); conn.processStderr();
readInt(conn->from); readInt(conn->from);
} }
@ -613,8 +617,8 @@ Roots RemoteStore::findRoots(bool censor)
Roots result; Roots result;
while (count--) { while (count--) {
Path link = readString(conn->from); Path link = readString(conn->from);
Path target = readStorePath(*this, conn->from); auto target = parseStorePath(readString(conn->from));
result[target].emplace(link); result[std::move(target)].emplace(link);
} }
return result; return result;
} }
@ -625,7 +629,9 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
auto conn(getConnection()); auto conn(getConnection());
conn->to conn->to
<< wopCollectGarbage << options.action << options.pathsToDelete << options.ignoreLiveness << wopCollectGarbage << options.action;
writeStorePaths(*this, conn->to, options.pathsToDelete);
conn->to << options.ignoreLiveness
<< options.maxFreed << options.maxFreed
/* removed options */ /* removed options */
<< 0 << 0 << 0; << 0 << 0 << 0;
@ -661,17 +667,17 @@ bool RemoteStore::verifyStore(bool checkContents, RepairFlag repair)
} }
void RemoteStore::addSignatures(const Path & storePath, const StringSet & sigs) void RemoteStore::addSignatures(const StorePath & storePath, const StringSet & sigs)
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << wopAddSignatures << storePath << sigs; conn->to << wopAddSignatures << printStorePath(storePath) << sigs;
conn.processStderr(); conn.processStderr();
readInt(conn->from); readInt(conn->from);
} }
void RemoteStore::queryMissing(const PathSet & targets, void RemoteStore::queryMissing(const std::vector<StorePathWithOutputs> & targets,
PathSet & willBuild, PathSet & willSubstitute, PathSet & unknown, StorePathSet & willBuild, StorePathSet & willSubstitute, StorePathSet & unknown,
unsigned long long & downloadSize, unsigned long long & narSize) unsigned long long & downloadSize, unsigned long long & narSize)
{ {
{ {
@ -680,11 +686,15 @@ void RemoteStore::queryMissing(const PathSet & targets,
// Don't hold the connection handle in the fallback case // Don't hold the connection handle in the fallback case
// to prevent a deadlock. // to prevent a deadlock.
goto fallback; goto fallback;
conn->to << wopQueryMissing << targets; conn->to << wopQueryMissing;
Strings ss;
for (auto & p : targets)
ss.push_back(p.to_string(*this));
conn->to << ss;
conn.processStderr(); conn.processStderr();
willBuild = readStorePaths<PathSet>(*this, conn->from); willBuild = readStorePaths<StorePathSet>(*this, conn->from);
willSubstitute = readStorePaths<PathSet>(*this, conn->from); willSubstitute = readStorePaths<StorePathSet>(*this, conn->from);
unknown = readStorePaths<PathSet>(*this, conn->from); unknown = readStorePaths<StorePathSet>(*this, conn->from);
conn->from >> downloadSize >> narSize; conn->from >> downloadSize >> narSize;
return; return;
} }

View file

@ -35,50 +35,50 @@ public:
/* Implementations of abstract store API methods. */ /* Implementations of abstract store API methods. */
bool isValidPathUncached(const Path & path) override; bool isValidPathUncached(const StorePath & path) override;
PathSet queryValidPaths(const PathSet & paths, StorePathSet queryValidPaths(const StorePathSet & paths,
SubstituteFlag maybeSubstitute = NoSubstitute) override; SubstituteFlag maybeSubstitute = NoSubstitute) override;
PathSet queryAllValidPaths() override; StorePathSet queryAllValidPaths() override;
void queryPathInfoUncached(const Path & path, void queryPathInfoUncached(const StorePath & path,
Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override; Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override;
void queryReferrers(const Path & path, PathSet & referrers) override; void queryReferrers(const StorePath & path, StorePathSet & referrers) override;
PathSet queryValidDerivers(const Path & path) override; StorePathSet queryValidDerivers(const StorePath & path) override;
PathSet queryDerivationOutputs(const Path & path) override; StorePathSet queryDerivationOutputs(const StorePath & path) override;
StringSet queryDerivationOutputNames(const Path & path) override; StringSet queryDerivationOutputNames(const StorePath & path) override;
Path queryPathFromHashPart(const string & hashPart) override; std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override;
PathSet querySubstitutablePaths(const PathSet & paths) override; StorePathSet querySubstitutablePaths(const StorePathSet & paths) override;
void querySubstitutablePathInfos(const PathSet & paths, void querySubstitutablePathInfos(const StorePathSet & paths,
SubstitutablePathInfos & infos) override; SubstitutablePathInfos & infos) override;
void addToStore(const ValidPathInfo & info, Source & nar, void addToStore(const ValidPathInfo & info, Source & nar,
RepairFlag repair, CheckSigsFlag checkSigs, RepairFlag repair, CheckSigsFlag checkSigs,
std::shared_ptr<FSAccessor> accessor) override; std::shared_ptr<FSAccessor> accessor) override;
Path addToStore(const string & name, const Path & srcPath, StorePath addToStore(const string & name, const Path & srcPath,
bool recursive = true, HashType hashAlgo = htSHA256, bool recursive = true, HashType hashAlgo = htSHA256,
PathFilter & filter = defaultPathFilter, RepairFlag repair = NoRepair) override; PathFilter & filter = defaultPathFilter, RepairFlag repair = NoRepair) override;
Path addTextToStore(const string & name, const string & s, StorePath addTextToStore(const string & name, const string & s,
const PathSet & references, RepairFlag repair) override; const StorePathSet & references, RepairFlag repair) override;
void buildPaths(const PathSet & paths, BuildMode buildMode) override; void buildPaths(const std::vector<StorePathWithOutputs> & paths, BuildMode buildMode) override;
BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv, BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode) override; BuildMode buildMode) override;
void ensurePath(const Path & path) override; void ensurePath(const StorePath & path) override;
void addTempRoot(const Path & path) override; void addTempRoot(const StorePath & path) override;
void addIndirectRoot(const Path & path) override; void addIndirectRoot(const Path & path) override;
@ -92,10 +92,10 @@ public:
bool verifyStore(bool checkContents, RepairFlag repair) override; bool verifyStore(bool checkContents, RepairFlag repair) override;
void addSignatures(const Path & storePath, const StringSet & sigs) override; void addSignatures(const StorePath & storePath, const StringSet & sigs) override;
void queryMissing(const PathSet & targets, void queryMissing(const std::vector<StorePathWithOutputs> & targets,
PathSet & willBuild, PathSet & willSubstitute, PathSet & unknown, StorePathSet & willBuild, StorePathSet & willSubstitute, StorePathSet & unknown,
unsigned long long & downloadSize, unsigned long long & narSize) override; unsigned long long & downloadSize, unsigned long long & narSize) override;
void connect() override; void connect() override;

View file

@ -222,7 +222,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
fetches the .narinfo file, rather than first checking for its fetches the .narinfo file, rather than first checking for its
existence via a HEAD request. Since .narinfos are small, doing existence via a HEAD request. Since .narinfos are small, doing
a GET is unlikely to be slower than HEAD. */ a GET is unlikely to be slower than HEAD. */
bool isValidPathUncached(const Path & storePath) override bool isValidPathUncached(const StorePath & storePath) override
{ {
try { try {
queryPathInfo(storePath); queryPathInfo(storePath);
@ -382,9 +382,9 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
throw NoSuchBinaryCacheFile("file '%s' does not exist in binary cache '%s'", path, getUri()); throw NoSuchBinaryCacheFile("file '%s' does not exist in binary cache '%s'", path, getUri());
} }
PathSet queryAllValidPaths() override StorePathSet queryAllValidPaths() override
{ {
PathSet paths; StorePathSet paths;
std::string marker; std::string marker;
do { do {
@ -405,7 +405,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
for (auto object : contents) { for (auto object : contents) {
auto & key = object.GetKey(); auto & key = object.GetKey();
if (key.size() != 40 || !hasSuffix(key, ".narinfo")) continue; if (key.size() != 40 || !hasSuffix(key, ".narinfo")) continue;
paths.insert(storeDir + "/" + key.substr(0, key.size() - 8)); paths.insert(parseStorePath(storeDir + "/" + key.substr(0, key.size() - 8) + "-unknown"));
} }
marker = res.GetNextMarker(); marker = res.GetNextMarker();

View file

@ -38,7 +38,7 @@ public:
bool sameMachine() override bool sameMachine() override
{ return false; } { return false; }
void narFromPath(const Path & path, Sink & sink) override; void narFromPath(const StorePath & path, Sink & sink) override;
ref<FSAccessor> getFSAccessor() override; ref<FSAccessor> getFSAccessor() override;
@ -66,10 +66,10 @@ private:
}; };
}; };
void SSHStore::narFromPath(const Path & path, Sink & sink) void SSHStore::narFromPath(const StorePath & path, Sink & sink)
{ {
auto conn(connections->get()); auto conn(connections->get());
conn->to << wopNarFromPath << path; conn->to << wopNarFromPath << printStorePath(path);
conn->processStderr(); conn->processStderr();
copyNAR(conn->from, sink); copyNAR(conn->from, sink);
} }

View file

@ -27,13 +27,6 @@ bool Store::isStorePath(const Path & path) const
} }
void Store::assertStorePath(const Path & path) const
{
if (!isStorePath(path))
throw Error(format("path '%1%' is not in the Nix store") % path);
}
Path Store::toStorePath(const Path & path) const Path Store::toStorePath(const Path & path) const
{ {
if (!isInStore(path)) if (!isInStore(path))
@ -60,17 +53,9 @@ Path Store::followLinksToStore(const Path & _path) const
} }
Path Store::followLinksToStorePath(const Path & path) const StorePath Store::followLinksToStorePath(const Path & path) const
{ {
return toStorePath(followLinksToStore(path)); return parseStorePath(toStorePath(followLinksToStore(path)));
}
string storePathToName(const Path & path)
{
auto base = baseNameOf(path);
assert(base.size() == storePathHashLen || (base.size() > storePathHashLen && base[storePathHashLen] == '-'));
return base.size() == storePathHashLen ? "" : string(base, storePathHashLen + 1);
} }
@ -82,41 +67,6 @@ string storePathToHash(const Path & path)
} }
void checkStoreName(const string & name)
{
string validChars = "+-._?=";
auto baseError = format("The path name '%2%' is invalid: %3%. "
"Path names are alphanumeric and can include the symbols %1% "
"and must not begin with a period. "
"Note: If '%2%' is a source file and you cannot rename it on "
"disk, 'builtins.path { name = ... }' can be used to give it an "
"alternative name.") % validChars % name;
if (name.empty())
throw Error(baseError % "it is an empty string");
/* Disallow names starting with a dot for possible security
reasons (e.g., "." and ".."). */
if (name[0] == '.')
throw Error(baseError % "it is illegal to start the name with a period");
/* Disallow names longer than 211 characters. ext4s max is 256,
but we need extra space for the hash and .chroot extensions. */
if (name.length() > 211)
throw Error(baseError % "name must be less than 212 characters");
for (auto & i : name)
if (!((i >= 'A' && i <= 'Z') ||
(i >= 'a' && i <= 'z') ||
(i >= '0' && i <= '9') ||
validChars.find(i) != string::npos))
{
throw Error(baseError % (format("the '%1%' character is invalid") % i));
}
}
/* Store paths have the following form: /* Store paths have the following form:
<store>/<h>-<name> <store>/<h>-<name>
@ -188,43 +138,48 @@ void checkStoreName(const string & name)
*/ */
Path Store::makeStorePath(const string & type, StorePath Store::makeStorePath(const string & type,
const Hash & hash, const string & name) const const Hash & hash, std::string_view name) const
{ {
/* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */ /* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
string s = type + ":" + hash.to_string(Base16) + ":" + storeDir + ":" + name; string s = type + ":" + hash.to_string(Base16) + ":" + storeDir + ":" + std::string(name);
auto h = compressHash(hashString(htSHA256, s), 20);
checkStoreName(name); return StorePath::make(h.hash, name);
return storeDir + "/"
+ compressHash(hashString(htSHA256, s), 20).to_string(Base32, false)
+ "-" + name;
} }
Path Store::makeOutputPath(const string & id, StorePath Store::makeOutputPath(const string & id,
const Hash & hash, const string & name) const const Hash & hash, std::string_view name) const
{ {
return makeStorePath("output:" + id, hash, return makeStorePath("output:" + id, hash,
name + (id == "out" ? "" : "-" + id)); std::string(name) + (id == "out" ? "" : "-" + id));
} }
static std::string makeType(string && type, const PathSet & references) static std::string makeType(
const Store & store,
string && type,
const StorePathSet & references,
bool hasSelfReference = false)
{ {
for (auto & i : references) { for (auto & i : references) {
type += ":"; type += ":";
type += i; type += store.printStorePath(i);
} }
if (hasSelfReference) type += ":self";
return std::move(type); return std::move(type);
} }
Path Store::makeFixedOutputPath(bool recursive, StorePath Store::makeFixedOutputPath(
const Hash & hash, const string & name, const PathSet & references) const bool recursive,
const Hash & hash,
std::string_view name,
const StorePathSet & references,
bool hasSelfReference) const
{ {
if (hash.type == htSHA256 && recursive) { if (hash.type == htSHA256 && recursive) {
return makeStorePath(makeType("source", references), hash, name); return makeStorePath(makeType(*this, "source", references, hasSelfReference), hash, name);
} else { } else {
assert(references.empty()); assert(references.empty());
return makeStorePath("output:out", hashString(htSHA256, return makeStorePath("output:out", hashString(htSHA256,
@ -234,28 +189,27 @@ Path Store::makeFixedOutputPath(bool recursive,
} }
Path Store::makeTextPath(const string & name, const Hash & hash, StorePath Store::makeTextPath(std::string_view name, const Hash & hash,
const PathSet & references) const const StorePathSet & references) const
{ {
assert(hash.type == htSHA256); assert(hash.type == htSHA256);
/* Stuff the references (if any) into the type. This is a bit /* Stuff the references (if any) into the type. This is a bit
hacky, but we can't put them in `s' since that would be hacky, but we can't put them in `s' since that would be
ambiguous. */ ambiguous. */
return makeStorePath(makeType("text", references), hash, name); return makeStorePath(makeType(*this, "text", references), hash, name);
} }
std::pair<Path, Hash> Store::computeStorePathForPath(const string & name, std::pair<StorePath, Hash> Store::computeStorePathForPath(std::string_view name,
const Path & srcPath, bool recursive, HashType hashAlgo, PathFilter & filter) const const Path & srcPath, bool recursive, HashType hashAlgo, PathFilter & filter) const
{ {
Hash h = recursive ? hashPath(hashAlgo, srcPath, filter).first : hashFile(hashAlgo, srcPath); Hash h = recursive ? hashPath(hashAlgo, srcPath, filter).first : hashFile(hashAlgo, srcPath);
Path dstPath = makeFixedOutputPath(recursive, h, name); return std::make_pair(makeFixedOutputPath(recursive, h, name), h);
return std::pair<Path, Hash>(dstPath, h);
} }
Path Store::computeStorePathForText(const string & name, const string & s, StorePath Store::computeStorePathForText(const string & name, const string & s,
const PathSet & references) const const StorePathSet & references) const
{ {
return makeTextPath(name, hashString(htSHA256, s), references); return makeTextPath(name, hashString(htSHA256, s), references);
} }
@ -274,11 +228,9 @@ std::string Store::getUri()
} }
bool Store::isValidPath(const Path & storePath) bool Store::isValidPath(const StorePath & storePath)
{ {
assertStorePath(storePath); auto hashPart = storePathToHash(printStorePath(storePath));
auto hashPart = storePathToHash(storePath);
{ {
auto state_(state.lock()); auto state_(state.lock());
@ -312,7 +264,7 @@ bool Store::isValidPath(const Path & storePath)
/* Default implementation for stores that only implement /* Default implementation for stores that only implement
queryPathInfoUncached(). */ queryPathInfoUncached(). */
bool Store::isValidPathUncached(const Path & path) bool Store::isValidPathUncached(const StorePath & path)
{ {
try { try {
queryPathInfo(path); queryPathInfo(path);
@ -323,7 +275,7 @@ bool Store::isValidPathUncached(const Path & path)
} }
ref<const ValidPathInfo> Store::queryPathInfo(const Path & storePath) ref<const ValidPathInfo> Store::queryPathInfo(const StorePath & storePath)
{ {
std::promise<ref<const ValidPathInfo>> promise; std::promise<ref<const ValidPathInfo>> promise;
@ -340,22 +292,20 @@ ref<const ValidPathInfo> Store::queryPathInfo(const Path & storePath)
} }
void Store::queryPathInfo(const Path & storePath, void Store::queryPathInfo(const StorePath & storePath,
Callback<ref<const ValidPathInfo>> callback) noexcept Callback<ref<const ValidPathInfo>> callback) noexcept
{ {
std::string hashPart; std::string hashPart;
try { try {
assertStorePath(storePath); hashPart = storePathToHash(printStorePath(storePath));
hashPart = storePathToHash(storePath);
{ {
auto res = state.lock()->pathInfoCache.get(hashPart); auto res = state.lock()->pathInfoCache.get(hashPart);
if (res) { if (res) {
stats.narInfoReadAverted++; stats.narInfoReadAverted++;
if (!*res) if (!*res)
throw InvalidPath(format("path '%s' is not valid") % storePath); throw InvalidPath("path '%s' is not valid", printStorePath(storePath));
return callback(ref<const ValidPathInfo>(*res)); return callback(ref<const ValidPathInfo>(*res));
} }
} }
@ -369,8 +319,8 @@ void Store::queryPathInfo(const Path & storePath,
state_->pathInfoCache.upsert(hashPart, state_->pathInfoCache.upsert(hashPart,
res.first == NarInfoDiskCache::oInvalid ? 0 : res.second); res.first == NarInfoDiskCache::oInvalid ? 0 : res.second);
if (res.first == NarInfoDiskCache::oInvalid || if (res.first == NarInfoDiskCache::oInvalid ||
(res.second->path != storePath && storePathToName(storePath) != "")) res.second->path != storePath)
throw InvalidPath(format("path '%s' is not valid") % storePath); throw InvalidPath("path '%s' is not valid", printStorePath(storePath));
} }
return callback(ref<const ValidPathInfo>(res.second)); return callback(ref<const ValidPathInfo>(res.second));
} }
@ -381,7 +331,7 @@ void Store::queryPathInfo(const Path & storePath,
auto callbackPtr = std::make_shared<decltype(callback)>(std::move(callback)); auto callbackPtr = std::make_shared<decltype(callback)>(std::move(callback));
queryPathInfoUncached(storePath, queryPathInfoUncached(storePath,
{[this, storePath, hashPart, callbackPtr](std::future<std::shared_ptr<const ValidPathInfo>> fut) { {[this, storePath{printStorePath(storePath)}, hashPart, callbackPtr](std::future<std::shared_ptr<const ValidPathInfo>> fut) {
try { try {
auto info = fut.get(); auto info = fut.get();
@ -394,9 +344,7 @@ void Store::queryPathInfo(const Path & storePath,
state_->pathInfoCache.upsert(hashPart, info); state_->pathInfoCache.upsert(hashPart, info);
} }
if (!info if (!info || info->path != parseStorePath(storePath)) {
|| (info->path != storePath && storePathToName(storePath) != ""))
{
stats.narInfoMissing++; stats.narInfoMissing++;
throw InvalidPath("path '%s' is not valid", storePath); throw InvalidPath("path '%s' is not valid", storePath);
} }
@ -407,27 +355,27 @@ void Store::queryPathInfo(const Path & storePath,
} }
PathSet Store::queryValidPaths(const PathSet & paths, SubstituteFlag maybeSubstitute) StorePathSet Store::queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute)
{ {
struct State struct State
{ {
size_t left; size_t left;
PathSet valid; StorePathSet valid;
std::exception_ptr exc; std::exception_ptr exc;
}; };
Sync<State> state_(State{paths.size(), PathSet()}); Sync<State> state_(State{paths.size(), StorePathSet()});
std::condition_variable wakeup; std::condition_variable wakeup;
ThreadPool pool; ThreadPool pool;
auto doQuery = [&](const Path & path ) { auto doQuery = [&](const Path & path) {
checkInterrupt(); checkInterrupt();
queryPathInfo(path, {[path, &state_, &wakeup](std::future<ref<const ValidPathInfo>> fut) { queryPathInfo(parseStorePath(path), {[path, this, &state_, &wakeup](std::future<ref<const ValidPathInfo>> fut) {
auto state(state_.lock()); auto state(state_.lock());
try { try {
auto info = fut.get(); auto info = fut.get();
state->valid.insert(path); state->valid.insert(parseStorePath(path));
} catch (InvalidPath &) { } catch (InvalidPath &) {
} catch (...) { } catch (...) {
state->exc = std::current_exception(); state->exc = std::current_exception();
@ -439,7 +387,7 @@ PathSet Store::queryValidPaths(const PathSet & paths, SubstituteFlag maybeSubsti
}; };
for (auto & path : paths) for (auto & path : paths)
pool.enqueue(std::bind(doQuery, path)); pool.enqueue(std::bind(doQuery, printStorePath(path))); // FIXME
pool.process(); pool.process();
@ -447,7 +395,7 @@ PathSet Store::queryValidPaths(const PathSet & paths, SubstituteFlag maybeSubsti
auto state(state_.lock()); auto state(state_.lock());
if (!state->left) { if (!state->left) {
if (state->exc) std::rethrow_exception(state->exc); if (state->exc) std::rethrow_exception(state->exc);
return state->valid; return std::move(state->valid);
} }
state.wait(wakeup); state.wait(wakeup);
} }
@ -457,13 +405,13 @@ PathSet Store::queryValidPaths(const PathSet & paths, SubstituteFlag maybeSubsti
/* Return a string accepted by decodeValidPathInfo() that /* Return a string accepted by decodeValidPathInfo() that
registers the specified paths as valid. Note: it's the registers the specified paths as valid. Note: it's the
responsibility of the caller to provide a closure. */ responsibility of the caller to provide a closure. */
string Store::makeValidityRegistration(const PathSet & paths, string Store::makeValidityRegistration(const StorePathSet & paths,
bool showDerivers, bool showHash) bool showDerivers, bool showHash)
{ {
string s = ""; string s = "";
for (auto & i : paths) { for (auto & i : paths) {
s += i + "\n"; s += printStorePath(i) + "\n";
auto info = queryPathInfo(i); auto info = queryPathInfo(i);
@ -472,31 +420,30 @@ string Store::makeValidityRegistration(const PathSet & paths,
s += (format("%1%\n") % info->narSize).str(); s += (format("%1%\n") % info->narSize).str();
} }
Path deriver = showDerivers ? info->deriver : ""; auto deriver = showDerivers && info->deriver ? printStorePath(*info->deriver) : "";
s += deriver + "\n"; s += deriver + "\n";
s += (format("%1%\n") % info->references.size()).str(); s += (format("%1%\n") % info->references.size()).str();
for (auto & j : info->references) for (auto & j : info->references)
s += j + "\n"; s += printStorePath(j) + "\n";
} }
return s; return s;
} }
void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const PathSet & storePaths, void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & storePaths,
bool includeImpureInfo, bool showClosureSize, AllowInvalidFlag allowInvalid) bool includeImpureInfo, bool showClosureSize, AllowInvalidFlag allowInvalid)
{ {
auto jsonList = jsonOut.list(); auto jsonList = jsonOut.list();
for (auto storePath : storePaths) { for (auto & storePath : storePaths) {
auto jsonPath = jsonList.object(); auto jsonPath = jsonList.object();
jsonPath.attr("path", storePath); jsonPath.attr("path", printStorePath(storePath));
try { try {
auto info = queryPathInfo(storePath); auto info = queryPathInfo(storePath);
storePath = info->path;
jsonPath jsonPath
.attr("narHash", info->narHash.to_string()) .attr("narHash", info->narHash.to_string())
@ -505,7 +452,7 @@ void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const PathSet & storePaths
{ {
auto jsonRefs = jsonPath.list("references"); auto jsonRefs = jsonPath.list("references");
for (auto & ref : info->references) for (auto & ref : info->references)
jsonRefs.elem(ref); jsonRefs.elem(printStorePath(ref));
} }
if (info->ca != "") if (info->ca != "")
@ -514,14 +461,14 @@ void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const PathSet & storePaths
std::pair<uint64_t, uint64_t> closureSizes; std::pair<uint64_t, uint64_t> closureSizes;
if (showClosureSize) { if (showClosureSize) {
closureSizes = getClosureSize(storePath); closureSizes = getClosureSize(info->path);
jsonPath.attr("closureSize", closureSizes.first); jsonPath.attr("closureSize", closureSizes.first);
} }
if (includeImpureInfo) { if (includeImpureInfo) {
if (info->deriver != "") if (info->deriver)
jsonPath.attr("deriver", info->deriver); jsonPath.attr("deriver", printStorePath(*info->deriver));
if (info->registrationTime) if (info->registrationTime)
jsonPath.attr("registrationTime", info->registrationTime); jsonPath.attr("registrationTime", info->registrationTime);
@ -557,10 +504,10 @@ void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const PathSet & storePaths
} }
std::pair<uint64_t, uint64_t> Store::getClosureSize(const Path & storePath) std::pair<uint64_t, uint64_t> Store::getClosureSize(const StorePath & storePath)
{ {
uint64_t totalNarSize = 0, totalDownloadSize = 0; uint64_t totalNarSize = 0, totalDownloadSize = 0;
PathSet closure; StorePathSet closure;
computeFSClosure(storePath, closure, false, false); computeFSClosure(storePath, closure, false, false);
for (auto & p : closure) { for (auto & p : closure) {
auto info = queryPathInfo(p); auto info = queryPathInfo(p);
@ -584,30 +531,34 @@ const Store::Stats & Store::getStats()
} }
void Store::buildPaths(const PathSet & paths, BuildMode buildMode) void Store::buildPaths(const std::vector<StorePathWithOutputs> & paths, BuildMode buildMode)
{ {
for (auto & path : paths) StorePathSet paths2;
if (isDerivation(path))
unsupported("buildPaths");
if (queryValidPaths(paths).size() != paths.size()) for (auto & path : paths) {
if (path.path.isDerivation())
unsupported("buildPaths");
paths2.insert(path.path.clone());
}
if (queryValidPaths(paths2).size() != paths2.size())
unsupported("buildPaths"); unsupported("buildPaths");
} }
void copyStorePath(ref<Store> srcStore, ref<Store> dstStore, void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
const Path & storePath, RepairFlag repair, CheckSigsFlag checkSigs) const StorePath & storePath, RepairFlag repair, CheckSigsFlag checkSigs)
{ {
auto srcUri = srcStore->getUri(); auto srcUri = srcStore->getUri();
auto dstUri = dstStore->getUri(); auto dstUri = dstStore->getUri();
Activity act(*logger, lvlInfo, actCopyPath, Activity act(*logger, lvlInfo, actCopyPath,
srcUri == "local" || srcUri == "daemon" srcUri == "local" || srcUri == "daemon"
? fmt("copying path '%s' to '%s'", storePath, dstUri) ? fmt("copying path '%s' to '%s'", srcStore->printStorePath(storePath), dstUri)
: dstUri == "local" || dstUri == "daemon" : dstUri == "local" || dstUri == "daemon"
? fmt("copying path '%s' from '%s'", storePath, srcUri) ? fmt("copying path '%s' from '%s'", srcStore->printStorePath(storePath), srcUri)
: fmt("copying path '%s' from '%s' to '%s'", storePath, srcUri, dstUri), : fmt("copying path '%s' from '%s' to '%s'", srcStore->printStorePath(storePath), srcUri, dstUri),
{storePath, srcUri, dstUri}); {srcStore->printStorePath(storePath), srcUri, dstUri});
PushActivity pact(act.id); PushActivity pact(act.id);
auto info = srcStore->queryPathInfo(storePath); auto info = srcStore->queryPathInfo(storePath);
@ -640,23 +591,23 @@ void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
total += len; total += len;
act.progress(total, info->narSize); act.progress(total, info->narSize);
}); });
srcStore->narFromPath({storePath}, wrapperSink); srcStore->narFromPath(storePath, wrapperSink);
}, [&]() { }, [&]() {
throw EndOfFile("NAR for '%s' fetched from '%s' is incomplete", storePath, srcStore->getUri()); throw EndOfFile("NAR for '%s' fetched from '%s' is incomplete", srcStore->printStorePath(storePath), srcStore->getUri());
}); });
dstStore->addToStore(*info, *source, repair, checkSigs); dstStore->addToStore(*info, *source, repair, checkSigs);
} }
void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const PathSet & storePaths, void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const StorePathSet & storePaths,
RepairFlag repair, CheckSigsFlag checkSigs, SubstituteFlag substitute) RepairFlag repair, CheckSigsFlag checkSigs, SubstituteFlag substitute)
{ {
PathSet valid = dstStore->queryValidPaths(storePaths, substitute); auto valid = dstStore->queryValidPaths(storePaths, substitute);
PathSet missing; PathSet missing;
for (auto & path : storePaths) for (auto & path : storePaths)
if (!valid.count(path)) missing.insert(path); if (!valid.count(path)) missing.insert(srcStore->printStorePath(path));
if (missing.empty()) return; if (missing.empty()) return;
@ -677,23 +628,25 @@ void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const PathSet & storePa
PathSet(missing.begin(), missing.end()), PathSet(missing.begin(), missing.end()),
[&](const Path & storePath) { [&](const Path & storePath) {
if (dstStore->isValidPath(storePath)) { if (dstStore->isValidPath(dstStore->parseStorePath(storePath))) {
nrDone++; nrDone++;
showProgress(); showProgress();
return PathSet(); return PathSet();
} }
auto info = srcStore->queryPathInfo(storePath); auto info = srcStore->queryPathInfo(srcStore->parseStorePath(storePath));
bytesExpected += info->narSize; bytesExpected += info->narSize;
act.setExpected(actCopyPath, bytesExpected); act.setExpected(actCopyPath, bytesExpected);
return info->references; return srcStore->printStorePathSet(info->references);
}, },
[&](const Path & storePath) { [&](const Path & storePathS) {
checkInterrupt(); checkInterrupt();
auto storePath = dstStore->parseStorePath(storePathS);
if (!dstStore->isValidPath(storePath)) { if (!dstStore->isValidPath(storePath)) {
MaintainCount<decltype(nrRunning)> mc(nrRunning); MaintainCount<decltype(nrRunning)> mc(nrRunning);
showProgress(); showProgress();
@ -703,7 +656,7 @@ void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const PathSet & storePa
nrFailed++; nrFailed++;
if (!settings.keepGoing) if (!settings.keepGoing)
throw e; throw e;
logger->log(lvlError, format("could not copy %s: %s") % storePath % e.what()); logger->log(lvlError, fmt("could not copy %s: %s", storePathS, e.what()));
showProgress(); showProgress();
return; return;
} }
@ -716,20 +669,36 @@ void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const PathSet & storePa
void copyClosure(ref<Store> srcStore, ref<Store> dstStore, void copyClosure(ref<Store> srcStore, ref<Store> dstStore,
const PathSet & storePaths, RepairFlag repair, CheckSigsFlag checkSigs, const StorePathSet & storePaths, RepairFlag repair, CheckSigsFlag checkSigs,
SubstituteFlag substitute) SubstituteFlag substitute)
{ {
PathSet closure; StorePathSet closure;
srcStore->computeFSClosure({storePaths}, closure); srcStore->computeFSClosure(storePaths, closure);
copyPaths(srcStore, dstStore, closure, repair, checkSigs, substitute); copyPaths(srcStore, dstStore, closure, repair, checkSigs, substitute);
} }
ValidPathInfo decodeValidPathInfo(std::istream & str, bool hashGiven) ValidPathInfo::ValidPathInfo(const ValidPathInfo & other)
: path(other.path.clone())
, deriver(other.deriver ? other.deriver->clone(): std::optional<StorePath>{})
, narHash(other.narHash)
, references(cloneStorePathSet(other.references))
, registrationTime(other.registrationTime)
, narSize(other.narSize)
, id(other.id)
, ultimate(other.ultimate)
, sigs(other.sigs)
, ca(other.ca)
{ {
ValidPathInfo info; }
getline(str, info.path);
if (str.eof()) { info.path = ""; return info; }
std::optional<ValidPathInfo> decodeValidPathInfo(const Store & store, std::istream & str, bool hashGiven)
{
std::string path;
getline(str, path);
if (str.eof()) { return {}; }
ValidPathInfo info(store.parseStorePath(path));
if (hashGiven) { if (hashGiven) {
string s; string s;
getline(str, s); getline(str, s);
@ -737,16 +706,29 @@ ValidPathInfo decodeValidPathInfo(std::istream & str, bool hashGiven)
getline(str, s); getline(str, s);
if (!string2Int(s, info.narSize)) throw Error("number expected"); if (!string2Int(s, info.narSize)) throw Error("number expected");
} }
getline(str, info.deriver); std::string deriver;
getline(str, deriver);
if (deriver != "") info.deriver = store.parseStorePath(deriver);
string s; int n; string s; int n;
getline(str, s); getline(str, s);
if (!string2Int(s, n)) throw Error("number expected"); if (!string2Int(s, n)) throw Error("number expected");
while (n--) { while (n--) {
getline(str, s); getline(str, s);
info.references.insert(s); info.references.insert(store.parseStorePath(s));
} }
if (!str || str.eof()) throw Error("missing input"); if (!str || str.eof()) throw Error("missing input");
return info; return std::optional<ValidPathInfo>(std::move(info));
}
std::string Store::showPaths(const StorePathSet & paths)
{
std::string s;
for (auto & i : paths) {
if (s.size() != 0) s += ", ";
s += "'" + printStorePath(i) + "'";
}
return s;
} }
@ -761,34 +743,34 @@ string showPaths(const PathSet & paths)
} }
std::string ValidPathInfo::fingerprint() const std::string ValidPathInfo::fingerprint(const Store & store) const
{ {
if (narSize == 0 || !narHash) if (narSize == 0 || !narHash)
throw Error(format("cannot calculate fingerprint of path '%s' because its size/hash is not known") throw Error("cannot calculate fingerprint of path '%s' because its size/hash is not known",
% path); store.printStorePath(path));
return return
"1;" + path + ";" "1;" + store.printStorePath(path) + ";"
+ narHash.to_string(Base32) + ";" + narHash.to_string(Base32) + ";"
+ std::to_string(narSize) + ";" + std::to_string(narSize) + ";"
+ concatStringsSep(",", references); + concatStringsSep(",", store.printStorePathSet(references));
} }
void ValidPathInfo::sign(const SecretKey & secretKey) void ValidPathInfo::sign(const Store & store, const SecretKey & secretKey)
{ {
sigs.insert(secretKey.signDetached(fingerprint())); sigs.insert(secretKey.signDetached(fingerprint(store)));
} }
bool ValidPathInfo::isContentAddressed(const Store & store) const bool ValidPathInfo::isContentAddressed(const Store & store) const
{ {
auto warn = [&]() { auto warn = [&]() {
printError(format("warning: path '%s' claims to be content-addressed but isn't") % path); printError("warning: path '%s' claims to be content-addressed but isn't", store.printStorePath(path));
}; };
if (hasPrefix(ca, "text:")) { if (hasPrefix(ca, "text:")) {
Hash hash(std::string(ca, 5)); Hash hash(std::string(ca, 5));
if (store.makeTextPath(storePathToName(path), hash, references) == path) if (store.makeTextPath(path.name(), hash, references) == path)
return true; return true;
else else
warn(); warn();
@ -797,9 +779,13 @@ bool ValidPathInfo::isContentAddressed(const Store & store) const
else if (hasPrefix(ca, "fixed:")) { else if (hasPrefix(ca, "fixed:")) {
bool recursive = ca.compare(6, 2, "r:") == 0; bool recursive = ca.compare(6, 2, "r:") == 0;
Hash hash(std::string(ca, recursive ? 8 : 6)); Hash hash(std::string(ca, recursive ? 8 : 6));
auto refs = references; auto refs = cloneStorePathSet(references);
replaceInSet(refs, path, std::string("self")); bool hasSelfReference = false;
if (store.makeFixedOutputPath(recursive, hash, storePathToName(path), refs) == path) if (refs.count(path)) {
hasSelfReference = true;
refs.erase(path);
}
if (store.makeFixedOutputPath(recursive, hash, path.name(), refs, hasSelfReference) == path)
return true; return true;
else else
warn(); warn();
@ -815,15 +801,15 @@ size_t ValidPathInfo::checkSignatures(const Store & store, const PublicKeys & pu
size_t good = 0; size_t good = 0;
for (auto & sig : sigs) for (auto & sig : sigs)
if (checkSignature(publicKeys, sig)) if (checkSignature(store, publicKeys, sig))
good++; good++;
return good; return good;
} }
bool ValidPathInfo::checkSignature(const PublicKeys & publicKeys, const std::string & sig) const bool ValidPathInfo::checkSignature(const Store & store, const PublicKeys & publicKeys, const std::string & sig) const
{ {
return verifyDetached(fingerprint(), sig, publicKeys); return verifyDetached(fingerprint(store), sig, publicKeys);
} }
@ -831,7 +817,7 @@ Strings ValidPathInfo::shortRefs() const
{ {
Strings refs; Strings refs;
for (auto & r : references) for (auto & r : references)
refs.push_back(baseNameOf(r)); refs.push_back(std::string(r.to_string()));
return refs; return refs;
} }
@ -944,7 +930,7 @@ static RegisterStoreImplementation regStore([](
const std::string & uri, const Store::Params & params) const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store> -> std::shared_ptr<Store>
{ {
switch (getStoreType(uri, get(params, "state", settings.nixStateDir))) { switch (getStoreType(uri, get(params, "state").value_or(settings.nixStateDir))) {
case tDaemon: case tDaemon:
return std::shared_ptr<Store>(std::make_shared<UDSRemoteStore>(params)); return std::shared_ptr<Store>(std::make_shared<UDSRemoteStore>(params));
case tLocal: { case tLocal: {

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "path.hh"
#include "hash.hh" #include "hash.hh"
#include "serialise.hh" #include "serialise.hh"
#include "crypto.hh" #include "crypto.hh"
@ -42,14 +43,11 @@ enum SubstituteFlag : bool { NoSubstitute = false, Substitute = true };
enum AllowInvalidFlag : bool { DisallowInvalid = false, AllowInvalid = true }; enum AllowInvalidFlag : bool { DisallowInvalid = false, AllowInvalid = true };
/* Size of the hash part of store paths, in base-32 characters. */
const size_t storePathHashLen = 32; // i.e. 160 bits
/* Magic header of exportPath() output (obsolete). */ /* Magic header of exportPath() output (obsolete). */
const uint32_t exportMagic = 0x4558494e; const uint32_t exportMagic = 0x4558494e;
typedef std::unordered_map<Path, std::unordered_set<std::string>> Roots; typedef std::unordered_map<StorePath, std::unordered_set<std::string>> Roots;
struct GCOptions struct GCOptions
@ -83,7 +81,7 @@ struct GCOptions
bool ignoreLiveness{false}; bool ignoreLiveness{false};
/* For `gcDeleteSpecific', the paths to delete. */ /* For `gcDeleteSpecific', the paths to delete. */
PathSet pathsToDelete; StorePathSet pathsToDelete;
/* Stop after at least `maxFreed' bytes have been freed. */ /* Stop after at least `maxFreed' bytes have been freed. */
unsigned long long maxFreed{std::numeric_limits<unsigned long long>::max()}; unsigned long long maxFreed{std::numeric_limits<unsigned long long>::max()};
@ -104,21 +102,21 @@ struct GCResults
struct SubstitutablePathInfo struct SubstitutablePathInfo
{ {
Path deriver; std::optional<StorePath> deriver;
PathSet references; StorePathSet references;
unsigned long long downloadSize; /* 0 = unknown or inapplicable */ unsigned long long downloadSize; /* 0 = unknown or inapplicable */
unsigned long long narSize; /* 0 = unknown */ unsigned long long narSize; /* 0 = unknown */
}; };
typedef std::map<Path, SubstitutablePathInfo> SubstitutablePathInfos; typedef std::map<StorePath, SubstitutablePathInfo> SubstitutablePathInfos;
struct ValidPathInfo struct ValidPathInfo
{ {
Path path; StorePath path;
Path deriver; std::optional<StorePath> deriver;
Hash narHash; Hash narHash;
PathSet references; StorePathSet references;
time_t registrationTime = 0; time_t registrationTime = 0;
uint64_t narSize = 0; // 0 = unknown uint64_t narSize = 0; // 0 = unknown
uint64_t id; // internal use only uint64_t id; // internal use only
@ -143,7 +141,7 @@ struct ValidPathInfo
Ideally, the content-addressability assertion would just be a Ideally, the content-addressability assertion would just be a
Boolean, and the store path would be computed from Boolean, and the store path would be computed from
storePathToName(path), narHash and references. However, the name component, narHash and references. However,
1) we've accumulated several types of content-addressed paths 1) we've accumulated several types of content-addressed paths
over the years; and 2) fixed-output derivations support over the years; and 2) fixed-output derivations support
multiple hash algorithms and serialisation methods (flat file multiple hash algorithms and serialisation methods (flat file
@ -171,9 +169,9 @@ struct ValidPathInfo
the NAR, and the sorted references. The size field is strictly the NAR, and the sorted references. The size field is strictly
speaking superfluous, but might prevent endless/excessive data speaking superfluous, but might prevent endless/excessive data
attacks. */ attacks. */
std::string fingerprint() const; std::string fingerprint(const Store & store) const;
void sign(const SecretKey & secretKey); void sign(const Store & store, const SecretKey & secretKey);
/* Return true iff the path is verifiably content-addressed. */ /* Return true iff the path is verifiably content-addressed. */
bool isContentAddressed(const Store & store) const; bool isContentAddressed(const Store & store) const;
@ -186,10 +184,13 @@ struct ValidPathInfo
size_t checkSignatures(const Store & store, const PublicKeys & publicKeys) const; size_t checkSignatures(const Store & store, const PublicKeys & publicKeys) const;
/* Verify a single signature. */ /* Verify a single signature. */
bool checkSignature(const PublicKeys & publicKeys, const std::string & sig) const; bool checkSignature(const Store & store, const PublicKeys & publicKeys, const std::string & sig) const;
Strings shortRefs() const; Strings shortRefs() const;
ValidPathInfo(StorePath && path) : path(std::move(path)) { }
explicit ValidPathInfo(const ValidPathInfo & other);
virtual ~ValidPathInfo() { } virtual ~ValidPathInfo() { }
}; };
@ -240,6 +241,23 @@ struct BuildResult
}; };
struct StorePathWithOutputs
{
StorePath path;
std::set<std::string> outputs;
StorePathWithOutputs(const StorePath & path, const std::set<std::string> & outputs = {})
: path(path.clone()), outputs(outputs)
{ }
StorePathWithOutputs(const StorePathWithOutputs & other)
: path(other.path.clone()), outputs(other.outputs)
{ }
std::string to_string(const Store & store) const;
};
class Store : public std::enable_shared_from_this<Store>, public Config class Store : public std::enable_shared_from_this<Store>, public Config
{ {
public: public:
@ -258,6 +276,7 @@ protected:
struct State struct State
{ {
// FIXME: fix key
LRUCache<std::string, std::shared_ptr<const ValidPathInfo>> pathInfoCache; LRUCache<std::string, std::shared_ptr<const ValidPathInfo>> pathInfoCache;
}; };
@ -273,6 +292,24 @@ public:
virtual std::string getUri() = 0; virtual std::string getUri() = 0;
StorePath parseStorePath(std::string_view path) const;
std::string printStorePath(const StorePath & path) const;
// FIXME: remove
StorePathSet parseStorePathSet(const PathSet & paths) const;
PathSet printStorePathSet(const StorePathSet & path) const;
/* Split a string specifying a derivation and a set of outputs
(/nix/store/hash-foo!out1,out2,...) into the derivation path
and the outputs. */
StorePathWithOutputs parseDrvPathWithOutputs(const string & s);
/* Display a set of paths in human-readable form (i.e., between quotes
and separated by commas). */
std::string showPaths(const StorePathSet & paths);
/* Return true if path is in the Nix store (but not the Nix /* Return true if path is in the Nix store (but not the Nix
store itself). */ store itself). */
bool isInStore(const Path & path) const; bool isInStore(const Path & path) const;
@ -281,9 +318,6 @@ public:
the Nix store. */ the Nix store. */
bool isStorePath(const Path & path) const; bool isStorePath(const Path & path) const;
/* Throw an exception if path is not a store path. */
void assertStorePath(const Path & path) const;
/* Chop off the parts after the top-level store name, e.g., /* Chop off the parts after the top-level store name, e.g.,
/nix/store/abcd-foo/bar => /nix/store/abcd-foo. */ /nix/store/abcd-foo/bar => /nix/store/abcd-foo. */
Path toStorePath(const Path & path) const; Path toStorePath(const Path & path) const;
@ -293,26 +327,27 @@ public:
/* Same as followLinksToStore(), but apply toStorePath() to the /* Same as followLinksToStore(), but apply toStorePath() to the
result. */ result. */
Path followLinksToStorePath(const Path & path) const; StorePath followLinksToStorePath(const Path & path) const;
/* Constructs a unique store path name. */ /* Constructs a unique store path name. */
Path makeStorePath(const string & type, StorePath makeStorePath(const string & type,
const Hash & hash, const string & name) const; const Hash & hash, std::string_view name) const;
Path makeOutputPath(const string & id, StorePath makeOutputPath(const string & id,
const Hash & hash, const string & name) const; const Hash & hash, std::string_view name) const;
Path makeFixedOutputPath(bool recursive, StorePath makeFixedOutputPath(bool recursive,
const Hash & hash, const string & name, const Hash & hash, std::string_view name,
const PathSet & references = {}) const; const StorePathSet & references = {},
bool hasSelfReference = false) const;
Path makeTextPath(const string & name, const Hash & hash, StorePath makeTextPath(std::string_view name, const Hash & hash,
const PathSet & references) const; const StorePathSet & references) const;
/* This is the preparatory part of addToStore(); it computes the /* This is the preparatory part of addToStore(); it computes the
store path to which srcPath is to be copied. Returns the store store path to which srcPath is to be copied. Returns the store
path and the cryptographic hash of the contents of srcPath. */ path and the cryptographic hash of the contents of srcPath. */
std::pair<Path, Hash> computeStorePathForPath(const string & name, std::pair<StorePath, Hash> computeStorePathForPath(std::string_view name,
const Path & srcPath, bool recursive = true, const Path & srcPath, bool recursive = true,
HashType hashAlgo = htSHA256, PathFilter & filter = defaultPathFilter) const; HashType hashAlgo = htSHA256, PathFilter & filter = defaultPathFilter) const;
@ -330,21 +365,21 @@ public:
simply yield a different store path, so other users wouldn't be simply yield a different store path, so other users wouldn't be
affected), but it has some backwards compatibility issues (the affected), but it has some backwards compatibility issues (the
hashing scheme changes), so I'm not doing that for now. */ hashing scheme changes), so I'm not doing that for now. */
Path computeStorePathForText(const string & name, const string & s, StorePath computeStorePathForText(const string & name, const string & s,
const PathSet & references) const; const StorePathSet & references) const;
/* Check whether a path is valid. */ /* Check whether a path is valid. */
bool isValidPath(const Path & path); bool isValidPath(const StorePath & path);
protected: protected:
virtual bool isValidPathUncached(const Path & path); virtual bool isValidPathUncached(const StorePath & path);
public: public:
/* Query which of the given paths is valid. Optionally, try to /* Query which of the given paths is valid. Optionally, try to
substitute missing paths. */ substitute missing paths. */
virtual PathSet queryValidPaths(const PathSet & paths, virtual StorePathSet queryValidPaths(const StorePathSet & paths,
SubstituteFlag maybeSubstitute = NoSubstitute); SubstituteFlag maybeSubstitute = NoSubstitute);
/* Query the set of all valid paths. Note that for some store /* Query the set of all valid paths. Note that for some store
@ -352,54 +387,54 @@ public:
(i.e. you'll get /nix/store/<hash> rather than (i.e. you'll get /nix/store/<hash> rather than
/nix/store/<hash>-<name>). Use queryPathInfo() to obtain the /nix/store/<hash>-<name>). Use queryPathInfo() to obtain the
full store path. */ full store path. */
virtual PathSet queryAllValidPaths() virtual StorePathSet queryAllValidPaths()
{ unsupported("queryAllValidPaths"); } { unsupported("queryAllValidPaths"); }
/* Query information about a valid path. It is permitted to omit /* Query information about a valid path. It is permitted to omit
the name part of the store path. */ the name part of the store path. */
ref<const ValidPathInfo> queryPathInfo(const Path & path); ref<const ValidPathInfo> queryPathInfo(const StorePath & path);
/* Asynchronous version of queryPathInfo(). */ /* Asynchronous version of queryPathInfo(). */
void queryPathInfo(const Path & path, void queryPathInfo(const StorePath & path,
Callback<ref<const ValidPathInfo>> callback) noexcept; Callback<ref<const ValidPathInfo>> callback) noexcept;
protected: protected:
virtual void queryPathInfoUncached(const Path & path, virtual void queryPathInfoUncached(const StorePath & path,
Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept = 0; Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept = 0;
public: public:
/* Queries the set of incoming FS references for a store path. /* Queries the set of incoming FS references for a store path.
The result is not cleared. */ The result is not cleared. */
virtual void queryReferrers(const Path & path, PathSet & referrers) virtual void queryReferrers(const StorePath & path, StorePathSet & referrers)
{ unsupported("queryReferrers"); } { unsupported("queryReferrers"); }
/* Return all currently valid derivations that have `path' as an /* Return all currently valid derivations that have `path' as an
output. (Note that the result of `queryDeriver()' is the output. (Note that the result of `queryDeriver()' is the
derivation that was actually used to produce `path', which may derivation that was actually used to produce `path', which may
not exist anymore.) */ not exist anymore.) */
virtual PathSet queryValidDerivers(const Path & path) { return {}; }; virtual StorePathSet queryValidDerivers(const StorePath & path) { return {}; };
/* Query the outputs of the derivation denoted by `path'. */ /* Query the outputs of the derivation denoted by `path'. */
virtual PathSet queryDerivationOutputs(const Path & path) virtual StorePathSet queryDerivationOutputs(const StorePath & path)
{ unsupported("queryDerivationOutputs"); } { unsupported("queryDerivationOutputs"); }
/* Query the output names of the derivation denoted by `path'. */ /* Query the output names of the derivation denoted by `path'. */
virtual StringSet queryDerivationOutputNames(const Path & path) virtual StringSet queryDerivationOutputNames(const StorePath & path)
{ unsupported("queryDerivationOutputNames"); } { unsupported("queryDerivationOutputNames"); }
/* Query the full store path given the hash part of a valid store /* Query the full store path given the hash part of a valid store
path, or "" if the path doesn't exist. */ path, or empty if the path doesn't exist. */
virtual Path queryPathFromHashPart(const string & hashPart) = 0; virtual std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) = 0;
/* Query which of the given paths have substitutes. */ /* Query which of the given paths have substitutes. */
virtual PathSet querySubstitutablePaths(const PathSet & paths) { return {}; }; virtual StorePathSet querySubstitutablePaths(const StorePathSet & paths) { return {}; };
/* Query substitute info (i.e. references, derivers and download /* Query substitute info (i.e. references, derivers and download
sizes) of a set of paths. If a path does not have substitute sizes) of a set of paths. If a path does not have substitute
info, it's omitted from the resulting infos map. */ info, it's omitted from the resulting infos map. */
virtual void querySubstitutablePathInfos(const PathSet & paths, virtual void querySubstitutablePathInfos(const StorePathSet & paths,
SubstitutablePathInfos & infos) { return; }; SubstitutablePathInfos & infos) { return; };
virtual bool wantMassQuery() { return false; } virtual bool wantMassQuery() { return false; }
@ -418,12 +453,12 @@ public:
validity the resulting path. The resulting path is returned. validity the resulting path. The resulting path is returned.
The function object `filter' can be used to exclude files (see The function object `filter' can be used to exclude files (see
libutil/archive.hh). */ libutil/archive.hh). */
virtual Path addToStore(const string & name, const Path & srcPath, virtual StorePath addToStore(const string & name, const Path & srcPath,
bool recursive = true, HashType hashAlgo = htSHA256, bool recursive = true, HashType hashAlgo = htSHA256,
PathFilter & filter = defaultPathFilter, RepairFlag repair = NoRepair) = 0; PathFilter & filter = defaultPathFilter, RepairFlag repair = NoRepair) = 0;
// FIXME: remove? // FIXME: remove?
virtual Path addToStoreFromDump(const string & dump, const string & name, virtual StorePath addToStoreFromDump(const string & dump, const string & name,
bool recursive = true, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair) bool recursive = true, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair)
{ {
throw Error("addToStoreFromDump() is not supported by this store"); throw Error("addToStoreFromDump() is not supported by this store");
@ -431,11 +466,11 @@ public:
/* Like addToStore, but the contents written to the output path is /* Like addToStore, but the contents written to the output path is
a regular file containing the given string. */ a regular file containing the given string. */
virtual Path addTextToStore(const string & name, const string & s, virtual StorePath addTextToStore(const string & name, const string & s,
const PathSet & references, RepairFlag repair = NoRepair) = 0; const StorePathSet & references, RepairFlag repair = NoRepair) = 0;
/* Write a NAR dump of a store path. */ /* Write a NAR dump of a store path. */
virtual void narFromPath(const Path & path, Sink & sink) = 0; virtual void narFromPath(const StorePath & path, Sink & sink) = 0;
/* For each path, if it's a derivation, build it. Building a /* For each path, if it's a derivation, build it. Building a
derivation means ensuring that the output paths are valid. If derivation means ensuring that the output paths are valid. If
@ -445,22 +480,24 @@ public:
output paths can be created by running the builder, after output paths can be created by running the builder, after
recursively building any sub-derivations. For inputs that are recursively building any sub-derivations. For inputs that are
not derivations, substitute them. */ not derivations, substitute them. */
virtual void buildPaths(const PathSet & paths, BuildMode buildMode = bmNormal); virtual void buildPaths(
const std::vector<StorePathWithOutputs> & paths,
BuildMode buildMode = bmNormal);
/* Build a single non-materialized derivation (i.e. not from an /* Build a single non-materialized derivation (i.e. not from an
on-disk .drv file). Note that drvPath is only used for on-disk .drv file). Note that drvPath is only used for
informational purposes. */ informational purposes. */
virtual BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv, virtual BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode = bmNormal) = 0; BuildMode buildMode = bmNormal) = 0;
/* Ensure that a path is valid. If it is not currently valid, it /* Ensure that a path is valid. If it is not currently valid, it
may be made valid by running a substitute (if defined for the may be made valid by running a substitute (if defined for the
path). */ path). */
virtual void ensurePath(const Path & path) = 0; virtual void ensurePath(const StorePath & path) = 0;
/* Add a store path as a temporary root of the garbage collector. /* Add a store path as a temporary root of the garbage collector.
The root disappears as soon as we exit. */ The root disappears as soon as we exit. */
virtual void addTempRoot(const Path & path) virtual void addTempRoot(const StorePath & path)
{ unsupported("addTempRoot"); } { unsupported("addTempRoot"); }
/* Add an indirect root, which is merely a symlink to `path' from /* Add an indirect root, which is merely a symlink to `path' from
@ -506,7 +543,7 @@ public:
/* Return a string representing information about the path that /* Return a string representing information about the path that
can be loaded into the database using `nix-store --load-db' or can be loaded into the database using `nix-store --load-db' or
`nix-store --register-validity'. */ `nix-store --register-validity'. */
string makeValidityRegistration(const PathSet & paths, string makeValidityRegistration(const StorePathSet & paths,
bool showDerivers, bool showHash); bool showDerivers, bool showHash);
/* Write a JSON representation of store path metadata, such as the /* Write a JSON representation of store path metadata, such as the
@ -514,14 +551,14 @@ public:
variable elements such as the registration time are variable elements such as the registration time are
included. If showClosureSize is true, the closure size of included. If showClosureSize is true, the closure size of
each path is included. */ each path is included. */
void pathInfoToJSON(JSONPlaceholder & jsonOut, const PathSet & storePaths, void pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & storePaths,
bool includeImpureInfo, bool showClosureSize, bool includeImpureInfo, bool showClosureSize,
AllowInvalidFlag allowInvalid = DisallowInvalid); AllowInvalidFlag allowInvalid = DisallowInvalid);
/* Return the size of the closure of the specified path, that is, /* Return the size of the closure of the specified path, that is,
the sum of the size of the NAR serialisation of each path in the sum of the size of the NAR serialisation of each path in
the closure. */ the closure. */
std::pair<uint64_t, uint64_t> getClosureSize(const Path & storePath); std::pair<uint64_t, uint64_t> getClosureSize(const StorePath & storePath);
/* Optimise the disk space usage of the Nix store by hard-linking files /* Optimise the disk space usage of the Nix store by hard-linking files
with the same contents. */ with the same contents. */
@ -537,14 +574,14 @@ public:
/* Add signatures to the specified store path. The signatures are /* Add signatures to the specified store path. The signatures are
not verified. */ not verified. */
virtual void addSignatures(const Path & storePath, const StringSet & sigs) virtual void addSignatures(const StorePath & storePath, const StringSet & sigs)
{ unsupported("addSignatures"); } { unsupported("addSignatures"); }
/* Utility functions. */ /* Utility functions. */
/* Read a derivation, after ensuring its existence through /* Read a derivation, after ensuring its existence through
ensurePath(). */ ensurePath(). */
Derivation derivationFromPath(const Path & drvPath); Derivation derivationFromPath(const StorePath & drvPath);
/* Place in `out' the set of all store paths in the file system /* Place in `out' the set of all store paths in the file system
closure of `storePath'; that is, all paths than can be directly closure of `storePath'; that is, all paths than can be directly
@ -553,36 +590,36 @@ public:
`storePath' is returned; that is, the closures under the `storePath' is returned; that is, the closures under the
`referrers' relation instead of the `references' relation is `referrers' relation instead of the `references' relation is
returned. */ returned. */
virtual void computeFSClosure(const PathSet & paths, virtual void computeFSClosure(const StorePathSet & paths,
PathSet & out, bool flipDirection = false, StorePathSet & out, bool flipDirection = false,
bool includeOutputs = false, bool includeDerivers = false); bool includeOutputs = false, bool includeDerivers = false);
void computeFSClosure(const Path & path, void computeFSClosure(const StorePath & path,
PathSet & out, bool flipDirection = false, StorePathSet & out, bool flipDirection = false,
bool includeOutputs = false, bool includeDerivers = false); bool includeOutputs = false, bool includeDerivers = false);
/* Given a set of paths that are to be built, return the set of /* Given a set of paths that are to be built, return the set of
derivations that will be built, and the set of output paths derivations that will be built, and the set of output paths
that will be substituted. */ that will be substituted. */
virtual void queryMissing(const PathSet & targets, virtual void queryMissing(const std::vector<StorePathWithOutputs> & targets,
PathSet & willBuild, PathSet & willSubstitute, PathSet & unknown, StorePathSet & willBuild, StorePathSet & willSubstitute, StorePathSet & unknown,
unsigned long long & downloadSize, unsigned long long & narSize); unsigned long long & downloadSize, unsigned long long & narSize);
/* Sort a set of paths topologically under the references /* Sort a set of paths topologically under the references
relation. If p refers to q, then p precedes q in this list. */ relation. If p refers to q, then p precedes q in this list. */
Paths topoSortPaths(const PathSet & paths); StorePaths topoSortPaths(const StorePathSet & paths);
/* Export multiple paths in the format expected by nix-store /* Export multiple paths in the format expected by nix-store
--import. */ --import. */
void exportPaths(const Paths & paths, Sink & sink); void exportPaths(const StorePathSet & paths, Sink & sink);
void exportPath(const Path & path, Sink & sink); void exportPath(const StorePath & path, Sink & sink);
/* Import a sequence of NAR dumps created by exportPaths() into /* Import a sequence of NAR dumps created by exportPaths() into
the Nix store. Optionally, the contents of the NARs are the Nix store. Optionally, the contents of the NARs are
preloaded into the specified FS accessor to speed up subsequent preloaded into the specified FS accessor to speed up subsequent
access. */ access. */
Paths importPaths(Source & source, std::shared_ptr<FSAccessor> accessor, StorePaths importPaths(Source & source, std::shared_ptr<FSAccessor> accessor,
CheckSigsFlag checkSigs = CheckSigs); CheckSigsFlag checkSigs = CheckSigs);
struct Stats struct Stats
@ -606,7 +643,7 @@ public:
/* Return the build log of the specified store path, if available, /* Return the build log of the specified store path, if available,
or null otherwise. */ or null otherwise. */
virtual std::shared_ptr<std::string> getBuildLog(const Path & path) virtual std::shared_ptr<std::string> getBuildLog(const StorePath & path)
{ return nullptr; } { return nullptr; }
/* Hack to allow long-running processes like hydra-queue-runner to /* Hack to allow long-running processes like hydra-queue-runner to
@ -672,11 +709,11 @@ public:
LocalFSStore(const Params & params); LocalFSStore(const Params & params);
void narFromPath(const Path & path, Sink & sink) override; void narFromPath(const StorePath & path, Sink & sink) override;
ref<FSAccessor> getFSAccessor() override; ref<FSAccessor> getFSAccessor() override;
/* Register a permanent GC root. */ /* Register a permanent GC root. */
Path addPermRoot(const Path & storePath, Path addPermRoot(const StorePath & storePath,
const Path & gcRoot, bool indirect, bool allowOutsideRootsDir = false); const Path & gcRoot, bool indirect, bool allowOutsideRootsDir = false);
virtual Path getRealStoreDir() { return storeDir; } virtual Path getRealStoreDir() { return storeDir; }
@ -687,25 +724,17 @@ public:
return getRealStoreDir() + "/" + std::string(storePath, storeDir.size() + 1); return getRealStoreDir() + "/" + std::string(storePath, storeDir.size() + 1);
} }
std::shared_ptr<std::string> getBuildLog(const Path & path) override; std::shared_ptr<std::string> getBuildLog(const StorePath & path) override;
}; };
/* Extract the name part of the given store path. */
string storePathToName(const Path & path);
/* Extract the hash part of the given store path. */ /* Extract the hash part of the given store path. */
string storePathToHash(const Path & path); string storePathToHash(const Path & path);
/* Check whether name is a valid store path name part, i.e. contains
only the characters [a-zA-Z0-9\+\-\.\_\?\=] and doesn't start with
a dot. */
void checkStoreName(const string & name);
/* 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,
const Path & storePath, RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs); const StorePath & storePath, RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs);
/* Copy store paths from one store to another. The paths may be copied /* Copy store paths from one store to another. The paths may be copied
@ -713,7 +742,7 @@ void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
(i.e. if A is a reference of B, then A is copied before B), but (i.e. if A is a reference of B, then A is copied before B), but
the set of store paths is not automatically closed; use the set of store paths is not automatically closed; use
copyClosure() for that. */ copyClosure() for that. */
void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const PathSet & storePaths, void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const StorePathSet & storePaths,
RepairFlag repair = NoRepair, RepairFlag repair = NoRepair,
CheckSigsFlag checkSigs = CheckSigs, CheckSigsFlag checkSigs = CheckSigs,
SubstituteFlag substitute = NoSubstitute); SubstituteFlag substitute = NoSubstitute);
@ -721,7 +750,7 @@ void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const PathSet & storePa
/* Copy the closure of the specified paths from one store to another. */ /* Copy the closure of the specified paths from one store to another. */
void copyClosure(ref<Store> srcStore, ref<Store> dstStore, void copyClosure(ref<Store> srcStore, ref<Store> dstStore,
const PathSet & storePaths, const StorePathSet & storePaths,
RepairFlag repair = NoRepair, RepairFlag repair = NoRepair,
CheckSigsFlag checkSigs = CheckSigs, CheckSigsFlag checkSigs = CheckSigs,
SubstituteFlag substitute = NoSubstitute); SubstituteFlag substitute = NoSubstitute);
@ -804,7 +833,9 @@ struct RegisterStoreImplementation
string showPaths(const PathSet & paths); string showPaths(const PathSet & paths);
ValidPathInfo decodeValidPathInfo(std::istream & str, std::optional<ValidPathInfo> decodeValidPathInfo(
const Store & store,
std::istream & str,
bool hashGiven = false); bool hashGiven = false);

View file

@ -65,8 +65,9 @@ typedef enum {
class Store; class Store;
struct Source; struct Source;
Path readStorePath(Store & store, Source & from); template<class T> T readStorePaths(const Store & store, Source & from);
template<class T> T readStorePaths(Store & store, Source & from);
void writeStorePaths(const Store & store, Sink & out, const StorePathSet & paths);
} }

View file

@ -1,12 +1,18 @@
#include "logging.hh" #include "logging.hh"
#include "rust-ffi.hh" #include "rust-ffi.hh"
namespace nix {
extern "C" std::exception_ptr * make_error(rust::StringSlice s) extern "C" std::exception_ptr * make_error(rust::StringSlice s)
{ {
// FIXME: leak // FIXME: leak
return new std::exception_ptr(std::make_exception_ptr(Error(std::string(s.ptr, s.size)))); return new std::exception_ptr(std::make_exception_ptr(nix::Error(std::string(s.ptr, s.size))));
}
namespace rust {
std::ostream & operator << (std::ostream & str, const String & s)
{
str << (std::string_view) s;
return str;
} }
} }

View file

@ -1,16 +1,91 @@
#pragma once
#include "serialise.hh" #include "serialise.hh"
#include <string_view>
#include <cstring>
#include <array>
namespace rust { namespace rust {
// Depending on the internal representation of Rust slices is slightly typedef void (*DropFun)(void *);
// evil...
/* A Rust value of N bytes. It can be moved but not copied. When it
goes out of scope, the C++ destructor will run the drop
function. */
template<std::size_t N, DropFun drop>
struct Value
{
protected:
std::array<char, N> raw;
~Value()
{
if (!isEvacuated()) {
drop(this);
evacuate();
}
}
// Must not be called directly.
Value()
{ }
Value(Value && other)
: raw(other.raw)
{
other.evacuate();
}
void operator =(Value && other)
{
if (!isEvacuated())
drop(this);
raw = other.raw;
other.evacuate();
}
private:
/* FIXME: optimize these (ideally in such a way that the compiler
can elide most calls to evacuate() / isEvacuated(). */
inline void evacuate()
{
for (auto & i : raw) i = 0;
}
inline bool isEvacuated()
{
for (auto & i : raw)
if (i != 0) return false;
return true;
}
};
/* A Rust vector. */
template<typename T, DropFun drop>
struct Vec : Value<3 * sizeof(void *), drop>
{
inline size_t size() const
{
return ((const size_t *) &this->raw)[2];
}
const T * data() const
{
return ((const T * *) &this->raw)[0];
}
};
/* A Rust slice. */
template<typename T> template<typename T>
struct Slice struct Slice
{ {
T * ptr; const T * ptr;
size_t size; size_t size;
Slice(T * ptr, size_t size) : ptr(ptr), size(size) Slice(const T * ptr, size_t size) : ptr(ptr), size(size)
{ {
assert(ptr); assert(ptr);
} }
@ -18,9 +93,44 @@ struct Slice
struct StringSlice : Slice<char> struct StringSlice : Slice<char>
{ {
StringSlice(const std::string & s): Slice((char *) s.data(), s.size()) {} StringSlice(const std::string & s): Slice(s.data(), s.size()) {}
explicit StringSlice(std::string_view s): Slice(s.data(), s.size()) {}
StringSlice(const char * s): Slice(s, strlen(s)) {}
operator std::string_view() const
{
return std::string_view(ptr, size);
}
}; };
/* A Rust string. */
struct String;
extern "C" {
void ffi_String_new(StringSlice s, String * out);
void ffi_String_drop(void * s);
}
struct String : Vec<char, ffi_String_drop>
{
String(std::string_view s)
{
ffi_String_new(StringSlice(s), this);
}
String(const char * s)
: String({s, std::strlen(s)})
{
}
operator std::string_view() const
{
return std::string_view(data(), size());
}
};
std::ostream & operator << (std::ostream & str, const String & s);
struct Source struct Source
{ {
size_t (*fun)(void * source_this, rust::Slice<uint8_t> data); size_t (*fun)(void * source_this, rust::Slice<uint8_t> data);
@ -33,7 +143,7 @@ struct Source
// FIXME: how to propagate exceptions? // FIXME: how to propagate exceptions?
static size_t sourceWrapper(void * _this, rust::Slice<uint8_t> data) static size_t sourceWrapper(void * _this, rust::Slice<uint8_t> data)
{ {
auto n = ((nix::Source *) _this)->read(data.ptr, data.size); auto n = ((nix::Source *) _this)->read((unsigned char *) data.ptr, data.size);
return n; return n;
} }
}; };
@ -49,11 +159,20 @@ struct Result
std::exception_ptr * exc; std::exception_ptr * exc;
}; };
~Result()
{
if (tag == 0)
data.~T();
else if (tag == 1)
// FIXME: don't leak exc
;
}
/* Rethrow the wrapped exception or return the wrapped value. */ /* Rethrow the wrapped exception or return the wrapped value. */
T unwrap() T unwrap()
{ {
if (tag == 0) if (tag == 0)
return data; return std::move(data);
else if (tag == 1) else if (tag == 1)
std::rethrow_exception(*exc); std::rethrow_exception(*exc);
else else

View file

@ -17,7 +17,7 @@ void unpackTarfile(Source & source, const Path & destDir)
void unpackTarfile(const Path & tarFile, const Path & destDir, void unpackTarfile(const Path & tarFile, const Path & destDir,
std::optional<std::string> baseName) std::optional<std::string> baseName)
{ {
if (!baseName) baseName = baseNameOf(tarFile); if (!baseName) baseName = std::string(baseNameOf(tarFile));
auto source = sinkToSource([&](Sink & sink) { auto source = sinkToSource([&](Sink & sink) {
// FIXME: look at first few bytes to determine compression type. // FIXME: look at first few bytes to determine compression type.

View file

@ -188,22 +188,22 @@ Path dirOf(const Path & path)
} }
string baseNameOf(const Path & path) std::string_view baseNameOf(std::string_view path)
{ {
if (path.empty()) if (path.empty())
return ""; return "";
Path::size_type last = path.length() - 1; auto last = path.size() - 1;
if (path[last] == '/' && last > 0) if (path[last] == '/' && last > 0)
last -= 1; last -= 1;
Path::size_type pos = path.rfind('/', last); auto pos = path.rfind('/', last);
if (pos == string::npos) if (pos == string::npos)
pos = 0; pos = 0;
else else
pos += 1; pos += 1;
return string(path, pos, last - pos + 1); return path.substr(pos, last - pos + 1);
} }
@ -1302,9 +1302,10 @@ bool hasPrefix(const string & s, const string & prefix)
} }
bool hasSuffix(const string & s, const string & suffix) bool hasSuffix(std::string_view s, std::string_view suffix)
{ {
return s.size() >= suffix.size() && string(s, s.size() - suffix.size()) == suffix; return s.size() >= suffix.size()
&& s.substr(s.size() - suffix.size()) == suffix;
} }

View file

@ -62,7 +62,7 @@ Path dirOf(const Path & path);
/* Return the base name of the given canonical path, i.e., everything /* Return the base name of the given canonical path, i.e., everything
following the final `/'. */ following the final `/'. */
string baseNameOf(const Path & path); std::string_view baseNameOf(std::string_view path);
/* Check whether 'path' is a descendant of 'dir'. */ /* Check whether 'path' is a descendant of 'dir'. */
bool isInDir(const Path & path, const Path & dir); bool isInDir(const Path & path, const Path & dir);
@ -407,7 +407,7 @@ bool hasPrefix(const string & s, const string & prefix);
/* Return true iff `s' ends in `suffix'. */ /* Return true iff `s' ends in `suffix'. */
bool hasSuffix(const string & s, const string & suffix); bool hasSuffix(std::string_view s, std::string_view suffix);
/* Convert a string to lower case. */ /* Convert a string to lower case. */
@ -450,10 +450,10 @@ string base64Decode(const string & s);
/* Get a value for the specified key from an associate container, or a /* Get a value for the specified key from an associate container, or a
default value if the key doesn't exist. */ default value if the key doesn't exist. */
template <class T> template <class T>
string get(const T & map, const string & key, const string & def = "") std::optional<std::string> get(const T & map, const std::string & key)
{ {
auto i = map.find(key); auto i = map.find(key);
return i == map.end() ? def : i->second; return i == map.end() ? std::optional<std::string>() : i->second;
} }

View file

@ -317,11 +317,11 @@ static void _main(int argc, char * * argv)
state->printStats(); state->printStats();
auto buildPaths = [&](const PathSet & paths) { auto buildPaths = [&](const std::vector<StorePathWithOutputs> & paths) {
/* Note: we do this even when !printMissing to efficiently /* Note: we do this even when !printMissing to efficiently
fetch binary cache data. */ fetch binary cache data. */
unsigned long long downloadSize, narSize; unsigned long long downloadSize, narSize;
PathSet willBuild, willSubstitute, unknown; StorePathSet willBuild, willSubstitute, unknown;
store->queryMissing(paths, store->queryMissing(paths,
willBuild, willSubstitute, unknown, downloadSize, narSize); willBuild, willSubstitute, unknown, downloadSize, narSize);
@ -337,9 +337,9 @@ static void _main(int argc, char * * argv)
throw UsageError("nix-shell requires a single derivation"); throw UsageError("nix-shell requires a single derivation");
auto & drvInfo = drvs.front(); auto & drvInfo = drvs.front();
auto drv = store->derivationFromPath(drvInfo.queryDrvPath()); auto drv = store->derivationFromPath(store->parseStorePath(drvInfo.queryDrvPath()));
PathSet pathsToBuild; std::vector<StorePathWithOutputs> pathsToBuild;
/* Figure out what bash shell to use. If $NIX_BUILD_SHELL /* Figure out what bash shell to use. If $NIX_BUILD_SHELL
is not set, then build bashInteractive from is not set, then build bashInteractive from
@ -358,7 +358,7 @@ static void _main(int argc, char * * argv)
if (!drv) if (!drv)
throw Error("the 'bashInteractive' attribute in <nixpkgs> did not evaluate to a derivation"); throw Error("the 'bashInteractive' attribute in <nixpkgs> did not evaluate to a derivation");
pathsToBuild.insert(drv->queryDrvPath()); pathsToBuild.emplace_back(store->parseStorePath(drv->queryDrvPath()));
shell = drv->queryOutPath() + "/bin/bash"; shell = drv->queryOutPath() + "/bin/bash";
@ -370,10 +370,11 @@ static void _main(int argc, char * * argv)
// Build or fetch all dependencies of the derivation. // Build or fetch all dependencies of the derivation.
for (const auto & input : drv.inputDrvs) for (const auto & input : drv.inputDrvs)
if (std::all_of(envExclude.cbegin(), envExclude.cend(), [&](const string & exclude) { return !std::regex_search(input.first, std::regex(exclude)); })) if (std::all_of(envExclude.cbegin(), envExclude.cend(),
pathsToBuild.insert(makeDrvPathWithOutputs(input.first, input.second)); [&](const string & exclude) { return !std::regex_search(store->printStorePath(input.first), std::regex(exclude)); }))
pathsToBuild.emplace_back(input.first, input.second);
for (const auto & src : drv.inputSrcs) for (const auto & src : drv.inputSrcs)
pathsToBuild.insert(src); pathsToBuild.emplace_back(src);
buildPaths(pathsToBuild); buildPaths(pathsToBuild);
@ -399,7 +400,7 @@ static void _main(int argc, char * * argv)
env["NIX_STORE"] = store->storeDir; env["NIX_STORE"] = store->storeDir;
env["NIX_BUILD_CORES"] = std::to_string(settings.buildCores); env["NIX_BUILD_CORES"] = std::to_string(settings.buildCores);
auto passAsFile = tokenizeString<StringSet>(get(drv.env, "passAsFile", "")); auto passAsFile = tokenizeString<StringSet>(get(drv.env, "passAsFile").value_or(""));
bool keepTmp = false; bool keepTmp = false;
int fileNr = 0; int fileNr = 0;
@ -468,7 +469,7 @@ static void _main(int argc, char * * argv)
else { else {
PathSet pathsToBuild; std::vector<StorePathWithOutputs> pathsToBuild;
std::map<Path, Path> drvPrefixes; std::map<Path, Path> drvPrefixes;
std::map<Path, Path> resultSymlinks; std::map<Path, Path> resultSymlinks;
@ -482,7 +483,7 @@ static void _main(int argc, char * * argv)
if (outputName == "") if (outputName == "")
throw Error("derivation '%s' lacks an 'outputName' attribute", drvPath); throw Error("derivation '%s' lacks an 'outputName' attribute", drvPath);
pathsToBuild.insert(drvPath + "!" + outputName); pathsToBuild.emplace_back(store->parseStorePath(drvPath), StringSet{outputName});
std::string drvPrefix; std::string drvPrefix;
auto i = drvPrefixes.find(drvPath); auto i = drvPrefixes.find(drvPath);
@ -508,7 +509,7 @@ static void _main(int argc, char * * argv)
for (auto & symlink : resultSymlinks) for (auto & symlink : resultSymlinks)
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>()) if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>())
store2->addPermRoot(symlink.second, absPath(symlink.first), true); store2->addPermRoot(store->parseStorePath(symlink.second), absPath(symlink.first), true);
for (auto & path : outPaths) for (auto & path : outPaths)
std::cout << path << '\n'; std::cout << path << '\n';

View file

@ -27,7 +27,7 @@ static void readChannels()
continue; continue;
auto split = tokenizeString<std::vector<string>>(line, " "); auto split = tokenizeString<std::vector<string>>(line, " ");
auto url = std::regex_replace(split[0], std::regex("/*$"), ""); auto url = std::regex_replace(split[0], std::regex("/*$"), "");
auto name = split.size() > 1 ? split[1] : baseNameOf(url); auto name = split.size() > 1 ? split[1] : std::string(baseNameOf(url));
channels[name] = url; channels[name] = url;
} }
} }
@ -98,10 +98,9 @@ static void update(const StringSet & channelNames)
// shows something useful). // shows something useful).
auto cname = name; auto cname = name;
std::smatch match; std::smatch match;
auto urlBase = baseNameOf(url); auto urlBase = std::string(baseNameOf(url));
if (std::regex_search(urlBase, match, std::regex("(-\\d.*)$"))) { if (std::regex_search(urlBase, match, std::regex("(-\\d.*)$")))
cname = cname + (string) match[1]; cname = cname + (string) match[1];
}
std::string extraAttrs; std::string extraAttrs;

View file

@ -52,11 +52,11 @@ static int _main(int argc, char ** argv)
auto to = toMode ? openStore(remoteUri) : openStore(); auto to = toMode ? openStore(remoteUri) : openStore();
auto from = toMode ? openStore() : openStore(remoteUri); auto from = toMode ? openStore() : openStore(remoteUri);
PathSet storePaths2; StorePathSet storePaths2;
for (auto & path : storePaths) for (auto & path : storePaths)
storePaths2.insert(from->followLinksToStorePath(path)); storePaths2.insert(from->followLinksToStorePath(path));
PathSet closure; StorePathSet closure;
from->computeFSClosure(storePaths2, closure, false, includeOutputs); from->computeFSClosure(storePaths2, closure, false, includeOutputs);
copyPaths(from, to, closure, NoRepair, NoCheckSigs, useSubstitutes); copyPaths(from, to, closure, NoRepair, NoCheckSigs, useSubstitutes);

View file

@ -286,7 +286,7 @@ static int _main(int argc, char * * argv)
if (chdir(socketDir.c_str()) == -1) if (chdir(socketDir.c_str()) == -1)
throw SysError(format("changing to socket directory '%1%'") % socketDir); throw SysError(format("changing to socket directory '%1%'") % socketDir);
auto socketName = baseNameOf(socketPath); auto socketName = std::string(baseNameOf(socketPath));
auto addr = sockaddr_un{}; auto addr = sockaddr_un{};
addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX;
if (socketName.size() + 1 >= sizeof(addr.sun_path)) if (socketName.size() + 1 >= sizeof(addr.sun_path))

View file

@ -208,10 +208,11 @@ static long comparePriorities(EvalState & state, DrvInfo & drv1, DrvInfo & drv2)
// at a time. // at a time.
static bool isPrebuilt(EvalState & state, DrvInfo & elem) static bool isPrebuilt(EvalState & state, DrvInfo & elem)
{ {
Path path = elem.queryOutPath(); auto path = state.store->parseStorePath(elem.queryOutPath());
if (state.store->isValidPath(path)) return true; if (state.store->isValidPath(path)) return true;
PathSet ps = state.store->querySubstitutablePaths({path}); StorePathSet paths;
return ps.find(path) != ps.end(); paths.insert(path.clone()); // FIXME: why doesn't StorePathSet{path.clone()} work?
return state.store->querySubstitutablePaths(paths).count(path);
} }
@ -371,24 +372,21 @@ static void queryInstSources(EvalState & state,
case srcStorePaths: { case srcStorePaths: {
for (auto & i : args) { for (auto & i : args) {
Path path = state.store->followLinksToStorePath(i); auto path = state.store->followLinksToStorePath(i);
string name = baseNameOf(path); std::string name(path.name());
string::size_type dash = name.find('-');
if (dash != string::npos)
name = string(name, dash + 1);
DrvInfo elem(state, "", nullptr); DrvInfo elem(state, "", nullptr);
elem.setName(name); elem.setName(name);
if (isDerivation(path)) { if (path.isDerivation()) {
elem.setDrvPath(path); elem.setDrvPath(state.store->printStorePath(path));
elem.setOutPath(state.store->derivationFromPath(path).findOutput("out")); elem.setOutPath(state.store->printStorePath(state.store->derivationFromPath(path).findOutput("out")));
if (name.size() >= drvExtension.size() && if (name.size() >= drvExtension.size() &&
string(name, name.size() - drvExtension.size()) == drvExtension) string(name, name.size() - drvExtension.size()) == drvExtension)
name = string(name, 0, name.size() - drvExtension.size()); name = string(name, 0, name.size() - drvExtension.size());
} }
else elem.setOutPath(path); else elem.setOutPath(state.store->printStorePath(path));
elems.push_back(elem); elems.push_back(elem);
} }
@ -421,13 +419,13 @@ static void queryInstSources(EvalState & state,
static void printMissing(EvalState & state, DrvInfos & elems) static void printMissing(EvalState & state, DrvInfos & elems)
{ {
PathSet targets; std::vector<StorePathWithOutputs> targets;
for (auto & i : elems) { for (auto & i : elems) {
Path drvPath = i.queryDrvPath(); Path drvPath = i.queryDrvPath();
if (drvPath != "") if (drvPath != "")
targets.insert(drvPath); targets.emplace_back(state.store->parseStorePath(drvPath));
else else
targets.insert(i.queryOutPath()); targets.emplace_back(state.store->parseStorePath(i.queryOutPath()));
} }
printMissing(state.store, targets); printMissing(state.store, targets);
@ -697,15 +695,15 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
drv.setName(globals.forceName); drv.setName(globals.forceName);
if (drv.queryDrvPath() != "") { if (drv.queryDrvPath() != "") {
PathSet paths = {drv.queryDrvPath()}; std::vector<StorePathWithOutputs> paths{globals.state->store->parseStorePath(drv.queryDrvPath())};
printMissing(globals.state->store, paths); printMissing(globals.state->store, paths);
if (globals.dryRun) return; if (globals.dryRun) return;
globals.state->store->buildPaths(paths, globals.state->repair ? bmRepair : bmNormal); globals.state->store->buildPaths(paths, globals.state->repair ? bmRepair : bmNormal);
} } else {
else { printMissing(globals.state->store,
printMissing(globals.state->store, {drv.queryOutPath()}); {globals.state->store->parseStorePath(drv.queryOutPath())});
if (globals.dryRun) return; if (globals.dryRun) return;
globals.state->store->ensurePath(drv.queryOutPath()); globals.state->store->ensurePath(globals.state->store->parseStorePath(drv.queryOutPath()));
} }
debug(format("switching to new user environment")); debug(format("switching to new user environment"));
@ -729,7 +727,7 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
for (auto & j : selectors) for (auto & j : selectors)
/* !!! the repeated calls to followLinksToStorePath() /* !!! the repeated calls to followLinksToStorePath()
are expensive, should pre-compute them. */ are expensive, should pre-compute them. */
if ((isPath(j) && i.queryOutPath() == globals.state->store->followLinksToStorePath(j)) if ((isPath(j) && globals.state->store->parseStorePath(i.queryOutPath()) == globals.state->store->followLinksToStorePath(j))
|| DrvName(j).matches(drvName)) || DrvName(j).matches(drvName))
{ {
printInfo("uninstalling '%s'", i.queryName()); printInfo("uninstalling '%s'", i.queryName());
@ -953,12 +951,13 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
/* Query which paths have substitutes. */ /* Query which paths have substitutes. */
PathSet validPaths, substitutablePaths; StorePathSet validPaths;
StorePathSet substitutablePaths;
if (printStatus || globals.prebuiltOnly) { if (printStatus || globals.prebuiltOnly) {
PathSet paths; StorePathSet paths;
for (auto & i : elems) for (auto & i : elems)
try { try {
paths.insert(i.queryOutPath()); paths.insert(globals.state->store->parseStorePath(i.queryOutPath()));
} catch (AssertionError & e) { } catch (AssertionError & e) {
printMsg(lvlTalkative, "skipping derivation named '%s' which gives an assertion failure", i.queryName()); printMsg(lvlTalkative, "skipping derivation named '%s' which gives an assertion failure", i.queryName());
i.setFailed(); i.setFailed();
@ -989,8 +988,8 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
//Activity act(*logger, lvlDebug, format("outputting query result '%1%'") % i.attrPath); //Activity act(*logger, lvlDebug, format("outputting query result '%1%'") % i.attrPath);
if (globals.prebuiltOnly && if (globals.prebuiltOnly &&
validPaths.find(i.queryOutPath()) == validPaths.end() && !validPaths.count(globals.state->store->parseStorePath(i.queryOutPath())) &&
substitutablePaths.find(i.queryOutPath()) == substitutablePaths.end()) !substitutablePaths.count(globals.state->store->parseStorePath(i.queryOutPath())))
continue; continue;
/* For table output. */ /* For table output. */
@ -1001,9 +1000,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
if (printStatus) { if (printStatus) {
Path outPath = i.queryOutPath(); Path outPath = i.queryOutPath();
bool hasSubs = substitutablePaths.find(outPath) != substitutablePaths.end(); bool hasSubs = substitutablePaths.count(globals.state->store->parseStorePath(outPath));
bool isInstalled = installed.find(outPath) != installed.end(); bool isInstalled = installed.find(outPath) != installed.end();
bool isValid = validPaths.find(outPath) != validPaths.end(); bool isValid = validPaths.count(globals.state->store->parseStorePath(outPath));
if (xmlOutput) { if (xmlOutput) {
attrs["installed"] = isInstalled ? "1" : "0"; attrs["installed"] = isInstalled ? "1" : "0";
attrs["valid"] = isValid ? "1" : "0"; attrs["valid"] = isValid ? "1" : "0";
@ -1347,7 +1346,7 @@ static int _main(int argc, char * * argv)
using LegacyArgs::LegacyArgs; using LegacyArgs::LegacyArgs;
}; };
MyArgs myArgs(baseNameOf(argv[0]), [&](Strings::iterator & arg, const Strings::iterator & end) { MyArgs myArgs(std::string(baseNameOf(argv[0])), [&](Strings::iterator & arg, const Strings::iterator & end) {
Operation oldOp = op; Operation oldOp = op;
if (*arg == "--help") if (*arg == "--help")

View file

@ -32,16 +32,16 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
{ {
/* Build the components in the user environment, if they don't /* Build the components in the user environment, if they don't
exist already. */ exist already. */
PathSet drvsToBuild; std::vector<StorePathWithOutputs> drvsToBuild;
for (auto & i : elems) for (auto & i : elems)
if (i.queryDrvPath() != "") if (i.queryDrvPath() != "")
drvsToBuild.insert(i.queryDrvPath()); drvsToBuild.push_back({state.store->parseStorePath(i.queryDrvPath())});
debug(format("building user environment dependencies")); debug(format("building user environment dependencies"));
state.store->buildPaths(drvsToBuild, state.repair ? bmRepair : bmNormal); state.store->buildPaths(drvsToBuild, state.repair ? bmRepair : bmNormal);
/* Construct the whole top level derivation. */ /* Construct the whole top level derivation. */
PathSet references; StorePathSet references;
Value manifest; Value manifest;
state.mkList(manifest, elems.size()); state.mkList(manifest, elems.size());
unsigned int n = 0; unsigned int n = 0;
@ -77,10 +77,10 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
/* This is only necessary when installing store paths, e.g., /* This is only necessary when installing store paths, e.g.,
`nix-env -i /nix/store/abcd...-foo'. */ `nix-env -i /nix/store/abcd...-foo'. */
state.store->addTempRoot(j.second); state.store->addTempRoot(state.store->parseStorePath(j.second));
state.store->ensurePath(j.second); state.store->ensurePath(state.store->parseStorePath(j.second));
references.insert(j.second); references.insert(state.store->parseStorePath(j.second));
} }
// Copy the meta attributes. // Copy the meta attributes.
@ -95,14 +95,14 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
vMeta.attrs->sort(); vMeta.attrs->sort();
v.attrs->sort(); v.attrs->sort();
if (drvPath != "") references.insert(drvPath); if (drvPath != "") references.insert(state.store->parseStorePath(drvPath));
} }
/* Also write a copy of the list of user environment elements to /* Also write a copy of the list of user environment elements to
the store; we need it for future modifications of the the store; we need it for future modifications of the
environment. */ environment. */
Path manifestFile = state.store->addTextToStore("env-manifest.nix", auto manifestFile = state.store->addTextToStore("env-manifest.nix",
(format("%1%") % manifest).str(), references); fmt("%s", manifest), references);
/* Get the environment builder expression. */ /* Get the environment builder expression. */
Value envBuilder; Value envBuilder;
@ -113,7 +113,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
Value args, topLevel; Value args, topLevel;
state.mkAttrs(args, 3); state.mkAttrs(args, 3);
mkString(*state.allocAttr(args, state.symbols.create("manifest")), mkString(*state.allocAttr(args, state.symbols.create("manifest")),
manifestFile, {manifestFile}); state.store->printStorePath(manifestFile), {state.store->printStorePath(manifestFile)});
args.attrs->push_back(Attr(state.symbols.create("derivations"), &manifest)); args.attrs->push_back(Attr(state.symbols.create("derivations"), &manifest));
args.attrs->sort(); args.attrs->sort();
mkApp(topLevel, envBuilder, args); mkApp(topLevel, envBuilder, args);
@ -123,13 +123,15 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
state.forceValue(topLevel); state.forceValue(topLevel);
PathSet context; PathSet context;
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath)); Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
Path topLevelDrv = state.coerceToPath(aDrvPath.pos ? *(aDrvPath.pos) : noPos, *(aDrvPath.value), context); auto topLevelDrv = state.store->parseStorePath(state.coerceToPath(aDrvPath.pos ? *(aDrvPath.pos) : noPos, *(aDrvPath.value), context));
Attr & aOutPath(*topLevel.attrs->find(state.sOutPath)); Attr & aOutPath(*topLevel.attrs->find(state.sOutPath));
Path topLevelOut = state.coerceToPath(aOutPath.pos ? *(aOutPath.pos) : noPos, *(aOutPath.value), context); Path topLevelOut = state.coerceToPath(aOutPath.pos ? *(aOutPath.pos) : noPos, *(aOutPath.value), context);
/* Realise the resulting store expression. */ /* Realise the resulting store expression. */
debug("building user environment"); debug("building user environment");
state.store->buildPaths({topLevelDrv}, state.repair ? bmRepair : bmNormal); std::vector<StorePathWithOutputs> topLevelDrvs;
topLevelDrvs.push_back(StorePathWithOutputs{topLevelDrv.clone()});
state.store->buildPaths(topLevelDrvs, state.repair ? bmRepair : bmNormal);
/* Switch the current user environment to the output path. */ /* Switch the current user environment to the output path. */
auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>(); auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>();

View file

@ -75,9 +75,9 @@ void processExpr(EvalState & state, const Strings & attrPaths,
if (++rootNr > 1) rootName += "-" + std::to_string(rootNr); if (++rootNr > 1) rootName += "-" + std::to_string(rootNr);
auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>(); auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>();
if (store2) if (store2)
drvPath = store2->addPermRoot(drvPath, rootName, indirectRoot); drvPath = store2->addPermRoot(store2->parseStorePath(drvPath), rootName, indirectRoot);
} }
std::cout << format("%1%%2%\n") % drvPath % (outputName != "out" ? "!" + outputName : ""); std::cout << fmt("%s%s\n", drvPath, (outputName != "out" ? "!" + outputName : ""));
} }
} }
} }
@ -105,7 +105,7 @@ static int _main(int argc, char * * argv)
using LegacyArgs::LegacyArgs; using LegacyArgs::LegacyArgs;
}; };
MyArgs myArgs(baseNameOf(argv[0]), [&](Strings::iterator & arg, const Strings::iterator & end) { MyArgs myArgs(std::string(baseNameOf(argv[0])), [&](Strings::iterator & arg, const Strings::iterator & end) {
if (*arg == "--help") if (*arg == "--help")
showManPage("nix-instantiate"); showManPage("nix-instantiate");
else if (*arg == "--version") else if (*arg == "--version")

View file

@ -64,7 +64,7 @@ static int _main(int argc, char * * argv)
using LegacyArgs::LegacyArgs; using LegacyArgs::LegacyArgs;
}; };
MyArgs myArgs(baseNameOf(argv[0]), [&](Strings::iterator & arg, const Strings::iterator & end) { MyArgs myArgs(std::string(baseNameOf(argv[0])), [&](Strings::iterator & arg, const Strings::iterator & end) {
if (*arg == "--help") if (*arg == "--help")
showManPage("nix-prefetch-url"); showManPage("nix-prefetch-url");
else if (*arg == "--version") else if (*arg == "--version")
@ -156,17 +156,17 @@ static int _main(int argc, char * * argv)
/* If an expected hash is given, the file may already exist in /* If an expected hash is given, the file may already exist in
the store. */ the store. */
Hash hash, expectedHash(ht); Hash hash, expectedHash(ht);
Path storePath; std::optional<StorePath> storePath;
if (args.size() == 2) { if (args.size() == 2) {
expectedHash = Hash(args[1], ht); expectedHash = Hash(args[1], ht);
storePath = store->makeFixedOutputPath(unpack, expectedHash, name); storePath = store->makeFixedOutputPath(unpack, expectedHash, name);
if (store->isValidPath(storePath)) if (store->isValidPath(*storePath))
hash = expectedHash; hash = expectedHash;
else else
storePath.clear(); storePath.reset();
} }
if (storePath.empty()) { if (!storePath) {
auto actualUri = resolveMirrorUri(*state, uri); auto actualUri = resolveMirrorUri(*state, uri);
@ -193,7 +193,7 @@ static int _main(int argc, char * * argv)
if (hasSuffix(baseNameOf(uri), ".zip")) if (hasSuffix(baseNameOf(uri), ".zip"))
runProgram("unzip", true, {"-qq", tmpFile, "-d", unpacked}); runProgram("unzip", true, {"-qq", tmpFile, "-d", unpacked});
else else
unpackTarfile(tmpFile, unpacked, baseNameOf(uri)); unpackTarfile(tmpFile, unpacked, std::string(baseNameOf(uri)));
/* If the archive unpacks to a single file/directory, then use /* If the archive unpacks to a single file/directory, then use
that as the top-level. */ that as the top-level. */
@ -217,17 +217,17 @@ static int _main(int argc, char * * argv)
into the Nix store. */ into the Nix store. */
storePath = store->addToStore(name, tmpFile, unpack, ht); storePath = store->addToStore(name, tmpFile, unpack, ht);
assert(storePath == store->makeFixedOutputPath(unpack, hash, name)); assert(*storePath == store->makeFixedOutputPath(unpack, hash, name));
} }
stopProgressBar(); stopProgressBar();
if (!printPath) if (!printPath)
printInfo(format("path is '%1%'") % storePath); printInfo("path is '%s'", store->printStorePath(*storePath));
std::cout << printHash16or32(hash) << std::endl; std::cout << printHash16or32(hash) << std::endl;
if (printPath) if (printPath)
std::cout << storePath << std::endl; std::cout << store->printStorePath(*storePath) << std::endl;
return 0; return 0;
} }

View file

@ -10,9 +10,9 @@ using std::cout;
namespace nix { namespace nix {
static string dotQuote(const string & s) static string dotQuote(std::string_view s)
{ {
return "\"" + s + "\""; return "\"" + std::string(s) + "\"";
} }
@ -34,7 +34,7 @@ static string makeEdge(const string & src, const string & dst)
} }
static string makeNode(const string & id, const string & label, static string makeNode(const string & id, std::string_view label,
const string & colour) const string & colour)
{ {
format f = format("%1% [label = %2%, shape = box, " format f = format("%1% [label = %2%, shape = box, "
@ -44,13 +44,6 @@ static string makeNode(const string & id, const string & label,
} }
static string symbolicName(const string & path)
{
string p = baseNameOf(path);
return string(p, p.find('-') + 1);
}
#if 0 #if 0
string pathLabel(const Path & nePath, const string & elemPath) string pathLabel(const Path & nePath, const string & elemPath)
{ {
@ -91,25 +84,24 @@ void printClosure(const Path & nePath, const StoreExpr & fs)
#endif #endif
void printDotGraph(ref<Store> store, const PathSet & roots) void printDotGraph(ref<Store> store, StorePathSet && roots)
{ {
PathSet workList(roots); StorePathSet workList(std::move(roots));
PathSet doneSet; StorePathSet doneSet;
cout << "digraph G {\n"; cout << "digraph G {\n";
while (!workList.empty()) { while (!workList.empty()) {
Path path = *(workList.begin()); auto path = std::move(workList.extract(workList.begin()).value());
workList.erase(path);
if (!doneSet.insert(path).second) continue; if (!doneSet.insert(path.clone()).second) continue;
cout << makeNode(path, symbolicName(path), "#ff0000"); cout << makeNode(std::string(path.to_string()), path.name(), "#ff0000");
for (auto & p : store->queryPathInfo(path)->references) { for (auto & p : store->queryPathInfo(path)->references) {
if (p != path) { if (p != path) {
workList.insert(p); workList.insert(p.clone());
cout << makeEdge(p, path); cout << makeEdge(std::string(p.to_string()), std::string(p.to_string()));
} }
} }

View file

@ -1,11 +1,9 @@
#pragma once #pragma once
#include "types.hh" #include "store-api.hh"
namespace nix { namespace nix {
class Store; void printDotGraph(ref<Store> store, StorePathSet && roots);
void printDotGraph(ref<Store> store, const PathSet & roots);
} }

View file

@ -11,7 +11,7 @@ using std::cout;
namespace nix { namespace nix {
static inline const string & xmlQuote(const string & s) static inline std::string_view xmlQuote(std::string_view s)
{ {
// Luckily, store paths shouldn't contain any character that needs to be // Luckily, store paths shouldn't contain any character that needs to be
// quoted. // quoted.
@ -19,14 +19,13 @@ static inline const string & xmlQuote(const string & s)
} }
static string symbolicName(const string & path) static string symbolicName(const std::string & p)
{ {
string p = baseNameOf(path);
return string(p, p.find('-') + 1); return string(p, p.find('-') + 1);
} }
static string makeEdge(const string & src, const string & dst) static string makeEdge(std::string_view src, std::string_view dst)
{ {
return fmt(" <edge source=\"%1%\" target=\"%2%\"/>\n", return fmt(" <edge source=\"%1%\" target=\"%2%\"/>\n",
xmlQuote(src), xmlQuote(dst)); xmlQuote(src), xmlQuote(dst));
@ -41,18 +40,18 @@ static string makeNode(const ValidPathInfo & info)
" <data key=\"name\">%3%</data>\n" " <data key=\"name\">%3%</data>\n"
" <data key=\"type\">%4%</data>\n" " <data key=\"type\">%4%</data>\n"
" </node>\n", " </node>\n",
info.path, info.path.to_string(),
info.narSize, info.narSize,
symbolicName(info.path), symbolicName(std::string(info.path.name())),
(isDerivation(info.path) ? "derivation" : "output-path")); (info.path.isDerivation() ? "derivation" : "output-path"));
} }
void printGraphML(ref<Store> store, const PathSet & roots) void printGraphML(ref<Store> store, StorePathSet && roots)
{ {
PathSet workList(roots); StorePathSet workList(std::move(roots));
PathSet doneSet; StorePathSet doneSet;
std::pair<PathSet::iterator,bool> ret; std::pair<StorePathSet::iterator, bool> ret;
cout << "<?xml version='1.0' encoding='utf-8'?>\n" cout << "<?xml version='1.0' encoding='utf-8'?>\n"
<< "<graphml xmlns='http://graphml.graphdrawing.org/xmlns'\n" << "<graphml xmlns='http://graphml.graphdrawing.org/xmlns'\n"
@ -64,19 +63,18 @@ void printGraphML(ref<Store> store, const PathSet & roots)
<< "<graph id='G' edgedefault='directed'>\n"; << "<graph id='G' edgedefault='directed'>\n";
while (!workList.empty()) { while (!workList.empty()) {
Path path = *(workList.begin()); auto path = std::move(workList.extract(workList.begin()).value());
workList.erase(path);
ret = doneSet.insert(path); ret = doneSet.insert(path.clone());
if (ret.second == false) continue; if (ret.second == false) continue;
ValidPathInfo info = *(store->queryPathInfo(path)); auto info = store->queryPathInfo(path);
cout << makeNode(info); cout << makeNode(*info);
for (auto & p : store->queryPathInfo(path)->references) { for (auto & p : info->references) {
if (p != path) { if (p != path) {
workList.insert(p); workList.insert(p.clone());
cout << makeEdge(path, p); cout << makeEdge(path.to_string(), p.to_string());
} }
} }

View file

@ -1,11 +1,9 @@
#pragma once #pragma once
#include "types.hh" #include "store-api.hh"
namespace nix { namespace nix {
class Store; void printGraphML(ref<Store> store, StorePathSet && roots);
void printGraphML(ref<Store> store, const PathSet & roots);
} }

View file

@ -47,38 +47,37 @@ ref<LocalStore> ensureLocalStore()
} }
static Path useDeriver(Path path) static StorePath useDeriver(const StorePath & path)
{ {
if (isDerivation(path)) return path; if (path.isDerivation()) return path.clone();
Path drvPath = store->queryPathInfo(path)->deriver; auto info = store->queryPathInfo(path);
if (drvPath == "") if (!info->deriver)
throw Error(format("deriver of path '%1%' is not known") % path); throw Error("deriver of path '%s' is not known", store->printStorePath(path));
return drvPath; return info->deriver->clone();
} }
/* Realise the given path. For a derivation that means build it; for /* Realise the given path. For a derivation that means build it; for
other paths it means ensure their validity. */ other paths it means ensure their validity. */
static PathSet realisePath(Path path, bool build = true) static PathSet realisePath(StorePathWithOutputs path, bool build = true)
{ {
DrvPathWithOutputs p = parseDrvPathWithOutputs(path);
auto store2 = std::dynamic_pointer_cast<LocalFSStore>(store); auto store2 = std::dynamic_pointer_cast<LocalFSStore>(store);
if (isDerivation(p.first)) { if (path.path.isDerivation()) {
if (build) store->buildPaths({path}); if (build) store->buildPaths({path});
Derivation drv = store->derivationFromPath(p.first); Derivation drv = store->derivationFromPath(path.path);
rootNr++; rootNr++;
if (p.second.empty()) if (path.outputs.empty())
for (auto & i : drv.outputs) p.second.insert(i.first); for (auto & i : drv.outputs) path.outputs.insert(i.first);
PathSet outputs; PathSet outputs;
for (auto & j : p.second) { for (auto & j : path.outputs) {
DerivationOutputs::iterator i = drv.outputs.find(j); DerivationOutputs::iterator i = drv.outputs.find(j);
if (i == drv.outputs.end()) if (i == drv.outputs.end())
throw Error(format("derivation '%1%' does not have an output named '%2%'") % p.first % j); throw Error("derivation '%s' does not have an output named '%s'",
Path outPath = i->second.path; store2->printStorePath(path.path), j);
auto outPath = store2->printStorePath(i->second.path);
if (store2) { if (store2) {
if (gcRoot == "") if (gcRoot == "")
printGCWarning(); printGCWarning();
@ -86,7 +85,7 @@ static PathSet realisePath(Path path, bool build = true)
Path rootName = gcRoot; Path rootName = gcRoot;
if (rootNr > 1) rootName += "-" + std::to_string(rootNr); if (rootNr > 1) rootName += "-" + std::to_string(rootNr);
if (i->first != "out") rootName += "-" + i->first; if (i->first != "out") rootName += "-" + i->first;
outPath = store2->addPermRoot(outPath, rootName, indirectRoot); outPath = store2->addPermRoot(store->parseStorePath(outPath), rootName, indirectRoot);
} }
} }
outputs.insert(outPath); outputs.insert(outPath);
@ -95,8 +94,9 @@ static PathSet realisePath(Path path, bool build = true)
} }
else { else {
if (build) store->ensurePath(path); if (build) store->ensurePath(path.path);
else if (!store->isValidPath(path)) throw Error(format("path '%1%' does not exist and cannot be created") % path); else if (!store->isValidPath(path.path))
throw Error("path '%s' does not exist and cannot be created", store->printStorePath(path.path));
if (store2) { if (store2) {
if (gcRoot == "") if (gcRoot == "")
printGCWarning(); printGCWarning();
@ -104,10 +104,10 @@ static PathSet realisePath(Path path, bool build = true)
Path rootName = gcRoot; Path rootName = gcRoot;
rootNr++; rootNr++;
if (rootNr > 1) rootName += "-" + std::to_string(rootNr); if (rootNr > 1) rootName += "-" + std::to_string(rootNr);
path = store2->addPermRoot(path, rootName, indirectRoot); return {store2->addPermRoot(path.path, rootName, indirectRoot)};
} }
} }
return {path}; return {store->printStorePath(path.path)};
} }
} }
@ -126,23 +126,20 @@ static void opRealise(Strings opFlags, Strings opArgs)
else if (i == "--ignore-unknown") ignoreUnknown = true; else if (i == "--ignore-unknown") ignoreUnknown = true;
else throw UsageError(format("unknown flag '%1%'") % i); else throw UsageError(format("unknown flag '%1%'") % i);
Paths paths; std::vector<StorePathWithOutputs> paths;
for (auto & i : opArgs) { for (auto & i : opArgs)
DrvPathWithOutputs p = parseDrvPathWithOutputs(i); paths.push_back(store->parseDrvPathWithOutputs(i));
paths.push_back(makeDrvPathWithOutputs(store->followLinksToStorePath(p.first), p.second));
}
unsigned long long downloadSize, narSize; unsigned long long downloadSize, narSize;
PathSet willBuild, willSubstitute, unknown; StorePathSet willBuild, willSubstitute, unknown;
store->queryMissing(PathSet(paths.begin(), paths.end()), store->queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
willBuild, willSubstitute, unknown, downloadSize, narSize);
if (ignoreUnknown) { if (ignoreUnknown) {
Paths paths2; std::vector<StorePathWithOutputs> paths2;
for (auto & i : paths) for (auto & i : paths)
if (unknown.find(i) == unknown.end()) paths2.push_back(i); if (!unknown.count(i.path)) paths2.push_back(i);
paths = paths2; paths = std::move(paths2);
unknown = PathSet(); unknown = StorePathSet();
} }
if (settings.printMissing) if (settings.printMissing)
@ -151,14 +148,14 @@ static void opRealise(Strings opFlags, Strings opArgs)
if (dryRun) return; if (dryRun) return;
/* Build all paths at the same time to exploit parallelism. */ /* Build all paths at the same time to exploit parallelism. */
store->buildPaths(PathSet(paths.begin(), paths.end()), buildMode); store->buildPaths(paths, buildMode);
if (!ignoreUnknown) if (!ignoreUnknown)
for (auto & i : paths) { for (auto & i : paths) {
PathSet paths = realisePath(i, false); auto paths2 = realisePath(i, false);
if (!noOutput) if (!noOutput)
for (auto & j : paths) for (auto & j : paths2)
cout << format("%1%\n") % j; cout << fmt("%1%\n", j);
} }
} }
@ -169,7 +166,7 @@ static void opAdd(Strings opFlags, Strings opArgs)
if (!opFlags.empty()) throw UsageError("unknown flag"); if (!opFlags.empty()) throw UsageError("unknown flag");
for (auto & i : opArgs) for (auto & i : opArgs)
cout << format("%1%\n") % store->addToStore(baseNameOf(i), i); cout << fmt("%s\n", store->printStorePath(store->addToStore(std::string(baseNameOf(i)), i)));
} }
@ -190,7 +187,7 @@ static void opAddFixed(Strings opFlags, Strings opArgs)
opArgs.pop_front(); opArgs.pop_front();
for (auto & i : opArgs) for (auto & i : opArgs)
cout << format("%1%\n") % store->addToStore(baseNameOf(i), i, recursive, hashAlgo); cout << fmt("%s\n", store->printStorePath(store->addToStore(std::string(baseNameOf(i)), i, recursive, hashAlgo)));
} }
@ -211,22 +208,21 @@ static void opPrintFixedPath(Strings opFlags, Strings opArgs)
string hash = *i++; string hash = *i++;
string name = *i++; string name = *i++;
cout << format("%1%\n") % cout << fmt("%s\n", store->printStorePath(store->makeFixedOutputPath(recursive, Hash(hash, hashAlgo), name)));
store->makeFixedOutputPath(recursive, Hash(hash, hashAlgo), name);
} }
static PathSet maybeUseOutputs(const Path & storePath, bool useOutput, bool forceRealise) static StorePathSet maybeUseOutputs(const StorePath & storePath, bool useOutput, bool forceRealise)
{ {
if (forceRealise) realisePath(storePath); if (forceRealise) realisePath(storePath);
if (useOutput && isDerivation(storePath)) { if (useOutput && storePath.isDerivation()) {
Derivation drv = store->derivationFromPath(storePath); auto drv = store->derivationFromPath(storePath);
PathSet outputs; StorePathSet outputs;
for (auto & i : drv.outputs) for (auto & i : drv.outputs)
outputs.insert(i.second.path); outputs.insert(i.second.path.clone());
return outputs; return outputs;
} }
else return {storePath}; else return singleton(storePath.clone());
} }
@ -239,23 +235,23 @@ const string treeLine = "| ";
const string treeNull = " "; const string treeNull = " ";
static void printTree(const Path & path, static void printTree(const StorePath & path,
const string & firstPad, const string & tailPad, PathSet & done) const string & firstPad, const string & tailPad, StorePathSet & done)
{ {
if (!done.insert(path).second) { if (!done.insert(path.clone()).second) {
cout << format("%1%%2% [...]\n") % firstPad % path; cout << fmt("%s%s [...]\n", firstPad, store->printStorePath(path));
return; return;
} }
cout << format("%1%%2%\n") % firstPad % path; cout << fmt("%s%s\n", firstPad, store->printStorePath(path));
auto references = store->queryPathInfo(path)->references; auto info = store->queryPathInfo(path);
/* Topologically sort under the relation A < B iff A \in /* Topologically sort under the relation A < B iff A \in
closure(B). That is, if derivation A is an (possibly indirect) closure(B). That is, if derivation A is an (possibly indirect)
input of B, then A is printed first. This has the effect of input of B, then A is printed first. This has the effect of
flattening the tree, preventing deeply nested structures. */ flattening the tree, preventing deeply nested structures. */
Paths sorted = store->topoSortPaths(references); auto sorted = store->topoSortPaths(info->references);
reverse(sorted.begin(), sorted.end()); reverse(sorted.begin(), sorted.end());
for (auto i = sorted.begin(); i != sorted.end(); ++i) { for (auto i = sorted.begin(); i != sorted.end(); ++i) {
@ -318,11 +314,11 @@ static void opQuery(Strings opFlags, Strings opArgs)
case qOutputs: { case qOutputs: {
for (auto & i : opArgs) { for (auto & i : opArgs) {
i = store->followLinksToStorePath(i); auto i2 = store->followLinksToStorePath(i);
if (forceRealise) realisePath(i); if (forceRealise) realisePath(i2);
Derivation drv = store->derivationFromPath(i); Derivation drv = store->derivationFromPath(i2);
for (auto & j : drv.outputs) for (auto & j : drv.outputs)
cout << format("%1%\n") % j.second.path; cout << fmt("%1%\n", store->printStorePath(j.second.path));
} }
break; break;
} }
@ -331,51 +327,54 @@ static void opQuery(Strings opFlags, Strings opArgs)
case qReferences: case qReferences:
case qReferrers: case qReferrers:
case qReferrersClosure: { case qReferrersClosure: {
PathSet paths; StorePathSet paths;
for (auto & i : opArgs) { for (auto & i : opArgs) {
PathSet ps = maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise); auto ps = maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise);
for (auto & j : ps) { for (auto & j : ps) {
if (query == qRequisites) store->computeFSClosure(j, paths, false, includeOutputs); if (query == qRequisites) store->computeFSClosure(j, paths, false, includeOutputs);
else if (query == qReferences) { else if (query == qReferences) {
for (auto & p : store->queryPathInfo(j)->references) for (auto & p : store->queryPathInfo(j)->references)
paths.insert(p); paths.insert(p.clone());
}
else if (query == qReferrers) {
StorePathSet tmp;
store->queryReferrers(j, tmp);
for (auto & i : tmp)
paths.insert(i.clone());
} }
else if (query == qReferrers) store->queryReferrers(j, paths);
else if (query == qReferrersClosure) store->computeFSClosure(j, paths, true); else if (query == qReferrersClosure) store->computeFSClosure(j, paths, true);
} }
} }
Paths sorted = store->topoSortPaths(paths); auto sorted = store->topoSortPaths(paths);
for (Paths::reverse_iterator i = sorted.rbegin(); for (StorePaths::reverse_iterator i = sorted.rbegin();
i != sorted.rend(); ++i) i != sorted.rend(); ++i)
cout << format("%s\n") % *i; cout << fmt("%s\n", store->printStorePath(*i));
break; break;
} }
case qDeriver: case qDeriver:
for (auto & i : opArgs) { for (auto & i : opArgs) {
Path deriver = store->queryPathInfo(store->followLinksToStorePath(i))->deriver; auto info = store->queryPathInfo(store->followLinksToStorePath(i));
cout << format("%1%\n") % cout << fmt("%s\n", info->deriver ? store->printStorePath(*info->deriver) : "unknown-deriver");
(deriver == "" ? "unknown-deriver" : deriver);
} }
break; break;
case qBinding: case qBinding:
for (auto & i : opArgs) { for (auto & i : opArgs) {
Path path = useDeriver(store->followLinksToStorePath(i)); auto path = useDeriver(store->followLinksToStorePath(i));
Derivation drv = store->derivationFromPath(path); Derivation drv = store->derivationFromPath(path);
StringPairs::iterator j = drv.env.find(bindingName); StringPairs::iterator j = drv.env.find(bindingName);
if (j == drv.env.end()) if (j == drv.env.end())
throw Error(format("derivation '%1%' has no environment binding named '%2%'") throw Error("derivation '%s' has no environment binding named '%s'",
% path % bindingName); store->printStorePath(path), bindingName);
cout << format("%1%\n") % j->second; cout << fmt("%s\n", j->second);
} }
break; break;
case qHash: case qHash:
case qSize: case qSize:
for (auto & i : opArgs) { for (auto & i : opArgs) {
PathSet paths = maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise); for (auto & j : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise)) {
for (auto & j : paths) {
auto info = store->queryPathInfo(j); auto info = store->queryPathInfo(j);
if (query == qHash) { if (query == qHash) {
assert(info->narHash.type == htSHA256); assert(info->narHash.type == htSHA256);
@ -387,50 +386,51 @@ static void opQuery(Strings opFlags, Strings opArgs)
break; break;
case qTree: { case qTree: {
PathSet done; StorePathSet done;
for (auto & i : opArgs) for (auto & i : opArgs)
printTree(store->followLinksToStorePath(i), "", "", done); printTree(store->followLinksToStorePath(i), "", "", done);
break; break;
} }
case qGraph: { case qGraph: {
PathSet roots; StorePathSet roots;
for (auto & i : opArgs) { for (auto & i : opArgs)
PathSet paths = maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise); for (auto & j : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise))
roots.insert(paths.begin(), paths.end()); roots.insert(j.clone());
} printDotGraph(ref<Store>(store), std::move(roots));
printDotGraph(ref<Store>(store), roots);
break; break;
} }
case qGraphML: { case qGraphML: {
PathSet roots; StorePathSet roots;
for (auto & i : opArgs) { for (auto & i : opArgs)
PathSet paths = maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise); for (auto & j : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise))
roots.insert(paths.begin(), paths.end()); roots.insert(j.clone());
} printGraphML(ref<Store>(store), std::move(roots));
printGraphML(ref<Store>(store), roots);
break; break;
} }
case qResolve: { case qResolve: {
for (auto & i : opArgs) for (auto & i : opArgs)
cout << format("%1%\n") % store->followLinksToStorePath(i); cout << fmt("%s\n", store->printStorePath(store->followLinksToStorePath(i)));
break; break;
} }
case qRoots: { case qRoots: {
PathSet referrers; StorePathSet args;
for (auto & i : opArgs) { for (auto & i : opArgs)
store->computeFSClosure( for (auto & p : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise))
maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise), args.insert(p.clone());
referrers, true, settings.gcKeepOutputs, settings.gcKeepDerivations);
} StorePathSet referrers;
store->computeFSClosure(
args, referrers, true, settings.gcKeepOutputs, settings.gcKeepDerivations);
Roots roots = store->findRoots(false); Roots roots = store->findRoots(false);
for (auto & [target, links] : roots) for (auto & [target, links] : roots)
if (referrers.find(target) != referrers.end()) if (referrers.find(target) != referrers.end())
for (auto & link : links) for (auto & link : links)
cout << format("%1% -> %2%\n") % link % target; cout << fmt("%1% -> %2%\n", link, store->printStorePath(target));
break; break;
} }
@ -446,7 +446,7 @@ static void opPrintEnv(Strings opFlags, Strings opArgs)
if (opArgs.size() != 1) throw UsageError("'--print-env' requires one derivation store path"); if (opArgs.size() != 1) throw UsageError("'--print-env' requires one derivation store path");
Path drvPath = opArgs.front(); Path drvPath = opArgs.front();
Derivation drv = store->derivationFromPath(drvPath); Derivation drv = store->derivationFromPath(store->parseStorePath(drvPath));
/* Print each environment variable in the derivation in a format /* Print each environment variable in the derivation in a format
that can be sourced by the shell. */ that can be sourced by the shell. */
@ -476,7 +476,7 @@ static void opReadLog(Strings opFlags, Strings opArgs)
auto path = store->followLinksToStorePath(i); auto path = store->followLinksToStorePath(i);
auto log = store->getBuildLog(path); auto log = store->getBuildLog(path);
if (!log) if (!log)
throw Error("build log of derivation '%s' is not available", path); throw Error("build log of derivation '%s' is not available", store->printStorePath(path));
std::cout << *log; std::cout << *log;
} }
} }
@ -487,13 +487,10 @@ static void opDumpDB(Strings opFlags, Strings opArgs)
if (!opFlags.empty()) throw UsageError("unknown flag"); if (!opFlags.empty()) throw UsageError("unknown flag");
if (!opArgs.empty()) { if (!opArgs.empty()) {
for (auto & i : opArgs) for (auto & i : opArgs)
i = store->followLinksToStorePath(i); cout << store->makeValidityRegistration(singleton(store->followLinksToStorePath(i)), true, true);
for (auto & i : opArgs)
cout << store->makeValidityRegistration({i}, true, true);
} else { } else {
PathSet validPaths = store->queryAllValidPaths(); for (auto & i : store->queryAllValidPaths())
for (auto & i : validPaths) cout << store->makeValidityRegistration(singleton(i), true, true);
cout << store->makeValidityRegistration({i}, true, true);
} }
} }
@ -503,18 +500,18 @@ static void registerValidity(bool reregister, bool hashGiven, bool canonicalise)
ValidPathInfos infos; ValidPathInfos infos;
while (1) { while (1) {
ValidPathInfo info = decodeValidPathInfo(cin, hashGiven); auto info = decodeValidPathInfo(*store, cin, hashGiven);
if (info.path == "") break; if (!info) break;
if (!store->isValidPath(info.path) || reregister) { if (!store->isValidPath(info->path) || reregister) {
/* !!! races */ /* !!! races */
if (canonicalise) if (canonicalise)
canonicalisePathMetaData(info.path, -1); canonicalisePathMetaData(store->printStorePath(info->path), -1);
if (!hashGiven) { if (!hashGiven) {
HashResult hash = hashPath(htSHA256, info.path); HashResult hash = hashPath(htSHA256, store->printStorePath(info->path));
info.narHash = hash.first; info->narHash = hash.first;
info.narSize = hash.second; info->narSize = hash.second;
} }
infos.push_back(info); infos.push_back(std::move(*info));
} }
} }
@ -556,12 +553,12 @@ static void opCheckValidity(Strings opFlags, Strings opArgs)
else throw UsageError(format("unknown flag '%1%'") % i); else throw UsageError(format("unknown flag '%1%'") % i);
for (auto & i : opArgs) { for (auto & i : opArgs) {
Path path = store->followLinksToStorePath(i); auto path = store->followLinksToStorePath(i);
if (!store->isValidPath(path)) { if (!store->isValidPath(path)) {
if (printInvalid) if (printInvalid)
cout << format("%1%\n") % path; cout << fmt("%s\n", store->printStorePath(path));
else else
throw Error(format("path '%1%' is not valid") % path); throw Error("path '%s' is not valid", store->printStorePath(path));
} }
} }
} }
@ -591,13 +588,13 @@ static void opGC(Strings opFlags, Strings opArgs)
if (printRoots) { if (printRoots) {
Roots roots = store->findRoots(false); Roots roots = store->findRoots(false);
std::set<std::pair<Path, Path>> roots2; std::set<std::pair<Path, StorePath>> roots2;
// Transpose and sort the roots. // Transpose and sort the roots.
for (auto & [target, links] : roots) for (auto & [target, links] : roots)
for (auto & link : links) for (auto & link : links)
roots2.emplace(link, target); roots2.emplace(link, target.clone());
for (auto & [link, target] : roots2) for (auto & [link, target] : roots2)
std::cout << link << " -> " << target << "\n"; std::cout << link << " -> " << store->printStorePath(target) << "\n";
} }
else { else {
@ -661,11 +658,13 @@ static void opExport(Strings opFlags, Strings opArgs)
for (auto & i : opFlags) for (auto & i : opFlags)
throw UsageError(format("unknown flag '%1%'") % i); throw UsageError(format("unknown flag '%1%'") % i);
StorePathSet paths;
for (auto & i : opArgs) for (auto & i : opArgs)
i = store->followLinksToStorePath(i); paths.insert(store->followLinksToStorePath(i));
FdSink sink(STDOUT_FILENO); FdSink sink(STDOUT_FILENO);
store->exportPaths(opArgs, sink); store->exportPaths(paths, sink);
sink.flush(); sink.flush();
} }
@ -678,10 +677,10 @@ static void opImport(Strings opFlags, Strings opArgs)
if (!opArgs.empty()) throw UsageError("no arguments expected"); if (!opArgs.empty()) throw UsageError("no arguments expected");
FdSource source(STDIN_FILENO); FdSource source(STDIN_FILENO);
Paths paths = store->importPaths(source, nullptr, NoCheckSigs); auto paths = store->importPaths(source, nullptr, NoCheckSigs);
for (auto & i : paths) for (auto & i : paths)
cout << format("%1%\n") % i << std::flush; cout << fmt("%s\n", store->printStorePath(i)) << std::flush;
} }
@ -726,16 +725,16 @@ static void opVerifyPath(Strings opFlags, Strings opArgs)
int status = 0; int status = 0;
for (auto & i : opArgs) { for (auto & i : opArgs) {
Path path = store->followLinksToStorePath(i); auto path = store->followLinksToStorePath(i);
printMsg(lvlTalkative, format("checking path '%1%'...") % path); printMsg(lvlTalkative, "checking path '%s'...", store->printStorePath(path));
auto info = store->queryPathInfo(path); auto info = store->queryPathInfo(path);
HashSink sink(info->narHash.type); HashSink sink(info->narHash.type);
store->narFromPath(path, sink); store->narFromPath(path, sink);
auto current = sink.finish(); auto current = sink.finish();
if (current.first != info->narHash) { if (current.first != info->narHash) {
printError( printError(
format("path '%1%' was modified! expected hash '%2%', got '%3%'") "path '%s' was modified! expected hash '%s', got '%s'",
% path % info->narHash.to_string() % current.first.to_string()); store->printStorePath(path), info->narHash.to_string(), current.first.to_string());
status = 1; status = 1;
} }
} }
@ -751,10 +750,8 @@ static void opRepairPath(Strings opFlags, Strings opArgs)
if (!opFlags.empty()) if (!opFlags.empty())
throw UsageError("no flags expected"); throw UsageError("no flags expected");
for (auto & i : opArgs) { for (auto & i : opArgs)
Path path = store->followLinksToStorePath(i); ensureLocalStore()->repairPath(store->followLinksToStorePath(i));
ensureLocalStore()->repairPath(path);
}
} }
/* Optimise the disk space usage of the Nix store by hard-linking /* Optimise the disk space usage of the Nix store by hard-linking
@ -818,7 +815,7 @@ static void opServe(Strings opFlags, Strings opArgs)
case cmdQueryValidPaths: { case cmdQueryValidPaths: {
bool lock = readInt(in); bool lock = readInt(in);
bool substitute = readInt(in); bool substitute = readInt(in);
PathSet paths = readStorePaths<PathSet>(*store, in); auto paths = readStorePaths<StorePathSet>(*store, in);
if (lock && writeAllowed) if (lock && writeAllowed)
for (auto & path : paths) for (auto & path : paths)
store->addTempRoot(path); store->addTempRoot(path);
@ -828,34 +825,39 @@ static void opServe(Strings opFlags, Strings opArgs)
flag. */ flag. */
if (substitute && writeAllowed) { if (substitute && writeAllowed) {
/* Filter out .drv files (we don't want to build anything). */ /* Filter out .drv files (we don't want to build anything). */
PathSet paths2; std::vector<StorePathWithOutputs> paths2;
for (auto & path : paths) for (auto & path : paths)
if (!isDerivation(path)) paths2.insert(path); if (!path.isDerivation())
paths2.emplace_back(path.clone());
unsigned long long downloadSize, narSize; unsigned long long downloadSize, narSize;
PathSet willBuild, willSubstitute, unknown; StorePathSet willBuild, willSubstitute, unknown;
store->queryMissing(PathSet(paths2.begin(), paths2.end()), store->queryMissing(paths2,
willBuild, willSubstitute, unknown, downloadSize, narSize); willBuild, willSubstitute, unknown, downloadSize, narSize);
/* FIXME: should use ensurePath(), but it only /* FIXME: should use ensurePath(), but it only
does one path at a time. */ does one path at a time. */
if (!willSubstitute.empty()) if (!willSubstitute.empty())
try { try {
store->buildPaths(willSubstitute); std::vector<StorePathWithOutputs> subs;
for (auto & p : willSubstitute) subs.emplace_back(p.clone());
store->buildPaths(subs);
} catch (Error & e) { } catch (Error & e) {
printError(format("warning: %1%") % e.msg()); printError(format("warning: %1%") % e.msg());
} }
} }
out << store->queryValidPaths(paths); writeStorePaths(*store, out, store->queryValidPaths(paths));
break; break;
} }
case cmdQueryPathInfos: { case cmdQueryPathInfos: {
PathSet paths = readStorePaths<PathSet>(*store, in); auto paths = readStorePaths<StorePathSet>(*store, in);
// !!! Maybe we want a queryPathInfos? // !!! Maybe we want a queryPathInfos?
for (auto & i : paths) { for (auto & i : paths) {
try { try {
auto info = store->queryPathInfo(i); auto info = store->queryPathInfo(i);
out << info->path << info->deriver << info->references; out << store->printStorePath(info->path)
<< (info->deriver ? store->printStorePath(*info->deriver) : "");
writeStorePaths(*store, out, info->references);
// !!! Maybe we want compression? // !!! Maybe we want compression?
out << info->narSize // downloadSize out << info->narSize // downloadSize
<< info->narSize; << info->narSize;
@ -869,7 +871,7 @@ static void opServe(Strings opFlags, Strings opArgs)
} }
case cmdDumpStorePath: case cmdDumpStorePath:
store->narFromPath(readStorePath(*store, in), out); store->narFromPath(store->parseStorePath(readString(in)), out);
break; break;
case cmdImportPaths: { case cmdImportPaths: {
@ -881,14 +883,17 @@ static void opServe(Strings opFlags, Strings opArgs)
case cmdExportPaths: { case cmdExportPaths: {
readInt(in); // obsolete readInt(in); // obsolete
store->exportPaths(readStorePaths<Paths>(*store, in), out); store->exportPaths(readStorePaths<StorePathSet>(*store, in), out);
break; break;
} }
case cmdBuildPaths: { case cmdBuildPaths: {
if (!writeAllowed) throw Error("building paths is not allowed"); if (!writeAllowed) throw Error("building paths is not allowed");
PathSet paths = readStorePaths<PathSet>(*store, in);
std::vector<StorePathWithOutputs> paths;
for (auto & s : readStrings<Strings>(in))
paths.emplace_back(store->parseDrvPathWithOutputs(s));
getBuildSettings(); getBuildSettings();
@ -907,7 +912,7 @@ static void opServe(Strings opFlags, Strings opArgs)
if (!writeAllowed) throw Error("building paths is not allowed"); if (!writeAllowed) throw Error("building paths is not allowed");
Path drvPath = readStorePath(*store, in); // informational only auto drvPath = store->parseStorePath(readString(in)); // informational only
BasicDerivation drv; BasicDerivation drv;
readDerivation(in, *store, drv); readDerivation(in, *store, drv);
@ -926,30 +931,29 @@ static void opServe(Strings opFlags, Strings opArgs)
case cmdQueryClosure: { case cmdQueryClosure: {
bool includeOutputs = readInt(in); bool includeOutputs = readInt(in);
PathSet closure; StorePathSet closure;
store->computeFSClosure(readStorePaths<PathSet>(*store, in), store->computeFSClosure(readStorePaths<StorePathSet>(*store, in),
closure, false, includeOutputs); closure, false, includeOutputs);
out << closure; writeStorePaths(*store, out, closure);
break; break;
} }
case cmdAddToStoreNar: { case cmdAddToStoreNar: {
if (!writeAllowed) throw Error("importing paths is not allowed"); if (!writeAllowed) throw Error("importing paths is not allowed");
ValidPathInfo info; auto path = readString(in);
info.path = readStorePath(*store, in); ValidPathInfo info(store->parseStorePath(path));
in >> info.deriver; auto deriver = readString(in);
if (!info.deriver.empty()) if (deriver != "")
store->assertStorePath(info.deriver); info.deriver = store->parseStorePath(deriver);
info.narHash = Hash(readString(in), htSHA256); info.narHash = Hash(readString(in), htSHA256);
info.references = readStorePaths<PathSet>(*store, in); info.references = readStorePaths<StorePathSet>(*store, in);
in >> info.registrationTime >> info.narSize >> info.ultimate; in >> info.registrationTime >> info.narSize >> info.ultimate;
info.sigs = readStrings<StringSet>(in); info.sigs = readStrings<StringSet>(in);
in >> info.ca; in >> info.ca;
if (info.narSize == 0) { if (info.narSize == 0)
throw Error("narInfo is too old and missing the narSize field"); throw Error("narInfo is too old and missing the narSize field");
}
SizedSource sizedSource(in, info.narSize); SizedSource sizedSource(in, info.narSize);

View file

@ -40,16 +40,17 @@ struct CmdAddToStore : MixDryRun, StoreCommand
StringSink sink; StringSink sink;
dumpPath(path, sink); dumpPath(path, sink);
ValidPathInfo info; auto narHash = hashString(htSHA256, *sink.s);
info.narHash = hashString(htSHA256, *sink.s);
ValidPathInfo info(store->makeFixedOutputPath(true, narHash, *namePart));
info.narHash = narHash;
info.narSize = sink.s->size(); info.narSize = sink.s->size();
info.path = store->makeFixedOutputPath(true, info.narHash, *namePart);
info.ca = makeFixedOutputCA(true, info.narHash); info.ca = makeFixedOutputCA(true, info.narHash);
if (!dryRun) if (!dryRun)
store->addToStore(info, sink.s); store->addToStore(info, sink.s);
std::cout << fmt("%s\n", info.path); std::cout << fmt("%s\n", store->printStorePath(info.path));
} }
}; };

View file

@ -48,28 +48,29 @@ StorePathsCommand::StorePathsCommand(bool recursive)
void StorePathsCommand::run(ref<Store> store) void StorePathsCommand::run(ref<Store> store)
{ {
Paths storePaths; StorePaths storePaths;
if (all) { if (all) {
if (installables.size()) if (installables.size())
throw UsageError("'--all' does not expect arguments"); throw UsageError("'--all' does not expect arguments");
for (auto & p : store->queryAllValidPaths()) for (auto & p : store->queryAllValidPaths())
storePaths.push_back(p); storePaths.push_back(p.clone());
} }
else { else {
for (auto & p : toStorePaths(store, realiseMode, installables)) for (auto & p : toStorePaths(store, realiseMode, installables))
storePaths.push_back(p); storePaths.push_back(p.clone());
if (recursive) { if (recursive) {
PathSet closure; StorePathSet closure;
store->computeFSClosure(PathSet(storePaths.begin(), storePaths.end()), store->computeFSClosure(storePathsToSet(storePaths), closure, false, false);
closure, false, false); storePaths.clear();
storePaths = Paths(closure.begin(), closure.end()); for (auto & p : closure)
storePaths.push_back(p.clone());
} }
} }
run(store, storePaths); run(store, std::move(storePaths));
} }
void StorePathCommand::run(ref<Store> store) void StorePathCommand::run(ref<Store> store)

View file

@ -2,6 +2,7 @@
#include "args.hh" #include "args.hh"
#include "common-eval-args.hh" #include "common-eval-args.hh"
#include "path.hh"
namespace nix { namespace nix {
@ -28,8 +29,8 @@ private:
struct Buildable struct Buildable
{ {
Path drvPath; // may be empty std::optional<StorePath> drvPath;
std::map<std::string, Path> outputs; std::map<std::string, StorePath> outputs;
}; };
typedef std::vector<Buildable> Buildables; typedef std::vector<Buildable> Buildables;
@ -131,7 +132,7 @@ public:
using StoreCommand::run; using StoreCommand::run;
virtual void run(ref<Store> store, Paths storePaths) = 0; virtual void run(ref<Store> store, std::vector<StorePath> storePaths) = 0;
void run(ref<Store> store) override; void run(ref<Store> store) override;
@ -143,7 +144,7 @@ struct StorePathCommand : public InstallablesCommand
{ {
using StoreCommand::run; using StoreCommand::run;
virtual void run(ref<Store> store, const Path & storePath) = 0; virtual void run(ref<Store> store, const StorePath & storePath) = 0;
void run(ref<Store> store) override; void run(ref<Store> store) override;
}; };
@ -174,13 +175,13 @@ std::shared_ptr<Installable> parseInstallable(
Buildables build(ref<Store> store, RealiseMode mode, Buildables build(ref<Store> store, RealiseMode mode,
std::vector<std::shared_ptr<Installable>> installables); std::vector<std::shared_ptr<Installable>> installables);
PathSet toStorePaths(ref<Store> store, RealiseMode mode, std::set<StorePath> toStorePaths(ref<Store> store, RealiseMode mode,
std::vector<std::shared_ptr<Installable>> installables); std::vector<std::shared_ptr<Installable>> installables);
Path toStorePath(ref<Store> store, RealiseMode mode, StorePath toStorePath(ref<Store> store, RealiseMode mode,
std::shared_ptr<Installable> installable); std::shared_ptr<Installable> installable);
PathSet toDerivations(ref<Store> store, std::set<StorePath> toDerivations(ref<Store> store,
std::vector<std::shared_ptr<Installable>> installables, std::vector<std::shared_ptr<Installable>> installables,
bool useDeriver = false); bool useDeriver = false);

View file

@ -80,14 +80,14 @@ struct CmdCopy : StorePathsCommand
return srcUri.empty() ? StoreCommand::createStore() : openStore(srcUri); return srcUri.empty() ? StoreCommand::createStore() : openStore(srcUri);
} }
void run(ref<Store> srcStore, Paths storePaths) override void run(ref<Store> srcStore, StorePaths storePaths) override
{ {
if (srcUri.empty() && dstUri.empty()) if (srcUri.empty() && dstUri.empty())
throw UsageError("you must pass '--from' and/or '--to'"); throw UsageError("you must pass '--from' and/or '--to'");
ref<Store> dstStore = dstUri.empty() ? openStore() : openStore(dstUri); ref<Store> dstStore = dstUri.empty() ? openStore() : openStore(dstUri);
copyPaths(srcStore, dstStore, PathSet(storePaths.begin(), storePaths.end()), copyPaths(srcStore, dstStore, storePathsToSet(storePaths),
NoRepair, checkSigs, substitute); NoRepair, checkSigs, substitute);
} }
}; };

View file

@ -20,7 +20,7 @@ struct CmdDumpPath : StorePathCommand
}; };
} }
void run(ref<Store> store, const Path & storePath) override void run(ref<Store> store, const StorePath & storePath) override
{ {
FdSink sink(STDOUT_FILENO); FdSink sink(STDOUT_FILENO);
store->narFromPath(storePath, sink); store->narFromPath(storePath, sink);

View file

@ -89,15 +89,25 @@ Buildable Installable::toBuildable()
struct InstallableStorePath : Installable struct InstallableStorePath : Installable
{ {
Path storePath; ref<Store> store;
StorePath storePath;
InstallableStorePath(const Path & storePath) : storePath(storePath) { } InstallableStorePath(ref<Store> store, const Path & storePath)
: store(store), storePath(store->parseStorePath(storePath)) { }
std::string what() override { return storePath; } std::string what() override { return store->printStorePath(storePath); }
Buildables toBuildables() override Buildables toBuildables() override
{ {
return {{isDerivation(storePath) ? storePath : "", {{"out", storePath}}}}; std::map<std::string, StorePath> outputs;
outputs.insert_or_assign("out", storePath.clone());
Buildable b{
.drvPath = storePath.isDerivation() ? storePath.clone() : std::optional<StorePath>(),
.outputs = std::move(outputs)
};
Buildables bs;
bs.push_back(std::move(b));
return bs;
} }
}; };
@ -120,17 +130,17 @@ struct InstallableValue : Installable
Buildables res; Buildables res;
PathSet drvPaths; StorePathSet drvPaths;
for (auto & drv : drvs) { for (auto & drv : drvs) {
Buildable b{drv.queryDrvPath()}; Buildable b{.drvPath = state->store->parseStorePath(drv.queryDrvPath())};
drvPaths.insert(b.drvPath); drvPaths.insert(b.drvPath->clone());
auto outputName = drv.queryOutputName(); auto outputName = drv.queryOutputName();
if (outputName == "") if (outputName == "")
throw Error("derivation '%s' lacks an 'outputName' attribute", b.drvPath); throw Error("derivation '%s' lacks an 'outputName' attribute", state->store->printStorePath(*b.drvPath));
b.outputs.emplace(outputName, drv.queryOutPath()); b.outputs.emplace(outputName, state->store->parseStorePath(drv.queryOutPath()));
res.push_back(std::move(b)); res.push_back(std::move(b));
} }
@ -138,10 +148,13 @@ struct InstallableValue : Installable
// Hack to recognize .all: if all drvs have the same drvPath, // Hack to recognize .all: if all drvs have the same drvPath,
// merge the buildables. // merge the buildables.
if (drvPaths.size() == 1) { if (drvPaths.size() == 1) {
Buildable b{*drvPaths.begin()}; Buildable b{.drvPath = drvPaths.begin()->clone()};
for (auto & b2 : res) for (auto & b2 : res)
b.outputs.insert(b2.outputs.begin(), b2.outputs.end()); for (auto & output : b2.outputs)
return {b}; b.outputs.insert_or_assign(output.first, output.second.clone());
Buildables bs;
bs.push_back(std::move(b));
return bs;
} else } else
return res; return res;
} }
@ -212,7 +225,7 @@ static std::vector<std::shared_ptr<Installable>> parseInstallables(
auto path = store->toStorePath(store->followLinksToStore(s)); auto path = store->toStorePath(store->followLinksToStore(s));
if (store->isStorePath(path)) if (store->isStorePath(path))
result.push_back(std::make_shared<InstallableStorePath>(path)); result.push_back(std::make_shared<InstallableStorePath>(store, path));
} }
else if (s == "" || std::regex_match(s, attrPathRegex)) else if (s == "" || std::regex_match(s, attrPathRegex))
@ -242,19 +255,18 @@ Buildables build(ref<Store> store, RealiseMode mode,
Buildables buildables; Buildables buildables;
PathSet pathsToBuild; std::vector<StorePathWithOutputs> pathsToBuild;
for (auto & i : installables) { for (auto & i : installables) {
for (auto & b : i->toBuildables()) { for (auto & b : i->toBuildables()) {
if (b.drvPath != "") { if (b.drvPath) {
StringSet outputNames; StringSet outputNames;
for (auto & output : b.outputs) for (auto & output : b.outputs)
outputNames.insert(output.first); outputNames.insert(output.first);
pathsToBuild.insert( pathsToBuild.push_back({*b.drvPath, outputNames});
b.drvPath + "!" + concatStringsSep(",", outputNames));
} else } else
for (auto & output : b.outputs) for (auto & output : b.outputs)
pathsToBuild.insert(output.second); pathsToBuild.push_back({output.second.clone()});
buildables.push_back(std::move(b)); buildables.push_back(std::move(b));
} }
} }
@ -267,19 +279,19 @@ Buildables build(ref<Store> store, RealiseMode mode,
return buildables; return buildables;
} }
PathSet toStorePaths(ref<Store> store, RealiseMode mode, StorePathSet toStorePaths(ref<Store> store, RealiseMode mode,
std::vector<std::shared_ptr<Installable>> installables) std::vector<std::shared_ptr<Installable>> installables)
{ {
PathSet outPaths; StorePathSet outPaths;
for (auto & b : build(store, mode, installables)) for (auto & b : build(store, mode, installables))
for (auto & output : b.outputs) for (auto & output : b.outputs)
outPaths.insert(output.second); outPaths.insert(output.second.clone());
return outPaths; return outPaths;
} }
Path toStorePath(ref<Store> store, RealiseMode mode, StorePath toStorePath(ref<Store> store, RealiseMode mode,
std::shared_ptr<Installable> installable) std::shared_ptr<Installable> installable)
{ {
auto paths = toStorePaths(store, mode, {installable}); auto paths = toStorePaths(store, mode, {installable});
@ -287,17 +299,17 @@ Path toStorePath(ref<Store> store, RealiseMode mode,
if (paths.size() != 1) if (paths.size() != 1)
throw Error("argument '%s' should evaluate to one store path", installable->what()); throw Error("argument '%s' should evaluate to one store path", installable->what());
return *paths.begin(); return paths.begin()->clone();
} }
PathSet toDerivations(ref<Store> store, StorePathSet toDerivations(ref<Store> store,
std::vector<std::shared_ptr<Installable>> installables, bool useDeriver) std::vector<std::shared_ptr<Installable>> installables, bool useDeriver)
{ {
PathSet drvPaths; StorePathSet drvPaths;
for (auto & i : installables) for (auto & i : installables)
for (auto & b : i->toBuildables()) { for (auto & b : i->toBuildables()) {
if (b.drvPath.empty()) { if (!b.drvPath) {
if (!useDeriver) if (!useDeriver)
throw Error("argument '%s' did not evaluate to a derivation", i->what()); throw Error("argument '%s' did not evaluate to a derivation", i->what());
for (auto & output : b.outputs) { for (auto & output : b.outputs) {
@ -305,10 +317,10 @@ PathSet toDerivations(ref<Store> store,
if (derivers.empty()) if (derivers.empty())
throw Error("'%s' does not have a known deriver", i->what()); throw Error("'%s' does not have a known deriver", i->what());
// FIXME: use all derivers? // FIXME: use all derivers?
drvPaths.insert(*derivers.begin()); drvPaths.insert(derivers.begin()->clone());
} }
} else } else
drvPaths.insert(b.drvPath); drvPaths.insert(b.drvPath->clone());
} }
return drvPaths; return drvPaths;

View file

@ -15,7 +15,7 @@ nix_SOURCES := \
$(wildcard src/nix-prefetch-url/*.cc) \ $(wildcard src/nix-prefetch-url/*.cc) \
$(wildcard src/nix-store/*.cc) \ $(wildcard src/nix-store/*.cc) \
nix_LIBS = libexpr libmain libstore libutil nix_LIBS = libexpr libmain libstore libutil libnixrust
nix_LDFLAGS = -pthread $(SODIUM_LIBS) $(EDITLINE_LIBS) $(BOOST_LDFLAGS) -lboost_context -lboost_thread -lboost_system nix_LDFLAGS = -pthread $(SODIUM_LIBS) $(EDITLINE_LIBS) $(BOOST_LDFLAGS) -lboost_context -lboost_thread -lboost_system

View file

@ -43,7 +43,7 @@ struct CmdLog : InstallableCommand
RunPager pager; RunPager pager;
for (auto & sub : subs) { for (auto & sub : subs) {
auto log = b.drvPath != "" ? sub->getBuildLog(b.drvPath) : nullptr; auto log = b.drvPath ? sub->getBuildLog(*b.drvPath) : nullptr;
for (auto & output : b.outputs) { for (auto & output : b.outputs) {
if (log) break; if (log) break;
log = sub->getBuildLog(output.second); log = sub->getBuildLog(output.second);

View file

@ -67,7 +67,7 @@ struct MixLs : virtual Args, MixJSON
if (st.type == FSAccessor::Type::tMissing) if (st.type == FSAccessor::Type::tMissing)
throw Error(format("path '%1%' does not exist") % path); throw Error(format("path '%1%' does not exist") % path);
doPath(st, path, doPath(st, path,
st.type == FSAccessor::Type::tDirectory ? "." : baseNameOf(path), st.type == FSAccessor::Type::tDirectory ? "." : std::string(baseNameOf(path)),
showDirectory); showDirectory);
} }

View file

@ -135,7 +135,7 @@ void mainWrapped(int argc, char * * argv)
initGC(); initGC();
programPath = argv[0]; programPath = argv[0];
string programName = baseNameOf(programPath); auto programName = std::string(baseNameOf(programPath));
{ {
auto legacy = (*RegisterLegacyCommand::commands)[programName]; auto legacy = (*RegisterLegacyCommand::commands)[programName];

View file

@ -29,34 +29,36 @@ struct CmdMakeContentAddressable : StorePathsCommand
}, },
}; };
} }
void run(ref<Store> store, Paths storePaths) override void run(ref<Store> store, StorePaths storePaths) override
{ {
auto paths = store->topoSortPaths(PathSet(storePaths.begin(), storePaths.end())); auto paths = store->topoSortPaths(storePathsToSet(storePaths));
paths.reverse(); std::reverse(paths.begin(), paths.end());
std::map<Path, Path> remappings; std::map<StorePath, StorePath> remappings;
for (auto & path : paths) { for (auto & path : paths) {
auto pathS = store->printStorePath(path);
auto oldInfo = store->queryPathInfo(path); auto oldInfo = store->queryPathInfo(path);
auto oldHashPart = storePathToHash(path); auto oldHashPart = storePathToHash(pathS);
auto name = storePathToName(path);
StringSink sink; StringSink sink;
store->narFromPath(path, sink); store->narFromPath(path, sink);
StringMap rewrites; StringMap rewrites;
ValidPathInfo info; StorePathSet references;
bool hasSelfReference = false;
for (auto & ref : oldInfo->references) { for (auto & ref : oldInfo->references) {
if (ref == path) if (ref == path)
info.references.insert("self"); hasSelfReference = true;
else { else {
auto replacement = get(remappings, ref, ref); auto i = remappings.find(ref);
auto replacement = i != remappings.end() ? i->second.clone() : ref.clone();
// FIXME: warn about unremapped paths? // FIXME: warn about unremapped paths?
info.references.insert(replacement);
if (replacement != ref) if (replacement != ref)
rewrites[storePathToHash(ref)] = storePathToHash(replacement); rewrites.insert_or_assign(store->printStorePath(ref), store->printStorePath(replacement));
references.insert(std::move(replacement));
} }
} }
@ -65,24 +67,26 @@ struct CmdMakeContentAddressable : StorePathsCommand
HashModuloSink hashModuloSink(htSHA256, oldHashPart); HashModuloSink hashModuloSink(htSHA256, oldHashPart);
hashModuloSink((unsigned char *) sink.s->data(), sink.s->size()); hashModuloSink((unsigned char *) sink.s->data(), sink.s->size());
info.narHash = hashModuloSink.finish().first; auto narHash = hashModuloSink.finish().first;
ValidPathInfo info(store->makeFixedOutputPath(true, narHash, path.name(), references, hasSelfReference));
info.references = std::move(references);
if (hasSelfReference) info.references.insert(info.path.clone());
info.narHash = narHash;
info.narSize = sink.s->size(); info.narSize = sink.s->size();
replaceInSet(info.references, path, std::string("self"));
info.path = store->makeFixedOutputPath(true, info.narHash, name, info.references);
replaceInSet(info.references, std::string("self"), info.path);
info.ca = makeFixedOutputCA(true, info.narHash); info.ca = makeFixedOutputCA(true, info.narHash);
printError("rewrote '%s' to '%s'", path, info.path); printError("rewrote '%s' to '%s'", pathS, store->printStorePath(info.path));
auto source = sinkToSource([&](Sink & nextSink) { auto source = sinkToSource([&](Sink & nextSink) {
RewritingSink rsink2(oldHashPart, storePathToHash(info.path), nextSink); RewritingSink rsink2(oldHashPart, storePathToHash(store->printStorePath(info.path)), nextSink);
rsink2((unsigned char *) sink.s->data(), sink.s->size()); rsink2((unsigned char *) sink.s->data(), sink.s->size());
rsink2.flush(); rsink2.flush();
}); });
store->addToStore(info, *source); store->addToStore(info, *source);
remappings[path] = info.path; remappings.insert_or_assign(std::move(path), std::move(info.path));
} }
} }
}; };

View file

@ -78,36 +78,36 @@ struct CmdPathInfo : StorePathsCommand, MixJSON
std::cout << fmt("\t%6.1f%c", res, idents.at(power)); std::cout << fmt("\t%6.1f%c", res, idents.at(power));
} }
void run(ref<Store> store, Paths storePaths) override void run(ref<Store> store, StorePaths storePaths) override
{ {
size_t pathLen = 0; size_t pathLen = 0;
for (auto & storePath : storePaths) for (auto & storePath : storePaths)
pathLen = std::max(pathLen, storePath.size()); pathLen = std::max(pathLen, store->printStorePath(storePath).size());
if (json) { if (json) {
JSONPlaceholder jsonRoot(std::cout); JSONPlaceholder jsonRoot(std::cout);
store->pathInfoToJSON(jsonRoot, store->pathInfoToJSON(jsonRoot,
// FIXME: preserve order? // FIXME: preserve order?
PathSet(storePaths.begin(), storePaths.end()), storePathsToSet(storePaths),
true, showClosureSize, AllowInvalid); true, showClosureSize, AllowInvalid);
} }
else { else {
for (auto storePath : storePaths) { for (auto & storePath : storePaths) {
auto info = store->queryPathInfo(storePath); auto info = store->queryPathInfo(storePath);
storePath = info->path; // FIXME: screws up padding auto storePathS = store->printStorePath(storePath);
std::cout << storePath; std::cout << storePathS;
if (showSize || showClosureSize || showSigs) if (showSize || showClosureSize || showSigs)
std::cout << std::string(std::max(0, (int) pathLen - (int) storePath.size()), ' '); std::cout << std::string(std::max(0, (int) pathLen - (int) storePathS.size()), ' ');
if (showSize) if (showSize)
printSize(info->narSize); printSize(info->narSize);
if (showClosureSize) if (showClosureSize)
printSize(store->getClosureSize(storePath).first); printSize(store->getClosureSize(info->path).first);
if (showSigs) { if (showSigs) {
std::cout << '\t'; std::cout << '\t';

View file

@ -24,6 +24,13 @@ static uint64_t getI(const std::vector<Logger::Field> & fields, size_t n)
return fields[n].i; return fields[n].i;
} }
static std::string_view storePathToName(std::string_view path)
{
auto base = baseNameOf(path);
auto i = base.find('-');
return i == std::string::npos ? base.substr(0, 0) : base.substr(i + 1);
}
class ProgressBar : public Logger class ProgressBar : public Logger
{ {
private: private:
@ -148,7 +155,7 @@ public:
if (type == actBuild) { if (type == actBuild) {
auto name = storePathToName(getS(fields, 0)); auto name = storePathToName(getS(fields, 0));
if (hasSuffix(name, ".drv")) if (hasSuffix(name, ".drv"))
name.resize(name.size() - 4); name = name.substr(name.size() - 4);
i->s = fmt("building " ANSI_BOLD "%s" ANSI_NORMAL, name); i->s = fmt("building " ANSI_BOLD "%s" ANSI_NORMAL, name);
auto machineName = getS(fields, 1); auto machineName = getS(fields, 1);
if (machineName != "") if (machineName != "")
@ -173,7 +180,7 @@ public:
if (type == actPostBuildHook) { if (type == actPostBuildHook) {
auto name = storePathToName(getS(fields, 0)); auto name = storePathToName(getS(fields, 0));
if (hasSuffix(name, ".drv")) if (hasSuffix(name, ".drv"))
name.resize(name.size() - 4); name = name.substr(name.size() - 4);
i->s = fmt("post-build " ANSI_BOLD "%s" ANSI_NORMAL, name); i->s = fmt("post-build " ANSI_BOLD "%s" ANSI_NORMAL, name);
i->name = DrvName(name).name; i->name = DrvName(name).name;
} }

View file

@ -413,7 +413,7 @@ Path NixRepl::getDerivationPath(Value & v) {
if (!drvInfo) if (!drvInfo)
throw Error("expression does not evaluate to a derivation, so I can't build it"); throw Error("expression does not evaluate to a derivation, so I can't build it");
Path drvPath = drvInfo->queryDrvPath(); Path drvPath = drvInfo->queryDrvPath();
if (drvPath == "" || !state.store->isValidPath(drvPath)) if (drvPath == "" || !state.store->isValidPath(state.store->parseStorePath(drvPath)))
throw Error("expression did not evaluate to a valid derivation"); throw Error("expression did not evaluate to a valid derivation");
return drvPath; return drvPath;
} }
@ -521,10 +521,10 @@ bool NixRepl::processLine(string line)
but doing it in a child makes it easier to recover from but doing it in a child makes it easier to recover from
problems / SIGINT. */ problems / SIGINT. */
if (runProgram(settings.nixBinDir + "/nix", Strings{"build", "--no-link", drvPath}) == 0) { if (runProgram(settings.nixBinDir + "/nix", Strings{"build", "--no-link", drvPath}) == 0) {
Derivation drv = readDerivation(drvPath); auto drv = readDerivation(*state.store, drvPath);
std::cout << std::endl << "this derivation produced the following outputs:" << std::endl; std::cout << std::endl << "this derivation produced the following outputs:" << std::endl;
for (auto & i : drv.outputs) for (auto & i : drv.outputs)
std::cout << format(" %1% -> %2%") % i.first % i.second.path << std::endl; std::cout << fmt(" %s -> %s\n", i.first, state.store->printStorePath(i.second.path));
} }
} else if (command == ":i") { } else if (command == ":i") {
runProgram(settings.nixBinDir + "/nix-env", Strings{"-i", drvPath}); runProgram(settings.nixBinDir + "/nix-env", Strings{"-i", drvPath});

View file

@ -119,24 +119,24 @@ struct CmdRun : InstallablesCommand
unsetenv(var.c_str()); unsetenv(var.c_str());
} }
std::unordered_set<Path> done; std::unordered_set<StorePath> done;
std::queue<Path> todo; std::queue<StorePath> todo;
for (auto & path : outPaths) todo.push(path); for (auto & path : outPaths) todo.push(path.clone());
auto unixPath = tokenizeString<Strings>(getEnv("PATH").value_or(""), ":"); auto unixPath = tokenizeString<Strings>(getEnv("PATH").value_or(""), ":");
while (!todo.empty()) { while (!todo.empty()) {
Path path = todo.front(); auto path = todo.front().clone();
todo.pop(); todo.pop();
if (!done.insert(path).second) continue; if (!done.insert(path.clone()).second) continue;
if (true) if (true)
unixPath.push_front(path + "/bin"); unixPath.push_front(store->printStorePath(path) + "/bin");
auto propPath = path + "/nix-support/propagated-user-env-packages"; auto propPath = store->printStorePath(path) + "/nix-support/propagated-user-env-packages";
if (accessor->stat(propPath).type == FSAccessor::tRegular) { if (accessor->stat(propPath).type == FSAccessor::tRegular) {
for (auto & p : tokenizeString<Paths>(readFile(propPath))) for (auto & p : tokenizeString<Paths>(readFile(propPath)))
todo.push(p); todo.push(store->parseStorePath(p));
} }
} }

View file

@ -46,9 +46,9 @@ struct CmdShowDerivation : InstallablesCommand
auto drvPaths = toDerivations(store, installables, true); auto drvPaths = toDerivations(store, installables, true);
if (recursive) { if (recursive) {
PathSet closure; StorePathSet closure;
store->computeFSClosure(drvPaths, closure); store->computeFSClosure(drvPaths, closure);
drvPaths = closure; drvPaths = std::move(closure);
} }
{ {
@ -56,17 +56,19 @@ struct CmdShowDerivation : InstallablesCommand
JSONObject jsonRoot(std::cout, true); JSONObject jsonRoot(std::cout, true);
for (auto & drvPath : drvPaths) { for (auto & drvPath : drvPaths) {
if (!isDerivation(drvPath)) continue; if (!drvPath.isDerivation()) continue;
auto drvObj(jsonRoot.object(drvPath)); auto drvPathS = store->printStorePath(drvPath);
auto drv = readDerivation(drvPath); auto drvObj(jsonRoot.object(drvPathS));
auto drv = readDerivation(*store, drvPathS);
{ {
auto outputsObj(drvObj.object("outputs")); auto outputsObj(drvObj.object("outputs"));
for (auto & output : drv.outputs) { for (auto & output : drv.outputs) {
auto outputObj(outputsObj.object(output.first)); auto outputObj(outputsObj.object(output.first));
outputObj.attr("path", output.second.path); outputObj.attr("path", store->printStorePath(output.second.path));
if (output.second.hash != "") { if (output.second.hash != "") {
outputObj.attr("hashAlgo", output.second.hashAlgo); outputObj.attr("hashAlgo", output.second.hashAlgo);
outputObj.attr("hash", output.second.hash); outputObj.attr("hash", output.second.hash);
@ -77,13 +79,13 @@ struct CmdShowDerivation : InstallablesCommand
{ {
auto inputsList(drvObj.list("inputSrcs")); auto inputsList(drvObj.list("inputSrcs"));
for (auto & input : drv.inputSrcs) for (auto & input : drv.inputSrcs)
inputsList.elem(input); inputsList.elem(store->printStorePath(input));
} }
{ {
auto inputDrvsObj(drvObj.object("inputDrvs")); auto inputDrvsObj(drvObj.object("inputDrvs"));
for (auto & input : drv.inputDrvs) { for (auto & input : drv.inputDrvs) {
auto inputList(inputDrvsObj.list(input.first)); auto inputList(inputDrvsObj.list(store->printStorePath(input.first)));
for (auto & outputId : input.second) for (auto & outputId : input.second)
inputList.elem(outputId); inputList.elem(outputId);
} }

View file

@ -27,7 +27,7 @@ struct CmdCopySigs : StorePathsCommand
return "copy path signatures from substituters (like binary caches)"; return "copy path signatures from substituters (like binary caches)";
} }
void run(ref<Store> store, Paths storePaths) override void run(ref<Store> store, StorePaths storePaths) override
{ {
if (substituterUris.empty()) if (substituterUris.empty())
throw UsageError("you must specify at least one substituter using '-s'"); throw UsageError("you must specify at least one substituter using '-s'");
@ -44,18 +44,20 @@ struct CmdCopySigs : StorePathsCommand
//logger->setExpected(doneLabel, storePaths.size()); //logger->setExpected(doneLabel, storePaths.size());
auto doPath = [&](const Path & storePath) { auto doPath = [&](const Path & storePathS) {
//Activity act(*logger, lvlInfo, format("getting signatures for '%s'") % storePath); //Activity act(*logger, lvlInfo, format("getting signatures for '%s'") % storePath);
checkInterrupt(); checkInterrupt();
auto storePath = store->parseStorePath(storePathS);
auto info = store->queryPathInfo(storePath); auto info = store->queryPathInfo(storePath);
StringSet newSigs; StringSet newSigs;
for (auto & store2 : substituters) { for (auto & store2 : substituters) {
try { try {
auto info2 = store2->queryPathInfo(storePath); auto info2 = store2->queryPathInfo(info->path);
/* Don't import signatures that don't match this /* Don't import signatures that don't match this
binary. */ binary. */
@ -80,11 +82,11 @@ struct CmdCopySigs : StorePathsCommand
}; };
for (auto & storePath : storePaths) for (auto & storePath : storePaths)
pool.enqueue(std::bind(doPath, storePath)); pool.enqueue(std::bind(doPath, store->printStorePath(storePath)));
pool.process(); pool.process();
printInfo(format("imported %d signatures") % added); printInfo("imported %d signatures", added);
} }
}; };
@ -109,7 +111,7 @@ struct CmdSignPaths : StorePathsCommand
return "sign the specified paths"; return "sign the specified paths";
} }
void run(ref<Store> store, Paths storePaths) override void run(ref<Store> store, StorePaths storePaths) override
{ {
if (secretKeyFile.empty()) if (secretKeyFile.empty())
throw UsageError("you must specify a secret key file using '-k'"); throw UsageError("you must specify a secret key file using '-k'");
@ -123,7 +125,7 @@ struct CmdSignPaths : StorePathsCommand
auto info2(*info); auto info2(*info);
info2.sigs.clear(); info2.sigs.clear();
info2.sign(secretKey); info2.sign(*store, secretKey);
assert(!info2.sigs.empty()); assert(!info2.sigs.empty());
if (!info->sigs.count(*info2.sigs.begin())) { if (!info->sigs.count(*info2.sigs.begin())) {
@ -132,7 +134,7 @@ struct CmdSignPaths : StorePathsCommand
} }
} }
printInfo(format("added %d signatures") % added); printInfo("added %d signatures", added);
} }
}; };

View file

@ -58,13 +58,9 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
printInfo("upgrading Nix in profile '%s'", profileDir); printInfo("upgrading Nix in profile '%s'", profileDir);
Path storePath; auto storePath = getLatestNix(store);
{
Activity act(*logger, lvlInfo, actUnknown, "querying latest Nix version");
storePath = getLatestNix(store);
}
auto version = DrvName(storePathToName(storePath)).version; auto version = DrvName(storePath.name()).version;
if (dryRun) { if (dryRun) {
stopProgressBar(); stopProgressBar();
@ -73,13 +69,13 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
} }
{ {
Activity act(*logger, lvlInfo, actUnknown, fmt("downloading '%s'...", storePath)); Activity act(*logger, lvlInfo, actUnknown, fmt("downloading '%s'...", store->printStorePath(storePath)));
store->ensurePath(storePath); store->ensurePath(storePath);
} }
{ {
Activity act(*logger, lvlInfo, actUnknown, fmt("verifying that '%s' works...", storePath)); Activity act(*logger, lvlInfo, actUnknown, fmt("verifying that '%s' works...", store->printStorePath(storePath)));
auto program = storePath + "/bin/nix-env"; auto program = store->printStorePath(storePath) + "/bin/nix-env";
auto s = runProgram(program, false, {"--version"}); auto s = runProgram(program, false, {"--version"});
if (s.find("Nix") == std::string::npos) if (s.find("Nix") == std::string::npos)
throw Error("could not verify that '%s' works", program); throw Error("could not verify that '%s' works", program);
@ -88,9 +84,10 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
stopProgressBar(); stopProgressBar();
{ {
Activity act(*logger, lvlInfo, actUnknown, fmt("installing '%s' into profile '%s'...", storePath, profileDir)); Activity act(*logger, lvlInfo, actUnknown,
fmt("installing '%s' into profile '%s'...", store->printStorePath(storePath), profileDir));
runProgram(settings.nixBinDir + "/nix-env", false, runProgram(settings.nixBinDir + "/nix-env", false,
{"--profile", profileDir, "-i", storePath, "--no-sandbox"}); {"--profile", profileDir, "-i", store->printStorePath(storePath), "--no-sandbox"});
} }
printError(ANSI_GREEN "upgrade to version %s done" ANSI_NORMAL, version); printError(ANSI_GREEN "upgrade to version %s done" ANSI_NORMAL, version);
@ -129,15 +126,17 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
!hasSuffix(userEnv, "user-environment")) !hasSuffix(userEnv, "user-environment"))
throw Error("directory '%s' does not appear to be part of a Nix profile", where); throw Error("directory '%s' does not appear to be part of a Nix profile", where);
if (!store->isValidPath(userEnv)) if (!store->isValidPath(store->parseStorePath(userEnv)))
throw Error("directory '%s' is not in the Nix store", userEnv); throw Error("directory '%s' is not in the Nix store", userEnv);
return profileDir; return profileDir;
} }
/* Return the store path of the latest stable Nix. */ /* Return the store path of the latest stable Nix. */
Path getLatestNix(ref<Store> store) StorePath getLatestNix(ref<Store> store)
{ {
Activity act(*logger, lvlInfo, actUnknown, "querying latest Nix version");
// FIXME: use nixos.org? // FIXME: use nixos.org?
auto req = DownloadRequest(storePathsUrl); auto req = DownloadRequest(storePathsUrl);
auto res = getDownloader()->download(req); auto res = getDownloader()->download(req);
@ -148,7 +147,7 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
Bindings & bindings(*state->allocBindings(0)); Bindings & bindings(*state->allocBindings(0));
auto v2 = findAlongAttrPath(*state, settings.thisSystem, bindings, *v); auto v2 = findAlongAttrPath(*state, settings.thisSystem, bindings, *v);
return state->forceString(*v2); return store->parseStorePath(state->forceString(*v2));
} }
}; };

View file

@ -49,7 +49,7 @@ struct CmdVerify : StorePathsCommand
}; };
} }
void run(ref<Store> store, Paths storePaths) override void run(ref<Store> store, StorePaths storePaths) override
{ {
std::vector<ref<Store>> substituters; std::vector<ref<Store>> substituters;
for (auto & s : substituterUris) for (auto & s : substituterUris)
@ -80,7 +80,7 @@ struct CmdVerify : StorePathsCommand
MaintainCount<std::atomic<size_t>> mcActive(active); MaintainCount<std::atomic<size_t>> mcActive(active);
update(); update();
auto info = store->queryPathInfo(storePath); auto info = store->queryPathInfo(store->parseStorePath(storePath));
if (!noContents) { if (!noContents) {
@ -88,7 +88,7 @@ struct CmdVerify : StorePathsCommand
if (info->ca == "") if (info->ca == "")
hashSink = std::make_unique<HashSink>(info->narHash.type); hashSink = std::make_unique<HashSink>(info->narHash.type);
else else
hashSink = std::make_unique<HashModuloSink>(info->narHash.type, storePathToHash(info->path)); hashSink = std::make_unique<HashModuloSink>(info->narHash.type, storePathToHash(store->printStorePath(info->path)));
store->narFromPath(info->path, *hashSink); store->narFromPath(info->path, *hashSink);
@ -96,10 +96,10 @@ struct CmdVerify : StorePathsCommand
if (hash.first != info->narHash) { if (hash.first != info->narHash) {
corrupted++; corrupted++;
act2.result(resCorruptedPath, info->path); act2.result(resCorruptedPath, store->printStorePath(info->path));
printError( printError(
format("path '%s' was modified! expected hash '%s', got '%s'") "path '%s' was modified! expected hash '%s', got '%s'",
% info->path % info->narHash.to_string() % hash.first.to_string()); store->printStorePath(info->path), info->narHash.to_string(), hash.first.to_string());
} }
} }
@ -120,7 +120,7 @@ struct CmdVerify : StorePathsCommand
auto doSigs = [&](StringSet sigs) { auto doSigs = [&](StringSet sigs) {
for (auto sig : sigs) { for (auto sig : sigs) {
if (!sigsSeen.insert(sig).second) continue; if (!sigsSeen.insert(sig).second) continue;
if (validSigs < ValidPathInfo::maxSigs && info->checkSignature(publicKeys, sig)) if (validSigs < ValidPathInfo::maxSigs && info->checkSignature(*store, publicKeys, sig))
validSigs++; validSigs++;
} }
}; };
@ -147,8 +147,8 @@ struct CmdVerify : StorePathsCommand
if (!good) { if (!good) {
untrusted++; untrusted++;
act2.result(resUntrustedPath, info->path); act2.result(resUntrustedPath, store->printStorePath(info->path));
printError(format("path '%s' is untrusted") % info->path); printError("path '%s' is untrusted", store->printStorePath(info->path));
} }
} }
@ -164,7 +164,7 @@ struct CmdVerify : StorePathsCommand
}; };
for (auto & storePath : storePaths) for (auto & storePath : storePaths)
pool.enqueue(std::bind(doPath, storePath)); pool.enqueue(std::bind(doPath, store->printStorePath(storePath)));
pool.process(); pool.process();

View file

@ -73,9 +73,9 @@ struct CmdWhyDepends : SourceExprCommand
auto packagePath = toStorePath(store, Build, package); auto packagePath = toStorePath(store, Build, package);
auto dependency = parseInstallable(*this, store, _dependency, false); auto dependency = parseInstallable(*this, store, _dependency, false);
auto dependencyPath = toStorePath(store, NoBuild, dependency); auto dependencyPath = toStorePath(store, NoBuild, dependency);
auto dependencyPathHash = storePathToHash(dependencyPath); auto dependencyPathHash = storePathToHash(store->printStorePath(dependencyPath));
PathSet closure; StorePathSet closure;
store->computeFSClosure({packagePath}, closure, false, false); store->computeFSClosure({packagePath}, closure, false, false);
if (!closure.count(dependencyPath)) { if (!closure.count(dependencyPath)) {
@ -91,28 +91,28 @@ struct CmdWhyDepends : SourceExprCommand
struct Node struct Node
{ {
Path path; StorePath path;
PathSet refs; StorePathSet refs;
PathSet rrefs; StorePathSet rrefs;
size_t dist = inf; size_t dist = inf;
Node * prev = nullptr; Node * prev = nullptr;
bool queued = false; bool queued = false;
bool visited = false; bool visited = false;
}; };
std::map<Path, Node> graph; std::map<StorePath, Node> graph;
for (auto & path : closure) for (auto & path : closure)
graph.emplace(path, Node{path, store->queryPathInfo(path)->references}); graph.emplace(path.clone(), Node{path.clone(), cloneStorePathSet(store->queryPathInfo(path)->references)});
// Transpose the graph. // Transpose the graph.
for (auto & node : graph) for (auto & node : graph)
for (auto & ref : node.second.refs) for (auto & ref : node.second.refs)
graph[ref].rrefs.insert(node.first); graph.find(ref)->second.rrefs.insert(node.first.clone());
/* Run Dijkstra's shortest path algorithm to get the distance /* Run Dijkstra's shortest path algorithm to get the distance
of every path in the closure to 'dependency'. */ of every path in the closure to 'dependency'. */
graph[dependencyPath].dist = 0; graph[dependencyPath.clone()].dist = 0;
std::priority_queue<Node *> queue; std::priority_queue<Node *> queue;
@ -151,12 +151,14 @@ struct CmdWhyDepends : SourceExprCommand
struct BailOut { }; struct BailOut { };
printNode = [&](Node & node, const string & firstPad, const string & tailPad) { printNode = [&](Node & node, const string & firstPad, const string & tailPad) {
auto pathS = store->printStorePath(node.path);
assert(node.dist != inf); assert(node.dist != inf);
std::cout << fmt("%s%s%s%s" ANSI_NORMAL "\n", std::cout << fmt("%s%s%s%s" ANSI_NORMAL "\n",
firstPad, firstPad,
node.visited ? "\e[38;5;244m" : "", node.visited ? "\e[38;5;244m" : "",
firstPad != "" ? "=> " : "", firstPad != "" ? "=> " : "",
node.path); pathS);
if (node.path == dependencyPath && !all if (node.path == dependencyPath && !all
&& packagePath != dependencyPath) && packagePath != dependencyPath)
@ -175,7 +177,7 @@ struct CmdWhyDepends : SourceExprCommand
auto & node2 = graph.at(ref); auto & node2 = graph.at(ref);
if (node2.dist == inf) continue; if (node2.dist == inf) continue;
refs.emplace(node2.dist, &node2); refs.emplace(node2.dist, &node2);
hashes.insert(storePathToHash(node2.path)); hashes.insert(storePathToHash(store->printStorePath(node2.path)));
} }
/* For each reference, find the files and symlinks that /* For each reference, find the files and symlinks that
@ -187,7 +189,7 @@ struct CmdWhyDepends : SourceExprCommand
visitPath = [&](const Path & p) { visitPath = [&](const Path & p) {
auto st = accessor->stat(p); auto st = accessor->stat(p);
auto p2 = p == node.path ? "/" : std::string(p, node.path.size() + 1); auto p2 = p == pathS ? "/" : std::string(p, pathS.size() + 1);
auto getColour = [&](const std::string & hash) { auto getColour = [&](const std::string & hash) {
return hash == dependencyPathHash ? ANSI_GREEN : ANSI_BLUE; return hash == dependencyPathHash ? ANSI_GREEN : ANSI_BLUE;
@ -231,11 +233,11 @@ struct CmdWhyDepends : SourceExprCommand
// FIXME: should use scanForReferences(). // FIXME: should use scanForReferences().
visitPath(node.path); visitPath(pathS);
RunPager pager; RunPager pager;
for (auto & ref : refs) { for (auto & ref : refs) {
auto hash = storePathToHash(ref.second->path); auto hash = storePathToHash(store->printStorePath(ref.second->path));
bool last = all ? ref == *refs.rbegin() : true; bool last = all ? ref == *refs.rbegin() : true;

View file

@ -6,6 +6,6 @@ resolve-system-dependencies_DIR := $(d)
resolve-system-dependencies_INSTALL_DIR := $(libexecdir)/nix resolve-system-dependencies_INSTALL_DIR := $(libexecdir)/nix
resolve-system-dependencies_LIBS := libstore libmain libutil resolve-system-dependencies_LIBS := libstore libmain libutil libnixrust
resolve-system-dependencies_SOURCES := $(d)/resolve-system-dependencies.cc resolve-system-dependencies_SOURCES := $(d)/resolve-system-dependencies.cc

View file

@ -179,8 +179,8 @@ int main(int argc, char ** argv)
if (std::string(argv[1]) == "--test") if (std::string(argv[1]) == "--test")
impurePaths.insert(argv[2]); impurePaths.insert(argv[2]);
else { else {
auto drv = store->derivationFromPath(Path(argv[1])); auto drv = store->derivationFromPath(store->parseStorePath(argv[1]));
impurePaths = tokenizeString<StringSet>(get(drv.env, "__impureHostDeps")); impurePaths = tokenizeString<StringSet>(get(drv.env, "__impureHostDeps").value_or(""));
impurePaths.insert("/usr/lib/libSystem.dylib"); impurePaths.insert("/usr/lib/libSystem.dylib");
} }