Merge remote-tracking branch 'origin/master' into flakes
This commit is contained in:
commit
ecb3a1afa2
2
local.mk
2
local.mk
|
@ -6,7 +6,7 @@ dist-files += configure config.h.in perl/configure
|
||||||
|
|
||||||
clean-files += Makefile.config
|
clean-files += Makefile.config
|
||||||
|
|
||||||
GLOBAL_CXXFLAGS += -I . -I src -I src/libutil -I src/libstore -I src/libmain -I src/libexpr -I src/nix
|
GLOBAL_CXXFLAGS += -I . -I src -I src/libutil -I src/libstore -I src/libmain -I src/libexpr -I src/nix -Wno-deprecated-declarations
|
||||||
|
|
||||||
$(foreach i, config.h $(call rwildcard, src/lib*, *.hh), \
|
$(foreach i, config.h $(call rwildcard, src/lib*, *.hh), \
|
||||||
$(eval $(call install-file-in, $(i), $(includedir)/nix, 0644)))
|
$(eval $(call install-file-in, $(i), $(includedir)/nix, 0644)))
|
||||||
|
|
361
nix-rust/Cargo.lock
generated
361
nix-rust/Cargo.lock
generated
|
@ -1,50 +1,361 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "assert_matches"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-set"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-vec"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "c2-chacha"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cloudabi"
|
||||||
|
version = "0.0.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)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "filetime"
|
name = "filetime"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.65 (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)",
|
"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)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fnv"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fuchsia-cprng"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.1.13"
|
||||||
|
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)",
|
||||||
|
"wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.65"
|
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]]
|
[[package]]
|
||||||
name = "nix-rust"
|
name = "nix-rust"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
"assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"hex 0.3.2 (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)",
|
||||||
|
"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)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.10"
|
||||||
|
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 = "ppv-lite86"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proptest"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-error"
|
||||||
|
version = "1.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_hc"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_hc"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_isaac"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_jitter"
|
||||||
|
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)",
|
||||||
|
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_os"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_pcg"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_xorshift"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rdrand"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.1.56"
|
version = "0.1.56"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "remove_dir_all"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rusty-fork"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tempfile 3.1.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]]
|
[[package]]
|
||||||
name = "tar"
|
name = "tar"
|
||||||
version = "0.4.26"
|
version = "0.4.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.65 (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)",
|
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.1.0"
|
||||||
|
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)",
|
||||||
|
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wait-timeout"
|
||||||
|
version = "0.2.0"
|
||||||
|
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 = "wasi"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
|
@ -69,15 +380,53 @@ name = "xattr"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
|
"checksum assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7deb0a829ca7bcfaf5da70b073a8d128619259a7be8216a355e23f00763059e5"
|
||||||
|
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||||
|
"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
|
||||||
|
"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 byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
|
||||||
|
"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 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 libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8"
|
"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 getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407"
|
||||||
|
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
||||||
|
"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 num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
|
||||||
|
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
||||||
|
"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 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_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
|
||||||
|
"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
|
||||||
|
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||||
|
"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||||
|
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||||
|
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
|
||||||
|
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||||
|
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
|
||||||
|
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
|
||||||
|
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
|
||||||
|
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
|
||||||
|
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
|
||||||
|
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||||
"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 remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
||||||
|
"checksum rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae"
|
||||||
"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 wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||||
|
"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d"
|
||||||
"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-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"
|
||||||
|
|
|
@ -11,3 +11,14 @@ 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" }
|
||||||
|
#hyper = "0.13.0-alpha.4"
|
||||||
|
#http = "0.1"
|
||||||
|
#tokio = { version = "0.2.0-alpha.6", default-features = false, features = ["rt-full"] }
|
||||||
|
lazy_static = "1.4"
|
||||||
|
#byteorder = "1.3"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
hex = "0.3"
|
||||||
|
assert_matches = "1.3"
|
||||||
|
proptest = "0.9"
|
||||||
|
|
|
@ -18,7 +18,7 @@ libnixrust_LDFLAGS_USE += -Wl,-rpath,$(abspath $(d)/target/$(RUST_DIR))
|
||||||
libnixrust_LDFLAGS_USE_INSTALLED += -Wl,-rpath,$(libdir)
|
libnixrust_LDFLAGS_USE_INSTALLED += -Wl,-rpath,$(libdir)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(libnixrust_PATH): $(wildcard $(d)/src/*.rs) $(d)/Cargo.toml
|
$(libnixrust_PATH): $(call rwildcard, $(d)/src, *.rs) $(d)/Cargo.toml
|
||||||
$(trace-gen) cd nix-rust && CARGO_HOME=$$(if [[ -d vendor ]]; then echo vendor; fi) \
|
$(trace-gen) cd nix-rust && CARGO_HOME=$$(if [[ -d vendor ]]; then echo vendor; fi) \
|
||||||
$(libnixrust_BUILD_FLAGS) \
|
$(libnixrust_BUILD_FLAGS) \
|
||||||
cargo build $(RUST_MODE) $$(if [[ -d vendor ]]; then echo --offline; fi) \
|
cargo build $(RUST_MODE) $$(if [[ -d vendor ]]; then echo --offline; fi) \
|
||||||
|
@ -36,3 +36,10 @@ 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
|
||||||
|
|
||||||
|
rust-tests:
|
||||||
|
cd nix-rust && CARGO_HOME=$$(if [[ -d vendor ]]; then echo vendor; fi) cargo test --release $$(if [[ -d vendor ]]; then echo --offline; fi)
|
||||||
|
endif
|
||||||
|
|
90
nix-rust/src/c.rs
Normal file
90
nix-rust/src/c.rs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
use super::{
|
||||||
|
error,
|
||||||
|
foreign::{self, CBox},
|
||||||
|
store::path,
|
||||||
|
store::StorePath,
|
||||||
|
util,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn unpack_tarfile(
|
||||||
|
source: foreign::Source,
|
||||||
|
dest_dir: &str,
|
||||||
|
) -> CBox<Result<(), error::CppException>> {
|
||||||
|
CBox::new(util::tarfile::unpack_tarfile(source, dest_dir).map_err(|err| err.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn ffi_String_new(s: &str, out: *mut String) {
|
||||||
|
// FIXME: check whether 's' is valid UTF-8?
|
||||||
|
out.write(s.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn ffi_String_drop(self_: *mut String) {
|
||||||
|
std::ptr::drop_in_place(self_);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn ffi_StorePath_new(
|
||||||
|
path: &str,
|
||||||
|
store_dir: &str,
|
||||||
|
) -> Result<StorePath, error::CppException> {
|
||||||
|
StorePath::new(std::path::Path::new(path), store_dir).map_err(|err| err.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn ffi_StorePath_new2(
|
||||||
|
hash: &[u8; crate::store::path::STORE_PATH_HASH_BYTES],
|
||||||
|
name: &str,
|
||||||
|
) -> Result<StorePath, error::CppException> {
|
||||||
|
StorePath::from_parts(*hash, name).map_err(|err| err.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn ffi_StorePath_fromBaseName(
|
||||||
|
base_name: &str,
|
||||||
|
) -> Result<StorePath, error::CppException> {
|
||||||
|
StorePath::new_from_base_name(base_name).map_err(|err| err.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn ffi_StorePath_drop(self_: *mut StorePath) {
|
||||||
|
std::ptr::drop_in_place(self_);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn ffi_StorePath_to_string(self_: &StorePath) -> Vec<u8> {
|
||||||
|
let mut buf = vec![0; path::STORE_PATH_HASH_CHARS + 1 + self_.name.name().len()];
|
||||||
|
util::base32::encode_into(self_.hash.hash(), &mut buf[0..path::STORE_PATH_HASH_CHARS]);
|
||||||
|
buf[path::STORE_PATH_HASH_CHARS] = b'-';
|
||||||
|
buf[path::STORE_PATH_HASH_CHARS + 1..].clone_from_slice(self_.name.name().as_bytes());
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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()
|
||||||
|
}
|
|
@ -1,6 +1,26 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
InvalidPath(crate::store::StorePath),
|
||||||
|
BadStorePath(std::path::PathBuf),
|
||||||
|
BadNarInfo,
|
||||||
|
BadBase32,
|
||||||
|
StorePathNameEmpty,
|
||||||
|
StorePathNameTooLong,
|
||||||
|
BadStorePathName,
|
||||||
|
NarSizeFieldTooBig,
|
||||||
|
BadNarString,
|
||||||
|
BadNarPadding,
|
||||||
|
BadNarVersionMagic,
|
||||||
|
MissingNarOpenTag,
|
||||||
|
MissingNarCloseTag,
|
||||||
|
MissingNarField,
|
||||||
|
BadNarField(String),
|
||||||
|
BadExecutableField,
|
||||||
IOError(std::io::Error),
|
IOError(std::io::Error),
|
||||||
|
#[cfg(unused)]
|
||||||
|
HttpError(hyper::error::Error),
|
||||||
Misc(String),
|
Misc(String),
|
||||||
Foreign(CppException),
|
Foreign(CppException),
|
||||||
}
|
}
|
||||||
|
@ -11,12 +31,48 @@ impl From<std::io::Error> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unused)]
|
||||||
|
impl From<hyper::error::Error> for Error {
|
||||||
|
fn from(err: hyper::error::Error) -> Self {
|
||||||
|
Error::HttpError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Error::InvalidPath(_) => write!(f, "invalid path"),
|
||||||
|
Error::BadNarInfo => write!(f, ".narinfo file is corrupt"),
|
||||||
|
Error::BadStorePath(path) => write!(f, "path '{}' is not a store path", path.display()),
|
||||||
|
Error::BadBase32 => write!(f, "invalid base32 string"),
|
||||||
|
Error::StorePathNameEmpty => write!(f, "store path name is empty"),
|
||||||
|
Error::StorePathNameTooLong => {
|
||||||
|
write!(f, "store path name is longer than 211 characters")
|
||||||
|
}
|
||||||
|
Error::BadStorePathName => write!(f, "store path name contains forbidden character"),
|
||||||
|
Error::NarSizeFieldTooBig => write!(f, "size field in NAR is too big"),
|
||||||
|
Error::BadNarString => write!(f, "NAR string is not valid UTF-8"),
|
||||||
|
Error::BadNarPadding => write!(f, "NAR padding is not zero"),
|
||||||
|
Error::BadNarVersionMagic => write!(f, "unsupported NAR version"),
|
||||||
|
Error::MissingNarOpenTag => write!(f, "NAR open tag is missing"),
|
||||||
|
Error::MissingNarCloseTag => write!(f, "NAR close tag is missing"),
|
||||||
|
Error::MissingNarField => write!(f, "expected NAR field is missing"),
|
||||||
|
Error::BadNarField(s) => write!(f, "unrecognized NAR field '{}'", s),
|
||||||
|
Error::BadExecutableField => write!(f, "bad 'executable' field in NAR"),
|
||||||
|
Error::IOError(err) => write!(f, "I/O error: {}", err),
|
||||||
|
#[cfg(unused)]
|
||||||
|
Error::HttpError(err) => write!(f, "HTTP error: {}", err),
|
||||||
|
Error::Foreign(_) => write!(f, "<C++ exception>"), // FIXME
|
||||||
|
Error::Misc(s) => write!(f, "{}", s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Error> for CppException {
|
impl From<Error> for CppException {
|
||||||
fn from(err: Error) -> Self {
|
fn from(err: Error) -> Self {
|
||||||
match err {
|
match err {
|
||||||
Error::Foreign(ex) => ex,
|
Error::Foreign(ex) => ex,
|
||||||
Error::Misc(s) => unsafe { make_error(&s) },
|
_ => unsafe { make_error(&err.to_string()) },
|
||||||
Error::IOError(err) => unsafe { make_error(&err.to_string()) },
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,3 +12,22 @@ impl std::io::Read for Source {
|
||||||
Ok(n)
|
Ok(n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CBox<T> {
|
||||||
|
pub ptr: *mut libc::c_void,
|
||||||
|
phantom: std::marker::PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> CBox<T> {
|
||||||
|
pub fn new(t: T) -> Self {
|
||||||
|
unsafe {
|
||||||
|
let size = std::mem::size_of::<T>();
|
||||||
|
let ptr = libc::malloc(size);
|
||||||
|
*(ptr as *mut T) = t; // FIXME: probably UB
|
||||||
|
Self {
|
||||||
|
ptr,
|
||||||
|
phantom: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,32 +1,20 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate assert_matches;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate proptest;
|
||||||
|
|
||||||
|
mod c;
|
||||||
mod error;
|
mod error;
|
||||||
mod foreign;
|
mod foreign;
|
||||||
mod tarfile;
|
#[cfg(unused)]
|
||||||
|
mod nar;
|
||||||
|
mod store;
|
||||||
|
mod util;
|
||||||
|
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
|
|
||||||
pub struct CBox<T> {
|
|
||||||
pub ptr: *mut libc::c_void,
|
|
||||||
phantom: std::marker::PhantomData<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> CBox<T> {
|
|
||||||
fn new(t: T) -> Self {
|
|
||||||
unsafe {
|
|
||||||
let size = std::mem::size_of::<T>();
|
|
||||||
let ptr = libc::malloc(size);
|
|
||||||
*(ptr as *mut T) = t; // FIXME: probably UB
|
|
||||||
Self {
|
|
||||||
ptr,
|
|
||||||
phantom: std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn unpack_tarfile(
|
|
||||||
source: foreign::Source,
|
|
||||||
dest_dir: &str,
|
|
||||||
) -> CBox<Result<(), error::CppException>> {
|
|
||||||
CBox::new(tarfile::unpack_tarfile(source, dest_dir).map_err(|err| err.into()))
|
|
||||||
}
|
|
||||||
|
|
126
nix-rust/src/nar.rs
Normal file
126
nix-rust/src/nar.rs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
use crate::Error;
|
||||||
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
pub fn parse<R: Read>(input: &mut R) -> Result<(), Error> {
|
||||||
|
if String::read(input)? != NAR_VERSION_MAGIC {
|
||||||
|
return Err(Error::BadNarVersionMagic);
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_file(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
const NAR_VERSION_MAGIC: &str = "nix-archive-1";
|
||||||
|
|
||||||
|
fn parse_file<R: Read>(input: &mut R) -> Result<(), Error> {
|
||||||
|
if String::read(input)? != "(" {
|
||||||
|
return Err(Error::MissingNarOpenTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if String::read(input)? != "type" {
|
||||||
|
return Err(Error::MissingNarField);
|
||||||
|
}
|
||||||
|
|
||||||
|
match String::read(input)?.as_ref() {
|
||||||
|
"regular" => {
|
||||||
|
let mut _executable = false;
|
||||||
|
let mut tag = String::read(input)?;
|
||||||
|
if tag == "executable" {
|
||||||
|
_executable = true;
|
||||||
|
if String::read(input)? != "" {
|
||||||
|
return Err(Error::BadExecutableField);
|
||||||
|
}
|
||||||
|
tag = String::read(input)?;
|
||||||
|
}
|
||||||
|
if tag != "contents" {
|
||||||
|
return Err(Error::MissingNarField);
|
||||||
|
}
|
||||||
|
let _contents = Vec::<u8>::read(input)?;
|
||||||
|
if String::read(input)? != ")" {
|
||||||
|
return Err(Error::MissingNarCloseTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"directory" => loop {
|
||||||
|
match String::read(input)?.as_ref() {
|
||||||
|
"entry" => {
|
||||||
|
if String::read(input)? != "(" {
|
||||||
|
return Err(Error::MissingNarOpenTag);
|
||||||
|
}
|
||||||
|
if String::read(input)? != "name" {
|
||||||
|
return Err(Error::MissingNarField);
|
||||||
|
}
|
||||||
|
let _name = String::read(input)?;
|
||||||
|
if String::read(input)? != "node" {
|
||||||
|
return Err(Error::MissingNarField);
|
||||||
|
}
|
||||||
|
parse_file(input)?;
|
||||||
|
let tag = String::read(input)?;
|
||||||
|
if tag != ")" {
|
||||||
|
return Err(Error::MissingNarCloseTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
")" => break,
|
||||||
|
s => return Err(Error::BadNarField(s.into())),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"symlink" => {
|
||||||
|
if String::read(input)? != "target" {
|
||||||
|
return Err(Error::MissingNarField);
|
||||||
|
}
|
||||||
|
let _target = String::read(input)?;
|
||||||
|
if String::read(input)? != ")" {
|
||||||
|
return Err(Error::MissingNarCloseTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s => return Err(Error::BadNarField(s.into())),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Deserialize: Sized {
|
||||||
|
fn read<R: Read>(input: &mut R) -> Result<Self, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for String {
|
||||||
|
fn read<R: Read>(input: &mut R) -> Result<Self, Error> {
|
||||||
|
let buf = Deserialize::read(input)?;
|
||||||
|
Ok(String::from_utf8(buf).map_err(|_| Error::BadNarString)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for Vec<u8> {
|
||||||
|
fn read<R: Read>(input: &mut R) -> Result<Self, Error> {
|
||||||
|
let n: usize = Deserialize::read(input)?;
|
||||||
|
let mut buf = vec![0; n];
|
||||||
|
input.read_exact(&mut buf)?;
|
||||||
|
skip_padding(input, n)?;
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip_padding<R: Read>(input: &mut R, len: usize) -> Result<(), Error> {
|
||||||
|
if len % 8 != 0 {
|
||||||
|
let mut buf = [0; 8];
|
||||||
|
let buf = &mut buf[0..8 - (len % 8)];
|
||||||
|
input.read_exact(buf)?;
|
||||||
|
if !buf.iter().all(|b| *b == 0) {
|
||||||
|
return Err(Error::BadNarPadding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for u64 {
|
||||||
|
fn read<R: Read>(input: &mut R) -> Result<Self, Error> {
|
||||||
|
Ok(input.read_u64::<LittleEndian>()?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for usize {
|
||||||
|
fn read<R: Read>(input: &mut R) -> Result<Self, Error> {
|
||||||
|
let n: u64 = Deserialize::read(input)?;
|
||||||
|
Ok(usize::try_from(n).map_err(|_| Error::NarSizeFieldTooBig)?)
|
||||||
|
}
|
||||||
|
}
|
48
nix-rust/src/store/binary_cache_store.rs
Normal file
48
nix-rust/src/store/binary_cache_store.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
use super::{PathInfo, Store, StorePath};
|
||||||
|
use crate::Error;
|
||||||
|
use hyper::client::Client;
|
||||||
|
|
||||||
|
pub struct BinaryCacheStore {
|
||||||
|
base_uri: String,
|
||||||
|
client: Client<hyper::client::HttpConnector, hyper::Body>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BinaryCacheStore {
|
||||||
|
pub fn new(base_uri: String) -> Self {
|
||||||
|
Self {
|
||||||
|
base_uri,
|
||||||
|
client: Client::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Store for BinaryCacheStore {
|
||||||
|
fn query_path_info(
|
||||||
|
&self,
|
||||||
|
path: &StorePath,
|
||||||
|
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<PathInfo, Error>> + Send>> {
|
||||||
|
let uri = format!("{}/{}.narinfo", self.base_uri.clone(), path.hash);
|
||||||
|
let path = path.clone();
|
||||||
|
let client = self.client.clone();
|
||||||
|
let store_dir = self.store_dir().to_string();
|
||||||
|
|
||||||
|
Box::pin(async move {
|
||||||
|
let response = client.get(uri.parse::<hyper::Uri>().unwrap()).await?;
|
||||||
|
|
||||||
|
if response.status() == hyper::StatusCode::NOT_FOUND
|
||||||
|
|| response.status() == hyper::StatusCode::FORBIDDEN
|
||||||
|
{
|
||||||
|
return Err(Error::InvalidPath(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut body = response.into_body();
|
||||||
|
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
while let Some(next) = body.next().await {
|
||||||
|
bytes.extend(next?);
|
||||||
|
}
|
||||||
|
|
||||||
|
PathInfo::parse_nar_info(std::str::from_utf8(&bytes).unwrap(), &store_dir)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
17
nix-rust/src/store/mod.rs
Normal file
17
nix-rust/src/store/mod.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
pub mod path;
|
||||||
|
|
||||||
|
#[cfg(unused)]
|
||||||
|
mod binary_cache_store;
|
||||||
|
#[cfg(unused)]
|
||||||
|
mod path_info;
|
||||||
|
#[cfg(unused)]
|
||||||
|
mod store;
|
||||||
|
|
||||||
|
pub use path::{StorePath, StorePathHash, StorePathName};
|
||||||
|
|
||||||
|
#[cfg(unused)]
|
||||||
|
pub use binary_cache_store::BinaryCacheStore;
|
||||||
|
#[cfg(unused)]
|
||||||
|
pub use path_info::PathInfo;
|
||||||
|
#[cfg(unused)]
|
||||||
|
pub use store::Store;
|
222
nix-rust/src/store/path.rs
Normal file
222
nix-rust/src/store/path.rs
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::util::base32;
|
||||||
|
use std::fmt;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||||
|
pub struct StorePath {
|
||||||
|
pub hash: StorePathHash,
|
||||||
|
pub name: StorePathName,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const STORE_PATH_HASH_BYTES: usize = 20;
|
||||||
|
pub const STORE_PATH_HASH_CHARS: usize = 32;
|
||||||
|
|
||||||
|
impl StorePath {
|
||||||
|
pub fn new(path: &Path, _store_dir: &str) -> Result<Self, Error> {
|
||||||
|
// FIXME: check store_dir
|
||||||
|
Self::new_from_base_name(
|
||||||
|
path.file_name()
|
||||||
|
.ok_or(Error::BadStorePath(path.into()))?
|
||||||
|
.to_str()
|
||||||
|
.ok_or(Error::BadStorePath(path.into()))?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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> {
|
||||||
|
if base_name.len() < STORE_PATH_HASH_CHARS + 1
|
||||||
|
|| base_name.as_bytes()[STORE_PATH_HASH_CHARS] != '-' as u8
|
||||||
|
{
|
||||||
|
return Err(Error::BadStorePath(base_name.into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(StorePath {
|
||||||
|
hash: StorePathHash::new(&base_name[0..STORE_PATH_HASH_CHARS])?,
|
||||||
|
name: StorePathName::new(&base_name[STORE_PATH_HASH_CHARS + 1..])?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for StorePath {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}-{}", self.hash, self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub struct StorePathHash([u8; STORE_PATH_HASH_BYTES]);
|
||||||
|
|
||||||
|
impl StorePathHash {
|
||||||
|
pub fn new(s: &str) -> Result<Self, Error> {
|
||||||
|
assert_eq!(s.len(), STORE_PATH_HASH_CHARS);
|
||||||
|
let v = base32::decode(s)?;
|
||||||
|
assert_eq!(v.len(), STORE_PATH_HASH_BYTES);
|
||||||
|
let mut bytes: [u8; 20] = Default::default();
|
||||||
|
bytes.copy_from_slice(&v[0..STORE_PATH_HASH_BYTES]);
|
||||||
|
Ok(Self(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash<'a>(&'a self) -> &'a [u8; STORE_PATH_HASH_BYTES] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for StorePathHash {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let mut buf = vec![0; STORE_PATH_HASH_CHARS];
|
||||||
|
base32::encode_into(&self.0, &mut buf);
|
||||||
|
f.write_str(std::str::from_utf8(&buf).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)]
|
||||||
|
pub struct StorePathName(String);
|
||||||
|
|
||||||
|
impl StorePathName {
|
||||||
|
pub fn new(s: &str) -> Result<Self, Error> {
|
||||||
|
if s.len() == 0 {
|
||||||
|
return Err(Error::StorePathNameEmpty);
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.len() > 211 {
|
||||||
|
return Err(Error::StorePathNameTooLong);
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.starts_with('.')
|
||||||
|
|| !s.chars().all(|c| {
|
||||||
|
c.is_ascii_alphabetic()
|
||||||
|
|| c.is_ascii_digit()
|
||||||
|
|| c == '+'
|
||||||
|
|| c == '-'
|
||||||
|
|| c == '.'
|
||||||
|
|| c == '_'
|
||||||
|
|| c == '?'
|
||||||
|
|| c == '='
|
||||||
|
})
|
||||||
|
{
|
||||||
|
return Err(Error::BadStorePathName);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self(s.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name<'a>(&'a self) -> &'a str {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for StorePathName {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse() {
|
||||||
|
let s = "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3";
|
||||||
|
let p = StorePath::new_from_base_name(&s).unwrap();
|
||||||
|
assert_eq!(p.name.0, "konsole-18.12.3");
|
||||||
|
assert_eq!(
|
||||||
|
p.hash.0,
|
||||||
|
[
|
||||||
|
0x9f, 0x76, 0x49, 0x20, 0xf6, 0x5d, 0xe9, 0x71, 0xc4, 0xca, 0x46, 0x21, 0xab, 0xff,
|
||||||
|
0x9b, 0x44, 0xef, 0x87, 0x0f, 0x3c
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_no_name() {
|
||||||
|
let s = "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-";
|
||||||
|
assert_matches!(
|
||||||
|
StorePath::new_from_base_name(&s),
|
||||||
|
Err(Error::StorePathNameEmpty)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_no_dash() {
|
||||||
|
let s = "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz";
|
||||||
|
assert_matches!(
|
||||||
|
StorePath::new_from_base_name(&s),
|
||||||
|
Err(Error::BadStorePath(_))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_short_hash() {
|
||||||
|
let s = "7h7qgvs4kgzsn8a6rb273saxyqh4jxl-konsole-18.12.3";
|
||||||
|
assert_matches!(
|
||||||
|
StorePath::new_from_base_name(&s),
|
||||||
|
Err(Error::BadStorePath(_))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_invalid_hash() {
|
||||||
|
let s = "7h7qgvs4kgzsn8e6rb273saxyqh4jxlz-konsole-18.12.3";
|
||||||
|
assert_matches!(StorePath::new_from_base_name(&s), Err(Error::BadBase32));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_long_name() {
|
||||||
|
let s = "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||||
|
assert_matches!(StorePath::new_from_base_name(&s), Ok(_));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_too_long_name() {
|
||||||
|
let s = "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||||
|
assert_matches!(
|
||||||
|
StorePath::new_from_base_name(&s),
|
||||||
|
Err(Error::StorePathNameTooLong)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bad_name() {
|
||||||
|
let s = "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-foo bar";
|
||||||
|
assert_matches!(
|
||||||
|
StorePath::new_from_base_name(&s),
|
||||||
|
Err(Error::BadStorePathName)
|
||||||
|
);
|
||||||
|
|
||||||
|
let s = "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-kónsole";
|
||||||
|
assert_matches!(
|
||||||
|
StorePath::new_from_base_name(&s),
|
||||||
|
Err(Error::BadStorePathName)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_roundtrip() {
|
||||||
|
let s = "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3";
|
||||||
|
assert_eq!(StorePath::new_from_base_name(&s).unwrap().to_string(), s);
|
||||||
|
}
|
||||||
|
}
|
70
nix-rust/src/store/path_info.rs
Normal file
70
nix-rust/src/store/path_info.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
use crate::store::StorePath;
|
||||||
|
use crate::Error;
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PathInfo {
|
||||||
|
pub path: StorePath,
|
||||||
|
pub references: BTreeSet<StorePath>,
|
||||||
|
pub nar_size: u64,
|
||||||
|
pub deriver: Option<StorePath>,
|
||||||
|
|
||||||
|
// Additional binary cache info.
|
||||||
|
pub url: Option<String>,
|
||||||
|
pub compression: Option<String>,
|
||||||
|
pub file_size: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PathInfo {
|
||||||
|
pub fn parse_nar_info(nar_info: &str, store_dir: &str) -> Result<Self, Error> {
|
||||||
|
let mut path = None;
|
||||||
|
let mut references = BTreeSet::new();
|
||||||
|
let mut nar_size = None;
|
||||||
|
let mut deriver = None;
|
||||||
|
let mut url = None;
|
||||||
|
let mut compression = None;
|
||||||
|
let mut file_size = None;
|
||||||
|
|
||||||
|
for line in nar_info.lines() {
|
||||||
|
let colon = line.find(':').ok_or(Error::BadNarInfo)?;
|
||||||
|
|
||||||
|
let (name, value) = line.split_at(colon);
|
||||||
|
|
||||||
|
if !value.starts_with(": ") {
|
||||||
|
return Err(Error::BadNarInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = &value[2..];
|
||||||
|
|
||||||
|
if name == "StorePath" {
|
||||||
|
path = Some(StorePath::new(std::path::Path::new(value), store_dir)?);
|
||||||
|
} else if name == "NarSize" {
|
||||||
|
nar_size = Some(u64::from_str_radix(value, 10).map_err(|_| Error::BadNarInfo)?);
|
||||||
|
} else if name == "References" {
|
||||||
|
if !value.is_empty() {
|
||||||
|
for r in value.split(' ') {
|
||||||
|
references.insert(StorePath::new_from_base_name(r)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if name == "Deriver" {
|
||||||
|
deriver = Some(StorePath::new_from_base_name(value)?);
|
||||||
|
} else if name == "URL" {
|
||||||
|
url = Some(value.into());
|
||||||
|
} else if name == "Compression" {
|
||||||
|
compression = Some(value.into());
|
||||||
|
} else if name == "FileSize" {
|
||||||
|
file_size = Some(u64::from_str_radix(value, 10).map_err(|_| Error::BadNarInfo)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(PathInfo {
|
||||||
|
path: path.ok_or(Error::BadNarInfo)?,
|
||||||
|
references,
|
||||||
|
nar_size: nar_size.ok_or(Error::BadNarInfo)?,
|
||||||
|
deriver,
|
||||||
|
url: Some(url.ok_or(Error::BadNarInfo)?),
|
||||||
|
compression,
|
||||||
|
file_size,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
53
nix-rust/src/store/store.rs
Normal file
53
nix-rust/src/store/store.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
use super::{PathInfo, StorePath};
|
||||||
|
use crate::Error;
|
||||||
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
pub trait Store: Send + Sync {
|
||||||
|
fn store_dir(&self) -> &str {
|
||||||
|
"/nix/store"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query_path_info(
|
||||||
|
&self,
|
||||||
|
store_path: &StorePath,
|
||||||
|
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<PathInfo, Error>> + Send>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl dyn Store {
|
||||||
|
pub fn parse_store_path(&self, path: &Path) -> Result<StorePath, Error> {
|
||||||
|
StorePath::new(path, self.store_dir())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn compute_path_closure(
|
||||||
|
&self,
|
||||||
|
roots: BTreeSet<StorePath>,
|
||||||
|
) -> Result<BTreeMap<StorePath, PathInfo>, Error> {
|
||||||
|
let mut done = BTreeSet::new();
|
||||||
|
let mut result = BTreeMap::new();
|
||||||
|
let mut pending = vec![];
|
||||||
|
|
||||||
|
for root in roots {
|
||||||
|
pending.push(self.query_path_info(&root));
|
||||||
|
done.insert(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
while !pending.is_empty() {
|
||||||
|
let (info, _, remaining) = futures::future::select_all(pending).await;
|
||||||
|
pending = remaining;
|
||||||
|
|
||||||
|
let info = info?;
|
||||||
|
|
||||||
|
for path in &info.references {
|
||||||
|
if !done.contains(path) {
|
||||||
|
pending.push(self.query_path_info(&path));
|
||||||
|
done.insert(path.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.insert(info.path.clone(), info);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
157
nix-rust/src/util/base32.rs
Normal file
157
nix-rust/src/util/base32.rs
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
use crate::error::Error;
|
||||||
|
|
||||||
|
pub fn encoded_len(input_len: usize) -> usize {
|
||||||
|
if input_len == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
(input_len * 8 - 1) / 5 + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decoded_len(input_len: usize) -> usize {
|
||||||
|
input_len * 5 / 8
|
||||||
|
}
|
||||||
|
|
||||||
|
static BASE32_CHARS: &'static [u8; 32] = &b"0123456789abcdfghijklmnpqrsvwxyz";
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref BASE32_CHARS_REVERSE: Box<[u8; 256]> = {
|
||||||
|
let mut xs = [0xffu8; 256];
|
||||||
|
for (n, c) in BASE32_CHARS.iter().enumerate() {
|
||||||
|
xs[*c as usize] = n as u8;
|
||||||
|
}
|
||||||
|
Box::new(xs)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode(input: &[u8]) -> String {
|
||||||
|
let mut buf = vec![0; encoded_len(input.len())];
|
||||||
|
encode_into(input, &mut buf);
|
||||||
|
std::str::from_utf8(&buf).unwrap().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode_into(input: &[u8], output: &mut [u8]) {
|
||||||
|
let len = encoded_len(input.len());
|
||||||
|
assert_eq!(len, output.len());
|
||||||
|
|
||||||
|
let mut nr_bits_left: usize = 0;
|
||||||
|
let mut bits_left: u16 = 0;
|
||||||
|
let mut pos = len;
|
||||||
|
|
||||||
|
for b in input {
|
||||||
|
bits_left |= (*b as u16) << nr_bits_left;
|
||||||
|
nr_bits_left += 8;
|
||||||
|
while nr_bits_left > 5 {
|
||||||
|
output[pos - 1] = BASE32_CHARS[(bits_left & 0x1f) as usize];
|
||||||
|
pos -= 1;
|
||||||
|
bits_left >>= 5;
|
||||||
|
nr_bits_left -= 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nr_bits_left > 0 {
|
||||||
|
output[pos - 1] = BASE32_CHARS[(bits_left & 0x1f) as usize];
|
||||||
|
pos -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(pos, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode(input: &str) -> Result<Vec<u8>, crate::Error> {
|
||||||
|
let mut res = Vec::with_capacity(decoded_len(input.len()));
|
||||||
|
|
||||||
|
let mut nr_bits_left: usize = 0;
|
||||||
|
let mut bits_left: u16 = 0;
|
||||||
|
|
||||||
|
for c in input.chars().rev() {
|
||||||
|
let b = BASE32_CHARS_REVERSE[c as usize];
|
||||||
|
if b == 0xff {
|
||||||
|
return Err(Error::BadBase32);
|
||||||
|
}
|
||||||
|
bits_left |= (b as u16) << nr_bits_left;
|
||||||
|
nr_bits_left += 5;
|
||||||
|
if nr_bits_left >= 8 {
|
||||||
|
res.push((bits_left & 0xff) as u8);
|
||||||
|
bits_left >>= 8;
|
||||||
|
nr_bits_left -= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nr_bits_left > 0 && bits_left != 0 {
|
||||||
|
return Err(Error::BadBase32);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use hex;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encode() {
|
||||||
|
assert_eq!(encode(&[]), "");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
encode(&hex::decode("0839703786356bca59b0f4a32987eb2e6de43ae8").unwrap()),
|
||||||
|
"x0xf8v9fxf3jk8zln1cwlsrmhqvp0f88"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
encode(
|
||||||
|
&hex::decode("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")
|
||||||
|
.unwrap()
|
||||||
|
),
|
||||||
|
"1b8m03r63zqhnjf7l5wnldhh7c134ap5vpj0850ymkq1iyzicy5s"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
encode(
|
||||||
|
&hex::decode("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f")
|
||||||
|
.unwrap()
|
||||||
|
),
|
||||||
|
"2gs8k559z4rlahfx0y688s49m2vvszylcikrfinm30ly9rak69236nkam5ydvly1ai7xac99vxfc4ii84hawjbk876blyk1jfhkbbyx"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_decode() {
|
||||||
|
assert_eq!(hex::encode(decode("").unwrap()), "");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
hex::encode(decode("x0xf8v9fxf3jk8zln1cwlsrmhqvp0f88").unwrap()),
|
||||||
|
"0839703786356bca59b0f4a32987eb2e6de43ae8"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
hex::encode(decode("1b8m03r63zqhnjf7l5wnldhh7c134ap5vpj0850ymkq1iyzicy5s").unwrap()),
|
||||||
|
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
hex::encode(decode("2gs8k559z4rlahfx0y688s49m2vvszylcikrfinm30ly9rak69236nkam5ydvly1ai7xac99vxfc4ii84hawjbk876blyk1jfhkbbyx").unwrap()),
|
||||||
|
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
decode("xoxf8v9fxf3jk8zln1cwlsrmhqvp0f88"),
|
||||||
|
Err(Error::BadBase32)
|
||||||
|
);
|
||||||
|
assert_matches!(
|
||||||
|
decode("2b8m03r63zqhnjf7l5wnldhh7c134ap5vpj0850ymkq1iyzicy5s"),
|
||||||
|
Err(Error::BadBase32)
|
||||||
|
);
|
||||||
|
assert_matches!(decode("2"), Err(Error::BadBase32));
|
||||||
|
assert_matches!(decode("2gs"), Err(Error::BadBase32));
|
||||||
|
assert_matches!(decode("2gs8"), Err(Error::BadBase32));
|
||||||
|
}
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn roundtrip(s: Vec<u8>) {
|
||||||
|
assert_eq!(s, decode(&encode(&s)).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
nix-rust/src/util/mod.rs
Normal file
2
nix-rust/src/util/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod base32;
|
||||||
|
pub mod tarfile;
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
25
shell.nix
Normal file
25
shell.nix
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{ useClang ? false }:
|
||||||
|
|
||||||
|
with import (builtins.fetchTarball https://github.com/NixOS/nixpkgs/archive/bb1013511e1e5edcf314df8321acf2f3c536df0d.tar.gz) {};
|
||||||
|
|
||||||
|
with import ./release-common.nix { inherit pkgs; };
|
||||||
|
|
||||||
|
(if useClang then clangStdenv else stdenv).mkDerivation {
|
||||||
|
name = "nix";
|
||||||
|
|
||||||
|
buildInputs = buildDeps ++ tarballDeps ++ perlDeps ++ [ pkgs.rustfmt ];
|
||||||
|
|
||||||
|
inherit configureFlags;
|
||||||
|
|
||||||
|
enableParallelBuilding = true;
|
||||||
|
|
||||||
|
installFlags = "sysconfdir=$(out)/etc";
|
||||||
|
|
||||||
|
shellHook =
|
||||||
|
''
|
||||||
|
export prefix=$(pwd)/inst
|
||||||
|
configureFlags+=" --prefix=$prefix"
|
||||||
|
PKG_CONFIG_PATH=$prefix/lib/pkgconfig:$PKG_CONFIG_PATH
|
||||||
|
PATH=$prefix/bin:$PATH
|
||||||
|
'';
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,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();
|
||||||
|
@ -358,10 +371,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);
|
||||||
}
|
}
|
||||||
|
@ -585,9 +598,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 * *)
|
||||||
|
@ -1131,10 +1146,9 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos)
|
||||||
|
|
||||||
void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & pos)
|
void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & pos)
|
||||||
{
|
{
|
||||||
std::optional<FunctionCallTrace> trace;
|
std::unique_ptr<FunctionCallTrace> trace;
|
||||||
if (evalSettings.traceFunctionCalls) {
|
if (evalSettings.traceFunctionCalls)
|
||||||
trace.emplace(pos);
|
trace = std::make_unique<FunctionCallTrace>(pos);
|
||||||
}
|
|
||||||
|
|
||||||
forceValue(fun, pos);
|
forceValue(fun, pos);
|
||||||
|
|
||||||
|
@ -1680,15 +1694,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);
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace nix {
|
||||||
|
|
||||||
class Store;
|
class Store;
|
||||||
class EvalState;
|
class EvalState;
|
||||||
|
struct StorePath;
|
||||||
enum RepairFlag : bool;
|
enum RepairFlag : bool;
|
||||||
|
|
||||||
namespace flake {
|
namespace flake {
|
||||||
|
@ -46,14 +47,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);
|
||||||
|
|
|
@ -77,7 +77,7 @@ void EvalCache::addDerivation(
|
||||||
(fingerprint.hash, fingerprint.hashSize)
|
(fingerprint.hash, fingerprint.hashSize)
|
||||||
(attrPath)
|
(attrPath)
|
||||||
(ValueType::Derivation)
|
(ValueType::Derivation)
|
||||||
(drv.drvPath + " " + drv.outPath + " " + drv.outputName).exec();
|
(std::string(drv.drvPath.to_string()) + " " + std::string(drv.outPath.to_string()) + " " + drv.outputName).exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<EvalCache::Derivation> EvalCache::getDerivation(
|
std::optional<EvalCache::Derivation> EvalCache::getDerivation(
|
||||||
|
@ -104,7 +104,7 @@ std::optional<EvalCache::Derivation> EvalCache::getDerivation(
|
||||||
|
|
||||||
debug("evaluation cache hit for '%s'", attrPath);
|
debug("evaluation cache hit for '%s'", attrPath);
|
||||||
|
|
||||||
return Derivation { ss[0], ss[1], ss[2] };
|
return Derivation { StorePath::fromBaseName(ss[0]), StorePath::fromBaseName(ss[1]), ss[2] };
|
||||||
}
|
}
|
||||||
|
|
||||||
EvalCache & EvalCache::singleton()
|
EvalCache & EvalCache::singleton()
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "sync.hh"
|
#include "sync.hh"
|
||||||
#include "flake.hh"
|
#include "flake.hh"
|
||||||
|
#include "path.hh"
|
||||||
|
|
||||||
namespace nix { struct SQLite; struct SQLiteStmt; }
|
namespace nix { struct SQLite; struct SQLiteStmt; }
|
||||||
|
|
||||||
|
@ -19,8 +20,8 @@ public:
|
||||||
|
|
||||||
struct Derivation
|
struct Derivation
|
||||||
{
|
{
|
||||||
Path drvPath;
|
StorePath drvPath;
|
||||||
Path outPath;
|
StorePath outPath;
|
||||||
std::string outputName;
|
std::string outputName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,7 @@ static SourceInfo fetchInput(EvalState & state, const FlakeRef & resolvedRef)
|
||||||
SourceInfo info(ref);
|
SourceInfo info(ref);
|
||||||
info.storePath = gitInfo.storePath;
|
info.storePath = gitInfo.storePath;
|
||||||
info.revCount = gitInfo.revCount;
|
info.revCount = gitInfo.revCount;
|
||||||
info.narHash = state.store->queryPathInfo(info.storePath)->narHash;
|
info.narHash = state.store->queryPathInfo(state.store->parseStorePath(info.storePath))->narHash;
|
||||||
info.lastModified = gitInfo.lastModified;
|
info.lastModified = gitInfo.lastModified;
|
||||||
return info;
|
return info;
|
||||||
};
|
};
|
||||||
|
@ -212,7 +212,7 @@ static Flake getFlake(EvalState & state, const FlakeRef & originalRef,
|
||||||
refMap.push_back({originalRef, resolvedRef});
|
refMap.push_back({originalRef, resolvedRef});
|
||||||
refMap.push_back({flakeRef, resolvedRef});
|
refMap.push_back({flakeRef, resolvedRef});
|
||||||
|
|
||||||
state.store->assertStorePath(sourceInfo.storePath);
|
state.store->parseStorePath(sourceInfo.storePath);
|
||||||
|
|
||||||
if (state.allowedPaths)
|
if (state.allowedPaths)
|
||||||
state.allowedPaths->insert(state.store->toRealPath(sourceInfo.storePath));
|
state.allowedPaths->insert(state.store->toRealPath(sourceInfo.storePath));
|
||||||
|
@ -334,7 +334,7 @@ static SourceInfo getNonFlake(EvalState & state, const FlakeRef & originalRef,
|
||||||
refMap.push_back({originalRef, resolvedRef});
|
refMap.push_back({originalRef, resolvedRef});
|
||||||
refMap.push_back({flakeRef, resolvedRef});
|
refMap.push_back({flakeRef, resolvedRef});
|
||||||
|
|
||||||
state.store->assertStorePath(sourceInfo.storePath);
|
state.store->parseStorePath(sourceInfo.storePath);
|
||||||
|
|
||||||
if (state.allowedPaths)
|
if (state.allowedPaths)
|
||||||
state.allowedPaths->insert(sourceInfo.storePath);
|
state.allowedPaths->insert(sourceInfo.storePath);
|
||||||
|
@ -490,7 +490,7 @@ void updateLockFile(EvalState & state, const FlakeRef & flakeRef, bool recreateL
|
||||||
static void emitSourceInfoAttrs(EvalState & state, const SourceInfo & sourceInfo, Value & vAttrs)
|
static void emitSourceInfoAttrs(EvalState & state, const SourceInfo & sourceInfo, Value & vAttrs)
|
||||||
{
|
{
|
||||||
auto & path = sourceInfo.storePath;
|
auto & path = sourceInfo.storePath;
|
||||||
assert(state.store->isValidPath(path));
|
assert(state.store->isValidPath(state.store->parseStorePath(path)));
|
||||||
mkString(*state.allocAttr(vAttrs, state.sOutPath), path, {path});
|
mkString(*state.allocAttr(vAttrs, state.sOutPath), path, {path});
|
||||||
|
|
||||||
if (sourceInfo.resolvedRef.rev) {
|
if (sourceInfo.resolvedRef.rev) {
|
||||||
|
@ -542,7 +542,7 @@ static void prim_callFlake(EvalState & state, const Pos & pos, Value * * args, V
|
||||||
|
|
||||||
state.mkAttrs(v, 8);
|
state.mkAttrs(v, 8);
|
||||||
|
|
||||||
assert(state.store->isValidPath(sourceInfo.storePath));
|
assert(state.store->isValidPath(state.store->parseStorePath(sourceInfo.storePath)));
|
||||||
|
|
||||||
mkString(*state.allocAttr(v, state.sOutPath),
|
mkString(*state.allocAttr(v, state.sOutPath),
|
||||||
sourceInfo.storePath, {sourceInfo.storePath});
|
sourceInfo.storePath, {sourceInfo.storePath});
|
||||||
|
|
|
@ -161,7 +161,7 @@ FlakeRef::FlakeRef(const std::string & uri_, bool allowRelative)
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
if (pathExists(d.path + "/.git")) break;
|
if (pathExists(d.path + "/.git")) break;
|
||||||
subdir = baseNameOf(d.path) + (subdir.empty() ? "" : "/" + subdir);
|
subdir = std::string(baseNameOf(d.path)) + (subdir.empty() ? "" : "/" + subdir);
|
||||||
d.path = dirOf(d.path);
|
d.path = dirOf(d.path);
|
||||||
if (d.path == "/")
|
if (d.path == "/")
|
||||||
throw MissingFlake("path '%s' is not a flake (because it does not reference a Git repository)", uri);
|
throw MissingFlake("path '%s' is not a flake (because it does not reference a Git repository)", uri);
|
||||||
|
|
|
@ -26,7 +26,7 @@ nlohmann::json LockedInput::toJson() const
|
||||||
|
|
||||||
Path LockedInput::computeStorePath(Store & store) const
|
Path LockedInput::computeStorePath(Store & store) const
|
||||||
{
|
{
|
||||||
return store.makeFixedOutputPath(true, narHash, "source");
|
return store.printStorePath(store.makeFixedOutputPath(true, narHash, "source"));
|
||||||
}
|
}
|
||||||
|
|
||||||
LockedInputs::LockedInputs(const nlohmann::json & json)
|
LockedInputs::LockedInputs(const nlohmann::json & json)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ libexpr_SOURCES := \
|
||||||
$(d)/lexer-tab.cc \
|
$(d)/lexer-tab.cc \
|
||||||
$(d)/parser-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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -44,19 +44,19 @@ 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) {
|
||||||
auto [ctx, outputName] = decodeContext(i);
|
auto [ctxS, outputName] = decodeContext(i);
|
||||||
assert(store->isStorePath(ctx));
|
auto ctx = store->parseStorePath(ctxS);
|
||||||
if (!store->isValidPath(ctx))
|
if (!store->isValidPath(ctx))
|
||||||
throw InvalidPathError(ctx);
|
throw InvalidPathError(store->printStorePath(ctx));
|
||||||
if (!outputName.empty() && nix::isDerivation(ctx)) {
|
if (!outputName.empty() && ctx.isDerivation()) {
|
||||||
drvs.insert(ctx + "!" + outputName);
|
drvs.push_back(StorePathWithOutputs{ctx.clone(), {outputName}});
|
||||||
|
|
||||||
/* Add the output of this derivation to the allowed
|
/* Add the output of this derivation to the allowed
|
||||||
paths. */
|
paths. */
|
||||||
|
@ -64,8 +64,8 @@ void EvalState::realiseContext(const PathSet & context)
|
||||||
auto drv = store->derivationFromPath(ctx);
|
auto drv = store->derivationFromPath(ctx);
|
||||||
DerivationOutputs::iterator i = drv.outputs.find(outputName);
|
DerivationOutputs::iterator i = drv.outputs.find(outputName);
|
||||||
if (i == drv.outputs.end())
|
if (i == drv.outputs.end())
|
||||||
throw Error("derivation '%s' does not have an output named '%s'", ctx, outputName);
|
throw Error("derivation '%s' does not have an output named '%s'", ctxS, outputName);
|
||||||
allowedPaths->insert(i->second.path);
|
allowedPaths->insert(store->printStorePath(i->second.path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,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);
|
||||||
|
|
||||||
|
@ -100,8 +101,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 +117,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 +678,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 +705,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 +716,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 +813,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 +1009,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 +1059,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 +1087,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 +2147,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -56,7 +56,7 @@ static std::optional<GitInfo> lookupGitInfo(
|
||||||
|
|
||||||
Path storePath = json["storePath"];
|
Path storePath = json["storePath"];
|
||||||
|
|
||||||
if (store->isValidPath(storePath)) {
|
if (store->isValidPath(store->parseStorePath(storePath))) {
|
||||||
GitInfo gitInfo;
|
GitInfo gitInfo;
|
||||||
gitInfo.storePath = storePath;
|
gitInfo.storePath = storePath;
|
||||||
gitInfo.rev = rev;
|
gitInfo.rev = rev;
|
||||||
|
@ -145,7 +145,7 @@ GitInfo exportGit(ref<Store> store, 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));
|
||||||
gitInfo.revCount = haveCommits ? std::stoull(runProgram("git", true, { "-C", uri, "rev-list", "--count", "HEAD" })) : 0;
|
gitInfo.revCount = haveCommits ? std::stoull(runProgram("git", true, { "-C", uri, "rev-list", "--count", "HEAD" })) : 0;
|
||||||
// FIXME: maybe we should use the timestamp of the last
|
// FIXME: maybe we should use the timestamp of the last
|
||||||
// modified dirty file?
|
// modified dirty file?
|
||||||
|
@ -265,7 +265,7 @@ GitInfo exportGit(ref<Store> store, 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", repoDir, "rev-list", "--count", gitInfo.rev.gitRev() }));
|
gitInfo.revCount = std::stoull(runProgram("git", true, { "-C", repoDir, "rev-list", "--count", gitInfo.rev.gitRev() }));
|
||||||
gitInfo.lastModified = std::stoull(runProgram("git", true, { "-C", repoDir, "log", "-1", "--format=%ct", gitInfo.rev.gitRev() }));
|
gitInfo.lastModified = std::stoull(runProgram("git", true, { "-C", repoDir, "log", "-1", "--format=%ct", gitInfo.rev.gitRev() }));
|
||||||
|
|
|
@ -64,7 +64,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;
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,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;
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
@ -9,7 +9,7 @@ struct Package {
|
||||||
Path path;
|
Path path;
|
||||||
bool active;
|
bool active;
|
||||||
int priority;
|
int priority;
|
||||||
Package(Path path, bool active, int priority) : path{path}, active{active}, priority{priority} {}
|
Package(const Path & path, bool active, int priority) : path{path}, active{active}, priority{priority} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Package> Packages;
|
typedef std::vector<Package> Packages;
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
assert(!request.getLastModified); // FIXME
|
assert(!request.getLastModified); // FIXME
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -833,7 +833,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;
|
||||||
|
|
||||||
|
@ -842,9 +842,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;
|
||||||
|
@ -858,7 +859,7 @@ CachedDownloadResult Downloader::downloadCached(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
storePath = "";
|
storePath.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skip) {
|
if (!skip) {
|
||||||
|
@ -871,46 +872,45 @@ 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);
|
store->addTempRoot(*unpackedStorePath);
|
||||||
if (!store->isValidPath(unpackedStorePath))
|
if (!store->isValidPath(*unpackedStorePath))
|
||||||
unpackedStorePath = "";
|
unpackedStorePath.reset();
|
||||||
else
|
else
|
||||||
result.lastModified = lstat(unpackedLink).st_mtime;
|
result.lastModified = lstat(unpackedLink).st_mtime;
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
@ -921,15 +921,15 @@ CachedDownloadResult Downloader::downloadCached(
|
||||||
// Store the last-modified date of the tarball in the symlink
|
// Store the last-modified date of the tarball in the symlink
|
||||||
// mtime. This saves us from having to store it somewhere
|
// mtime. This saves us from having to store it somewhere
|
||||||
// else.
|
// else.
|
||||||
replaceSymlink(unpackedStorePath, unpackedLink, result.lastModified);
|
replaceSymlink(store->printStorePath(*unpackedStorePath), unpackedLink, result.lastModified);
|
||||||
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());
|
||||||
}
|
}
|
||||||
|
@ -937,8 +937,8 @@ CachedDownloadResult Downloader::downloadCached(
|
||||||
if (request.gcRoot)
|
if (request.gcRoot)
|
||||||
store->addIndirectRoot(fileLink);
|
store->addIndirectRoot(fileLink);
|
||||||
|
|
||||||
result.storePath = storePath;
|
result.storePath = store->printStorePath(*storePath);
|
||||||
result.path = store->toRealPath(storePath);
|
result.path = store->toRealPath(result.storePath);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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++) {
|
||||||
|
|
||||||
|
|
|
@ -534,42 +534,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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,16 +572,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())
|
||||||
|
@ -599,8 +592,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
|
||||||
|
@ -613,34 +606,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>();
|
||||||
|
@ -650,13 +640,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);
|
||||||
|
@ -673,7 +663,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;
|
||||||
}));
|
}));
|
||||||
|
@ -691,27 +681,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());
|
||||||
|
@ -720,39 +710,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);
|
||||||
|
@ -760,42 +749,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());
|
||||||
|
@ -812,31 +799,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;
|
||||||
|
@ -845,12 +837,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);
|
||||||
}
|
}
|
||||||
|
@ -859,7 +851,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;
|
||||||
|
@ -867,17 +859,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) {
|
||||||
|
@ -911,7 +902,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);
|
||||||
|
@ -919,7 +910,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) {
|
||||||
|
@ -932,10 +923,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
|
||||||
|
@ -951,18 +942,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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -980,10 +971,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);
|
||||||
|
|
||||||
|
@ -991,12 +982,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)) {
|
||||||
|
@ -1011,7 +1002,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 {
|
||||||
|
@ -1026,11 +1017,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();
|
||||||
|
|
||||||
|
@ -1046,12 +1037,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);
|
||||||
|
|
||||||
|
@ -1060,7 +1051,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});
|
||||||
|
|
||||||
|
@ -1091,8 +1083,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);
|
||||||
|
@ -1106,7 +1097,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));
|
||||||
|
@ -1124,8 +1115,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);
|
||||||
|
@ -1134,7 +1125,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});
|
||||||
|
|
||||||
|
@ -1154,11 +1146,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);
|
||||||
}
|
}
|
||||||
|
@ -1180,27 +1171,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1219,18 +1208,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) {
|
||||||
|
@ -1265,21 +1255,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 {
|
||||||
|
|
||||||
|
@ -1287,14 +1276,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;
|
||||||
}
|
}
|
||||||
|
@ -1310,9 +1299,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1322,43 +1311,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;
|
||||||
|
@ -1367,7 +1356,7 @@ void LocalStore::verifyPath(const Path & path, const PathSet & store,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
validPaths.insert(path);
|
validPaths.insert(std::move(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1436,7 +1425,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());
|
||||||
|
@ -1462,7 +1451,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -188,11 +188,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))
|
||||||
|
@ -201,9 +198,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);
|
||||||
|
@ -225,12 +222,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)
|
||||||
|
@ -238,7 +235,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();
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -4,8 +4,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");
|
||||||
|
@ -13,7 +13,7 @@ ParsedDerivation::ParsedDerivation(const Path & drvPath, BasicDerivation & drv)
|
||||||
try {
|
try {
|
||||||
structuredAttrs = std::make_unique<nlohmann::json>(nlohmann::json::parse(jsonAttr->second));
|
structuredAttrs = std::make_unique<nlohmann::json>(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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,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 {
|
||||||
|
@ -48,7 +48,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 {
|
||||||
|
@ -68,11 +68,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;
|
||||||
|
|
|
@ -6,13 +6,13 @@ namespace nix {
|
||||||
|
|
||||||
class ParsedDerivation
|
class ParsedDerivation
|
||||||
{
|
{
|
||||||
Path drvPath;
|
StorePath drvPath;
|
||||||
BasicDerivation & drv;
|
BasicDerivation & drv;
|
||||||
std::unique_ptr<nlohmann::json> structuredAttrs;
|
std::unique_ptr<nlohmann::json> structuredAttrs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ParsedDerivation(const Path & drvPath, BasicDerivation & drv);
|
ParsedDerivation(StorePath && drvPath, BasicDerivation & drv);
|
||||||
|
|
||||||
~ParsedDerivation();
|
~ParsedDerivation();
|
||||||
|
|
||||||
|
|
99
src/libstore/path.cc
Normal file
99
src/libstore/path.cc
Normal 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
81
src/libstore/path.hh
Normal 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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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. ext4’s 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -756,34 +738,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();
|
||||||
|
@ -792,9 +774,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();
|
||||||
|
@ -810,15 +796,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -826,7 +812,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -939,7 +925,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: {
|
||||||
|
|
|
@ -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"
|
||||||
|
@ -43,14 +44,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
|
||||||
|
@ -84,7 +82,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()};
|
||||||
|
@ -105,21 +103,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
|
||||||
|
@ -144,7 +142,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
|
||||||
|
@ -172,9 +170,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;
|
||||||
|
@ -187,10 +185,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() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -241,6 +242,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:
|
||||||
|
@ -259,6 +277,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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -274,6 +293,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;
|
||||||
|
@ -282,9 +319,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;
|
||||||
|
@ -294,26 +328,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;
|
||||||
|
|
||||||
|
@ -331,21 +366,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
|
||||||
|
@ -353,54 +388,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; }
|
||||||
|
@ -419,12 +454,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");
|
||||||
|
@ -432,11 +467,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
|
||||||
|
@ -446,22 +481,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
|
||||||
|
@ -507,7 +544,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
|
||||||
|
@ -515,14 +552,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. */
|
||||||
|
@ -538,14 +575,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
|
||||||
|
@ -554,36 +591,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
|
||||||
|
@ -607,7 +644,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
|
||||||
|
@ -673,11 +710,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; }
|
||||||
|
@ -688,25 +725,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
|
||||||
|
@ -714,7 +743,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);
|
||||||
|
@ -722,7 +751,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);
|
||||||
|
@ -805,7 +834,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);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -189,22 +189,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1307,9 +1307,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -431,7 +431,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. */
|
||||||
|
@ -474,10 +474,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ static void _main(int argc, char * * argv)
|
||||||
// Heuristic to see if we're invoked as a shebang script, namely,
|
// Heuristic to see if we're invoked as a shebang script, namely,
|
||||||
// if we have at least one argument, it's the name of an
|
// if we have at least one argument, it's the name of an
|
||||||
// executable file, and it starts with "#!".
|
// executable file, and it starts with "#!".
|
||||||
if (runEnv && argc > 1 && !std::regex_search(baseNameOf(argv[1]), std::regex("nix-shell"))) {
|
if (runEnv && argc > 1 && !std::regex_search(std::string(baseNameOf(argv[1])), std::regex("nix-shell"))) {
|
||||||
script = argv[1];
|
script = argv[1];
|
||||||
try {
|
try {
|
||||||
auto lines = tokenizeString<Strings>(readFile(script), "\n");
|
auto lines = tokenizeString<Strings>(readFile(script), "\n");
|
||||||
|
@ -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';
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -51,28 +51,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)
|
||||||
|
@ -107,7 +108,7 @@ MixProfile::MixProfile()
|
||||||
.dest(&profile);
|
.dest(&profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MixProfile::updateProfile(const Path & storePath)
|
void MixProfile::updateProfile(const StorePath & storePath)
|
||||||
{
|
{
|
||||||
if (!profile) return;
|
if (!profile) return;
|
||||||
auto store = getStore().dynamic_pointer_cast<LocalFSStore>();
|
auto store = getStore().dynamic_pointer_cast<LocalFSStore>();
|
||||||
|
@ -116,20 +117,20 @@ void MixProfile::updateProfile(const Path & storePath)
|
||||||
switchLink(profile2,
|
switchLink(profile2,
|
||||||
createGeneration(
|
createGeneration(
|
||||||
ref<LocalFSStore>(store),
|
ref<LocalFSStore>(store),
|
||||||
profile2, storePath));
|
profile2, store->printStorePath(storePath)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MixProfile::updateProfile(const Buildables & buildables)
|
void MixProfile::updateProfile(const Buildables & buildables)
|
||||||
{
|
{
|
||||||
if (!profile) return;
|
if (!profile) return;
|
||||||
|
|
||||||
std::optional<Path> result;
|
std::optional<StorePath> result;
|
||||||
|
|
||||||
for (auto & buildable : buildables) {
|
for (auto & buildable : buildables) {
|
||||||
for (auto & output : buildable.outputs) {
|
for (auto & output : buildable.outputs) {
|
||||||
if (result)
|
if (result)
|
||||||
throw Error("'--profile' requires that the arguments produce a single store path, but there are multiple");
|
throw Error("'--profile' requires that the arguments produce a single store path, but there are multiple");
|
||||||
result = output.second;
|
result = output.second.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "installables.hh"
|
#include "installables.hh"
|
||||||
#include "args.hh"
|
#include "args.hh"
|
||||||
#include "common-eval-args.hh"
|
#include "common-eval-args.hh"
|
||||||
|
#include "path.hh"
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
@ -35,8 +36,6 @@ struct EvalCommand : virtual StoreCommand, MixEvalArgs
|
||||||
{
|
{
|
||||||
ref<EvalState> getEvalState();
|
ref<EvalState> getEvalState();
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::shared_ptr<EvalState> evalState;
|
std::shared_ptr<EvalState> evalState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -128,7 +127,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;
|
||||||
|
|
||||||
|
@ -140,7 +139,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;
|
||||||
};
|
};
|
||||||
|
@ -167,13 +166,13 @@ static RegisterCommand registerCommand(const std::string & name)
|
||||||
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);
|
||||||
|
|
||||||
|
@ -188,7 +187,7 @@ struct MixProfile : virtual Args, virtual StoreCommand
|
||||||
MixProfile();
|
MixProfile();
|
||||||
|
|
||||||
/* If 'profile' is set, make it point at 'storePath'. */
|
/* If 'profile' is set, make it point at 'storePath'. */
|
||||||
void updateProfile(const Path & storePath);
|
void updateProfile(const StorePath & storePath);
|
||||||
|
|
||||||
/* If 'profile' is set, make it point at the store path produced
|
/* If 'profile' is set, make it point at the store path produced
|
||||||
by 'buildables'. */
|
by 'buildables'. */
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -263,22 +263,23 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
|
||||||
if (!drvInfo)
|
if (!drvInfo)
|
||||||
throw Error("flake attribute '%s' is not a derivation", attrPath);
|
throw Error("flake attribute '%s' is not a derivation", attrPath);
|
||||||
// FIXME: check meta attributes
|
// FIXME: check meta attributes
|
||||||
return drvInfo->queryDrvPath();
|
return store->parseStorePath(drvInfo->queryDrvPath());
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addPrefix(fmt("while checking the derivation '" ANSI_BOLD "%s" ANSI_NORMAL "' at %s:\n", attrPath, pos));
|
e.addPrefix(fmt("while checking the derivation '" ANSI_BOLD "%s" ANSI_NORMAL "' at %s:\n", attrPath, pos));
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PathSet drvPaths;
|
std::vector<StorePathWithOutputs> drvPaths;
|
||||||
|
|
||||||
auto checkApp = [&](const std::string & attrPath, Value & v, const Pos & pos) {
|
auto checkApp = [&](const std::string & attrPath, Value & v, const Pos & pos) {
|
||||||
try {
|
try {
|
||||||
auto app = App(*state, v);
|
auto app = App(*state, v);
|
||||||
for (auto & i : app.context) {
|
for (auto & i : app.context) {
|
||||||
auto [drvPath, outputName] = decodeContext(i);
|
auto [drvPathS, outputName] = decodeContext(i);
|
||||||
if (!outputName.empty() && nix::isDerivation(drvPath))
|
auto drvPath = store->parseStorePath(drvPathS);
|
||||||
drvPaths.insert(drvPath + "!" + outputName);
|
if (!outputName.empty() && drvPath.isDerivation())
|
||||||
|
drvPaths.emplace_back(drvPath);
|
||||||
}
|
}
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
e.addPrefix(fmt("while checking the app definition '" ANSI_BOLD "%s" ANSI_NORMAL "' at %s:\n", attrPath, pos));
|
e.addPrefix(fmt("while checking the app definition '" ANSI_BOLD "%s" ANSI_NORMAL "' at %s:\n", attrPath, pos));
|
||||||
|
@ -388,7 +389,7 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
|
||||||
fmt("%s.%s.%s", name, attr.name, attr2.name),
|
fmt("%s.%s.%s", name, attr.name, attr2.name),
|
||||||
*attr2.value, *attr2.pos);
|
*attr2.value, *attr2.pos);
|
||||||
if ((std::string) attr.name == settings.thisSystem.get())
|
if ((std::string) attr.name == settings.thisSystem.get())
|
||||||
drvPaths.insert(drvPath);
|
drvPaths.emplace_back(drvPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,20 +118,30 @@ App Installable::toApp(EvalState & state)
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Path> getStorePath() override
|
std::optional<StorePath> getStorePath() override
|
||||||
{
|
{
|
||||||
return storePath;
|
return storePath.clone();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -149,8 +159,8 @@ std::vector<flake::EvalCache::Derivation> InstallableValue::toDerivations()
|
||||||
std::vector<flake::EvalCache::Derivation> res;
|
std::vector<flake::EvalCache::Derivation> res;
|
||||||
for (auto & drvInfo : drvInfos) {
|
for (auto & drvInfo : drvInfos) {
|
||||||
res.push_back({
|
res.push_back({
|
||||||
drvInfo.queryDrvPath(),
|
state->store->parseStorePath(drvInfo.queryDrvPath()),
|
||||||
drvInfo.queryOutPath(),
|
state->store->parseStorePath(drvInfo.queryOutPath()),
|
||||||
drvInfo.queryOutputName()
|
drvInfo.queryOutputName()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -160,19 +170,21 @@ std::vector<flake::EvalCache::Derivation> InstallableValue::toDerivations()
|
||||||
|
|
||||||
Buildables InstallableValue::toBuildables()
|
Buildables InstallableValue::toBuildables()
|
||||||
{
|
{
|
||||||
|
auto state = cmd.getEvalState();
|
||||||
|
|
||||||
Buildables res;
|
Buildables res;
|
||||||
|
|
||||||
PathSet drvPaths;
|
StorePathSet drvPaths;
|
||||||
|
|
||||||
for (auto & drv : toDerivations()) {
|
for (auto & drv : toDerivations()) {
|
||||||
Buildable b{drv.drvPath};
|
Buildable b{.drvPath = drv.drvPath.clone()};
|
||||||
drvPaths.insert(b.drvPath);
|
drvPaths.insert(drv.drvPath.clone());
|
||||||
|
|
||||||
auto outputName = drv.outputName;
|
auto outputName = drv.outputName;
|
||||||
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.outPath);
|
b.outputs.emplace(outputName, drv.outPath.clone());
|
||||||
|
|
||||||
res.push_back(std::move(b));
|
res.push_back(std::move(b));
|
||||||
}
|
}
|
||||||
|
@ -180,10 +192,13 @@ Buildables InstallableValue::toBuildables()
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
|
@ -231,10 +246,10 @@ void makeFlakeClosureGCRoot(Store & store,
|
||||||
if (std::get_if<FlakeRef::IsPath>(&origFlakeRef.data)) return;
|
if (std::get_if<FlakeRef::IsPath>(&origFlakeRef.data)) return;
|
||||||
|
|
||||||
/* Get the store paths of all non-local flakes. */
|
/* Get the store paths of all non-local flakes. */
|
||||||
PathSet closure;
|
StorePathSet closure;
|
||||||
|
|
||||||
assert(store.isValidPath(resFlake.flake.sourceInfo.storePath));
|
assert(store.isValidPath(store.parseStorePath(resFlake.flake.sourceInfo.storePath)));
|
||||||
closure.insert(resFlake.flake.sourceInfo.storePath);
|
closure.insert(store.parseStorePath(resFlake.flake.sourceInfo.storePath));
|
||||||
|
|
||||||
std::queue<std::reference_wrapper<const flake::LockedInputs>> queue;
|
std::queue<std::reference_wrapper<const flake::LockedInputs>> queue;
|
||||||
queue.push(resFlake.lockFile);
|
queue.push(resFlake.lockFile);
|
||||||
|
@ -246,8 +261,8 @@ void makeFlakeClosureGCRoot(Store & store,
|
||||||
yet. */
|
yet. */
|
||||||
for (auto & dep : flake.inputs) {
|
for (auto & dep : flake.inputs) {
|
||||||
auto path = dep.second.computeStorePath(store);
|
auto path = dep.second.computeStorePath(store);
|
||||||
if (store.isValidPath(path))
|
if (store.isValidPath(store.parseStorePath(path)))
|
||||||
closure.insert(path);
|
closure.insert(store.parseStorePath(path));
|
||||||
queue.push(dep.second);
|
queue.push(dep.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -255,7 +270,8 @@ void makeFlakeClosureGCRoot(Store & store,
|
||||||
if (closure.empty()) return;
|
if (closure.empty()) return;
|
||||||
|
|
||||||
/* Write the closure to a file in the store. */
|
/* Write the closure to a file in the store. */
|
||||||
auto closurePath = store.addTextToStore("flake-closure", concatStringsSep(" ", closure), closure);
|
auto closurePath = store.addTextToStore("flake-closure",
|
||||||
|
concatStringsSep(" ", store.printStorePathSet(closure)), closure);
|
||||||
|
|
||||||
Path cacheDir = getCacheDir() + "/nix/flake-closures";
|
Path cacheDir = getCacheDir() + "/nix/flake-closures";
|
||||||
createDirs(cacheDir);
|
createDirs(cacheDir);
|
||||||
|
@ -267,7 +283,7 @@ void makeFlakeClosureGCRoot(Store & store,
|
||||||
s = replaceStrings(s, ":", "%3a");
|
s = replaceStrings(s, ":", "%3a");
|
||||||
Path symlink = cacheDir + "/" + s;
|
Path symlink = cacheDir + "/" + s;
|
||||||
debug("writing GC root '%s' for flake closure of '%s'", symlink, origFlakeRef);
|
debug("writing GC root '%s' for flake closure of '%s'", symlink, origFlakeRef);
|
||||||
replaceSymlink(closurePath, symlink);
|
replaceSymlink(store.printStorePath(closurePath), symlink);
|
||||||
store.addIndirectRoot(symlink);
|
store.addIndirectRoot(symlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,7 +334,7 @@ std::tuple<std::string, FlakeRef, flake::EvalCache::Derivation> InstallableFlake
|
||||||
auto drv = evalCache.getDerivation(fingerprint, attrPath);
|
auto drv = evalCache.getDerivation(fingerprint, attrPath);
|
||||||
if (drv) {
|
if (drv) {
|
||||||
if (state->store->isValidPath(drv->drvPath))
|
if (state->store->isValidPath(drv->drvPath))
|
||||||
return {attrPath, resFlake.flake.sourceInfo.resolvedRef, *drv};
|
return {attrPath, resFlake.flake.sourceInfo.resolvedRef, std::move(*drv)};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vOutputs)
|
if (!vOutputs)
|
||||||
|
@ -333,14 +349,14 @@ std::tuple<std::string, FlakeRef, flake::EvalCache::Derivation> InstallableFlake
|
||||||
throw Error("flake output attribute '%s' is not a derivation", attrPath);
|
throw Error("flake output attribute '%s' is not a derivation", attrPath);
|
||||||
|
|
||||||
auto drv = flake::EvalCache::Derivation{
|
auto drv = flake::EvalCache::Derivation{
|
||||||
drvInfo->queryDrvPath(),
|
state->store->parseStorePath(drvInfo->queryDrvPath()),
|
||||||
drvInfo->queryOutPath(),
|
state->store->parseStorePath(drvInfo->queryOutPath()),
|
||||||
drvInfo->queryOutputName()
|
drvInfo->queryOutputName()
|
||||||
};
|
};
|
||||||
|
|
||||||
evalCache.addDerivation(fingerprint, attrPath, drv);
|
evalCache.addDerivation(fingerprint, attrPath, drv);
|
||||||
|
|
||||||
return {attrPath, resFlake.flake.sourceInfo.resolvedRef, drv};
|
return {attrPath, resFlake.flake.sourceInfo.resolvedRef, std::move(drv)};
|
||||||
} catch (AttrPathNotFound & e) {
|
} catch (AttrPathNotFound & e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,7 +367,9 @@ std::tuple<std::string, FlakeRef, flake::EvalCache::Derivation> InstallableFlake
|
||||||
|
|
||||||
std::vector<flake::EvalCache::Derivation> InstallableFlake::toDerivations()
|
std::vector<flake::EvalCache::Derivation> InstallableFlake::toDerivations()
|
||||||
{
|
{
|
||||||
return {std::get<2>(toDerivation())};
|
std::vector<flake::EvalCache::Derivation> res;
|
||||||
|
res.push_back(std::get<2>(toDerivation()));
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value * InstallableFlake::toValue(EvalState & state)
|
Value * InstallableFlake::toValue(EvalState & state)
|
||||||
|
@ -406,7 +424,7 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
auto follow = [&](const std::string & s) -> std::optional<Path> {
|
auto follow = [&](const std::string & s) -> std::optional<StorePath> {
|
||||||
try {
|
try {
|
||||||
return store->followLinksToStorePath(s);
|
return store->followLinksToStorePath(s);
|
||||||
} catch (NotInStore &) {
|
} catch (NotInStore &) {
|
||||||
|
@ -417,7 +435,7 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
|
||||||
for (auto & s : ss) {
|
for (auto & s : ss) {
|
||||||
|
|
||||||
size_t hash;
|
size_t hash;
|
||||||
std::optional<Path> storePath;
|
std::optional<StorePath> storePath;
|
||||||
|
|
||||||
if (hasPrefix(s, "nixpkgs.")) {
|
if (hasPrefix(s, "nixpkgs.")) {
|
||||||
bool static warned;
|
bool static warned;
|
||||||
|
@ -440,7 +458,7 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
|
||||||
*this, std::move(flakeRef), getDefaultFlakeAttrPaths()));
|
*this, std::move(flakeRef), getDefaultFlakeAttrPaths()));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
if (s.find('/') != std::string::npos && (storePath = follow(s)))
|
if (s.find('/') != std::string::npos && (storePath = follow(s)))
|
||||||
result.push_back(std::make_shared<InstallableStorePath>(*storePath));
|
result.push_back(std::make_shared<InstallableStorePath>(store, store->printStorePath(*storePath)));
|
||||||
else
|
else
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -467,19 +485,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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -492,19 +509,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});
|
||||||
|
@ -512,17 +529,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) {
|
||||||
|
@ -530,10 +547,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;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
#include "path.hh"
|
||||||
#include "flake/eval-cache.hh"
|
#include "flake/eval-cache.hh"
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -14,8 +15,8 @@ struct SourceExprCommand;
|
||||||
|
|
||||||
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;
|
||||||
|
@ -51,7 +52,7 @@ struct Installable
|
||||||
|
|
||||||
/* Return a value only if this installable is a store path or a
|
/* Return a value only if this installable is a store path or a
|
||||||
symlink to it. */
|
symlink to it. */
|
||||||
virtual std::optional<Path> getStorePath()
|
virtual std::optional<StorePath> getStorePath()
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue