From a35c6eb4a2209716fe1d40cebad2b3adb5d05e0f Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 11 Feb 2014 14:15:57 +0100 Subject: [PATCH 01/61] Support setting CFLAGS and CXXFLAGS for libraries/programs --- libraries.mk | 5 ++++- programs.mk | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/libraries.mk b/libraries.mk index c41694794b..35ce4983a1 100644 --- a/libraries.mk +++ b/libraries.mk @@ -17,6 +17,8 @@ endif # # - $(1)_SOURCES: the source files of the library. # +# - $(1)_CFLAGS: additional C compiler flags. +# # - $(1)_CXXFLAGS: additional C++ compiler flags. # # - $(1)_LIBS: the symbolic names of other libraries on which this @@ -102,7 +104,8 @@ define build-library $(1)_LDFLAGS_USE += $$($(1)_LDFLAGS_PROPAGATED) $(1)_LDFLAGS_USE_INSTALLED += $$($(1)_LDFLAGS_PROPAGATED) - # Propagate CXXFLAGS to the individual object files. + # Propagate CFLAGS and CXXFLAGS to the individual object files. + $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj)_CFLAGS=$$($(1)_CFLAGS))) $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj)_CXXFLAGS=$$($(1)_CXXFLAGS))) # Make each object file depend on the common dependencies. diff --git a/programs.mk b/programs.mk index ab04ff93e9..5e27a7d62f 100644 --- a/programs.mk +++ b/programs.mk @@ -8,6 +8,10 @@ programs-list := # # - $(1)_SOURCES: the source files of the program. # +# - $(1)_CFLAGS: additional C compiler flags. +# +# - $(1)_CXXFLAGS: additional C++ compiler flags. +# # - $(1)_LIBS: the symbolic names of libraries on which this program # depends. # @@ -48,7 +52,8 @@ define build-program endif - # Propagate CXXFLAGS to the individual object files. + # Propagate CFLAGS and CXXFLAGS to the individual object files. + $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj)_CFLAGS=$$($(1)_CFLAGS))) $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj)_CXXFLAGS=$$($(1)_CXXFLAGS))) # Make each object file depend on the common dependencies. From 581a160c11dd3de66d9cd1a6e01c0641909546ef Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 14 Feb 2014 20:12:04 +0100 Subject: [PATCH 02/61] Add a function for looking up programs in $PATH --- functions.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/functions.mk b/functions.mk index 51f6457016..1287e4321e 100644 --- a/functions.mk +++ b/functions.mk @@ -5,3 +5,7 @@ rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst # Given a file name, produce the corresponding dependency file # (e.g. ‘foo/bar.o’ becomes ‘foo/.bar.o.dep’). filename-to-dep = $(dir $1).$(notdir $1).dep + +# Return the full path to a program by looking it up in $PATH, or the +# empty string if not found. +find-program = $(shell for i in $$(IFS=: ; echo $$PATH); do p=$$i/$(strip $1); if [ -e $$p ]; then echo $$p; break; fi; done) From 79f699edca26c035a8bcd68c7d5a13b4fbcbf3be Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 18 Feb 2014 12:57:32 +0100 Subject: [PATCH 03/61] More GNU Make 3.81 compatibility --- functions.mk | 3 +++ install.mk | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/functions.mk b/functions.mk index 1287e4321e..c92cdbc54e 100644 --- a/functions.mk +++ b/functions.mk @@ -9,3 +9,6 @@ filename-to-dep = $(dir $1).$(notdir $1).dep # Return the full path to a program by looking it up in $PATH, or the # empty string if not found. find-program = $(shell for i in $$(IFS=: ; echo $$PATH); do p=$$i/$(strip $1); if [ -e $$p ]; then echo $$p; break; fi; done) + +# Remove trailing slash. +remove-trailing-slash = $(patsubst %/,%,$(1)) diff --git a/install.mk b/install.mk index e4bc734e11..0fe4cf938d 100644 --- a/install.mk +++ b/install.mk @@ -1,7 +1,7 @@ # Add a rule for creating $(1) as a directory. This template may be # called multiple times for the same directory. define create-dir - _i := $(DESTDIR)$$(strip $(1)) + _i := $$(call remove-trailing-slash, $(DESTDIR)$$(strip $(1))) ifndef $$(_i)_SEEN $$(_i)_SEEN = 1 $$(_i): From 7bef965d6f191efb9c671f49fd187f4214db6120 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 18 Feb 2014 13:35:35 +0100 Subject: [PATCH 04/61] Make it work on GNU Make > 3.81 again --- functions.mk | 2 +- install.mk | 2 +- libraries.mk | 6 +++--- programs.mk | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/functions.mk b/functions.mk index c92cdbc54e..45d9173993 100644 --- a/functions.mk +++ b/functions.mk @@ -11,4 +11,4 @@ filename-to-dep = $(dir $1).$(notdir $1).dep find-program = $(shell for i in $$(IFS=: ; echo $$PATH); do p=$$i/$(strip $1); if [ -e $$p ]; then echo $$p; break; fi; done) # Remove trailing slash. -remove-trailing-slash = $(patsubst %/,%,$(1)) +add-trailing-slash = $(patsubst %/,%,$(1))/ diff --git a/install.mk b/install.mk index 0fe4cf938d..dad0fd8533 100644 --- a/install.mk +++ b/install.mk @@ -1,7 +1,7 @@ # Add a rule for creating $(1) as a directory. This template may be # called multiple times for the same directory. define create-dir - _i := $$(call remove-trailing-slash, $(DESTDIR)$$(strip $(1))) + _i := $$(call add-trailing-slash, $(DESTDIR)$$(strip $(1))) ifndef $$(_i)_SEEN $$(_i)_SEEN = 1 $$(_i): diff --git a/libraries.mk b/libraries.mk index 35ce4983a1..21718c496a 100644 --- a/libraries.mk +++ b/libraries.mk @@ -68,7 +68,7 @@ define build-library $(1)_PATH := $$(_d)/$$($(1)_NAME).$(SO_EXT) - $$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d) + $$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d)/ $$(trace-ld) $(CXX) -o $$@ -shared $(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE)) $(1)_LDFLAGS_USE += -L$$(_d) -Wl,-rpath,$$(abspath $$(_d)) -l$$(patsubst lib%,%,$$(strip $$($(1)_NAME))) @@ -79,7 +79,7 @@ define build-library $$(eval $$(call create-dir, $$($(1)_INSTALL_DIR))) - $$($(1)_INSTALL_PATH): $$($(1)_OBJS) $$(_libs_final) | $(DESTDIR)$$($(1)_INSTALL_DIR) + $$($(1)_INSTALL_PATH): $$($(1)_OBJS) $$(_libs_final) | $(DESTDIR)$$($(1)_INSTALL_DIR)/ $$(trace-ld) $(CXX) -o $$@ -shared $(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED)) $(1)_LDFLAGS_USE_INSTALLED += -L$$(DESTDIR)$$($(1)_INSTALL_DIR) -Wl,-rpath,$$($(1)_INSTALL_DIR) -l$$(patsubst lib%,%,$$(strip $$($(1)_NAME))) @@ -92,7 +92,7 @@ define build-library $(1)_PATH := $$(_d)/$$($(1)_NAME).a - $$($(1)_PATH): $$($(1)_OBJS) | $$(_d) + $$($(1)_PATH): $$($(1)_OBJS) | $$(_d)/ $(trace-ar) ar crs $$@ $$? $(1)_LDFLAGS_USE += $$($(1)_PATH) $$($(1)_LDFLAGS) diff --git a/programs.mk b/programs.mk index 5e27a7d62f..04ba282b2c 100644 --- a/programs.mk +++ b/programs.mk @@ -28,7 +28,7 @@ define build-program $$(eval $$(call create-dir, $$(_d))) - $$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d) + $$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d)/ $$(trace-ld) $(CXX) -o $$@ $(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE)) $(1)_INSTALL_DIR ?= $$(bindir) @@ -42,12 +42,12 @@ define build-program _libs_final := $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_INSTALL_PATH)) - $(DESTDIR)$$($(1)_INSTALL_PATH): $$($(1)_OBJS) $$(_libs_final) | $(DESTDIR)$$($(1)_INSTALL_DIR) + $(DESTDIR)$$($(1)_INSTALL_PATH): $$($(1)_OBJS) $$(_libs_final) | $(DESTDIR)$$($(1)_INSTALL_DIR)/ $$(trace-ld) $(CXX) -o $$@ $(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED)) else - $(DESTDIR)$$($(1)_INSTALL_PATH): $$($(1)_PATH) | $(DESTDIR)$$($(1)_INSTALL_DIR) + $(DESTDIR)$$($(1)_INSTALL_PATH): $$($(1)_PATH) | $(DESTDIR)$$($(1)_INSTALL_DIR)/ install -t $$($(1)_INSTALL_DIR) $$< endif From 4e7e498ff95b553227a26fc20549bd69995a0b08 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 28 Feb 2014 12:01:42 +0100 Subject: [PATCH 05/61] Add variable GLOBAL_COMMON_DEPS This is a list of dependencies on which all C/C++ object files depend. Primarily useful for global precompiled headers. --- libraries.mk | 2 +- programs.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries.mk b/libraries.mk index 21718c496a..547f393e3a 100644 --- a/libraries.mk +++ b/libraries.mk @@ -109,7 +109,7 @@ define build-library $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj)_CXXFLAGS=$$($(1)_CXXFLAGS))) # Make each object file depend on the common dependencies. - $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj): $$($(1)_COMMON_DEPS))) + $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj): $$($(1)_COMMON_DEPS) $$(GLOBAL_COMMON_DEPS))) # Include .dep files, if they exist. $(1)_DEPS := $$(foreach fn, $$($(1)_OBJS), $$(call filename-to-dep, $$(fn))) diff --git a/programs.mk b/programs.mk index 04ba282b2c..d07c91448f 100644 --- a/programs.mk +++ b/programs.mk @@ -57,7 +57,7 @@ define build-program $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj)_CXXFLAGS=$$($(1)_CXXFLAGS))) # Make each object file depend on the common dependencies. - $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj): $$($(1)_COMMON_DEPS))) + $$(foreach obj, $$($(1)_OBJS), $$(eval $$(obj): $$($(1)_COMMON_DEPS) $$(GLOBAL_COMMON_DEPS))) # Include .dep files, if they exist. $(1)_DEPS := $$(foreach fn, $$($(1)_OBJS), $$(call filename-to-dep, $$(fn))) From 4eac3b2471063a3726790368665df963e809fc4e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 28 Feb 2014 12:13:20 +0100 Subject: [PATCH 06/61] Add a variable GLOBAL_CXXFLAGS_PCH for use by precompiled headers You don't want to use GLOBAL_CXXFLAGS for passing flags like "-include-pch" (clang), because that means you cannot use GLOBAL_CXXFLAGS when generating the PCH. --- patterns.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patterns.mk b/patterns.mk index f5674d4043..6b2cfd0170 100644 --- a/patterns.mk +++ b/patterns.mk @@ -1,8 +1,8 @@ %.o: %.cc - $(trace-cxx) $(CXX) -o $@ -c $< $(GLOBAL_CXXFLAGS) $(CXXFLAGS) $($@_CXXFLAGS) -MMD -MF $(call filename-to-dep, $@) -MP + $(trace-cxx) $(CXX) -o $@ -c $< $(GLOBAL_CXXFLAGS) $(GLOBAL_CXXFLAGS_PCH) $(CXXFLAGS) $($@_CXXFLAGS) -MMD -MF $(call filename-to-dep, $@) -MP %.o: %.cpp - $(trace-cxx) $(CXX) -o $@ -c $< $(GLOBAL_CXXFLAGS) $(CXXFLAGS) $($@_CXXFLAGS) -MMD -MF $(call filename-to-dep, $@) -MP + $(trace-cxx) $(CXX) -o $@ -c $< $(GLOBAL_CXXFLAGS) $(GLOBAL_CXXFLAGS_PCH) $(CXXFLAGS) $($@_CXXFLAGS) -MMD -MF $(call filename-to-dep, $@) -MP %.o: %.c $(trace-cc) $(CC) -o $@ -c $< $(GLOBAL_CFLAGS) $(CFLAGS) $($@_CFLAGS) -MMD -MF $(call filename-to-dep, $@) -MP From a3767628481eefc956eb9d9d70eda62930549205 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 3 Mar 2014 15:19:04 +0100 Subject: [PATCH 07/61] Add support for making relocatable packages using $ORIGIN --- lib.mk | 1 + libraries.mk | 9 ++++++--- programs.mk | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib.mk b/lib.mk index 6bcd83a06e..3fde7fe917 100644 --- a/lib.mk +++ b/lib.mk @@ -34,6 +34,7 @@ ifeq ($(BUILD_SHARED_LIBS), 1) ifneq ($(OS), Darwin) GLOBAL_LDFLAGS += -Wl,--no-copy-dt-needed-entries endif + SET_RPATH_TO_LIBS ?= 1 endif diff --git a/libraries.mk b/libraries.mk index 547f393e3a..2da6c9b6a6 100644 --- a/libraries.mk +++ b/libraries.mk @@ -69,7 +69,7 @@ define build-library $(1)_PATH := $$(_d)/$$($(1)_NAME).$(SO_EXT) $$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d)/ - $$(trace-ld) $(CXX) -o $$@ -shared $(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE)) + $$(trace-ld) $(CXX) -o $$@ -shared $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE)) $(1)_LDFLAGS_USE += -L$$(_d) -Wl,-rpath,$$(abspath $$(_d)) -l$$(patsubst lib%,%,$$(strip $$($(1)_NAME))) @@ -80,9 +80,12 @@ define build-library $$(eval $$(call create-dir, $$($(1)_INSTALL_DIR))) $$($(1)_INSTALL_PATH): $$($(1)_OBJS) $$(_libs_final) | $(DESTDIR)$$($(1)_INSTALL_DIR)/ - $$(trace-ld) $(CXX) -o $$@ -shared $(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED)) + $$(trace-ld) $(CXX) -o $$@ -shared $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED)) - $(1)_LDFLAGS_USE_INSTALLED += -L$$(DESTDIR)$$($(1)_INSTALL_DIR) -Wl,-rpath,$$($(1)_INSTALL_DIR) -l$$(patsubst lib%,%,$$(strip $$($(1)_NAME))) + $(1)_LDFLAGS_USE_INSTALLED += -L$$(DESTDIR)$$($(1)_INSTALL_DIR) -l$$(patsubst lib%,%,$$(strip $$($(1)_NAME))) + ifeq ($(SET_RPATH_TO_LIBS), 1) + $(1)_LDFLAGS_USE_INSTALLED += -Wl,-rpath,$$($(1)_INSTALL_DIR) + endif ifdef $(1)_FORCE_INSTALL install: $$($(1)_INSTALL_PATH) diff --git a/programs.mk b/programs.mk index d07c91448f..b6de068940 100644 --- a/programs.mk +++ b/programs.mk @@ -29,7 +29,7 @@ define build-program $$(eval $$(call create-dir, $$(_d))) $$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d)/ - $$(trace-ld) $(CXX) -o $$@ $(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE)) + $$(trace-ld) $(CXX) -o $$@ $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE)) $(1)_INSTALL_DIR ?= $$(bindir) $(1)_INSTALL_PATH := $$($(1)_INSTALL_DIR)/$(1) @@ -43,7 +43,7 @@ define build-program _libs_final := $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_INSTALL_PATH)) $(DESTDIR)$$($(1)_INSTALL_PATH): $$($(1)_OBJS) $$(_libs_final) | $(DESTDIR)$$($(1)_INSTALL_DIR)/ - $$(trace-ld) $(CXX) -o $$@ $(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED)) + $$(trace-ld) $(CXX) -o $$@ $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED)) else From d6a45f6bdbf7c71eda9e4ab1ab78b373be5422b9 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 3 Mar 2014 15:29:58 +0100 Subject: [PATCH 08/61] Don't set an absolute soname --- libraries.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries.mk b/libraries.mk index 2da6c9b6a6..4b8292cc20 100644 --- a/libraries.mk +++ b/libraries.mk @@ -66,6 +66,10 @@ define build-library endif endif + ifneq ($(OS), Darwin) + $(1)_LDFLAGS += -Wl,-soname=$$($(1)_NAME).$(SO_EXT) + endif + $(1)_PATH := $$(_d)/$$($(1)_NAME).$(SO_EXT) $$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d)/ From f0de86357c18e18eccd814c8bea3bfdaf10f75f5 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 3 Apr 2014 15:24:02 +0200 Subject: [PATCH 09/61] Tweak error message --- src/libutil/archive.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc index ab4cd47351..70a1c580dd 100644 --- a/src/libutil/archive.cc +++ b/src/libutil/archive.cc @@ -104,7 +104,7 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter) writeString(readLink(path), sink); } - else throw Error(format("file `%1%' has an unknown type") % path); + else throw Error(format("file `%1%' has an unsupported type") % path); writeString(")", sink); } From 7191a7394a3091ed2856508674f84f3a87eda5a6 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 3 Apr 2014 17:35:16 +0200 Subject: [PATCH 10/61] Support Illumos From https://github.com/NixOS/nix/pull/236 --- lib.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib.mk b/lib.mk index 3fde7fe917..56e162d500 100644 --- a/lib.mk +++ b/lib.mk @@ -32,7 +32,9 @@ ifeq ($(BUILD_SHARED_LIBS), 1) GLOBAL_CFLAGS += -fPIC GLOBAL_CXXFLAGS += -fPIC ifneq ($(OS), Darwin) + ifneq ($(OS), SunOS) GLOBAL_LDFLAGS += -Wl,--no-copy-dt-needed-entries + endif endif SET_RPATH_TO_LIBS ?= 1 endif From ae6b631dc48f4b923a6ed17b8d6e59524c4ea883 Mon Sep 17 00:00:00 2001 From: Danny Wilson Date: Thu, 3 Apr 2014 16:59:25 +0200 Subject: [PATCH 11/61] Fix compile errors on Illumos --- src/libstore/build.cc | 1 + src/libstore/local.mk | 4 ++++ src/nix-daemon/local.mk | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 2e2f92fadf..f38cd29940 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff --git a/src/libstore/local.mk b/src/libstore/local.mk index 2dddce740d..40cb25dc5f 100644 --- a/src/libstore/local.mk +++ b/src/libstore/local.mk @@ -10,6 +10,10 @@ libstore_LIBS = libutil libformat libstore_LDFLAGS = -lsqlite3 -lbz2 +ifeq ($(OS), SunOS) + libstore_LDFLAGS += -lsocket +endif + libstore_CXXFLAGS = \ -DNIX_STORE_DIR=\"$(storedir)\" \ -DNIX_DATA_DIR=\"$(datadir)\" \ diff --git a/src/nix-daemon/local.mk b/src/nix-daemon/local.mk index db071a3f7c..bab84e7add 100644 --- a/src/nix-daemon/local.mk +++ b/src/nix-daemon/local.mk @@ -6,4 +6,8 @@ nix-daemon_SOURCES := $(d)/nix-daemon.cc nix-daemon_LIBS = libmain libstore libutil libformat +ifeq ($(OS), SunOS) + nix-daemon_LDFLAGS += -lsocket +endif + $(eval $(call install-symlink, nix-daemon, $(bindir)/nix-worker)) From 1f19fdbd45d902a48fd8bacb25ef1a88020a0cc7 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 13:49:53 +0200 Subject: [PATCH 12/61] Document that we require a C++11 compiler --- doc/manual/release-notes.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/manual/release-notes.xml b/doc/manual/release-notes.xml index 5147f1f2f8..f993328523 100644 --- a/doc/manual/release-notes.xml +++ b/doc/manual/release-notes.xml @@ -232,6 +232,10 @@ $ bash <(curl https://nixos.org/nix/install) the same name from other packages. + + Nix now requires a compiler that supports C++11. + + From 3f8e1f56825f3ec2a9d99715609e362fe5e5a218 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 14:51:07 +0200 Subject: [PATCH 13/61] Update release notes --- doc/manual/release-notes.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/manual/release-notes.xml b/doc/manual/release-notes.xml index f993328523..9bfa169ac5 100644 --- a/doc/manual/release-notes.xml +++ b/doc/manual/release-notes.xml @@ -173,6 +173,16 @@ $ nix-instantiate --eval '<nixos>' -A 'config.systemd.units."nscd.service".te 1G will free up to 1 gigabyte of disk space. + + nix-collect-garbage has a new flag + + Nd, which deletes + all user environment generations older than + N days. Likewise, nix-env + --delete-generations accepts a + Nd age limit. + + Nix now heuristically detects whether a build failure was due to a disk-full condition. In that case, the build is not @@ -238,6 +248,10 @@ $ bash <(curl https://nixos.org/nix/install) +This release has contributions from Danny Wilson, Domen Kožar, +Eelco Dolstra, Ian-Woo Kim, Ludovic Courtès, Maxim Ivanov, Petr +Rockai, Ricardo M. Correia and Shea Levy. + From b72c8d2e5b5bbdc218f7c00694027cdd75b6a584 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 17:53:52 +0200 Subject: [PATCH 14/61] Include position info in function application This allows error messages like: error: the anonymous function at `/etc/nixos/configuration.nix:1:1' called without required argument `foo', at `/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/lib/modules.nix:77:59' --- src/libexpr/eval-inline.hh | 2 +- src/libexpr/eval.cc | 31 +++++++++++++++++++------------ src/libexpr/eval.hh | 2 +- src/libexpr/nixexpr.cc | 2 +- src/libexpr/nixexpr.hh | 18 +++++++++++++++++- src/libexpr/parser.y | 6 +++--- src/libexpr/primops.cc | 6 +++--- 7 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index 5801a20c3b..ffe8fa59cd 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -35,7 +35,7 @@ void EvalState::forceValue(Value & v) } } else if (v.type == tApp) - callFunction(*v.app.left, *v.app.right, v); + callFunction(*v.app.left, *v.app.right, v, noPos); else if (v.type == tBlackhole) throwEvalError("infinite recursion encountered"); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index bbf494387e..d26a0e2584 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -130,12 +130,14 @@ string showType(const Value & v) } +#if HAVE_BOEHMGC /* Called when the Boehm GC runs out of memory. */ static void * oomHandler(size_t requested) { /* Convert this to a proper C++ exception. */ throw std::bad_alloc(); } +#endif static Symbol getName(const AttrName & name, EvalState & state, Env & env) { @@ -292,14 +294,19 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1)) throw TypeError(format(s) % s1); } +LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v, const Pos & pos)) +{ + throw TypeError(format(s) % showType(v) % pos); +} + LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1, const string & s2)) { throw TypeError(format(s) % s1 % s2); } -LocalNoInlineNoReturn(void throwTypeError(const char * s, const ExprLambda & fun, const Symbol & s2)) +LocalNoInlineNoReturn(void throwTypeError(const char * s, const ExprLambda & fun, const Symbol & s2, const Pos & pos)) { - throw TypeError(format(s) % fun.showNamePos() % s2); + throw TypeError(format(s) % fun.showNamePos() % s2 % pos); } LocalNoInlineNoReturn(void throwAssertionError(const char * s, const Pos & pos)) @@ -317,9 +324,9 @@ LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2)) e.addPrefix(format(s) % s2); } -LocalNoInline(void addErrorPrefix(Error & e, const char * s, const ExprLambda & fun)) +LocalNoInline(void addErrorPrefix(Error & e, const char * s, const ExprLambda & fun, const Pos & pos)) { - e.addPrefix(format(s) % fun.showNamePos()); + e.addPrefix(format(s) % fun.showNamePos() % pos); } LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2, const Pos & pos)) @@ -783,7 +790,7 @@ void ExprApp::eval(EvalState & state, Env & env, Value & v) /* FIXME: vFun prevents GCC from doing tail call optimisation. */ Value vFun; e1->eval(state, env, vFun); - state.callFunction(vFun, *(e2->maybeThunk(state, env)), v); + state.callFunction(vFun, *(e2->maybeThunk(state, env)), v, pos); } @@ -824,7 +831,7 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v) } -void EvalState::callFunction(Value & fun, Value & arg, Value & v) +void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & pos) { if (fun.type == tPrimOp || fun.type == tPrimOpApp) { callPrimOp(fun, arg, v); @@ -832,7 +839,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) } if (fun.type != tLambda) - throwTypeError("attempt to call something which is not a function but %1%", fun); + throwTypeError("attempt to call something which is not a function but %1%, at %2%", fun, pos); ExprLambda & lambda(*fun.lambda.fun); @@ -860,8 +867,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) foreach (Formals::Formals_::iterator, i, lambda.formals->formals) { Bindings::iterator j = arg.attrs->find(i->name); if (j == arg.attrs->end()) { - if (!i->def) throwTypeError("%1% called without required argument `%2%'", - lambda, i->name); + if (!i->def) throwTypeError("%1% called without required argument `%2%', at %3%", + lambda, i->name, pos); env2.values[displ++] = i->def->maybeThunk(*this, env2); } else { attrsUsed++; @@ -876,7 +883,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) user. */ foreach (Bindings::iterator, i, *arg.attrs) if (lambda.formals->argNames.find(i->name) == lambda.formals->argNames.end()) - throwTypeError("%1% called with unexpected argument `%2%'", lambda, i->name); + throwTypeError("%1% called with unexpected argument `%2%', at %3%", lambda, i->name, pos); abort(); // can't happen } } @@ -890,7 +897,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) try { lambda.body->eval(*this, env2, v); } catch (Error & e) { - addErrorPrefix(e, "while evaluating %1%:\n", lambda); + addErrorPrefix(e, "while evaluating %1%, called from %2%:\n", lambda, pos); throw; } else @@ -928,7 +935,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) actualArgs->attrs->sort(); - callFunction(fun, *actualArgs, res); + callFunction(fun, *actualArgs, res, noPos); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 58d1318c2a..170b740790 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -226,7 +226,7 @@ public: elements and attributes are compared recursively. */ bool eqValues(Value & v1, Value & v2); - void callFunction(Value & fun, Value & arg, Value & v); + void callFunction(Value & fun, Value & arg, Value & v, const Pos & pos); void callPrimOp(Value & fun, Value & arg, Value & v); /* Automatically call a function for which each argument has a diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index bca2b7913b..ba1f4f078f 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -373,7 +373,7 @@ void ExprLambda::setName(Symbol & name) string ExprLambda::showNamePos() const { - return (format("%1% at %2%") % (name.set() ? "`" + (string) name + "'" : "an anonymous function") % pos).str(); + return (format("%1% at %2%") % (name.set() ? "`" + (string) name + "'" : "anonymous function") % pos).str(); } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index a5c5d0533c..527589147e 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -273,6 +273,23 @@ struct ExprBuiltin : Expr COMMON_METHODS }; +struct ExprApp : Expr +{ + Pos pos; + Expr * e1, * e2; + ExprApp(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; + ExprApp(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; + void show(std::ostream & str) + { + str << *e1 << " " << *e2; + } + void bindVars(const StaticEnv & env) + { + e1->bindVars(env); e2->bindVars(env); + } + void eval(EvalState & state, Env & env, Value & v); +}; + #define MakeBinOp(name, s) \ struct Expr##name : Expr \ { \ @@ -289,7 +306,6 @@ struct ExprBuiltin : Expr void eval(EvalState & state, Env & env, Value & v); \ }; -MakeBinOp(App, "") MakeBinOp(OpEq, "==") MakeBinOp(OpNEq, "!=") MakeBinOp(OpAnd, "&&") diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index ab0b862246..b8d4d7ca01 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -224,7 +224,7 @@ void backToString(yyscan_t scanner); void backToIndString(yyscan_t scanner); -static Pos makeCurPos(const YYLTYPE & loc, ParseData * data) +static inline Pos makeCurPos(const YYLTYPE & loc, ParseData * data) { return Pos(data->path, loc.first_line, loc.first_column); } @@ -355,7 +355,7 @@ expr_op expr_app : expr_app expr_select - { $$ = new ExprApp($1, $2); } + { $$ = new ExprApp(CUR_POS, $1, $2); } | expr_select { $$ = $1; } ; @@ -367,7 +367,7 @@ expr_select | /* Backwards compatibility: because Nixpkgs has a rarely used function named ‘or’, allow stuff like ‘map or [...]’. */ expr_simple OR_KW - { $$ = new ExprApp($1, new ExprVar(CUR_POS, data->symbols.create("or"))); } + { $$ = new ExprApp(CUR_POS, $1, new ExprVar(CUR_POS, data->symbols.create("or"))); } | expr_simple { $$ = $1; } ; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ca316f08af..422d68f380 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -711,7 +711,7 @@ struct FilterFromExpr : PathFilter mkString(arg1, path); Value fun2; - state.callFunction(filter, arg1, fun2); + state.callFunction(filter, arg1, fun2, noPos); Value arg2; mkString(arg2, @@ -721,7 +721,7 @@ struct FilterFromExpr : PathFilter "unknown" /* not supported, will fail! */); Value res; - state.callFunction(fun2, arg2, res); + state.callFunction(fun2, arg2, res, noPos); return state.forceBool(res); } @@ -1008,7 +1008,7 @@ static void prim_filter(EvalState & state, Value * * args, Value & v) bool same = true; for (unsigned int n = 0; n < args[1]->list.length; ++n) { Value res; - state.callFunction(*args[0], *args[1]->list.elems[n], res); + state.callFunction(*args[0], *args[1]->list.elems[n], res, noPos); if (state.forceBool(res)) vs[k++] = args[1]->list.elems[n]; else From 8b31ffd10de44871a3912184fedbeca57d8cf60f Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 17:58:23 +0200 Subject: [PATCH 15/61] Remove unnecessary quotes around file names --- src/libexpr/nixexpr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index ba1f4f078f..92f46b30a3 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -148,7 +148,7 @@ std::ostream & operator << (std::ostream & str, const Pos & pos) if (!pos.line) str << "undefined position"; else - str << (format("`%1%:%2%:%3%'") % pos.file % pos.line % pos.column).str(); + str << (format("%1%:%2%:%3%") % pos.file % pos.line % pos.column).str(); return str; } From c28de6d96e7bfea834a44deac5217d4696fa8d86 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 18:51:01 +0200 Subject: [PATCH 16/61] Pass position information to primop calls For example: error: `tail' called on an empty list, at /home/eelco/Dev/nixpkgs/pkgs/applications/misc/hello/ex-2/default.nix:13:7 --- corepkgs/derivation.nix | 2 +- src/libexpr/eval.cc | 6 +- src/libexpr/eval.hh | 6 +- src/libexpr/parser.y | 16 ++-- src/libexpr/primops.cc | 180 ++++++++++++++++++++-------------------- 5 files changed, 105 insertions(+), 105 deletions(-) diff --git a/corepkgs/derivation.nix b/corepkgs/derivation.nix index c0fbe8082c..374fe50104 100644 --- a/corepkgs/derivation.nix +++ b/corepkgs/derivation.nix @@ -1,7 +1,7 @@ /* This is the implementation of the ‘derivation’ builtin function. It's actually a wrapper around the ‘derivationStrict’ primop. */ -drvAttrs @ { outputs ? [ "out" ], ... }: +drvAttrs @ { outputs ? [ "out" ], name, builder, system, ... }: let diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index d26a0e2584..3a2a84916e 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -794,7 +794,7 @@ void ExprApp::eval(EvalState & state, Env & env, Value & v) } -void EvalState::callPrimOp(Value & fun, Value & arg, Value & v) +void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos) { /* Figure out the number of arguments still needed. */ unsigned int argsDone = 0; @@ -820,7 +820,7 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v) /* And call the primop. */ nrPrimOpCalls++; if (countCalls) primOpCalls[primOp->primOp->name]++; - primOp->primOp->fun(*this, vArgs, v); + primOp->primOp->fun(*this, pos, vArgs, v); } else { Value * fun2 = allocValue(); *fun2 = fun; @@ -834,7 +834,7 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v) void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & pos) { if (fun.type == tPrimOp || fun.type == tPrimOpApp) { - callPrimOp(fun, arg, v); + callPrimOp(fun, arg, v, pos); return; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 170b740790..e69b8455e4 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -36,7 +36,7 @@ public: }; -typedef void (* PrimOpFun) (EvalState & state, Value * * args, Value & v); +typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, Value & v); struct PrimOp @@ -227,7 +227,7 @@ public: bool eqValues(Value & v1, Value & v2); void callFunction(Value & fun, Value & arg, Value & v, const Pos & pos); - void callPrimOp(Value & fun, Value & arg, Value & v); + void callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos); /* Automatically call a function for which each argument has a default value or has a binding in the `args' map. */ @@ -278,7 +278,7 @@ private: friend struct ExprOpUpdate; friend struct ExprOpConcatLists; friend struct ExprSelect; - friend void prim_getAttr(EvalState & state, Value * * args, Value & v); + friend void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v); }; diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index b8d4d7ca01..4830e7ca1c 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -328,13 +328,13 @@ expr_if expr_op : '!' expr_op %prec NOT { $$ = new ExprOpNot($2); } -| '-' expr_op %prec NEGATE { $$ = new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("sub")), new ExprInt(0)), $2); } +| '-' expr_op %prec NEGATE { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("sub")), new ExprInt(0)), $2); } | expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); } | expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); } - | expr_op '<' expr_op { $$ = new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $1), $3); } - | expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $3), $1)); } - | expr_op '>' expr_op { $$ = new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $3), $1); } - | expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $1), $3)); } + | expr_op '<' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $1), $3); } + | expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $3), $1)); } + | expr_op '>' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $3), $1); } + | expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $1), $3)); } | expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); } | expr_op OR expr_op { $$ = new ExprOpOr($1, $3); } | expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); } @@ -346,9 +346,9 @@ expr_op l->push_back($3); $$ = new ExprConcatStrings(false, l); } - | expr_op '-' expr_op { $$ = new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("sub")), $1), $3); } - | expr_op '*' expr_op { $$ = new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("mul")), $1), $3); } - | expr_op '/' expr_op { $$ = new ExprApp(new ExprApp(new ExprBuiltin(data->symbols.create("div")), $1), $3); } + | expr_op '-' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("sub")), $1), $3); } + | expr_op '*' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("mul")), $1), $3); } + | expr_op '/' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("div")), $1), $3); } | expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); } | expr_app ; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 422d68f380..403edefab6 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -39,7 +39,7 @@ std::pair decodeContext(const string & s) /* Load and evaluate an expression from path specified by the argument. */ -static void prim_import(EvalState & state, Value * * args, Value & v) +static void prim_import(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; Path path = state.coerceToPath(*args[0], context); @@ -48,8 +48,8 @@ static void prim_import(EvalState & state, Value * * args, Value & v) Path ctx = decodeContext(*i).first; assert(isStorePath(ctx)); if (!store->isValidPath(ctx)) - throw EvalError(format("cannot import `%1%', since path `%2%' is not valid") - % path % ctx); + throw EvalError(format("cannot import `%1%', since path `%2%' is not valid, at %3%") + % path % ctx % pos); if (isDerivation(ctx)) try { /* For performance, prefetch all substitute info. */ @@ -94,7 +94,7 @@ static void prim_import(EvalState & state, Value * * args, Value & v) /* Return a string representing the type of the expression. */ -static void prim_typeOf(EvalState & state, Value * * args, Value & v) +static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0]); string t; @@ -118,7 +118,7 @@ static void prim_typeOf(EvalState & state, Value * * args, Value & v) /* Determine whether the argument is the null value. */ -static void prim_isNull(EvalState & state, Value * * args, Value & v) +static void prim_isNull(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0]); mkBool(v, args[0]->type == tNull); @@ -126,7 +126,7 @@ static void prim_isNull(EvalState & state, Value * * args, Value & v) /* Determine whether the argument is a function. */ -static void prim_isFunction(EvalState & state, Value * * args, Value & v) +static void prim_isFunction(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0]); mkBool(v, args[0]->type == tLambda); @@ -134,7 +134,7 @@ static void prim_isFunction(EvalState & state, Value * * args, Value & v) /* Determine whether the argument is an integer. */ -static void prim_isInt(EvalState & state, Value * * args, Value & v) +static void prim_isInt(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0]); mkBool(v, args[0]->type == tInt); @@ -142,7 +142,7 @@ static void prim_isInt(EvalState & state, Value * * args, Value & v) /* Determine whether the argument is a string. */ -static void prim_isString(EvalState & state, Value * * args, Value & v) +static void prim_isString(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0]); mkBool(v, args[0]->type == tString); @@ -150,7 +150,7 @@ static void prim_isString(EvalState & state, Value * * args, Value & v) /* Determine whether the argument is a Boolean. */ -static void prim_isBool(EvalState & state, Value * * args, Value & v) +static void prim_isBool(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0]); mkBool(v, args[0]->type == tBool); @@ -184,7 +184,7 @@ typedef list ValueList; #endif -static void prim_genericClosure(EvalState & state, Value * * args, Value & v) +static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * args, Value & v) { startNest(nest, lvlDebug, "finding dependencies"); @@ -194,7 +194,7 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v) Bindings::iterator startSet = args[0]->attrs->find(state.symbols.create("startSet")); if (startSet == args[0]->attrs->end()) - throw EvalError("attribute `startSet' required"); + throw EvalError(format("attribute `startSet' required, at %1%") % pos); state.forceList(*startSet->value); ValueList workSet; @@ -205,7 +205,7 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v) Bindings::iterator op = args[0]->attrs->find(state.symbols.create("operator")); if (op == args[0]->attrs->end()) - throw EvalError("attribute `operator' required"); + throw EvalError(format("attribute `operator' required, at %1%") % pos); state.forceValue(*op->value); /* Construct the closure by applying the operator to element of @@ -224,7 +224,7 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v) Bindings::iterator key = e->attrs->find(state.symbols.create("key")); if (key == e->attrs->end()) - throw EvalError("attribute `key' required"); + throw EvalError(format("attribute `key' required, at %1%") % pos); state.forceValue(*key->value); if (doneKeys.find(key->value) != doneKeys.end()) continue; @@ -251,7 +251,7 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v) } -static void prim_abort(EvalState & state, Value * * args, Value & v) +static void prim_abort(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; throw Abort(format("evaluation aborted with the following error message: `%1%'") % @@ -259,14 +259,14 @@ static void prim_abort(EvalState & state, Value * * args, Value & v) } -static void prim_throw(EvalState & state, Value * * args, Value & v) +static void prim_throw(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; throw ThrownError(format("%1%") % state.coerceToString(*args[0], context)); } -static void prim_addErrorContext(EvalState & state, Value * * args, Value & v) +static void prim_addErrorContext(EvalState & state, const Pos & pos, Value * * args, Value & v) { try { state.forceValue(*args[1]); @@ -281,7 +281,7 @@ static void prim_addErrorContext(EvalState & state, Value * * args, Value & v) /* Try evaluating the argument. Success => {success=true; value=something;}, * else => {success=false; value=false;} */ -static void prim_tryEval(EvalState & state, Value * * args, Value & v) +static void prim_tryEval(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.mkAttrs(v, 2); try { @@ -297,7 +297,7 @@ static void prim_tryEval(EvalState & state, Value * * args, Value & v) /* Return an environment variable. Use with care. */ -static void prim_getEnv(EvalState & state, Value * * args, Value & v) +static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v) { string name = state.forceStringNoCtx(*args[0]); mkString(v, getEnv(name)); @@ -306,7 +306,7 @@ static void prim_getEnv(EvalState & state, Value * * args, Value & v) /* Evaluate the first expression and print it on standard error. Then return the second expression. Useful for debugging. */ -static void prim_trace(EvalState & state, Value * * args, Value & v) +static void prim_trace(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0]); if (args[0]->type == tString) @@ -330,7 +330,7 @@ static void prim_trace(EvalState & state, Value * * args, Value & v) derivation; `drvPath' containing the path of the Nix expression; and `type' set to `derivation' to indicate that this is a derivation. */ -static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) +static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * args, Value & v) { startNest(nest, lvlVomit, "evaluating derivation"); @@ -339,7 +339,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) /* Figure out the name first (for stack backtraces). */ Bindings::iterator attr = args[0]->attrs->find(state.sName); if (attr == args[0]->attrs->end()) - throw EvalError("required attribute `name' missing"); + throw EvalError(format("required attribute `name' missing, at %1%") % pos); string drvName; Pos & posDrvName(*attr->pos); try { @@ -404,25 +404,25 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) else if (key == "outputHashMode") { if (s == "recursive") outputHashRecursive = true; else if (s == "flat") outputHashRecursive = false; - else throw EvalError(format("invalid value `%1%' for `outputHashMode' attribute") % s); + else throw EvalError(format("invalid value `%1%' for `outputHashMode' attribute, at %2%") % s % posDrvName); } else if (key == "outputs") { Strings tmp = tokenizeString(s); outputs.clear(); foreach (Strings::iterator, j, tmp) { if (outputs.find(*j) != outputs.end()) - throw EvalError(format("duplicate derivation output `%1%'") % *j); + throw EvalError(format("duplicate derivation output `%1%', at %2%") % *j % posDrvName); /* !!! Check whether *j is a valid attribute name. */ /* Derivations cannot be named ‘drv’, because then we'd have an attribute ‘drvPath’ in the resulting set. */ if (*j == "drv") - throw EvalError(format("invalid derivation output name `drv'") % *j); + throw EvalError(format("invalid derivation output name `drv', at %1%") % posDrvName); outputs.insert(*j); } if (outputs.empty()) - throw EvalError("derivation cannot have an empty set of outputs"); + throw EvalError(format("derivation cannot have an empty set of outputs, at %1%") % posDrvName); } } @@ -478,24 +478,24 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) /* Do we have all required attributes? */ if (drv.builder == "") - throw EvalError("required attribute `builder' missing"); + throw EvalError(format("required attribute `builder' missing, at %1%") % posDrvName); if (drv.platform == "") - throw EvalError("required attribute `system' missing"); + throw EvalError(format("required attribute `system' missing, at %1%") % posDrvName); /* Check whether the derivation name is valid. */ checkStoreName(drvName); if (isDerivation(drvName)) - throw EvalError(format("derivation names are not allowed to end in `%1%'") - % drvExtension); + throw EvalError(format("derivation names are not allowed to end in `%1%', at %2%") + % drvExtension % posDrvName); if (outputHash != "") { /* Handle fixed-output derivations. */ if (outputs.size() != 1 || *(outputs.begin()) != "out") - throw Error("multiple outputs are not supported in fixed-output derivations"); + throw Error(format("multiple outputs are not supported in fixed-output derivations, at %1%") % posDrvName); HashType ht = parseHashType(outputHashAlgo); if (ht == htUnknown) - throw EvalError(format("unknown hash algorithm `%1%'") % outputHashAlgo); + throw EvalError(format("unknown hash algorithm `%1%', at %2%") % outputHashAlgo % posDrvName); Hash h = parseHash16or32(ht, outputHash); outputHash = printHash(h); if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo; @@ -555,7 +555,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) /* Convert the argument to a path. !!! obsolete? */ -static void prim_toPath(EvalState & state, Value * * args, Value & v) +static void prim_toPath(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; Path path = state.coerceToPath(*args[0], context); @@ -571,7 +571,7 @@ static void prim_toPath(EvalState & state, Value * * args, Value & v) /nix/store/newhash-oldhash-oldname. In the past, `toPath' had special case behaviour for store paths, but that created weird corner cases. */ -static void prim_storePath(EvalState & state, Value * * args, Value & v) +static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; Path path = state.coerceToPath(*args[0], context); @@ -580,7 +580,7 @@ static void prim_storePath(EvalState & state, Value * * args, Value & v) e.g. nix-push does the right thing. */ if (!isStorePath(path)) path = canonPath(path, true); if (!isInStore(path)) - throw EvalError(format("path `%1%' is not in the Nix store") % path); + throw EvalError(format("path `%1%' is not in the Nix store, at %2%") % path % pos); Path path2 = toStorePath(path); if (!settings.readOnlyMode) store->ensurePath(path2); @@ -589,19 +589,19 @@ static void prim_storePath(EvalState & state, Value * * args, Value & v) } -static void prim_pathExists(EvalState & state, Value * * args, Value & v) +static void prim_pathExists(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; Path path = state.coerceToPath(*args[0], context); if (!context.empty()) - throw EvalError(format("string `%1%' cannot refer to other paths") % path); + throw EvalError(format("string `%1%' cannot refer to other paths, at %2%") % path % pos); mkBool(v, pathExists(path)); } /* Return the base name of the given string, i.e., everything following the last slash. */ -static void prim_baseNameOf(EvalState & state, Value * * args, Value & v) +static void prim_baseNameOf(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; mkString(v, baseNameOf(state.coerceToString(*args[0], context)), context); @@ -611,7 +611,7 @@ static void prim_baseNameOf(EvalState & state, Value * * args, Value & v) /* Return the directory of the given path, i.e., everything before the last slash. Return either a path or a string depending on the type of the argument. */ -static void prim_dirOf(EvalState & state, Value * * args, Value & v) +static void prim_dirOf(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; Path dir = dirOf(state.coerceToPath(*args[0], context)); @@ -620,12 +620,12 @@ static void prim_dirOf(EvalState & state, Value * * args, Value & v) /* Return the contents of a file as a string. */ -static void prim_readFile(EvalState & state, Value * * args, Value & v) +static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; Path path = state.coerceToPath(*args[0], context); if (!context.empty()) - throw EvalError(format("string `%1%' cannot refer to other paths") % path); + throw EvalError(format("string `%1%' cannot refer to other paths, at %2%") % path % pos); mkString(v, readFile(path).c_str()); } @@ -638,7 +638,7 @@ static void prim_readFile(EvalState & state, Value * * args, Value & v) /* Convert the argument (which can be any Nix expression) to an XML representation returned in a string. Not all Nix expressions can be sensibly or completely represented (e.g., functions). */ -static void prim_toXML(EvalState & state, Value * * args, Value & v) +static void prim_toXML(EvalState & state, const Pos & pos, Value * * args, Value & v) { std::ostringstream out; PathSet context; @@ -650,7 +650,7 @@ static void prim_toXML(EvalState & state, Value * * args, Value & v) /* Convert the argument (which can be any Nix expression) to a JSON string. Not all Nix expressions can be sensibly or completely represented (e.g., functions). */ -static void prim_toJSON(EvalState & state, Value * * args, Value & v) +static void prim_toJSON(EvalState & state, const Pos & pos, Value * * args, Value & v) { std::ostringstream out; PathSet context; @@ -661,7 +661,7 @@ static void prim_toJSON(EvalState & state, Value * * args, Value & v) /* Store a string in the Nix store as a source file that can be used as an input by derivations. */ -static void prim_toFile(EvalState & state, Value * * args, Value & v) +static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; string name = state.forceStringNoCtx(*args[0]); @@ -673,7 +673,7 @@ static void prim_toFile(EvalState & state, Value * * args, Value & v) Path path = *i; if (path.at(0) == '=') path = string(path, 1); if (isDerivation(path)) - throw EvalError(format("in `toFile': the file `%1%' cannot refer to derivation outputs") % name); + throw EvalError(format("in `toFile': the file `%1%' cannot refer to derivation outputs, at %2%") % name % pos); refs.insert(path); } @@ -728,16 +728,16 @@ struct FilterFromExpr : PathFilter }; -static void prim_filterSource(EvalState & state, Value * * args, Value & v) +static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; Path path = state.coerceToPath(*args[1], context); if (!context.empty()) - throw EvalError(format("string `%1%' cannot refer to other paths") % path); + throw EvalError(format("string `%1%' cannot refer to other paths, at %2%") % path % pos); state.forceValue(*args[0]); if (args[0]->type != tLambda) - throw TypeError(format("first argument in call to `filterSource' is not a function but %1%") % showType(*args[0])); + throw TypeError(format("first argument in call to `filterSource' is not a function but %1%, at %2%") % showType(*args[0]) % pos); FilterFromExpr filter(state, *args[0]); @@ -756,7 +756,7 @@ static void prim_filterSource(EvalState & state, Value * * args, Value & v) /* Return the names of the attributes in a set as a sorted list of strings. */ -static void prim_attrNames(EvalState & state, Value * * args, Value & v) +static void prim_attrNames(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceAttrs(*args[0]); @@ -773,14 +773,14 @@ static void prim_attrNames(EvalState & state, Value * * args, Value & v) /* Dynamic version of the `.' operator. */ -void prim_getAttr(EvalState & state, Value * * args, Value & v) +void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v) { string attr = state.forceStringNoCtx(*args[0]); state.forceAttrs(*args[1]); // !!! Should we create a symbol here or just do a lookup? Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr)); if (i == args[1]->attrs->end()) - throw EvalError(format("attribute `%1%' missing") % attr); + throw EvalError(format("attribute `%1%' missing, at %2%") % attr % pos); // !!! add to stack trace? if (state.countCalls && i->pos) state.attrSelects[*i->pos]++; state.forceValue(*i->value); @@ -789,7 +789,7 @@ void prim_getAttr(EvalState & state, Value * * args, Value & v) /* Return position information of the specified attribute. */ -void prim_unsafeGetAttrPos(EvalState & state, Value * * args, Value & v) +void prim_unsafeGetAttrPos(EvalState & state, const Pos & pos, Value * * args, Value & v) { string attr = state.forceStringNoCtx(*args[0]); state.forceAttrs(*args[1]); @@ -802,7 +802,7 @@ void prim_unsafeGetAttrPos(EvalState & state, Value * * args, Value & v) /* Dynamic version of the `?' operator. */ -static void prim_hasAttr(EvalState & state, Value * * args, Value & v) +static void prim_hasAttr(EvalState & state, const Pos & pos, Value * * args, Value & v) { string attr = state.forceStringNoCtx(*args[0]); state.forceAttrs(*args[1]); @@ -811,14 +811,14 @@ static void prim_hasAttr(EvalState & state, Value * * args, Value & v) /* Determine whether the argument is a set. */ -static void prim_isAttrs(EvalState & state, Value * * args, Value & v) +static void prim_isAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0]); mkBool(v, args[0]->type == tAttrs); } -static void prim_removeAttrs(EvalState & state, Value * * args, Value & v) +static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceAttrs(*args[0]); state.forceList(*args[1]); @@ -846,7 +846,7 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v) "nameN"; value = valueN;}] is transformed to {name1 = value1; ... nameN = valueN;}. In case of duplicate occurences of the same name, the first takes precedence. */ -static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) +static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceList(*args[0]); @@ -860,14 +860,14 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) Bindings::iterator j = v2.attrs->find(state.sName); if (j == v2.attrs->end()) - throw TypeError("`name' attribute missing in a call to `listToAttrs'"); + throw TypeError(format("`name' attribute missing in a call to `listToAttrs', at %1%") % pos); string name = state.forceStringNoCtx(*j->value); Symbol sym = state.symbols.create(name); if (seen.find(sym) == seen.end()) { Bindings::iterator j2 = v2.attrs->find(state.symbols.create(state.sValue)); if (j2 == v2.attrs->end()) - throw TypeError("`value' attribute missing in a call to `listToAttrs'"); + throw TypeError(format("`value' attribute missing in a call to `listToAttrs', at %1%") % pos); v.attrs->push_back(Attr(sym, j2->value, j2->pos)); seen.insert(sym); @@ -881,7 +881,7 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) /* Return the right-biased intersection of two sets as1 and as2, i.e. a set that contains every attribute from as2 that is also a member of as1. */ -static void prim_intersectAttrs(EvalState & state, Value * * args, Value & v) +static void prim_intersectAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceAttrs(*args[0]); state.forceAttrs(*args[1]); @@ -909,11 +909,11 @@ static void prim_intersectAttrs(EvalState & state, Value * * args, Value & v) functionArgs (x: ...) => { } */ -static void prim_functionArgs(EvalState & state, Value * * args, Value & v) +static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0]); if (args[0]->type != tLambda) - throw TypeError("`functionArgs' requires a function"); + throw TypeError(format("`functionArgs' requires a function, at %1%") % pos); if (!args[0]->lambda.fun->matchAttrs) { state.mkAttrs(v, 0); @@ -934,45 +934,45 @@ static void prim_functionArgs(EvalState & state, Value * * args, Value & v) /* Determine whether the argument is a list. */ -static void prim_isList(EvalState & state, Value * * args, Value & v) +static void prim_isList(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0]); mkBool(v, args[0]->type == tList); } -static void elemAt(EvalState & state, Value & list, int n, Value & v) +static void elemAt(EvalState & state, const Pos & pos, Value & list, int n, Value & v) { state.forceList(list); if (n < 0 || n >= list.list.length) - throw Error(format("list index %1% is out of bounds") % n); + throw Error(format("list index %1% is out of bounds, at %2%") % n % pos); state.forceValue(*list.list.elems[n]); v = *list.list.elems[n]; } /* Return the n-1'th element of a list. */ -static void prim_elemAt(EvalState & state, Value * * args, Value & v) +static void prim_elemAt(EvalState & state, const Pos & pos, Value * * args, Value & v) { - elemAt(state, *args[0], state.forceInt(*args[1]), v); + elemAt(state, pos, *args[0], state.forceInt(*args[1]), v); } /* Return the first element of a list. */ -static void prim_head(EvalState & state, Value * * args, Value & v) +static void prim_head(EvalState & state, const Pos & pos, Value * * args, Value & v) { - elemAt(state, *args[0], 0, v); + elemAt(state, pos, *args[0], 0, v); } /* Return a list consisting of everything but the the first element of a list. Warning: this function takes O(n) time, so you probably don't want to use it! */ -static void prim_tail(EvalState & state, Value * * args, Value & v) +static void prim_tail(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceList(*args[0]); if (args[0]->list.length == 0) - throw Error("`tail' called on an empty list"); + throw Error(format("`tail' called on an empty list, at %1%") % pos); state.mkList(v, args[0]->list.length - 1); for (unsigned int n = 0; n < v.list.length; ++n) v.list.elems[n] = args[0]->list.elems[n + 1]; @@ -980,7 +980,7 @@ static void prim_tail(EvalState & state, Value * * args, Value & v) /* Apply a function to every element of a list. */ -static void prim_map(EvalState & state, Value * * args, Value & v) +static void prim_map(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceFunction(*args[0]); state.forceList(*args[1]); @@ -996,7 +996,7 @@ static void prim_map(EvalState & state, Value * * args, Value & v) /* Filter a list using a predicate; that is, return a list containing every element from the list for which the predicate function returns true. */ -static void prim_filter(EvalState & state, Value * * args, Value & v) +static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceFunction(*args[0]); state.forceList(*args[1]); @@ -1025,7 +1025,7 @@ static void prim_filter(EvalState & state, Value * * args, Value & v) /* Return true if a list contains a given element. */ -static void prim_elem(EvalState & state, Value * * args, Value & v) +static void prim_elem(EvalState & state, const Pos & pos, Value * * args, Value & v) { bool res = false; state.forceList(*args[1]); @@ -1039,7 +1039,7 @@ static void prim_elem(EvalState & state, Value * * args, Value & v) /* Concatenate a list of lists. */ -static void prim_concatLists(EvalState & state, Value * * args, Value & v) +static void prim_concatLists(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceList(*args[0]); state.concatLists(v, args[0]->list.length, args[0]->list.elems); @@ -1047,7 +1047,7 @@ static void prim_concatLists(EvalState & state, Value * * args, Value & v) /* Return the length of a list. This is an O(1) time operation. */ -static void prim_length(EvalState & state, Value * * args, Value & v) +static void prim_length(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceList(*args[0]); mkInt(v, args[0]->list.length); @@ -1059,33 +1059,33 @@ static void prim_length(EvalState & state, Value * * args, Value & v) *************************************************************/ -static void prim_add(EvalState & state, Value * * args, Value & v) +static void prim_add(EvalState & state, const Pos & pos, Value * * args, Value & v) { mkInt(v, state.forceInt(*args[0]) + state.forceInt(*args[1])); } -static void prim_sub(EvalState & state, Value * * args, Value & v) +static void prim_sub(EvalState & state, const Pos & pos, Value * * args, Value & v) { mkInt(v, state.forceInt(*args[0]) - state.forceInt(*args[1])); } -static void prim_mul(EvalState & state, Value * * args, Value & v) +static void prim_mul(EvalState & state, const Pos & pos, Value * * args, Value & v) { mkInt(v, state.forceInt(*args[0]) * state.forceInt(*args[1])); } -static void prim_div(EvalState & state, Value * * args, Value & v) +static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value & v) { NixInt i2 = state.forceInt(*args[1]); - if (i2 == 0) throw EvalError("division by zero"); + if (i2 == 0) throw EvalError(format("division by zero, at %1%") % pos); mkInt(v, state.forceInt(*args[0]) / i2); } -static void prim_lessThan(EvalState & state, Value * * args, Value & v) +static void prim_lessThan(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0]); state.forceValue(*args[1]); @@ -1102,7 +1102,7 @@ static void prim_lessThan(EvalState & state, Value * * args, Value & v) /* Convert the argument to a string. Paths are *not* copied to the store, so `toString /foo/bar' yields `"/foo/bar"', not `"/nix/store/whatever..."'. */ -static void prim_toString(EvalState & state, Value * * args, Value & v) +static void prim_toString(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; string s = state.coerceToString(*args[0], context, true, false); @@ -1114,20 +1114,20 @@ static void prim_toString(EvalState & state, Value * * args, Value & v) at character position `min(start, stringLength str)' inclusive and ending at `min(start + len, stringLength str)'. `start' must be non-negative. */ -static void prim_substring(EvalState & state, Value * * args, Value & v) +static void prim_substring(EvalState & state, const Pos & pos, Value * * args, Value & v) { int start = state.forceInt(*args[0]); int len = state.forceInt(*args[1]); PathSet context; string s = state.coerceToString(*args[2], context); - if (start < 0) throw EvalError("negative start position in `substring'"); + if (start < 0) throw EvalError(format("negative start position in `substring', at %1%") % pos); mkString(v, start >= s.size() ? "" : string(s, start, len), context); } -static void prim_stringLength(EvalState & state, Value * * args, Value & v) +static void prim_stringLength(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; string s = state.coerceToString(*args[0], context); @@ -1135,7 +1135,7 @@ static void prim_stringLength(EvalState & state, Value * * args, Value & v) } -static void prim_unsafeDiscardStringContext(EvalState & state, Value * * args, Value & v) +static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; string s = state.coerceToString(*args[0], context); @@ -1149,7 +1149,7 @@ static void prim_unsafeDiscardStringContext(EvalState & state, Value * * args, V source-only deployment). This primop marks the string context so that builtins.derivation adds the path to drv.inputSrcs rather than drv.inputDrvs. */ -static void prim_unsafeDiscardOutputDependency(EvalState & state, Value * * args, Value & v) +static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; string s = state.coerceToString(*args[0], context); @@ -1166,12 +1166,12 @@ static void prim_unsafeDiscardOutputDependency(EvalState & state, Value * * args /* Return the cryptographic hash of a string in base-16. */ -static void prim_hashString(EvalState & state, Value * * args, Value & v) +static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, Value & v) { string type = state.forceStringNoCtx(*args[0]); HashType ht = parseHashType(type); if (ht == htUnknown) - throw Error(format("unknown hash type `%1%'") % type); + throw Error(format("unknown hash type `%1%', at %2%") % type % pos); PathSet context; // discarded string s = state.forceString(*args[1], context); @@ -1185,7 +1185,7 @@ static void prim_hashString(EvalState & state, Value * * args, Value & v) *************************************************************/ -static void prim_parseDrvName(EvalState & state, Value * * args, Value & v) +static void prim_parseDrvName(EvalState & state, const Pos & pos, Value * * args, Value & v) { string name = state.forceStringNoCtx(*args[0]); DrvName parsed(name); @@ -1196,7 +1196,7 @@ static void prim_parseDrvName(EvalState & state, Value * * args, Value & v) } -static void prim_compareVersions(EvalState & state, Value * * args, Value & v) +static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * args, Value & v) { string version1 = state.forceStringNoCtx(*args[0]); string version2 = state.forceStringNoCtx(*args[1]); From b62d36963c45ccaebb328fceaf0bb40f9c02a14b Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 18:58:15 +0200 Subject: [PATCH 17/61] forceInt: Show position info --- src/libexpr/eval.cc | 4 ++-- src/libexpr/eval.hh | 2 +- src/libexpr/primops.cc | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 3a2a84916e..0be1e73491 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1151,11 +1151,11 @@ void EvalState::strictForceValue(Value & v) } -NixInt EvalState::forceInt(Value & v) +NixInt EvalState::forceInt(Value & v, const Pos & pos) { forceValue(v); if (v.type != tInt) - throwTypeError("value is %1% while an integer was expected", v); + throwTypeError("value is %1% while an integer was expected, at %2%", v, pos); return v.integer; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index e69b8455e4..0a424ddb94 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -158,7 +158,7 @@ public: void strictForceValue(Value & v); /* Force `v', and then verify that it has the expected type. */ - NixInt forceInt(Value & v); + NixInt forceInt(Value & v, const Pos & pos); bool forceBool(Value & v); inline void forceAttrs(Value & v); inline void forceList(Value & v); diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 403edefab6..b33b76bca1 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -954,7 +954,7 @@ static void elemAt(EvalState & state, const Pos & pos, Value & list, int n, Valu /* Return the n-1'th element of a list. */ static void prim_elemAt(EvalState & state, const Pos & pos, Value * * args, Value & v) { - elemAt(state, pos, *args[0], state.forceInt(*args[1]), v); + elemAt(state, pos, *args[0], state.forceInt(*args[1], pos), v); } @@ -1061,27 +1061,27 @@ static void prim_length(EvalState & state, const Pos & pos, Value * * args, Valu static void prim_add(EvalState & state, const Pos & pos, Value * * args, Value & v) { - mkInt(v, state.forceInt(*args[0]) + state.forceInt(*args[1])); + mkInt(v, state.forceInt(*args[0], pos) + state.forceInt(*args[1], pos)); } static void prim_sub(EvalState & state, const Pos & pos, Value * * args, Value & v) { - mkInt(v, state.forceInt(*args[0]) - state.forceInt(*args[1])); + mkInt(v, state.forceInt(*args[0], pos) - state.forceInt(*args[1], pos)); } static void prim_mul(EvalState & state, const Pos & pos, Value * * args, Value & v) { - mkInt(v, state.forceInt(*args[0]) * state.forceInt(*args[1])); + mkInt(v, state.forceInt(*args[0], pos) * state.forceInt(*args[1], pos)); } static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value & v) { - NixInt i2 = state.forceInt(*args[1]); + NixInt i2 = state.forceInt(*args[1], pos); if (i2 == 0) throw EvalError(format("division by zero, at %1%") % pos); - mkInt(v, state.forceInt(*args[0]) / i2); + mkInt(v, state.forceInt(*args[0], pos) / i2); } @@ -1116,8 +1116,8 @@ static void prim_toString(EvalState & state, const Pos & pos, Value * * args, Va non-negative. */ static void prim_substring(EvalState & state, const Pos & pos, Value * * args, Value & v) { - int start = state.forceInt(*args[0]); - int len = state.forceInt(*args[1]); + int start = state.forceInt(*args[0], pos); + int len = state.forceInt(*args[1], pos); PathSet context; string s = state.coerceToString(*args[2], context); From 96b695ccab4a4c8c4ef7f14ac261df43dcc00743 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 19:05:36 +0200 Subject: [PATCH 18/61] forceList: Show position info --- src/libexpr/eval-inline.hh | 15 +++++++++++++++ src/libexpr/eval.cc | 9 ++------- src/libexpr/eval.hh | 3 ++- src/libexpr/get-drvs.cc | 2 +- src/libexpr/primops.cc | 30 +++++++++++++++--------------- 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index ffe8fa59cd..c34e24d3da 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -18,6 +18,12 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v)) } +LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v, const Pos & pos)) +{ + throw TypeError(format(s) % showType(v) % pos); +} + + void EvalState::forceValue(Value & v) { if (v.type == tThunk) { @@ -56,4 +62,13 @@ inline void EvalState::forceList(Value & v) throwTypeError("value is %1% while a list was expected", v); } + +inline void EvalState::forceList(Value & v, const Pos & pos) +{ + forceValue(v); + if (v.type != tList) + throwTypeError("value is %1% while a list was expected, at %2%", v, pos); +} + + } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 0be1e73491..b74170ecb1 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -294,11 +294,6 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1)) throw TypeError(format(s) % s1); } -LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v, const Pos & pos)) -{ - throw TypeError(format(s) % showType(v) % pos); -} - LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1, const string & s2)) { throw TypeError(format(s) % s1 % s2); @@ -1169,11 +1164,11 @@ bool EvalState::forceBool(Value & v) } -void EvalState::forceFunction(Value & v) +void EvalState::forceFunction(Value & v, const Pos & pos) { forceValue(v); if (v.type != tLambda && v.type != tPrimOp && v.type != tPrimOpApp) - throwTypeError("value is %1% while a function was expected", v); + throwTypeError("value is %1% while a function was expected, at %2%", v, pos); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 0a424ddb94..decca9e406 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -162,7 +162,8 @@ public: bool forceBool(Value & v); inline void forceAttrs(Value & v); inline void forceList(Value & v); - void forceFunction(Value & v); // either lambda or primop + inline void forceList(Value & v, const Pos & pos); + void forceFunction(Value & v, const Pos & pos); // either lambda or primop string forceString(Value & v); string forceString(Value & v, PathSet & context); string forceStringNoCtx(Value & v); diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 0ed644e9bc..96298556d8 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -36,7 +36,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs() /* Get the ‘outputs’ list. */ Bindings::iterator i; if (attrs && (i = attrs->find(state->sOutputs)) != attrs->end()) { - state->forceList(*i->value); + state->forceList(*i->value, *i->pos); /* For each output... */ for (unsigned int j = 0; j < i->value->list.length; ++j) { diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index b33b76bca1..7028ddc907 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -84,7 +84,7 @@ static void prim_import(EvalState & state, const Pos & pos, Value * * args, Valu w.attrs->sort(); Value fun; state.evalFile(state.findFile("nix/imported-drv-to-derivation.nix"), fun); - state.forceFunction(fun); + state.forceFunction(fun, pos); mkApp(v, fun, w); state.forceAttrs(v); } else { @@ -195,7 +195,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar args[0]->attrs->find(state.symbols.create("startSet")); if (startSet == args[0]->attrs->end()) throw EvalError(format("attribute `startSet' required, at %1%") % pos); - state.forceList(*startSet->value); + state.forceList(*startSet->value, pos); ValueList workSet; for (unsigned int n = 0; n < startSet->value->list.length; ++n) @@ -234,7 +234,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar /* Call the `operator' function with `e' as argument. */ Value call; mkApp(call, *op->value, *e); - state.forceList(call); + state.forceList(call, pos); /* Add the values returned by the operator to the work set. */ for (unsigned int n = 0; n < call.list.length; ++n) { @@ -381,7 +381,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* The `args' attribute is special: it supplies the command-line arguments to the builder. */ if (key == "args") { - state.forceList(*i->value); + state.forceList(*i->value, pos); for (unsigned int n = 0; n < i->value->list.length; ++n) { string s = state.coerceToString(*i->value->list.elems[n], context, true); drv.args.push_back(s); @@ -821,7 +821,7 @@ static void prim_isAttrs(EvalState & state, const Pos & pos, Value * * args, Val static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceAttrs(*args[0]); - state.forceList(*args[1]); + state.forceList(*args[1], pos); /* Get the attribute names to be removed. */ std::set names; @@ -848,7 +848,7 @@ static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args, name, the first takes precedence. */ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v) { - state.forceList(*args[0]); + state.forceList(*args[0], pos); state.mkAttrs(v, args[0]->list.length); @@ -943,7 +943,7 @@ static void prim_isList(EvalState & state, const Pos & pos, Value * * args, Valu static void elemAt(EvalState & state, const Pos & pos, Value & list, int n, Value & v) { - state.forceList(list); + state.forceList(list, pos); if (n < 0 || n >= list.list.length) throw Error(format("list index %1% is out of bounds, at %2%") % n % pos); state.forceValue(*list.list.elems[n]); @@ -970,7 +970,7 @@ static void prim_head(EvalState & state, const Pos & pos, Value * * args, Value don't want to use it! */ static void prim_tail(EvalState & state, const Pos & pos, Value * * args, Value & v) { - state.forceList(*args[0]); + state.forceList(*args[0], pos); if (args[0]->list.length == 0) throw Error(format("`tail' called on an empty list, at %1%") % pos); state.mkList(v, args[0]->list.length - 1); @@ -982,8 +982,8 @@ static void prim_tail(EvalState & state, const Pos & pos, Value * * args, Value /* Apply a function to every element of a list. */ static void prim_map(EvalState & state, const Pos & pos, Value * * args, Value & v) { - state.forceFunction(*args[0]); - state.forceList(*args[1]); + state.forceFunction(*args[0], pos); + state.forceList(*args[1], pos); state.mkList(v, args[1]->list.length); @@ -998,8 +998,8 @@ static void prim_map(EvalState & state, const Pos & pos, Value * * args, Value & returns true. */ static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Value & v) { - state.forceFunction(*args[0]); - state.forceList(*args[1]); + state.forceFunction(*args[0], pos); + state.forceList(*args[1], pos); // FIXME: putting this on the stack is risky. Value * vs[args[1]->list.length]; @@ -1028,7 +1028,7 @@ static void prim_filter(EvalState & state, const Pos & pos, Value * * args, Valu static void prim_elem(EvalState & state, const Pos & pos, Value * * args, Value & v) { bool res = false; - state.forceList(*args[1]); + state.forceList(*args[1], pos); for (unsigned int n = 0; n < args[1]->list.length; ++n) if (state.eqValues(*args[0], *args[1]->list.elems[n])) { res = true; @@ -1041,7 +1041,7 @@ static void prim_elem(EvalState & state, const Pos & pos, Value * * args, Value /* Concatenate a list of lists. */ static void prim_concatLists(EvalState & state, const Pos & pos, Value * * args, Value & v) { - state.forceList(*args[0]); + state.forceList(*args[0], pos); state.concatLists(v, args[0]->list.length, args[0]->list.elems); } @@ -1049,7 +1049,7 @@ static void prim_concatLists(EvalState & state, const Pos & pos, Value * * args, /* Return the length of a list. This is an O(1) time operation. */ static void prim_length(EvalState & state, const Pos & pos, Value * * args, Value & v) { - state.forceList(*args[0]); + state.forceList(*args[0], pos); mkInt(v, args[0]->list.length); } From 27b44b8cf7072b09a1929ee44ba784b1c8d5211a Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 19:11:40 +0200 Subject: [PATCH 19/61] forceAttrs: Show position info --- src/libexpr/eval-inline.hh | 8 ++++++++ src/libexpr/eval.cc | 2 +- src/libexpr/eval.hh | 1 + src/libexpr/get-drvs.cc | 2 +- src/libexpr/primops.cc | 24 ++++++++++++------------ 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index c34e24d3da..c275f7ba83 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -55,6 +55,14 @@ inline void EvalState::forceAttrs(Value & v) } +inline void EvalState::forceAttrs(Value & v, const Pos & pos) +{ + forceValue(v); + if (v.type != tAttrs) + throwTypeError("value is %1% while a set was expected, at %2%", v, pos); +} + + inline void EvalState::forceList(Value & v) { forceValue(v); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index b74170ecb1..5c88a34a92 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -850,7 +850,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po env2.values[displ++] = &arg; else { - forceAttrs(arg); + forceAttrs(arg, pos); if (!lambda.arg.empty()) env2.values[displ++] = &arg; diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index decca9e406..248805004c 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -161,6 +161,7 @@ public: NixInt forceInt(Value & v, const Pos & pos); bool forceBool(Value & v); inline void forceAttrs(Value & v); + inline void forceAttrs(Value & v, const Pos & pos); inline void forceList(Value & v); inline void forceList(Value & v, const Pos & pos); void forceFunction(Value & v, const Pos & pos); // either lambda or primop diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 96298556d8..4e7690063a 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -75,7 +75,7 @@ Bindings * DrvInfo::getMeta() if (!attrs) return 0; Bindings::iterator a = attrs->find(state->sMeta); if (a == attrs->end()) return 0; - state->forceAttrs(*a->value); + state->forceAttrs(*a->value, *a->pos); meta = a->value->attrs; return meta; } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 7028ddc907..2aa45525e6 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -86,7 +86,7 @@ static void prim_import(EvalState & state, const Pos & pos, Value * * args, Valu state.evalFile(state.findFile("nix/imported-drv-to-derivation.nix"), fun); state.forceFunction(fun, pos); mkApp(v, fun, w); - state.forceAttrs(v); + state.forceAttrs(v, pos); } else { state.evalFile(path, v); } @@ -188,7 +188,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar { startNest(nest, lvlDebug, "finding dependencies"); - state.forceAttrs(*args[0]); + state.forceAttrs(*args[0], pos); /* Get the start set. */ Bindings::iterator startSet = @@ -219,7 +219,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar Value * e = *(workSet.begin()); workSet.pop_front(); - state.forceAttrs(*e); + state.forceAttrs(*e, pos); Bindings::iterator key = e->attrs->find(state.symbols.create("key")); @@ -334,7 +334,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * { startNest(nest, lvlVomit, "evaluating derivation"); - state.forceAttrs(*args[0]); + state.forceAttrs(*args[0], pos); /* Figure out the name first (for stack backtraces). */ Bindings::iterator attr = args[0]->attrs->find(state.sName); @@ -758,7 +758,7 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args strings. */ static void prim_attrNames(EvalState & state, const Pos & pos, Value * * args, Value & v) { - state.forceAttrs(*args[0]); + state.forceAttrs(*args[0], pos); state.mkList(v, args[0]->attrs->size()); @@ -776,7 +776,7 @@ static void prim_attrNames(EvalState & state, const Pos & pos, Value * * args, V void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v) { string attr = state.forceStringNoCtx(*args[0]); - state.forceAttrs(*args[1]); + state.forceAttrs(*args[1], pos); // !!! Should we create a symbol here or just do a lookup? Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr)); if (i == args[1]->attrs->end()) @@ -792,7 +792,7 @@ void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v) void prim_unsafeGetAttrPos(EvalState & state, const Pos & pos, Value * * args, Value & v) { string attr = state.forceStringNoCtx(*args[0]); - state.forceAttrs(*args[1]); + state.forceAttrs(*args[1], pos); Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr)); if (i == args[1]->attrs->end()) mkNull(v); @@ -805,7 +805,7 @@ void prim_unsafeGetAttrPos(EvalState & state, const Pos & pos, Value * * args, V static void prim_hasAttr(EvalState & state, const Pos & pos, Value * * args, Value & v) { string attr = state.forceStringNoCtx(*args[0]); - state.forceAttrs(*args[1]); + state.forceAttrs(*args[1], pos); mkBool(v, args[1]->attrs->find(state.symbols.create(attr)) != args[1]->attrs->end()); } @@ -820,7 +820,7 @@ static void prim_isAttrs(EvalState & state, const Pos & pos, Value * * args, Val static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v) { - state.forceAttrs(*args[0]); + state.forceAttrs(*args[0], pos); state.forceList(*args[1], pos); /* Get the attribute names to be removed. */ @@ -856,7 +856,7 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args, for (unsigned int i = 0; i < args[0]->list.length; ++i) { Value & v2(*args[0]->list.elems[i]); - state.forceAttrs(v2); + state.forceAttrs(v2, pos); Bindings::iterator j = v2.attrs->find(state.sName); if (j == v2.attrs->end()) @@ -883,8 +883,8 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args, member of as1. */ static void prim_intersectAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v) { - state.forceAttrs(*args[0]); - state.forceAttrs(*args[1]); + state.forceAttrs(*args[0], pos); + state.forceAttrs(*args[1], pos); state.mkAttrs(v, std::min(args[0]->attrs->size(), args[1]->attrs->size())); From a5fe73094016973a50741db0c5d51ca96c14147b Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 21:14:11 +0200 Subject: [PATCH 20/61] forceString: Show position info --- src/libexpr/eval.cc | 33 ++++++++++++++++++++++++--------- src/libexpr/eval.hh | 4 ++-- src/libexpr/get-drvs.cc | 9 +++------ src/libexpr/nixexpr.cc | 2 +- src/libexpr/nixexpr.hh | 4 ++++ src/libexpr/primops.cc | 24 ++++++++++++------------ 6 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 5c88a34a92..30a8793ee7 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -140,7 +140,8 @@ static void * oomHandler(size_t requested) #endif -static Symbol getName(const AttrName & name, EvalState & state, Env & env) { +static Symbol getName(const AttrName & name, EvalState & state, Env & env) +{ if (name.symbol.set()) { return name.symbol; } else { @@ -279,6 +280,11 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, con throw EvalError(format(s) % s2 % s3); } +LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3, const Pos & pos)) +{ + throw EvalError(format(s) % s2 % s3 % pos); +} + LocalNoInlineNoReturn(void throwEvalError(const char * s, const Symbol & sym, const Pos & p1, const Pos & p2)) { throw EvalError(format(s) % sym % p1 % p2); @@ -1172,11 +1178,15 @@ void EvalState::forceFunction(Value & v, const Pos & pos) } -string EvalState::forceString(Value & v) +string EvalState::forceString(Value & v, const Pos & pos) { forceValue(v); - if (v.type != tString) - throwTypeError("value is %1% while a string was expected", v); + if (v.type != tString) { + if (pos) + throwTypeError("value is %1% while a string was expected, at %2%", v, pos); + else + throwTypeError("value is %1% while a string was expected", v); + } return string(v.string.s); } @@ -1197,12 +1207,17 @@ string EvalState::forceString(Value & v, PathSet & context) } -string EvalState::forceStringNoCtx(Value & v) +string EvalState::forceStringNoCtx(Value & v, const Pos & pos) { - string s = forceString(v); - if (v.string.context) - throwEvalError("the string `%1%' is not allowed to refer to a store path (such as `%2%')", - v.string.s, v.string.context[0]); + string s = forceString(v, pos); + if (v.string.context) { + if (pos) + throwEvalError("the string `%1%' is not allowed to refer to a store path (such as `%2%'), at %3%", + v.string.s, v.string.context[0], pos); + else + throwEvalError("the string `%1%' is not allowed to refer to a store path (such as `%2%')", + v.string.s, v.string.context[0]); + } return s; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 248805004c..1d53f49821 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -165,9 +165,9 @@ public: inline void forceList(Value & v); inline void forceList(Value & v, const Pos & pos); void forceFunction(Value & v, const Pos & pos); // either lambda or primop - string forceString(Value & v); + string forceString(Value & v, const Pos & pos = noPos); string forceString(Value & v, PathSet & context); - string forceStringNoCtx(Value & v); + string forceStringNoCtx(Value & v, const Pos & pos = noPos); /* Return true iff the value `v' denotes a derivation (i.e. a set with attribute `type = "derivation"'). */ diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 4e7690063a..88ea68a5f0 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -41,7 +41,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs() /* For each output... */ for (unsigned int j = 0; j < i->value->list.length; ++j) { /* Evaluate the corresponding set. */ - string name = state->forceStringNoCtx(*i->value->list.elems[j]); + string name = state->forceStringNoCtx(*i->value->list.elems[j], *i->pos); Bindings::iterator out = attrs->find(state->symbols.create(name)); if (out == attrs->end()) continue; // FIXME: throw error? state->forceAttrs(*out->value); @@ -199,11 +199,8 @@ static bool getDerivation(EvalState & state, Value & v, Bindings::iterator i2 = v.attrs->find(state.sSystem); - DrvInfo drv( - state, - state.forceStringNoCtx(*i->value), - attrPath, - i2 == v.attrs->end() ? "unknown" : state.forceStringNoCtx(*i2->value), + DrvInfo drv(state, state.forceStringNoCtx(*i->value), attrPath, + i2 == v.attrs->end() ? "unknown" : state.forceStringNoCtx(*i2->value, *i2->pos), v.attrs); drvs.push_back(drv); diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 92f46b30a3..d40250d877 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -145,7 +145,7 @@ void ExprPos::show(std::ostream & str) std::ostream & operator << (std::ostream & str, const Pos & pos) { - if (!pos.line) + if (!pos) str << "undefined position"; else str << (format("%1%:%2%:%3%") % pos.file % pos.line % pos.column).str(); diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 527589147e..9234e2970f 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -28,6 +28,10 @@ struct Pos Pos() : line(0), column(0) { }; Pos(const Symbol & file, unsigned int line, unsigned int column) : file(file), line(line), column(column) { }; + operator bool() const + { + return line != 0; + } bool operator < (const Pos & p2) const { if (!line) return p2.line; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 2aa45525e6..00833403d7 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -299,7 +299,7 @@ static void prim_tryEval(EvalState & state, const Pos & pos, Value * * args, Val /* Return an environment variable. Use with care. */ static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string name = state.forceStringNoCtx(*args[0]); + string name = state.forceStringNoCtx(*args[0], pos); mkString(v, getEnv(name)); } @@ -343,7 +343,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * string drvName; Pos & posDrvName(*attr->pos); try { - drvName = state.forceStringNoCtx(*attr->value); + drvName = state.forceStringNoCtx(*attr->value, pos); } catch (Error & e) { e.addPrefix(format("while evaluating the derivation attribute `name' at %1%:\n") % posDrvName); throw; @@ -664,7 +664,7 @@ static void prim_toJSON(EvalState & state, const Pos & pos, Value * * args, Valu static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - string name = state.forceStringNoCtx(*args[0]); + string name = state.forceStringNoCtx(*args[0], pos); string contents = state.forceString(*args[1], context); PathSet refs; @@ -775,7 +775,7 @@ static void prim_attrNames(EvalState & state, const Pos & pos, Value * * args, V /* Dynamic version of the `.' operator. */ void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string attr = state.forceStringNoCtx(*args[0]); + string attr = state.forceStringNoCtx(*args[0], pos); state.forceAttrs(*args[1], pos); // !!! Should we create a symbol here or just do a lookup? Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr)); @@ -791,7 +791,7 @@ void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v) /* Return position information of the specified attribute. */ void prim_unsafeGetAttrPos(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string attr = state.forceStringNoCtx(*args[0]); + string attr = state.forceStringNoCtx(*args[0], pos); state.forceAttrs(*args[1], pos); Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr)); if (i == args[1]->attrs->end()) @@ -804,7 +804,7 @@ void prim_unsafeGetAttrPos(EvalState & state, const Pos & pos, Value * * args, V /* Dynamic version of the `?' operator. */ static void prim_hasAttr(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string attr = state.forceStringNoCtx(*args[0]); + string attr = state.forceStringNoCtx(*args[0], pos); state.forceAttrs(*args[1], pos); mkBool(v, args[1]->attrs->find(state.symbols.create(attr)) != args[1]->attrs->end()); } @@ -826,7 +826,7 @@ static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args, /* Get the attribute names to be removed. */ std::set names; for (unsigned int i = 0; i < args[1]->list.length; ++i) { - state.forceStringNoCtx(*args[1]->list.elems[i]); + state.forceStringNoCtx(*args[1]->list.elems[i], pos); names.insert(state.symbols.create(args[1]->list.elems[i]->string.s)); } @@ -861,7 +861,7 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args, Bindings::iterator j = v2.attrs->find(state.sName); if (j == v2.attrs->end()) throw TypeError(format("`name' attribute missing in a call to `listToAttrs', at %1%") % pos); - string name = state.forceStringNoCtx(*j->value); + string name = state.forceStringNoCtx(*j->value, pos); Symbol sym = state.symbols.create(name); if (seen.find(sym) == seen.end()) { @@ -1168,7 +1168,7 @@ static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & po /* Return the cryptographic hash of a string in base-16. */ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string type = state.forceStringNoCtx(*args[0]); + string type = state.forceStringNoCtx(*args[0], pos); HashType ht = parseHashType(type); if (ht == htUnknown) throw Error(format("unknown hash type `%1%', at %2%") % type % pos); @@ -1187,7 +1187,7 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, static void prim_parseDrvName(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string name = state.forceStringNoCtx(*args[0]); + string name = state.forceStringNoCtx(*args[0], pos); DrvName parsed(name); state.mkAttrs(v, 2); mkString(*state.allocAttr(v, state.sName), parsed.name); @@ -1198,8 +1198,8 @@ static void prim_parseDrvName(EvalState & state, const Pos & pos, Value * * args static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * args, Value & v) { - string version1 = state.forceStringNoCtx(*args[0]); - string version2 = state.forceStringNoCtx(*args[1]); + string version1 = state.forceStringNoCtx(*args[0], pos); + string version2 = state.forceStringNoCtx(*args[1], pos); mkInt(v, compareVersions(version1, version2)); } From 8160f794e79a4a2a5269080b408d69fc93d7a305 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 21:53:47 +0200 Subject: [PATCH 21/61] derivation: Don't require certain function arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turns out that in Nixpkgs, derivation is actually called without a ‘name’ argument in some places :-( --- corepkgs/derivation.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/corepkgs/derivation.nix b/corepkgs/derivation.nix index 374fe50104..c0fbe8082c 100644 --- a/corepkgs/derivation.nix +++ b/corepkgs/derivation.nix @@ -1,7 +1,7 @@ /* This is the implementation of the ‘derivation’ builtin function. It's actually a wrapper around the ‘derivationStrict’ primop. */ -drvAttrs @ { outputs ? [ "out" ], name, builder, system, ... }: +drvAttrs @ { outputs ? [ "out" ], ... }: let From bd9b1d97b42f307c8b595bb2de9b15bec1405b23 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 22:19:33 +0200 Subject: [PATCH 22/61] Show position info in string concatenation / addition errors --- src/libexpr/eval.cc | 39 +++++++++++++++++++++++++++------------ src/libexpr/eval.hh | 4 ++-- src/libexpr/get-drvs.cc | 6 +++--- src/libexpr/nixexpr.hh | 5 +++-- src/libexpr/parser.y | 12 ++++++------ src/libexpr/primops.cc | 36 ++++++++++++++++++------------------ src/nix-env/user-env.cc | 6 ++++-- 7 files changed, 63 insertions(+), 45 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 30a8793ee7..e0451dfa77 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -275,6 +275,16 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2)) throw EvalError(format(s) % s2); } +LocalNoInlineNoReturn(void throwEvalError(const char * s, const Pos & pos)) +{ + throw EvalError(format(s) % pos); +} + +LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const Pos & pos)) +{ + throw EvalError(format(s) % s2 % pos); +} + LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3)) { throw EvalError(format(s) % s2 % s3); @@ -295,6 +305,11 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s)) throw TypeError(s); } +LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos)) +{ + throw TypeError(format(s) % pos); +} + LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1)) { throw TypeError(format(s) % s1); @@ -648,7 +663,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) foreach (AttrDefs::iterator, i, attrs) v.attrs->push_back(Attr(i->first, i->second.e->maybeThunk(state, env), &i->second.pos)); - /* dynamic attrs apply *after* rec and __overrides */ + /* Dynamic attrs apply *after* rec and __overrides. */ foreach (DynamicAttrDefs::iterator, i, dynamicAttrs) { Value nameVal; if (i->nameExpr->es->size() == 1) { @@ -1113,17 +1128,17 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) if (firstType == tInt) { if (vTmp.type != tInt) - throwEvalError("cannot add %1% to an integer", showType(vTmp)); + throwEvalError("cannot add %1% to an integer, at %2%", showType(vTmp), pos); n += vTmp.integer; } else - s << state.coerceToString(vTmp, context, false, firstType == tString); + s << state.coerceToString(pos, vTmp, context, false, firstType == tString); } if (firstType == tInt) mkInt(v, n); else if (firstType == tPath) { if (!context.empty()) - throwEvalError("a string that refers to a store path cannot be appended to a path, in `%1%'", s.str()); + throwEvalError("a string that refers to a store path cannot be appended to a path, at %1%", pos); mkPath(v, s.str().c_str()); } else mkString(v, s.str(), context); @@ -1233,7 +1248,7 @@ bool EvalState::isDerivation(Value & v) } -string EvalState::coerceToString(Value & v, PathSet & context, +string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, bool coerceMore, bool copyToStore) { forceValue(v); @@ -1252,8 +1267,8 @@ string EvalState::coerceToString(Value & v, PathSet & context, if (v.type == tAttrs) { Bindings::iterator i = v.attrs->find(sOutPath); - if (i == v.attrs->end()) throwTypeError("cannot coerce a set to a string"); - return coerceToString(*i->value, context, coerceMore, copyToStore); + if (i == v.attrs->end()) throwTypeError("cannot coerce a set to a string, at %1%", pos); + return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } if (coerceMore) { @@ -1268,7 +1283,7 @@ string EvalState::coerceToString(Value & v, PathSet & context, if (v.type == tList) { string result; for (unsigned int n = 0; n < v.list.length; ++n) { - result += coerceToString(*v.list.elems[n], + result += coerceToString(pos, *v.list.elems[n], context, coerceMore, copyToStore); if (n < v.list.length - 1 /* !!! not quite correct */ @@ -1279,7 +1294,7 @@ string EvalState::coerceToString(Value & v, PathSet & context, } } - throwTypeError("cannot coerce %1% to a string", v); + throwTypeError("cannot coerce %1% to a string, at %2%", v, pos); } @@ -1305,11 +1320,11 @@ string EvalState::copyPathToStore(PathSet & context, const Path & path) } -Path EvalState::coerceToPath(Value & v, PathSet & context) +Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context) { - string path = coerceToString(v, context, false, false); + string path = coerceToString(pos, v, context, false, false); if (path == "" || path[0] != '/') - throwEvalError("string `%1%' doesn't represent an absolute path", path); + throwEvalError("string `%1%' doesn't represent an absolute path, at %1%", path, pos); return path; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 1d53f49821..d1bd27f162 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -177,7 +177,7 @@ public: string. If `coerceMore' is set, also converts nulls, integers, booleans and lists to a string. If `copyToStore' is set, referenced paths are copied to the Nix store as a side effect. */ - string coerceToString(Value & v, PathSet & context, + string coerceToString(const Pos & pos, Value & v, PathSet & context, bool coerceMore = false, bool copyToStore = true); string copyPathToStore(PathSet & context, const Path & path); @@ -185,7 +185,7 @@ public: /* Path coercion. Converts strings, paths and derivations to a path. The result is guaranteed to be a canonicalised, absolute path. Nothing is copied to the store. */ - Path coerceToPath(Value & v, PathSet & context); + Path coerceToPath(const Pos & pos, Value & v, PathSet & context); public: diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 88ea68a5f0..57b87ab58d 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -13,7 +13,7 @@ string DrvInfo::queryDrvPath() if (drvPath == "" && attrs) { Bindings::iterator i = attrs->find(state->sDrvPath); PathSet context; - drvPath = i != attrs->end() ? state->coerceToPath(*i->value, context) : ""; + drvPath = i != attrs->end() ? state->coerceToPath(*i->pos, *i->value, context) : ""; } return drvPath; } @@ -24,7 +24,7 @@ string DrvInfo::queryOutPath() if (outPath == "" && attrs) { Bindings::iterator i = attrs->find(state->sOutPath); PathSet context; - outPath = i != attrs->end() ? state->coerceToPath(*i->value, context) : ""; + outPath = i != attrs->end() ? state->coerceToPath(*i->pos, *i->value, context) : ""; } return outPath; } @@ -50,7 +50,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs() Bindings::iterator outPath = out->value->attrs->find(state->sOutPath); if (outPath == out->value->attrs->end()) continue; // FIXME: throw error? PathSet context; - outputs[name] = state->coerceToPath(*outPath->value, context); + outputs[name] = state->coerceToPath(*outPath->pos, *outPath->value, context); } } else outputs["out"] = queryOutPath(); diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 9234e2970f..d781d92ba7 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -320,10 +320,11 @@ MakeBinOp(OpConcatLists, "++") struct ExprConcatStrings : Expr { + Pos pos; bool forceString; vector * es; - ExprConcatStrings(bool forceString, vector * es) - : forceString(forceString), es(es) { }; + ExprConcatStrings(const Pos & pos, bool forceString, vector * es) + : pos(pos), forceString(forceString), es(es) { }; COMMON_METHODS }; diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 4830e7ca1c..d39d0c0a75 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -130,7 +130,7 @@ static void addFormal(const Pos & pos, Formals * formals, const Formal & formal) } -static Expr * stripIndentation(SymbolTable & symbols, vector & es) +static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols, vector & es) { if (es.empty()) return new ExprString(symbols.create("")); @@ -216,7 +216,7 @@ static Expr * stripIndentation(SymbolTable & symbols, vector & es) } /* If this is a single string, then don't do a concatenation. */ - return es2->size() == 1 && dynamic_cast((*es2)[0]) ? (*es2)[0] : new ExprConcatStrings(true, es2); + return es2->size() == 1 && dynamic_cast((*es2)[0]) ? (*es2)[0] : new ExprConcatStrings(pos, true, es2); } @@ -344,7 +344,7 @@ expr_op { vector * l = new vector; l->push_back($1); l->push_back($3); - $$ = new ExprConcatStrings(false, l); + $$ = new ExprConcatStrings(CUR_POS, false, l); } | expr_op '-' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("sub")), $1), $3); } | expr_op '*' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("mul")), $1), $3); } @@ -381,7 +381,7 @@ expr_simple | INT { $$ = new ExprInt($1); } | '"' string_parts '"' { $$ = $2; } | IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE { - $$ = stripIndentation(data->symbols, *$2); + $$ = stripIndentation(CUR_POS, data->symbols, *$2); } | PATH { $$ = new ExprPath(absPath($1, data->basePath)); } | SPATH { @@ -413,7 +413,7 @@ expr_simple string_parts : STR - | string_parts_interpolated { $$ = new ExprConcatStrings(true, $1); } + | string_parts_interpolated { $$ = new ExprConcatStrings(CUR_POS, true, $1); } | { $$ = new ExprString(data->symbols.create("")); } ; @@ -509,7 +509,7 @@ attr string_attr : '"' string_parts '"' { $$ = $2; } - | DOLLAR_CURLY expr '}' { $$ = new ExprConcatStrings(true, new vector(1, $2)); } + | DOLLAR_CURLY expr '}' { $$ = new ExprConcatStrings(CUR_POS, true, new vector(1, $2)); } ; expr_list diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 00833403d7..84ef967ffa 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -42,7 +42,7 @@ std::pair decodeContext(const string & s) static void prim_import(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - Path path = state.coerceToPath(*args[0], context); + Path path = state.coerceToPath(pos, *args[0], context); foreach (PathSet::iterator, i, context) { Path ctx = decodeContext(*i).first; @@ -255,14 +255,14 @@ static void prim_abort(EvalState & state, const Pos & pos, Value * * args, Value { PathSet context; throw Abort(format("evaluation aborted with the following error message: `%1%'") % - state.coerceToString(*args[0], context)); + state.coerceToString(pos, *args[0], context)); } static void prim_throw(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - throw ThrownError(format("%1%") % state.coerceToString(*args[0], context)); + throw ThrownError(format("%1%") % state.coerceToString(pos, *args[0], context)); } @@ -273,7 +273,7 @@ static void prim_addErrorContext(EvalState & state, const Pos & pos, Value * * a v = *args[1]; } catch (Error & e) { PathSet context; - e.addPrefix(format("%1%\n") % state.coerceToString(*args[0], context)); + e.addPrefix(format("%1%\n") % state.coerceToString(pos, *args[0], context)); throw; } } @@ -383,7 +383,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * if (key == "args") { state.forceList(*i->value, pos); for (unsigned int n = 0; n < i->value->list.length; ++n) { - string s = state.coerceToString(*i->value->list.elems[n], context, true); + string s = state.coerceToString(posDrvName, *i->value->list.elems[n], context, true); drv.args.push_back(s); } } @@ -391,7 +391,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* All other attributes are passed to the builder through the environment. */ else { - string s = state.coerceToString(*i->value, context, true); + string s = state.coerceToString(posDrvName, *i->value, context, true); drv.env[key] = s; if (key == "builder") drv.builder = s; else if (i->name == state.sSystem) drv.platform = s; @@ -558,7 +558,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * static void prim_toPath(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - Path path = state.coerceToPath(*args[0], context); + Path path = state.coerceToPath(pos, *args[0], context); mkString(v, canonPath(path), context); } @@ -574,7 +574,7 @@ static void prim_toPath(EvalState & state, const Pos & pos, Value * * args, Valu static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - Path path = state.coerceToPath(*args[0], context); + Path path = state.coerceToPath(pos, *args[0], context); /* Resolve symlinks in ‘path’, unless ‘path’ itself is a symlink directly in the store. The latter condition is necessary so e.g. nix-push does the right thing. */ @@ -592,7 +592,7 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V static void prim_pathExists(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - Path path = state.coerceToPath(*args[0], context); + Path path = state.coerceToPath(pos, *args[0], context); if (!context.empty()) throw EvalError(format("string `%1%' cannot refer to other paths, at %2%") % path % pos); mkBool(v, pathExists(path)); @@ -604,7 +604,7 @@ static void prim_pathExists(EvalState & state, const Pos & pos, Value * * args, static void prim_baseNameOf(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - mkString(v, baseNameOf(state.coerceToString(*args[0], context)), context); + mkString(v, baseNameOf(state.coerceToString(pos, *args[0], context)), context); } @@ -614,7 +614,7 @@ static void prim_baseNameOf(EvalState & state, const Pos & pos, Value * * args, static void prim_dirOf(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - Path dir = dirOf(state.coerceToPath(*args[0], context)); + Path dir = dirOf(state.coerceToPath(pos, *args[0], context)); if (args[0]->type == tPath) mkPath(v, dir.c_str()); else mkString(v, dir, context); } @@ -623,7 +623,7 @@ static void prim_dirOf(EvalState & state, const Pos & pos, Value * * args, Value static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - Path path = state.coerceToPath(*args[0], context); + Path path = state.coerceToPath(pos, *args[0], context); if (!context.empty()) throw EvalError(format("string `%1%' cannot refer to other paths, at %2%") % path % pos); mkString(v, readFile(path).c_str()); @@ -731,7 +731,7 @@ struct FilterFromExpr : PathFilter static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - Path path = state.coerceToPath(*args[1], context); + Path path = state.coerceToPath(pos, *args[1], context); if (!context.empty()) throw EvalError(format("string `%1%' cannot refer to other paths, at %2%") % path % pos); @@ -1105,7 +1105,7 @@ static void prim_lessThan(EvalState & state, const Pos & pos, Value * * args, Va static void prim_toString(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - string s = state.coerceToString(*args[0], context, true, false); + string s = state.coerceToString(pos, *args[0], context, true, false); mkString(v, s, context); } @@ -1119,7 +1119,7 @@ static void prim_substring(EvalState & state, const Pos & pos, Value * * args, V int start = state.forceInt(*args[0], pos); int len = state.forceInt(*args[1], pos); PathSet context; - string s = state.coerceToString(*args[2], context); + string s = state.coerceToString(pos, *args[2], context); if (start < 0) throw EvalError(format("negative start position in `substring', at %1%") % pos); @@ -1130,7 +1130,7 @@ static void prim_substring(EvalState & state, const Pos & pos, Value * * args, V static void prim_stringLength(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - string s = state.coerceToString(*args[0], context); + string s = state.coerceToString(pos, *args[0], context); mkInt(v, s.size()); } @@ -1138,7 +1138,7 @@ static void prim_stringLength(EvalState & state, const Pos & pos, Value * * args static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - string s = state.coerceToString(*args[0], context); + string s = state.coerceToString(pos, *args[0], context); mkString(v, s, PathSet()); } @@ -1152,7 +1152,7 @@ static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - string s = state.coerceToString(*args[0], context); + string s = state.coerceToString(pos, *args[0], context); PathSet context2; foreach (PathSet::iterator, i, context) { diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index a95c4cba93..e71ad34edb 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -121,8 +121,10 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, debug("evaluating user environment builder"); state.forceValue(topLevel); PathSet context; - Path topLevelDrv = state.coerceToPath(*topLevel.attrs->find(state.sDrvPath)->value, context); - Path topLevelOut = state.coerceToPath(*topLevel.attrs->find(state.sOutPath)->value, context); + Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath)); + Path topLevelDrv = state.coerceToPath(aDrvPath.pos ? *(aDrvPath.pos) : noPos, *(aDrvPath.value), context); + Attr & aOutPath(*topLevel.attrs->find(state.sOutPath)); + Path topLevelOut = state.coerceToPath(aOutPath.pos ? *(aOutPath.pos) : noPos, *(aOutPath.value), context); /* Realise the resulting store expression. */ debug("building user environment"); From 4c5faad99408cdfc35a8b0923d1efdf288fd9990 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 22:43:52 +0200 Subject: [PATCH 23/61] Show position info in Boolean operations --- src/libexpr/eval.cc | 24 +++++++++++++++++------- src/libexpr/eval.hh | 3 ++- src/libexpr/nixexpr.hh | 20 +++----------------- src/libexpr/parser.y | 10 +++++----- src/libexpr/primops.cc | 2 +- 5 files changed, 28 insertions(+), 31 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index e0451dfa77..44d75bd8c0 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -574,6 +574,16 @@ inline bool EvalState::evalBool(Env & env, Expr * e) } +inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos) +{ + Value v; + e->eval(*this, env, v); + if (v.type != tBool) + throwTypeError("value is %1% while a Boolean was expected, at %2%", v, pos); + return v.boolean; +} + + inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v) { e->eval(*this, env, v); @@ -975,7 +985,7 @@ void ExprIf::eval(EvalState & state, Env & env, Value & v) void ExprAssert::eval(EvalState & state, Env & env, Value & v) { - if (!state.evalBool(env, cond)) + if (!state.evalBool(env, cond, pos)) throwAssertionError("assertion failed at %1%", pos); body->eval(state, env, v); } @@ -1016,19 +1026,19 @@ void ExprOpNEq::eval(EvalState & state, Env & env, Value & v) void ExprOpAnd::eval(EvalState & state, Env & env, Value & v) { - mkBool(v, state.evalBool(env, e1) && state.evalBool(env, e2)); + mkBool(v, state.evalBool(env, e1, pos) && state.evalBool(env, e2, pos)); } void ExprOpOr::eval(EvalState & state, Env & env, Value & v) { - mkBool(v, state.evalBool(env, e1) || state.evalBool(env, e2)); + mkBool(v, state.evalBool(env, e1, pos) || state.evalBool(env, e2, pos)); } void ExprOpImpl::eval(EvalState & state, Env & env, Value & v) { - mkBool(v, !state.evalBool(env, e1) || state.evalBool(env, e2)); + mkBool(v, !state.evalBool(env, e1, pos) || state.evalBool(env, e2, pos)); } @@ -1073,18 +1083,18 @@ void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v) Value v1; e1->eval(state, env, v1); Value v2; e2->eval(state, env, v2); Value * lists[2] = { &v1, &v2 }; - state.concatLists(v, 2, lists); + state.concatLists(v, 2, lists, pos); } -void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists) +void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists, const Pos & pos) { nrListConcats++; Value * nonEmpty = 0; unsigned int len = 0; for (unsigned int n = 0; n < nrLists; ++n) { - forceList(*lists[n]); + forceList(*lists[n], pos); unsigned int l = lists[n]->list.length; len += l; if (l) nonEmpty = lists[n]; diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index d1bd27f162..6d4cb8abe8 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -145,6 +145,7 @@ public: /* Evaluation the expression, then verify that it has the expected type. */ inline bool evalBool(Env & env, Expr * e); + inline bool evalBool(Env & env, Expr * e, const Pos & pos); inline void evalAttrs(Env & env, Expr * e, Value & v); /* If `v' is a thunk, enter it and overwrite `v' with the result @@ -246,7 +247,7 @@ public: void mkThunk_(Value & v, Expr * expr); void mkPos(Value & v, Pos * pos); - void concatLists(Value & v, unsigned int nrLists, Value * * lists); + void concatLists(Value & v, unsigned int nrLists, Value * * lists, const Pos & pos); /* Print statistics. */ void printStats(); diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index d781d92ba7..f07b85c834 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -277,28 +277,13 @@ struct ExprBuiltin : Expr COMMON_METHODS }; -struct ExprApp : Expr -{ - Pos pos; - Expr * e1, * e2; - ExprApp(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; - ExprApp(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; - void show(std::ostream & str) - { - str << *e1 << " " << *e2; - } - void bindVars(const StaticEnv & env) - { - e1->bindVars(env); e2->bindVars(env); - } - void eval(EvalState & state, Env & env, Value & v); -}; - #define MakeBinOp(name, s) \ struct Expr##name : Expr \ { \ + Pos pos; \ Expr * e1, * e2; \ Expr##name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \ + Expr##name(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \ void show(std::ostream & str) \ { \ str << *e1 << " " s " " << *e2; \ @@ -310,6 +295,7 @@ struct ExprApp : Expr void eval(EvalState & state, Env & env, Value & v); \ }; +MakeBinOp(App, "") MakeBinOp(OpEq, "==") MakeBinOp(OpNEq, "!=") MakeBinOp(OpAnd, "&&") diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index d39d0c0a75..021f8b0266 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -335,10 +335,10 @@ expr_op | expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $3), $1)); } | expr_op '>' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $3), $1); } | expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("lessThan")), $1), $3)); } - | expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); } - | expr_op OR expr_op { $$ = new ExprOpOr($1, $3); } - | expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); } - | expr_op UPDATE expr_op { $$ = new ExprOpUpdate($1, $3); } + | expr_op AND expr_op { $$ = new ExprOpAnd(CUR_POS, $1, $3); } + | expr_op OR expr_op { $$ = new ExprOpOr(CUR_POS, $1, $3); } + | expr_op IMPL expr_op { $$ = new ExprOpImpl(CUR_POS, $1, $3); } + | expr_op UPDATE expr_op { $$ = new ExprOpUpdate(CUR_POS, $1, $3); } | expr_op '?' attrpath { $$ = new ExprOpHasAttr($1, *$3); } | expr_op '+' expr_op { vector * l = new vector; @@ -349,7 +349,7 @@ expr_op | expr_op '-' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("sub")), $1), $3); } | expr_op '*' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("mul")), $1), $3); } | expr_op '/' expr_op { $$ = new ExprApp(CUR_POS, new ExprApp(new ExprBuiltin(data->symbols.create("div")), $1), $3); } - | expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); } + | expr_op CONCAT expr_op { $$ = new ExprOpConcatLists(CUR_POS, $1, $3); } | expr_app ; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 84ef967ffa..b4e75648f8 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1042,7 +1042,7 @@ static void prim_elem(EvalState & state, const Pos & pos, Value * * args, Value static void prim_concatLists(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceList(*args[0], pos); - state.concatLists(v, args[0]->list.length, args[0]->list.elems); + state.concatLists(v, args[0]->list.length, args[0]->list.elems, pos); } From 8e5fbf4d730b9fcf39eddf5539a206cf19d2cdce Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Apr 2014 22:52:14 +0200 Subject: [PATCH 24/61] Show position info in attribute selection errors --- src/libexpr/eval.cc | 14 +++++++------- src/libexpr/nixexpr.hh | 5 +++-- src/libexpr/parser.y | 8 ++++---- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 44d75bd8c0..0f7e8e385a 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -736,7 +736,7 @@ unsigned long nrLookups = 0; void ExprSelect::eval(EvalState & state, Env & env, Value & v) { Value vTmp; - Pos * pos = 0; + Pos * pos2 = 0; Value * vAttrs = &vTmp; e->eval(state, env, vTmp); @@ -756,21 +756,21 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) return; } } else { - state.forceAttrs(*vAttrs); + state.forceAttrs(*vAttrs, pos); if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) - throwEvalError("attribute `%1%' missing", showAttrPath(attrPath)); + throwEvalError("attribute `%1%' missing, at %2%", showAttrPath(attrPath), pos); } vAttrs = j->value; - pos = j->pos; - if (state.countCalls && pos) state.attrSelects[*pos]++; + pos2 = j->pos; + if (state.countCalls && pos2) state.attrSelects[*pos2]++; } state.forceValue(*vAttrs); } catch (Error & e) { - if (pos && pos->file != state.sDerivationNix) + if (pos2 && pos2->file != state.sDerivationNix) addErrorPrefix(e, "while evaluating the attribute `%1%' at %2%:\n", - showAttrPath(attrPath), *pos); + showAttrPath(attrPath), *pos2); throw; } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index f07b85c834..813efbe21a 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -149,10 +149,11 @@ struct ExprVar : Expr struct ExprSelect : Expr { + Pos pos; Expr * e, * def; AttrPath attrPath; - ExprSelect(Expr * e, const AttrPath & attrPath, Expr * def) : e(e), def(def), attrPath(attrPath) { }; - ExprSelect(Expr * e, const Symbol & name) : e(e), def(0) { attrPath.push_back(AttrName(name)); }; + ExprSelect(const Pos & pos, Expr * e, const AttrPath & attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(attrPath) { }; + ExprSelect(const Pos & pos, Expr * e, const Symbol & name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); }; COMMON_METHODS }; diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 021f8b0266..dbcffff996 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -361,9 +361,9 @@ expr_app expr_select : expr_simple '.' attrpath - { $$ = new ExprSelect($1, *$3, 0); } + { $$ = new ExprSelect(CUR_POS, $1, *$3, 0); } | expr_simple '.' attrpath OR_KW expr_select - { $$ = new ExprSelect($1, *$3, $5); } + { $$ = new ExprSelect(CUR_POS, $1, *$3, $5); } | /* Backwards compatibility: because Nixpkgs has a rarely used function named ‘or’, allow stuff like ‘map or [...]’. */ expr_simple OR_KW @@ -403,7 +403,7 @@ expr_simple /* Let expressions `let {..., body = ...}' are just desugared into `(rec {..., body = ...}).body'. */ | LET '{' binds '}' - { $3->recursive = true; $$ = new ExprSelect($3, data->symbols.create("body")); } + { $3->recursive = true; $$ = new ExprSelect(noPos, $3, data->symbols.create("body")); } | REC '{' binds '}' { $3->recursive = true; $$ = $3; } | '{' binds '}' @@ -458,7 +458,7 @@ binds foreach (AttrPath::iterator, i, *$6) { if ($$->attrs.find(i->symbol) != $$->attrs.end()) dupAttr(i->symbol, makeCurPos(@6, data), $$->attrs[i->symbol].pos); - $$->attrs[i->symbol] = ExprAttrs::AttrDef(new ExprSelect($4, i->symbol), makeCurPos(@6, data)); + $$->attrs[i->symbol] = ExprAttrs::AttrDef(new ExprSelect(CUR_POS, $4, i->symbol), makeCurPos(@6, data)); } } | { $$ = new ExprAttrs; } From 84d6936371037559704337614c65007a8e61b5e1 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 7 Apr 2014 11:18:54 +0200 Subject: [PATCH 25/61] Install systemd units --- .gitignore | 3 +++ Makefile | 1 + misc/systemd/local.mk | 1 + misc/systemd/nix-daemon.service | 10 ---------- misc/systemd/nix-daemon.service.in | 9 +++++++++ misc/systemd/nix-daemon.socket.in | 11 +++++++++++ nix.spec.in | 8 -------- 7 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 misc/systemd/local.mk delete mode 100644 misc/systemd/nix-daemon.service create mode 100644 misc/systemd/nix-daemon.service.in create mode 100644 misc/systemd/nix-daemon.socket.in diff --git a/.gitignore b/.gitignore index 76fc815eba..008f5de8a4 100644 --- a/.gitignore +++ b/.gitignore @@ -108,6 +108,9 @@ Makefile.config /perl/lib/Nix/Config.pm /perl/lib/Nix/Store.cc +/misc/systemd/nix-daemon.service +/misc/systemd/nix-daemon.socket + *.a *.o *.so diff --git a/Makefile b/Makefile index bcfa89dd23..77f22db9f2 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ makefiles = \ perl/local.mk \ scripts/local.mk \ corepkgs/local.mk \ + misc/systemd/local.mk \ misc/emacs/local.mk \ doc/manual/local.mk \ tests/local.mk diff --git a/misc/systemd/local.mk b/misc/systemd/local.mk new file mode 100644 index 0000000000..a5f6131ce8 --- /dev/null +++ b/misc/systemd/local.mk @@ -0,0 +1 @@ +$(foreach n, nix-daemon.socket nix-daemon.service, $(eval $(call install-file-in, $(d)/$(n), $(libdir)/systemd/system, 0644))) diff --git a/misc/systemd/nix-daemon.service b/misc/systemd/nix-daemon.service deleted file mode 100644 index ee28209f09..0000000000 --- a/misc/systemd/nix-daemon.service +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Helper daemon for managing secure, multi-user Nix stores -After=syslog.target - -[Service] -Type=simple -ExecStart=/usr/bin/nix-daemon - -[Install] -WantedBy=multi-user.target diff --git a/misc/systemd/nix-daemon.service.in b/misc/systemd/nix-daemon.service.in new file mode 100644 index 0000000000..5fc04a3f57 --- /dev/null +++ b/misc/systemd/nix-daemon.service.in @@ -0,0 +1,9 @@ +[Unit] +Description=Nix Daemon +RequiresMountsFor=@storedir@ +RequiresMountsFor=@localstatedir@ +ConditionPathIsReadWrite=@localstatedir@/nix/daemon-socket + +[Service] +ExecStart=@@bindir@/nix-daemon nix-daemon --daemon +KillMode=process diff --git a/misc/systemd/nix-daemon.socket.in b/misc/systemd/nix-daemon.socket.in new file mode 100644 index 0000000000..9ed39ffe6e --- /dev/null +++ b/misc/systemd/nix-daemon.socket.in @@ -0,0 +1,11 @@ +[Unit] +Description=Nix Daemon Socket +Before=multi-user.target +RequiresMountsFor=@storedir@ +ConditionPathIsReadWrite=@localstatedir@/nix/daemon-socket + +[Socket] +ListenStream=@localstatedir@/nix/daemon-socket/socket + +[Install] +WantedBy=sockets.target diff --git a/nix.spec.in b/nix.spec.in index f067c3896f..1457308d1e 100644 --- a/nix.spec.in +++ b/nix.spec.in @@ -132,14 +132,6 @@ done # (until this is fixed in the relevant Makefile) chmod -x $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/nix.sh -# systemd not available on RHEL yet -%if ! 0%{?rhel} -# install systemd service descriptor -mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/systemd/system -cp -p misc/systemd/nix-daemon.service \ - $RPM_BUILD_ROOT%{_prefix}/lib/systemd/system/ -%endif - # Copy the byte-compiled mode file by hand cp -p misc/emacs/nix-mode.elc $RPM_BUILD_ROOT%{_emacs_sitelispdir}/ From 89f923281335f695d4199e1fafaaeeb1729ba2d3 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 7 Apr 2014 12:00:23 +0200 Subject: [PATCH 26/61] Update release notes --- doc/manual/release-notes.xml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/doc/manual/release-notes.xml b/doc/manual/release-notes.xml index 9bfa169ac5..0cf61977e7 100644 --- a/doc/manual/release-notes.xml +++ b/doc/manual/release-notes.xml @@ -7,7 +7,7 @@ -
Release 1.7 (TBA) +
Release 1.7 (April 8, 2014) In addition to the usual bug fixes, this release has the following new features: @@ -225,6 +225,17 @@ $ bash <(curl https://nixos.org/nix/install) + + More evaluation errors include position information. For + instance, selecting a missing attribute will print something like + + +error: attribute `nixUnstabl' missing, at /etc/nixos/configurations/misc/eelco/mandark.nix:216:15 + + + + + The command nix-setuid-helper is gone. From 76cbf55a6d8953e393ba39896ccbb0948bac96d6 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 8 Apr 2014 13:51:34 +0200 Subject: [PATCH 27/61] Ensure that systemd units to into lib, not lib64 http://hydra.nixos.org/build/10170940 --- misc/systemd/local.mk | 2 +- nix.spec.in | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/misc/systemd/local.mk b/misc/systemd/local.mk index a5f6131ce8..5555818c52 100644 --- a/misc/systemd/local.mk +++ b/misc/systemd/local.mk @@ -1 +1 @@ -$(foreach n, nix-daemon.socket nix-daemon.service, $(eval $(call install-file-in, $(d)/$(n), $(libdir)/systemd/system, 0644))) +$(foreach n, nix-daemon.socket nix-daemon.service, $(eval $(call install-file-in, $(d)/$(n), $(prefix)/lib/systemd/system, 0644))) diff --git a/nix.spec.in b/nix.spec.in index 1457308d1e..4ec8cfe653 100644 --- a/nix.spec.in +++ b/nix.spec.in @@ -158,8 +158,8 @@ chgrp %{nixbld_group} /nix/store chmod 1775 /nix/store %if ! 0%{?rhel} # Enable and start Nix worker -systemctl enable nix-daemon.service -systemctl start nix-daemon.service +systemctl enable nix-daemon.socket nix-daemon.service +systemctl start nix-daemon.socket %endif %files @@ -169,6 +169,7 @@ systemctl start nix-daemon.service %exclude %dir %{perl_vendorarch}/auto/ %{_prefix}/libexec/* %if ! 0%{?rhel} +%{_prefix}/lib/systemd/system/nix-daemon.socket %{_prefix}/lib/systemd/system/nix-daemon.service %endif %{_datadir}/emacs/site-lisp/nix-mode.el From 2b6c8ef40121fdc418551e9b780bb909477c9a3c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 8 Apr 2014 14:08:57 +0200 Subject: [PATCH 28/61] nix-shell --pure: Keep the user's $PAGER --- scripts/nix-build.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nix-build.in b/scripts/nix-build.in index 187371d6e1..2f95e74755 100755 --- a/scripts/nix-build.in +++ b/scripts/nix-build.in @@ -208,7 +208,7 @@ foreach my $expr (@exprs) { # Set the environment. if ($pure) { foreach my $name (keys %ENV) { - next if grep { $_ eq $name } ("HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL", "TZ"); + next if grep { $_ eq $name } ("HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL", "TZ", "PAGER"); delete $ENV{$name}; } # NixOS hack: prevent /etc/bashrc from sourcing /etc/profile. From 48460057419ce651c9484a66d83e6b987b261d8c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 8 Apr 2014 16:09:56 +0200 Subject: [PATCH 29/61] Update installation instructions --- doc/manual/installation.xml | 54 ++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/doc/manual/installation.xml b/doc/manual/installation.xml index 4c433a6bf7..3e7ffc5373 100644 --- a/doc/manual/installation.xml +++ b/doc/manual/installation.xml @@ -42,7 +42,28 @@ platforms as well.
Installing a binary distribution -The easiest way to install Nix is to use a binary package. +The easiest way to install Nix is to run the following: + + +$ bash <(curl https://nixos.org/nix/install) + + +This will perform a single-user installation of Nix, meaning that +/nix is owned by the invoking user. You should +run this under your usual user account, not as +root. The script will invoke sudo to create +/nix if it doesn’t already exist. If you don’t +have sudo, you should manually create +/nix first as root: + + +$ mkdir /nix +$ chown alice /nix + + + + +You can also manually download and install a binary package. Binary packages of the latest stable release are available for Fedora, Debian, Ubuntu, Mac OS X and various other systems from the Nix homepage. @@ -55,7 +76,7 @@ build system. or upgraded using rpm -U. For example, -$ rpm -U nix-1.0-1.i386.rpm +$ rpm -U nix-1.7-1.i386.rpm @@ -63,34 +84,24 @@ $ rpm -U nix-1.0-1.i386.rpm install it like this: -$ dpkg -i nix_1.0-1_amd64.deb +$ dpkg -i nix_1.7-1_amd64.deb For other platforms, including Mac OS X (Darwin), FreeBSD and -other Linux distributions, you can download a binary tarball. It -contains Nix and all its dependencies. You should unpack it somewhere -(e.g. in /tmp), and then run the script named -install inside the binary tarball: +other Linux distributions, you can download a binary tarball that +contains Nix and all its dependencies. (This is what the install +script at https://nixos.org/nix/install uses.) You should +unpack it somewhere (e.g. in /tmp), and then run +the script named install inside the binary tarball: alice$ cd /tmp -alice$ tar xfj nix-1.1-x86_64-darwin.tar.bz2 -alice$ cd nix-1.1-x86_64-darwin +alice$ tar xfj nix-1.7-x86_64-darwin.tar.bz2 +alice$ cd nix-1.7-x86_64-darwin alice$ ./install -You should run this under your usual user account, -not as root. The script will invoke -sudo to create /nix if it -doesn’t already exist. If you don’t have sudo, you -should manually create /nix first as root: - - -$ mkdir /nix -$ chown alice /nix - - Nix can be uninstalled using rpm -e nix or @@ -117,8 +128,7 @@ a source distribution. GNU Make. - A fairly recent version of GCC/G++. Version 2.95 - and higher should work. Clang will also work. + A version of GCC or Clang that supports C++11. Perl 5.8 or higher. From d23931f3a448fddc43d81f774fa83797729910e7 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 8 Apr 2014 16:10:25 +0200 Subject: [PATCH 30/61] Remove redundant stuff --- doc/manual/introduction.xml | 64 ------------------------------------- 1 file changed, 64 deletions(-) diff --git a/doc/manual/introduction.xml b/doc/manual/introduction.xml index 21b1df1564..e0300dc86c 100644 --- a/doc/manual/introduction.xml +++ b/doc/manual/introduction.xml @@ -254,33 +254,6 @@ xlink:href="http://nixos.org/">NixOS homepage.
-
About us - -Nix was originally developed at the Department of Information and -Computing Sciences, Utrecht University by the TraCE -project (2003-2008). The project was funded by the Software -Engineering Research Program Jacquard to improve the -support for variability in software systems. Further funding was -provided by the NIRICT LaQuSo Build Farm project. Development is -currently supported by LogicBlox. - -
- - -
About this manual - -This manual tells you how to install and use Nix and how to -write Nix expressions for software not already in the Nix Packages -collection. It also discusses some advanced topics, such as setting -up distributed multi-platform building. - -
- -
License Nix is free software; you can redistribute it and/or modify it @@ -297,41 +270,4 @@ Lesser General Public License for more details.
-
More information - -Some background information on Nix can be found in a number of -papers. The ICSE 2004 paper Imposing -a Memory Management Discipline on Software Deployment -discusses the hashing mechanism used to ensure reliable dependency -identification and non-interference between different versions and -variants of packages. The LISA 2004 paper Nix: -A Safe and Policy-Free System for Software Deployment -gives a more general discussion of Nix from a system-administration -perspective. The CBSE 2005 paper Efficient -Upgrading in a Purely Functional Component Deployment Model - is about transparent patch deployment in Nix. The SCM-12 -paper -Service Configuration Management shows how services (e.g., -web servers) can be deployed and managed through Nix. An overview of -NixOS is given in the JFP article NixOS: -A Purely Functional Linux Distribution. The Nix homepage -has an up-to-date -list of Nix-related papers. - -Nix is the subject of Eelco Dolstra’s PhD thesis The -Purely Functional Software Deployment Model, which -contains most of the papers listed above. - -Nix has a homepage at . - -
- - From e0a947cde6d11b5182500f024719b04b8997189a Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 8 Apr 2014 16:28:39 +0200 Subject: [PATCH 31/61] Simplify quick start section --- doc/manual/quick-start.xml | 57 ++++++++------------------------------ 1 file changed, 11 insertions(+), 46 deletions(-) diff --git a/doc/manual/quick-start.xml b/doc/manual/quick-start.xml index 779b9b9b85..1707990639 100644 --- a/doc/manual/quick-start.xml +++ b/doc/manual/quick-start.xml @@ -11,56 +11,22 @@ to the following chapters. -Download a source tarball or RPM or Debian/Ubuntu -package from . Build source -distributions using the regular sequence: +Install Nix by running the following: -$ tar xvfj nix-version.tar.bz2 -$ cd nix-version -$ ./configure -$ make -$ make install (as root) +$ bash <(curl https://nixos.org/nix/install) + -This will install the Nix binaries in /usr/local -and keep the Nix store and other state in /nix. -You can change the former by specifying -. The -location of the store can be changed using -. -However, you shouldn't change the store location, if at all possible, -since that will make it impossible to use pre-built binaries from the -Nixpkgs channel and other channels. The location of the state can be -changed using - - -You should add -prefix/etc/profile.d/nix.sh -to your ~/.profile (or some other login -file). - -Subscribe to the Nix Packages channel. - - -$ nix-channel --add http://nixos.org/channels/nixpkgs-unstable - - - -Download the latest Nix expressions available in the channel. - -$ nix-channel --update - -Note that this in itself doesn't download any packages, it just -downloads the Nix expressions that build them and stores them -somewhere (under ~/.nix-defexpr, in case you're -curious). Also, it registers the fact that pre-built binaries are -available remotely. +This will install Nix in /nix. The install script +will create /nix using sudo, +so make sure you have sufficient rights. (For other installation +methods, see .) See what installable packages are currently available in the channel: -$ nix-env -qa \* +$ nix-env -qa docbook-xml-4.2 firefox-1.0pre-PR-0.10.1 hello-2.1.1 @@ -72,7 +38,7 @@ libxslt-1.1.0 Install some packages from the channel: -$ nix-env -i hello firefox ... +$ nix-env -i hello ... This should download pre-built packages; it should not build them locally (if it does, something went wrong). @@ -84,8 +50,7 @@ $ which hello /home/eelco/.nix-profile/bin/hello $ hello Hello, world! -$ firefox -(read Slashdot or something) +
@@ -99,7 +64,7 @@ $ nix-env -e hello To keep up-to-date with the channel, do: -$ nix-channel --update +$ nix-channel --update nixpkgs $ nix-env -u '*' The latter command will upgrade each installed package for which there From dfa2f77d2e1118f32771c2fceefd683435554b9d Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 8 Apr 2014 19:24:29 +0200 Subject: [PATCH 32/61] If a .drv cannot be parsed, show its path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise you just get ‘expected string `Derive(['’ which isn't very helpful. --- src/libexpr/primops.cc | 2 +- src/libstore/derivations.cc | 16 +++++++++++++--- src/libstore/derivations.hh | 4 ++-- src/libstore/local-store.cc | 4 ++-- src/libstore/misc.cc | 2 +- src/libutil/util.cc | 2 +- src/libutil/util.hh | 2 ++ 7 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index b4e75648f8..c69d520d3b 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -67,7 +67,7 @@ static void prim_import(EvalState & state, const Pos & pos, Value * * args, Valu } if (isStorePath(path) && store->isValidPath(path) && isDerivation(path)) { - Derivation drv = parseDerivation(readFile(path)); + Derivation drv = readDerivation(path); Value & w = *state.allocValue(); state.mkAttrs(w, 1 + drv.outputs.size()); mkString(*state.allocAttr(w, state.sDrvPath), path, singleton("=" + path)); diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index d91e42784c..b452aa2caf 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -48,7 +48,7 @@ static Path parsePath(std::istream & str) { string s = parseString(str); if (s.size() == 0 || s[0] != '/') - throw Error(format("bad path `%1%' in derivation") % s); + throw FormatError(format("bad path `%1%' in derivation") % s); return s; } @@ -62,7 +62,7 @@ static StringSet parseStrings(std::istream & str, bool arePaths) } -Derivation parseDerivation(const string & s) +static Derivation parseDerivation(const string & s) { Derivation drv; std::istringstream str(s); @@ -112,6 +112,16 @@ Derivation parseDerivation(const string & s) } +Derivation readDerivation(const Path & drvPath) +{ + try { + return parseDerivation(readFile(drvPath)); + } catch (FormatError & e) { + throw Error(format("error parsing derivation `%1%': %2%") % drvPath % e.msg()); + } +} + + static void printString(string & res, const string & s) { res += '"'; @@ -240,7 +250,7 @@ Hash hashDerivationModulo(StoreAPI & store, Derivation drv) Hash h = drvHashes[i->first]; if (h.type == htUnknown) { assert(store.isValidPath(i->first)); - Derivation drv2 = parseDerivation(readFile(i->first)); + Derivation drv2 = readDerivation(i->first); h = hashDerivationModulo(store, drv2); drvHashes[i->first] = h; } diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh index 703410b925..04b64dfc88 100644 --- a/src/libstore/derivations.hh +++ b/src/libstore/derivations.hh @@ -59,8 +59,8 @@ class StoreAPI; Path writeDerivation(StoreAPI & store, const Derivation & drv, const string & name, bool repair = false); -/* Parse a derivation. */ -Derivation parseDerivation(const string & s); +/* Read a derivation from a file. */ +Derivation readDerivation(const Path & drvPath); /* Print a derivation. */ string unparseDerivation(const Derivation & drv); diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 1293a6e8f2..567706d097 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -661,7 +661,7 @@ unsigned long long LocalStore::addValidPath(const ValidPathInfo & info, bool che efficiently query whether a path is an output of some derivation. */ if (isDerivation(info.path)) { - Derivation drv = parseDerivation(readFile(info.path)); + Derivation drv = readDerivation(info.path); /* Verify that the output paths in the derivation are correct (i.e., follow the scheme for computing output paths from @@ -1290,7 +1290,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos) if (isDerivation(i->path)) { // FIXME: inefficient; we already loaded the // derivation in addValidPath(). - Derivation drv = parseDerivation(readFile(i->path)); + Derivation drv = readDerivation(i->path); checkDerivationOutputs(i->path, drv); } diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc index 1bf3f93782..6ecf8787cf 100644 --- a/src/libstore/misc.cc +++ b/src/libstore/misc.cc @@ -11,7 +11,7 @@ Derivation derivationFromPath(StoreAPI & store, const Path & drvPath) { assertStorePath(drvPath); store.ensurePath(drvPath); - return parseDerivation(readFile(drvPath)); + return readDerivation(drvPath); } diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 15c462ce4e..846674a29d 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -1041,7 +1041,7 @@ void expect(std::istream & str, const string & s) char s2[s.size()]; str.read(s2, s.size()); if (string(s2, s.size()) != s) - throw Error(format("expected string `%1%'") % s); + throw FormatError(format("expected string `%1%'") % s); } diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 8bedfea9a0..ce2d77c19a 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -326,6 +326,8 @@ bool hasSuffix(const string & s, const string & suffix); /* Read string `s' from stream `str'. */ void expect(std::istream & str, const string & s); +MakeError(FormatError, Error) + /* Read a C-style string from stream `str'. */ string parseString(std::istream & str); From b0a09a6f320d3a0ac186e87edb1c1782d8d168d5 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 9 Apr 2014 14:52:43 +0200 Subject: [PATCH 33/61] Add docbook icons to the distribution Grmbl... --- .gitignore | 1 - doc/manual/images/callouts/1.gif | Bin 0 -> 889 bytes doc/manual/images/callouts/10.gif | Bin 0 -> 929 bytes doc/manual/images/callouts/11.gif | Bin 0 -> 202 bytes doc/manual/images/callouts/12.gif | Bin 0 -> 210 bytes doc/manual/images/callouts/13.gif | Bin 0 -> 209 bytes doc/manual/images/callouts/14.gif | Bin 0 -> 205 bytes doc/manual/images/callouts/15.gif | Bin 0 -> 210 bytes doc/manual/images/callouts/2.gif | Bin 0 -> 907 bytes doc/manual/images/callouts/3.gif | Bin 0 -> 914 bytes doc/manual/images/callouts/4.gif | Bin 0 -> 907 bytes doc/manual/images/callouts/5.gif | Bin 0 -> 916 bytes doc/manual/images/callouts/6.gif | Bin 0 -> 218 bytes doc/manual/images/callouts/7.gif | Bin 0 -> 907 bytes doc/manual/images/callouts/8.gif | Bin 0 -> 918 bytes doc/manual/images/callouts/9.gif | Bin 0 -> 923 bytes doc/manual/local.mk | 2 +- doc/manual/release-notes.xml | 2 +- 18 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 doc/manual/images/callouts/1.gif create mode 100644 doc/manual/images/callouts/10.gif create mode 100644 doc/manual/images/callouts/11.gif create mode 100644 doc/manual/images/callouts/12.gif create mode 100644 doc/manual/images/callouts/13.gif create mode 100644 doc/manual/images/callouts/14.gif create mode 100644 doc/manual/images/callouts/15.gif create mode 100644 doc/manual/images/callouts/2.gif create mode 100644 doc/manual/images/callouts/3.gif create mode 100644 doc/manual/images/callouts/4.gif create mode 100644 doc/manual/images/callouts/5.gif create mode 100644 doc/manual/images/callouts/6.gif create mode 100644 doc/manual/images/callouts/7.gif create mode 100644 doc/manual/images/callouts/8.gif create mode 100644 doc/manual/images/callouts/9.gif diff --git a/.gitignore b/.gitignore index 008f5de8a4..592a8c2392 100644 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,6 @@ Makefile.config /doc/manual/*.1 /doc/manual/*.5 /doc/manual/*.8 -/doc/manual/images /doc/manual/version.txt /doc/manual/release-notes.html diff --git a/doc/manual/images/callouts/1.gif b/doc/manual/images/callouts/1.gif new file mode 100644 index 0000000000000000000000000000000000000000..9e7a87f75461ce41cc91ee68246c7bfb47d37ca3 GIT binary patch literal 889 zcmV-<1BU!ZNk%w1VGIBa0O$Vz000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW0RaC1EC2ui01N;O000P90RIW3lmh~U9GnCyi~#@uf)ov7ENlpX zku!=C88uXL?%qX;j2KcZ^)Vs>iU2s3ba;}YN|XphHhhUuqsx_y{>fxi3!_4aC;>=R P_%9>^1UV=v36ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW0Ra90EC2ui01N;O000Pn0R0K%lmi2V9E=1i%mD!d00b!@#8`-+ zR;?7?dYzM!!e6Nn@BUe=1z?Uh0F0D8bXLpS8~`!?g^1x00Ly!00ATo+13^ue?{bFV z2|%UITFwXo$ng(Dj8XuOGO`ANk~5V4ascSX2|}-X)?#!Ns5RIspO!hirf Dy0E(c literal 0 HcmV?d00001 diff --git a/doc/manual/images/callouts/11.gif b/doc/manual/images/callouts/11.gif new file mode 100644 index 0000000000000000000000000000000000000000..67f91a239d66d622f8d254539b6fd580efa42b02 GIT binary patch literal 202 zcmZ?wbhEHb%*^WQ z>bADF{{H^y)2Gj!J9p8dMeEkB+q`-6jvYIW9656K?Ac3~F5SL;`|;z)Z{EE5@ZrP1 zfB*i&fZ|UUMn(pC1|5)1AUhdY-5;oT-OT9fVPH5?qIP(rnuCecF;(8lY%CHJA0|%J x(XwN3776fTXisr6DR7$1b@7l?>`pt$t64n;p&ZEvzI<6|A|t-7MudsM8UU#vRD1vc literal 0 HcmV?d00001 diff --git a/doc/manual/images/callouts/12.gif b/doc/manual/images/callouts/12.gif new file mode 100644 index 0000000000000000000000000000000000000000..54c4b42f1901629a81924c2f0f59338104adeedd GIT binary patch literal 210 zcmZ?wbhEHb(-#rlzKzo}S5*C(oKSYw6OZn>TOXy?ghOBS+4hIdl8=?Z=NFfBN+4-@kwVQGw!5 z7Dh$}c?KP@O+Y&tSp6TUNBM5@Ncv^za9iq?NB~b`s?Q`L(SI(T+y_1#WZ*J!SfIpc y)1^D>K$0MX%p%4Hwu?TqL@qKHD9DJsXySU9#jCf<|A~QyiNVJ`b^kdT8LR=FrC4|X literal 0 HcmV?d00001 diff --git a/doc/manual/images/callouts/13.gif b/doc/manual/images/callouts/13.gif new file mode 100644 index 0000000000000000000000000000000000000000..dd5d7d9b6439affca376bcd60785d528a24ce425 GIT binary patch literal 209 zcmZ?wbhEHbB&V9x4V*B03xgoIf)x xP}6;KaKZ)#6?t!lhL!-83*8xv4m?aeZ4A@2c0{pEJ&`E!gwv|=H~A1 z?x|C!&Y3f3>C&Z}Hf`Fwcki)d$4;F(b@l4iTeogKe*F0D+qWM-e*E|E-+v6C_>+Z^ zkwKn82V@h-P6k%52kLdAD!mz@3~xRxVRG8g@v!IkBvpn+%|^iofu1ZH;zuVO=~9sr r<5W2yU@F+%-l|kl%h$jrvB98Ei)orw&!RI?aaY=tCf$Ck$Y2cs9-Uok literal 0 HcmV?d00001 diff --git a/doc/manual/images/callouts/15.gif b/doc/manual/images/callouts/15.gif new file mode 100644 index 0000000000000000000000000000000000000000..1c9183d5bb619eb608a5b7543f042ae7fd18684b GIT binary patch literal 210 zcmZ?wbhEHbi7h7121rhDKRRXS|PKBUy%7g1c%!6qXjM*TZ@!<7MXS&a1%XU+t06ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW0RaC1EC2ui01N;O000PR0RIW3lmh~U9GnCyi~#^ZiVzKBECdk3 z+PQbeAOMias9`B<6z_Eez=$EqJq^9piin`0%NY0OG(^zSrIK^CY9cU6@*c{UBiGy; h6C(zOhK&9(6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW0Ra90EC2ui01N;O000PY0R0K1lmh~U9GnCyi~#^ajvNR8#8?Ob zf;Vg4oI#N2j}ZU>bIu`v@NdmWMhq*as95r2jEElrv^r-ECIXlrbBwuXvSCUs9sxM3 o+a%2oj3IhTFJI8abOaK4? literal 0 HcmV?d00001 diff --git a/doc/manual/images/callouts/4.gif b/doc/manual/images/callouts/4.gif new file mode 100644 index 0000000000000000000000000000000000000000..4bcbf7e31a17497e65fa0ccc9756961130be6ac7 GIT binary patch literal 907 zcmV;619bdHNk%w1VGIBa0O$Vz000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW0Ra90EC2ui01N;O000PR0R0JUB_%})C8Y!^R05!33J3slENlos z$-g-bCAOjn;oL=vlo&Q_Rq7qahA}WS)N&5Oy^{bCs0?8;#XUwUV=^4`uV>FvD1lN0 h@RA}Ue>sMFTjNk+(xCuSC=|#k1_T5#jtUG206WA?slNaK literal 0 HcmV?d00001 diff --git a/doc/manual/images/callouts/5.gif b/doc/manual/images/callouts/5.gif new file mode 100644 index 0000000000000000000000000000000000000000..1c62b4f920936c063c93d8551158a80500dfefbe GIT binary patch literal 916 zcmV;F18e+8Nk%w1VGIBa0O$Vz000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW0Ra90EC2ui01N;O000Pa0R0K%lmi2V9E=1i%z+?9iV!If#8?O* z$G>+Nl>kWLuM~ia{}6l}$w(u}R?Y~C1P}wmM~j4%oa6KnflB}(2z_MquBJ%{T0T-b q_c4Y?mj9H5@J4B;zZ@S4y}MTm!bXY!5Uk{=&>tm+5)%px2mm_@=(0fo literal 0 HcmV?d00001 diff --git a/doc/manual/images/callouts/6.gif b/doc/manual/images/callouts/6.gif new file mode 100644 index 0000000000000000000000000000000000000000..23bc5555d2a467d6c3025d7f334a2b5546bd4fd9 GIT binary patch literal 218 zcmZ?wbhEHbqb0L)3{T$ zGFay|aIp&P&{^Zgxx_WmLz?s!{{N9Xg1xktx)&MH` BUFZM+ literal 0 HcmV?d00001 diff --git a/doc/manual/images/callouts/7.gif b/doc/manual/images/callouts/7.gif new file mode 100644 index 0000000000000000000000000000000000000000..e55ce89585a8d5f80cc1a83df537578983a4d8e5 GIT binary patch literal 907 zcmV;619bdHNk%w1VGIBa0O$Vz000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW0Ra90EC2ui01N;O000PR0R0K9B_%})C9MQ1lmY=mLkJLZDAWR= z)xV4XtO1DOuNQ!iA2FPx2!IkvkhMI1%n<`504eucencSiqqSNt5uD8NPm0SJI6pGF hhrlHxe@Z^q3i>gHLLn}jDip{m2Lc2sjtUG206SSyt84%O literal 0 HcmV?d00001 diff --git a/doc/manual/images/callouts/8.gif b/doc/manual/images/callouts/8.gif new file mode 100644 index 0000000000000000000000000000000000000000..49375e09f4cc6397837fbb494c6c3cb1bca7091b GIT binary patch literal 918 zcmV;H18Mw6Nk%w1VGIBa0O$Vz000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW0Ra90EC2ui01N;O000Pc0R0JUB_%}&DWwD|R0041gb)pLC=}AL zls9X=AOMKruT(=N_cWfH(~uHF0760{c(%ZJL2W6v;Y7A literal 0 HcmV?d00001 diff --git a/doc/manual/images/callouts/9.gif b/doc/manual/images/callouts/9.gif new file mode 100644 index 0000000000000000000000000000000000000000..da12a4fe2825716c78f2d23c2f87afde98d3dd3e GIT binary patch literal 923 zcmV;M17!S1Nk%w1VGIBa0O$Vz000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW0Ra90EC2ui01N;O000Ph0R0JUB_%}&DXj!56aoMM1PBdtC{zLf zK`U$LN=5Y7s^J`O2r%5!(vT8G0Hrztu%;0}4h#+VfE3xQVaSFMdc8Y$u9i)PHW47O xMyX+pmO}1@Q1UNFLq`6b0%-N`-I|6e6vnXG5I_uX3jI-v0Rce_r~(5506VSIvSt7P literal 0 HcmV?d00001 diff --git a/doc/manual/local.mk b/doc/manual/local.mk index 0e583b281c..953a4d437a 100644 --- a/doc/manual/local.mk +++ b/doc/manual/local.mk @@ -60,7 +60,7 @@ $(foreach file, $(d)/manual.html $(d)/style.css, $(eval $(call install-data-in, $(foreach file, $(wildcard $(d)/figures/*.png), $(eval $(call install-data-in, $(file), $(docdir)/manual/figures))) -$(foreach file, $(wildcard $(docbookxsl)/images/callouts/*.gif), $(eval $(call install-data-in, $(file), $(docdir)/manual/images/callouts))) +$(foreach file, $(wildcard $(d)/images/callouts/*.gif), $(eval $(call install-data-in, $(file), $(docdir)/manual/images/callouts))) $(eval $(call install-symlink, manual.html, $(docdir)/manual/index.html)) diff --git a/doc/manual/release-notes.xml b/doc/manual/release-notes.xml index 0cf61977e7..53195924c8 100644 --- a/doc/manual/release-notes.xml +++ b/doc/manual/release-notes.xml @@ -7,7 +7,7 @@ -
Release 1.7 (April 8, 2014) +
Release 1.7 (April 9, 2014) In addition to the usual bug fixes, this release has the following new features: From 924e19341a5ee488634bc9ce1ea9758ac496afc3 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 10 Apr 2014 23:42:48 +0200 Subject: [PATCH 34/61] Don't barf when installing as root --- doc/manual/release-notes.xml | 2 +- scripts/install-nix-from-closure.sh | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/manual/release-notes.xml b/doc/manual/release-notes.xml index 53195924c8..fd5061cc01 100644 --- a/doc/manual/release-notes.xml +++ b/doc/manual/release-notes.xml @@ -7,7 +7,7 @@ -
Release 1.7 (April 9, 2014) +
Release 1.7 (April 11, 2014) In addition to the usual bug fixes, this release has the following new features: diff --git a/scripts/install-nix-from-closure.sh b/scripts/install-nix-from-closure.sh index 33ceeb37e2..5770c73661 100644 --- a/scripts/install-nix-from-closure.sh +++ b/scripts/install-nix-from-closure.sh @@ -18,7 +18,6 @@ fi if [ "$(id -u)" -eq 0 ]; then echo "warning: installing Nix as root is not recommended" >&2 - exit 1 fi echo "performing a single-user installation of Nix..." >&2 From 742933116fd803afbf8c36dbc1eab51612d4bb55 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 11 Apr 2014 11:15:24 +0200 Subject: [PATCH 35/61] Bump version to 1.8 --- version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version b/version index 7c483e8f4f..4684374946 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.7 \ No newline at end of file +1.8 \ No newline at end of file From a1917208c025e0a029cb33bbf3cf69e4d4128a39 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 11 Apr 2014 15:11:28 +0200 Subject: [PATCH 36/61] Bump date --- doc/manual/manual.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/manual.xml b/doc/manual/manual.xml index 4d518e31e6..6593d13987 100644 --- a/doc/manual/manual.xml +++ b/doc/manual/manual.xml @@ -19,11 +19,11 @@ - 2004-2013 + 2004-2014 Eelco Dolstra - July 2013 + April 2014 From fb5d76b89e8b0084fb147d79af5481e09b889386 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 15 Apr 2014 15:32:27 +0200 Subject: [PATCH 37/61] Fix test evaluation --- tests/nix-copy-closure.nix | 6 +++--- tests/remote-builds.nix | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/nix-copy-closure.nix b/tests/nix-copy-closure.nix index 66c19a45d4..bfd708404d 100644 --- a/tests/nix-copy-closure.nix +++ b/tests/nix-copy-closure.nix @@ -4,14 +4,14 @@ with import { inherit system; }; -makeTest ({ pkgs, ... }: let pkgA = pkgs.aterm; pkgB = pkgs.wget; in { +makeTest (let pkgA = pkgs.aterm; pkgB = pkgs.wget; in { nodes = { client = { config, pkgs, ... }: { virtualisation.writableStore = true; virtualisation.pathsInNixDB = [ pkgA ]; - environment.nix = nix; + nix.package = nix; }; server = @@ -19,7 +19,7 @@ makeTest ({ pkgs, ... }: let pkgA = pkgs.aterm; pkgB = pkgs.wget; in { { services.openssh.enable = true; virtualisation.writableStore = true; virtualisation.pathsInNixDB = [ pkgB ]; - environment.nix = nix; + nix.package = nix; }; }; diff --git a/tests/remote-builds.nix b/tests/remote-builds.nix index 56514e1749..571cdfbdd2 100644 --- a/tests/remote-builds.nix +++ b/tests/remote-builds.nix @@ -4,7 +4,7 @@ with import { inherit system; }; -makeTest ({ pkgs, ... }: +makeTest ( let @@ -57,7 +57,7 @@ in ]; virtualisation.writableStore = true; virtualisation.pathsInNixDB = [ config.system.build.extraUtils ]; - environment.nix = nix; + nix.package = nix; }; }; From 700c678c2eed5e05c3e68d722c41c2b37d0a2f45 Mon Sep 17 00:00:00 2001 From: "Ricardo M. Correia" Date: Fri, 11 Apr 2014 17:10:20 +0200 Subject: [PATCH 38/61] nix-env: Minor change to '--delete-generations Nd' semantics The option '--delete-generations Nd' deletes all generations older than N days. However, most likely the user does not want to delete the generation that was active N days ago. For example, say that you have these 3 generations: 1: <30 days ago> 2: <15 days ago> 3: <1 hour ago> If you do --delete-generations 7d (say, as part of a cron job), most likely you still want to keep generation 2, i.e. the generation that was active 7 days ago (and for most of the past 7 days, in fact). This patch fixes this issue. Note that this also affects 'nix-collect-garbage --delete-older-than Nd'. Thanks to @roconnor for noticing the issue! --- doc/manual/nix-collect-garbage.xml | 5 +++-- doc/manual/nix-env.xml | 3 ++- src/nix-env/nix-env.cc | 14 ++++++++++---- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/doc/manual/nix-collect-garbage.xml b/doc/manual/nix-collect-garbage.xml index a97e3b7c6b..cf870740f4 100644 --- a/doc/manual/nix-collect-garbage.xml +++ b/doc/manual/nix-collect-garbage.xml @@ -45,8 +45,9 @@ which deletes all old generations of all profiles in impossible); and period, where period is a value such as 30d, which deletes -all non-current generations that are older than the specified number of -days in all profiles in /nix/var/nix/profiles. +all generations older than the specified number of days in all profiles +in /nix/var/nix/profiles (except for the generations +that were active at that point in time). diff --git a/doc/manual/nix-env.xml b/doc/manual/nix-env.xml index 3bfcb15dba..c440208034 100644 --- a/doc/manual/nix-env.xml +++ b/doc/manual/nix-env.xml @@ -1170,7 +1170,8 @@ $ nix-env --list-generations profile. The generations can be a list of generation numbers, the special value old to delete all non-current generations, or a value such as 30d to delete all -non-current generations older than the specified number of days. +generations older than the specified number of days (except for the +generation that was active at that point in time). Periodically deleting old generations is important to make garbage collection effective. diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 8a80526347..3db84ff5c7 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1315,11 +1315,17 @@ static void opDeleteGenerations(Globals & globals, oldTime = curTime - days * 24 * 3600; - for (Generations::iterator j = gens.begin(); j != gens.end(); ++j) { - if (j->number == curGen) continue; - - if (j->creationTime < oldTime) + bool canDelete = false; + for (Generations::reverse_iterator j = gens.rbegin(); j != gens.rend(); ++j) { + if (canDelete) { + assert(j->creationTime < oldTime); deleteGeneration2(globals, j->number); + } else if (j->creationTime < oldTime) { + /* We may now start deleting generations, but we don't delete + this generation yet, because this generation was still the + one that was active at the requested point in time. */ + canDelete = true; + } } } else { int n; From 31fe55bb8e599702ac79b24b2109199be50a85a1 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 25 Apr 2014 14:55:13 +0200 Subject: [PATCH 39/61] trunk -> master --- doc/manual/installation.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/installation.xml b/doc/manual/installation.xml index 3e7ffc5373..a714091060 100644 --- a/doc/manual/installation.xml +++ b/doc/manual/installation.xml @@ -69,7 +69,7 @@ Debian, Ubuntu, Mac OS X and various other systems from the Nix homepage. You can also get builds of the latest development release from our continuous +xlink:href="http://hydra.nixos.org/job/nix/master/release/latest-finished#tabs-constituents">continuous build system. For Fedora, RPM packages are available. These can be installed @@ -197,7 +197,7 @@ a source distribution. downloaded from the Nix homepage. You can also grab the most +xlink:href="http://hydra.nixos.org/job/nix/master/release/latest-finished#tabs-constituents">most recent development release. Alternatively, the most recent sources of Nix can be obtained From eeffdb74dcdbd64bcdc44cff4e587b59c4f807b5 Mon Sep 17 00:00:00 2001 From: Charles Strahan Date: Sun, 27 Apr 2014 14:07:50 -0400 Subject: [PATCH 40/61] doc fix: swap 'import' and 'export' --- doc/manual/nix-store.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/nix-store.xml b/doc/manual/nix-store.xml index 416438a0bd..87cbc307a9 100644 --- a/doc/manual/nix-store.xml +++ b/doc/manual/nix-store.xml @@ -1060,9 +1060,9 @@ command. Description -The operation reads a serialisation of +The operation reads a serialisation of a set of store paths produced by nix-store --import from +linkend="refsec-nix-store-export">nix-store --export from standard input and adds those store paths to the Nix store. Paths that already exist in the Nix store are ignored. If a path refers to another path that doesn’t exist in the Nix store, the import From ada3e3fa15bc14aebb2bafd1240c15cf1fd99351 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 2 May 2014 12:46:03 +0200 Subject: [PATCH 41/61] When running as root, use build users by default This removes the need to have a nix.conf, and prevents people from accidentally running Nix builds as root. --- src/libstore/globals.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 86fa56739c..c359367bba 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -40,6 +40,7 @@ Settings::Settings() useSQLiteWAL = true; syncBeforeRegistering = false; useSubstitutes = true; + buildUsersGroup = getuid() == 0 ? "nixbld" : ""; useChroot = false; useSshSubstituter = false; impersonateLinux26 = false; From de4cdd0d47adc70a4db12397a42c18ee50b4e662 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 2 May 2014 12:51:43 +0200 Subject: [PATCH 42/61] Set build-max-jobs to the number of available cores by default More zero configuration. --- src/libstore/globals.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index c359367bba..739199d48e 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -5,6 +5,7 @@ #include #include +#include namespace nix { @@ -29,6 +30,10 @@ Settings::Settings() buildVerbosity = lvlError; maxBuildJobs = 1; buildCores = 1; +#ifdef _SC_NPROCESSORS_ONLN + long res = sysconf(_SC_NPROCESSORS_ONLN); + if (res > 0) buildCores = res; +#endif readOnlyMode = false; thisSystem = SYSTEM; maxSilentTime = 0; From 20668b136329da92be7c63e7f7c4918968ff0015 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 2 May 2014 13:14:10 +0200 Subject: [PATCH 43/61] Install an Upstart service --- .gitignore | 1 + Makefile | 1 + misc/upstart/local.mk | 1 + misc/upstart/nix-daemon.conf.in | 5 +++++ 4 files changed, 8 insertions(+) create mode 100644 misc/upstart/local.mk create mode 100644 misc/upstart/nix-daemon.conf.in diff --git a/.gitignore b/.gitignore index 592a8c2392..0a3c979208 100644 --- a/.gitignore +++ b/.gitignore @@ -109,6 +109,7 @@ Makefile.config /misc/systemd/nix-daemon.service /misc/systemd/nix-daemon.socket +/misc/upstart/nix-daemon.conf *.a *.o diff --git a/Makefile b/Makefile index 77f22db9f2..d6c645f0f3 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,7 @@ makefiles = \ scripts/local.mk \ corepkgs/local.mk \ misc/systemd/local.mk \ + misc/upstart/local.mk \ misc/emacs/local.mk \ doc/manual/local.mk \ tests/local.mk diff --git a/misc/upstart/local.mk b/misc/upstart/local.mk new file mode 100644 index 0000000000..249262d4f7 --- /dev/null +++ b/misc/upstart/local.mk @@ -0,0 +1 @@ +$(foreach n, nix-daemon.conf, $(eval $(call install-file-in, $(d)/$(n), $(sysconfdir)/init, 0644))) diff --git a/misc/upstart/nix-daemon.conf.in b/misc/upstart/nix-daemon.conf.in new file mode 100644 index 0000000000..0e806edbd7 --- /dev/null +++ b/misc/upstart/nix-daemon.conf.in @@ -0,0 +1,5 @@ +description "Nix Daemon" +start on filesystem +stop on shutdown +respawn +exec @bindir@/nix-daemon --daemon From 696f960dee35889433adfa6c08a2dbfb6ea0724f Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 2 May 2014 14:31:15 +0200 Subject: [PATCH 44/61] Set up directories and permissions for multi-user install automatically This automatically creates /nix/var/nix/profiles/per-user and sets the permissions/ownership on /nix/store to 1775 and root:nixbld. --- src/libstore/local-store.cc | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 567706d097..5d210ae017 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -20,6 +20,7 @@ #include #include #include +#include #if HAVE_UNSHARE && HAVE_STATVFS && HAVE_SYS_MOUNT_H #include @@ -237,7 +238,7 @@ LocalStore::LocalStore(bool reserveSpace) makeStoreWritable(); createDirs(linksDir = settings.nixStore + "/.links"); Path profilesDir = settings.nixStateDir + "/profiles"; - createDirs(settings.nixStateDir + "/profiles"); + createDirs(profilesDir); createDirs(settings.nixStateDir + "/temproots"); createDirs(settings.nixDBPath); Path gcRootsDir = settings.nixStateDir + "/gcroots"; @@ -246,6 +247,32 @@ LocalStore::LocalStore(bool reserveSpace) createSymlink(profilesDir, gcRootsDir + "/profiles"); } + /* Optionally, create directories and set permissions for a + multi-user install. */ + if (getuid() == 0 && settings.buildUsersGroup != "") { + + Path perUserDir = profilesDir + "/per-user"; + createDirs(perUserDir); + if (chmod(perUserDir.c_str(), 01777) == -1) + throw SysError(format("could not set permissions on `%1%' to 1777") % perUserDir); + + struct group * gr = getgrnam(settings.buildUsersGroup.c_str()); + if (!gr) + throw Error(format("the group `%1%' specified in `build-users-group' does not exist") + % settings.buildUsersGroup); + + struct stat st; + if (stat(settings.nixStore.c_str(), &st)) + throw SysError(format("getting attributes of path `%1%'") % settings.nixStore); + + if (st.st_uid != 0 || st.st_gid != gr->gr_gid || (st.st_mode & ~S_IFMT) != 01775) { + if (chown(settings.nixStore.c_str(), 0, gr->gr_gid) == -1) + throw SysError(format("changing ownership of path `%1%'") % settings.nixStore); + if (chmod(settings.nixStore.c_str(), 01775) == -1) + throw SysError(format("changing permissions on path `%1%'") % settings.nixStore); + } + } + checkStoreNotSymlink(); /* We can't open a SQLite database if the disk is full. Since From a8c31d501185c42de477a7e833af956d68e095c3 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 2 May 2014 14:44:44 +0200 Subject: [PATCH 45/61] Simplify multi-user installation instructions --- doc/manual/installation.xml | 61 ++++++++----------------------------- 1 file changed, 12 insertions(+), 49 deletions(-) diff --git a/doc/manual/installation.xml b/doc/manual/installation.xml index a714091060..423bef5e22 100644 --- a/doc/manual/installation.xml +++ b/doc/manual/installation.xml @@ -308,7 +308,7 @@ a Trojan horse.
Single-user mode - + In single-user mode, all Nix operations that access the database in prefix/var/nix/db or modify the Nix store in @@ -354,58 +354,21 @@ done by root. The build users are the special UIDs under which builds are performed. They should all be members of the -build users group (usually called -nixbld). This group should have no other members. -The build users should not be members of any other group. - -Here is a typical /etc/group definition of -the build users group with 10 build users: - - -nixbld:!:30000:nixbld1,nixbld2,nixbld3,nixbld4,nixbld5,nixbld6,nixbld7,nixbld8,nixbld9,nixbld10 - - -In this example the nixbld group has UID 30000, but -of course it can be anything that doesn’t collide with an existing -group. - -Here is the corresponding part of -/etc/passwd: - - -nixbld1:x:30001:65534:Nix build user 1:/var/empty:/noshell -nixbld2:x:30002:65534:Nix build user 2:/var/empty:/noshell -nixbld3:x:30003:65534:Nix build user 3:/var/empty:/noshell -... -nixbld10:x:30010:65534:Nix build user 10:/var/empty:/noshell - - -The home directory of the build users should not exist or should be an -empty directory to which they do not have write access. - -The build users should have write access to the Nix store, but -they should not have the right to delete files. Thus the Nix store’s -group should be the build users group, and it should have the sticky -bit turned on (like /tmp): +build users group nixbld. +This group should have no other members. The build users should not +be members of any other group. On Linux, you can create the group and +users as follows: -$ chown root.nixbld /nix/store -$ chmod 1775 /nix/store +$ groupadd -r nixbld +$ for n in $(seq 1 10); do useradd -c "Nix build user $n" \ + -d /var/empty -g nixbld -G nixbld -M -N -r -s "$(which nologin)" \ + nixbld$n; done - - -Finally, you should tell Nix to use the build users by -specifying the build users group in the build-users-group -option in the Nix configuration -file (usually /etc/nix/nix.conf): - - -build-users-group = nixbld - - - +This creates 10 build users. There can never be more concurrent builds +than the number of build users, so you may want to increase this if +you expect to do many builds at the same time.
From 6dd10873961d45fd246b48ad82b7f05ad3d4d077 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 2 May 2014 19:02:10 +0200 Subject: [PATCH 46/61] Fix Debian tests These actually run as root in a VM, so they get confused. http://hydra.nixos.org/build/10775854 --- tests/init.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/init.sh b/tests/init.sh index 37480f52bd..5be999e4b1 100644 --- a/tests/init.sh +++ b/tests/init.sh @@ -17,6 +17,7 @@ mkdir "$NIX_DB_DIR" mkdir "$NIX_CONF_DIR" cat > "$NIX_CONF_DIR"/nix.conf < Date: Fri, 2 May 2014 19:04:10 +0200 Subject: [PATCH 47/61] Don't install Upstart job on Fedora Also, don't install a nix.conf anymore, it's not needed. http://hydra.nixos.org/build/10775854 --- nix.spec.in | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/nix.spec.in b/nix.spec.in index 4ec8cfe653..6c7eaadddf 100644 --- a/nix.spec.in +++ b/nix.spec.in @@ -117,10 +117,6 @@ make DESTDIR=$RPM_BUILD_ROOT install find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' -# Specify build users group -mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/nix -echo "build-users-group = %{nixbld_group}" > $RPM_BUILD_ROOT%{_sysconfdir}/nix/nix.conf - # make per-user directories for d in profiles gcroots; do @@ -138,6 +134,9 @@ cp -p misc/emacs/nix-mode.elc $RPM_BUILD_ROOT%{_emacs_sitelispdir}/ # we ship this file in the base package rm -f $RPM_BUILD_ROOT%{_defaultdocdir}/%{name}-doc-%{version}/README +# Get rid of Upstart job. +rm -rf $RPM_BUILD_ROOT%{_sysconfdir}/init + %clean rm -rf $RPM_BUILD_ROOT From 93506e60d2f86079a6db260d376a92773900d0d3 Mon Sep 17 00:00:00 2001 From: Rob Vermaas Date: Sat, 3 May 2014 17:54:48 +0200 Subject: [PATCH 48/61] Add ubuntu 14.04 --- release.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/release.nix b/release.nix index 285b8fb4f4..1279ec3c59 100644 --- a/release.nix +++ b/release.nix @@ -201,6 +201,8 @@ let deb_ubuntu1304x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1304x86_64) 80; deb_ubuntu1310i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1310i386) 90; deb_ubuntu1310x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1310x86_64) 90; + deb_ubuntu1404i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1404i386) 90; + deb_ubuntu1404x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1404x86_64) 90; # System tests. @@ -235,6 +237,8 @@ let deb_ubuntu1304x86_64 deb_ubuntu1310i386 deb_ubuntu1310x86_64 + deb_ubuntu1404i386 + deb_ubuntu1404x86_64 rpm_fedora19i386 rpm_fedora19x86_64 rpm_fedora20i386 From 2c4affbaa88c8bfbee92093f0355b6e118fd5447 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 5 May 2014 20:22:35 +0200 Subject: [PATCH 49/61] Fix RPM build We don't install a nix.conf anymore. http://hydra.nixos.org/build/10826143 --- nix.spec.in | 1 - 1 file changed, 1 deletion(-) diff --git a/nix.spec.in b/nix.spec.in index 6c7eaadddf..b965dde276 100644 --- a/nix.spec.in +++ b/nix.spec.in @@ -179,7 +179,6 @@ systemctl start nix-daemon.socket %config(noreplace) %{_sysconfdir}/profile.d/nix.sh /nix %dir %{_sysconfdir}/nix -%config(noreplace) %{_sysconfdir}/nix/nix.conf %files devel %{_includedir}/nix From aa9b1cf48e6482a74dcc19e6aef1d8236b57abe4 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 6 May 2014 10:51:16 +0200 Subject: [PATCH 50/61] Really fix the RPM builds http://hydra.nixos.org/build/10840199 --- nix.spec.in | 1 - 1 file changed, 1 deletion(-) diff --git a/nix.spec.in b/nix.spec.in index b965dde276..7d7775b87c 100644 --- a/nix.spec.in +++ b/nix.spec.in @@ -178,7 +178,6 @@ systemctl start nix-daemon.socket %{_mandir}/man8/*.8* %config(noreplace) %{_sysconfdir}/profile.d/nix.sh /nix -%dir %{_sysconfdir}/nix %files devel %{_includedir}/nix From a84f503d863fd77de9b6ecf149399c2ca7642b75 Mon Sep 17 00:00:00 2001 From: wmertens Date: Sat, 10 May 2014 15:53:01 +0200 Subject: [PATCH 51/61] Shortcut already-hardlinked files If an inode in the Nix store has more than 1 link, it probably means that it was linked into .links/ by us. If so, skip. There's a possibility that something else hardlinked the file, so it would be nice to be able to override this. Also, by looking at the number of hardlinks for each of the files in .links/, you can get deduplication numbers and space savings. --- src/libstore/optimise-store.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index d833f3aa05..1b81f64078 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -71,6 +71,16 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path) return; } + stats.totalFiles++; + + /* If a store inode has 2 or more links we presume that it was + already linked by us */ + /* TODO: allow overriding this behavior */ + if (st.st_nlink > 1) { + printMsg(lvlDebug, format("`%1%' is already linked, with %2% other file(s).") % path % (st.st_nlink - 2)); + return; + } + /* Hash the file. Note that hashPath() returns the hash over the NAR serialisation, which includes the execute bit on the file. Thus, executable and non-executable files with the same @@ -81,7 +91,6 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path) contents of the symlink (i.e. the result of readlink()), not the contents of the target (which may not even exist). */ Hash hash = hashPath(htSHA256, path).first; - stats.totalFiles++; printMsg(lvlDebug, format("`%1%' has hash `%2%'") % path % printHash(hash)); /* Check if this is a known hash. */ From a55e77ae10a76336728be6fbb0f0d7957422b56a Mon Sep 17 00:00:00 2001 From: Charles Strahan Date: Mon, 12 May 2014 14:31:16 -0400 Subject: [PATCH 52/61] fix typo --- doc/manual/nix-install-package.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/nix-install-package.xml b/doc/manual/nix-install-package.xml index 5a081cd9a6..54a66348f0 100644 --- a/doc/manual/nix-install-package.xml +++ b/doc/manual/nix-install-package.xml @@ -125,7 +125,7 @@ format: NIXPKG1 manifestURL name system drvPath outPath -The elemens are as follows: +The elements are as follows: From 95501c4deea1d945022df18475340232bc6980be Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 13 May 2014 12:54:28 +0200 Subject: [PATCH 53/61] nix-instantiate --eval: Apply auto-arguments if the result is a function Fixes #254. --- src/nix-instantiate/nix-instantiate.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index afd16b3a52..7cdabcb924 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -52,14 +52,19 @@ void processExpr(EvalState & state, const Strings & attrPaths, state.forceValue(v); PathSet context; - if (evalOnly) + if (evalOnly) { + Value vRes; + if (autoArgs.empty()) + vRes = v; + else + state.autoCallFunction(autoArgs, v, vRes); if (xmlOutput) - printValueAsXML(state, strict, location, v, std::cout, context); + printValueAsXML(state, strict, location, vRes, std::cout, context); else { - if (strict) state.strictForceValue(v); - std::cout << v << std::endl; + if (strict) state.strictForceValue(vRes); + std::cout << vRes << std::endl; } - else { + } else { DrvInfos drvs; getDerivations(state, v, "", autoArgs, drvs, false); foreach (DrvInfos::iterator, i, drvs) { From 36662eb5629c31cfd1b8472c9b7eb136b3937a4d Mon Sep 17 00:00:00 2001 From: Ricky Elrod Date: Sun, 11 May 2014 18:57:53 -0400 Subject: [PATCH 54/61] Prepare nix-mode to be uploaded to marmalade Signed-off-by: Ricky Elrod --- misc/emacs/nix-mode.el | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/misc/emacs/nix-mode.el b/misc/emacs/nix-mode.el index 986edcf6e3..2c45d68576 100644 --- a/misc/emacs/nix-mode.el +++ b/misc/emacs/nix-mode.el @@ -1,3 +1,9 @@ +;;; nix-mode.el --- Major mode for editing Nix expressions. + +;; Author: Eelco Dolstra +;; URL: https://github.com/NixOS/nix/tree/master/misc/emacs +;; Version: 1.0 + (defun nix-mode () "Major mode for editing Nix expressions. @@ -21,9 +27,9 @@ The hook `nix-mode-hook' is run when Nix mode is started. " (interactive) - + (kill-all-local-variables) - + (setq major-mode 'nix-mode) (setq mode-name "Nix") @@ -53,9 +59,8 @@ The hook `nix-mode-hook' is run when Nix mode is started. (setq paragraph-start "[ \t]*\\(#+[ \t]*\\)?$") (make-local-variable 'paragraph-separate) (setq paragraph-separate paragraph-start) - - (run-hooks 'nix-mode-hook) - ) + + (run-hooks 'nix-mode-hook)) (defvar nix-mode-map nil @@ -83,8 +88,7 @@ The hook `nix-mode-hook' is run when Nix mode is started. ("<[a-zA-Z0-9._\\+-]+\\(/[a-zA-Z0-9._\\+-]+\\)*>" . font-lock-constant-face) ("[a-zA-Z0-9._\\+-]*\\(/[a-zA-Z0-9._\\+-]+\\)+" - . font-lock-constant-face) - )) + . font-lock-constant-face))) (defvar nix-mode-syntax-table nil @@ -97,8 +101,7 @@ The hook `nix-mode-hook' is run when Nix mode is started. (modify-syntax-entry ?/ ". 14" nix-mode-syntax-table) (modify-syntax-entry ?* ". 23" nix-mode-syntax-table) (modify-syntax-entry ?# "< b" nix-mode-syntax-table) - (modify-syntax-entry ?\n "> b" nix-mode-syntax-table) - )) + (modify-syntax-entry ?\n "> b" nix-mode-syntax-table))) (defun nix-indent-line () @@ -111,3 +114,5 @@ The hook `nix-mode-hook' is run when Nix mode is started. (setq auto-mode-alist (cons '("\\.nix.in\\'" . nix-mode) auto-mode-alist)) (provide 'nix-mode) + +;;; nix-mode.el ends here From e974f20c9811c3efe09cfca9bda7816f9091c0d5 Mon Sep 17 00:00:00 2001 From: Wout Mertens Date: Tue, 13 May 2014 23:10:06 +0200 Subject: [PATCH 55/61] Preload linked hashes to speed up lookups By preloading all inodes in the /nix/store/.links directory, we can quickly determine of a hardlinked file was already linked to the hashed links. This is tolerant of removing the .links directory, it will simply recalculate all hashes in the store. --- src/libstore/local-store.hh | 14 ++++++++++++- src/libstore/optimise-store.cc | 37 +++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 09639e74cf..71229f7a69 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -6,6 +6,11 @@ #include "util.hh" #include "pathlocks.hh" +#if HAVE_TR1_UNORDERED_SET +#include +#endif + + class sqlite3; class sqlite3_stmt; @@ -303,7 +308,14 @@ private: void checkDerivationOutputs(const Path & drvPath, const Derivation & drv); - void optimisePath_(OptimiseStats & stats, const Path & path); +#if HAVE_TR1_UNORDERED_SET + typedef std::tr1::unordered_set Hashes; +#else + typedef std::set Hashes; +#endif + + void loadHashes(Hashes & hashes); + void optimisePath_(OptimiseStats & stats, const Path & path, Hashes & hashes); // Internal versions that are not wrapped in retry_sqlite. bool isValidPath_(const Path & path); diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index 1b81f64078..78174e177e 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -39,8 +39,22 @@ struct MakeReadOnly } }; +// TODO Make this a map and keep count and size stats, for giggles +void LocalStore::loadHashes(Hashes & hashes) +{ + printMsg(lvlDebug, "loading hash inodes in memory"); + Strings names = readDirectory(linksDir); + foreach (Strings::iterator, i, names) { + struct stat st; + string path = linksDir + "/" + *i; + if (lstat(path.c_str(), &st)) + throw SysError(format("getting attributes of path `%1%'") % path); + hashes.insert(st.st_ino); + } + printMsg(lvlDebug, format("loaded %1% hashes") % hashes.size()); +} -void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path) +void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, Hashes & hashes) { checkInterrupt(); @@ -51,7 +65,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path) if (S_ISDIR(st.st_mode)) { Strings names = readDirectory(path); foreach (Strings::iterator, i, names) - optimisePath_(stats, path + "/" + *i); + optimisePath_(stats, path + "/" + *i, hashes); return; } @@ -73,10 +87,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path) stats.totalFiles++; - /* If a store inode has 2 or more links we presume that it was - already linked by us */ - /* TODO: allow overriding this behavior */ - if (st.st_nlink > 1) { + if (st.st_nlink > 1 && hashes.count(st.st_ino)) { printMsg(lvlDebug, format("`%1%' is already linked, with %2% other file(s).") % path % (st.st_nlink - 2)); return; } @@ -98,7 +109,10 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path) if (!pathExists(linkPath)) { /* Nope, create a hard link in the links directory. */ - if (link(path.c_str(), linkPath.c_str()) == 0) return; + if (link(path.c_str(), linkPath.c_str()) == 0) { + hashes.insert(st.st_ino); + return; + } if (errno != EEXIST) throw SysError(format("cannot link `%1%' to `%2%'") % linkPath % path); /* Fall through if another process created ‘linkPath’ before @@ -169,12 +183,15 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path) void LocalStore::optimiseStore(OptimiseStats & stats) { PathSet paths = queryAllValidPaths(); + Hashes hashes; + + loadHashes(hashes); foreach (PathSet::iterator, i, paths) { addTempRoot(*i); if (!isValidPath(*i)) continue; /* path was GC'ed, probably */ startNest(nest, lvlChatty, format("hashing files in `%1%'") % *i); - optimisePath_(stats, *i); + optimisePath_(stats, *i, hashes); } } @@ -182,7 +199,9 @@ void LocalStore::optimiseStore(OptimiseStats & stats) void LocalStore::optimisePath(const Path & path) { OptimiseStats stats; - if (settings.autoOptimiseStore) optimisePath_(stats, path); + Hashes hashes; + + if (settings.autoOptimiseStore) optimisePath_(stats, path, hashes); } From e384e7b387c4745f30032ef431a06aa26cee73a5 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 14 May 2014 22:25:25 +0200 Subject: [PATCH 56/61] Remove redundant code --- local.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local.mk b/local.mk index f27a97cd4f..6361e1872b 100644 --- a/local.mk +++ b/local.mk @@ -1,5 +1,5 @@ ifeq ($(MAKECMDGOALS), dist) - dist-files += $(shell git ls-files) $(shell git ls-files) + dist-files += $(shell git ls-files) endif dist-files += configure config.h.in nix.spec From d73ffc552f78e0d9048e3bcc1e84452d1e8d2ede Mon Sep 17 00:00:00 2001 From: Wout Mertens Date: Wed, 14 May 2014 22:52:10 +0200 Subject: [PATCH 57/61] Use the inodes given by readdir directly --- src/libstore/local-store.hh | 8 +++---- src/libstore/optimise-store.cc | 38 +++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 71229f7a69..b335092a20 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -309,13 +309,13 @@ private: void checkDerivationOutputs(const Path & drvPath, const Derivation & drv); #if HAVE_TR1_UNORDERED_SET - typedef std::tr1::unordered_set Hashes; + typedef std::tr1::unordered_set InodeHash; #else - typedef std::set Hashes; + typedef std::set InodeHash; #endif - void loadHashes(Hashes & hashes); - void optimisePath_(OptimiseStats & stats, const Path & path, Hashes & hashes); + InodeHash loadInodeHash(); + void optimisePath_(OptimiseStats & stats, const Path & path, InodeHash & inodeHash); // Internal versions that are not wrapped in retry_sqlite. bool isValidPath_(const Path & path); diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index 78174e177e..ed41801907 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -39,22 +39,28 @@ struct MakeReadOnly } }; -// TODO Make this a map and keep count and size stats, for giggles -void LocalStore::loadHashes(Hashes & hashes) +LocalStore::InodeHash LocalStore::loadInodeHash() { printMsg(lvlDebug, "loading hash inodes in memory"); - Strings names = readDirectory(linksDir); - foreach (Strings::iterator, i, names) { - struct stat st; - string path = linksDir + "/" + *i; - if (lstat(path.c_str(), &st)) - throw SysError(format("getting attributes of path `%1%'") % path); - hashes.insert(st.st_ino); + InodeHash hashes; + + AutoCloseDir dir = opendir(linksDir.c_str()); + if (!dir) throw SysError(format("opening directory `%1%'") % linksDir); + + struct dirent * dirent; + while (errno = 0, dirent = readdir(dir)) { /* sic */ + checkInterrupt(); + // We don't care if we hit non-hash files, anything goes + hashes.insert(dirent->d_ino); } - printMsg(lvlDebug, format("loaded %1% hashes") % hashes.size()); + if (errno) throw SysError(format("reading directory `%1%'") % linksDir); + + printMsg(lvlInfo, format("loaded %1% hash inodes") % hashes.size()); + + return hashes; } -void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, Hashes & hashes) +void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHash & hashes) { checkInterrupt(); @@ -183,15 +189,13 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, Hashes void LocalStore::optimiseStore(OptimiseStats & stats) { PathSet paths = queryAllValidPaths(); - Hashes hashes; - - loadHashes(hashes); + InodeHash inodeHash = loadInodeHash(); foreach (PathSet::iterator, i, paths) { addTempRoot(*i); if (!isValidPath(*i)) continue; /* path was GC'ed, probably */ startNest(nest, lvlChatty, format("hashing files in `%1%'") % *i); - optimisePath_(stats, *i, hashes); + optimisePath_(stats, *i, inodeHash); } } @@ -199,9 +203,9 @@ void LocalStore::optimiseStore(OptimiseStats & stats) void LocalStore::optimisePath(const Path & path) { OptimiseStats stats; - Hashes hashes; + InodeHash inodeHash; - if (settings.autoOptimiseStore) optimisePath_(stats, path, hashes); + if (settings.autoOptimiseStore) optimisePath_(stats, path, inodeHash); } From 3b9ea8452f102595874826e349fa38f85c00aa39 Mon Sep 17 00:00:00 2001 From: Wout Mertens Date: Thu, 15 May 2014 09:02:22 +0200 Subject: [PATCH 58/61] Shortcut store files before lstat readdir() already returns the inode numbers, so we don't need to call lstat to know if a file was already linked or not. --- src/libstore/local-store.hh | 1 + src/libstore/optimise-store.cc | 45 +++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index b335092a20..487bb711ea 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -315,6 +315,7 @@ private: #endif InodeHash loadInodeHash(); + Strings readDirectoryIgnoringInodes(const Path & path, const InodeHash & inodeHash, OptimiseStats & stats); void optimisePath_(OptimiseStats & stats, const Path & path, InodeHash & inodeHash); // Internal versions that are not wrapped in retry_sqlite. diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index ed41801907..3615bc300a 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -42,7 +42,7 @@ struct MakeReadOnly LocalStore::InodeHash LocalStore::loadInodeHash() { printMsg(lvlDebug, "loading hash inodes in memory"); - InodeHash hashes; + InodeHash inodeHash; AutoCloseDir dir = opendir(linksDir.c_str()); if (!dir) throw SysError(format("opening directory `%1%'") % linksDir); @@ -51,16 +51,42 @@ LocalStore::InodeHash LocalStore::loadInodeHash() while (errno = 0, dirent = readdir(dir)) { /* sic */ checkInterrupt(); // We don't care if we hit non-hash files, anything goes - hashes.insert(dirent->d_ino); + inodeHash.insert(dirent->d_ino); } if (errno) throw SysError(format("reading directory `%1%'") % linksDir); - printMsg(lvlInfo, format("loaded %1% hash inodes") % hashes.size()); + printMsg(lvlInfo, format("loaded %1% hash inodes") % inodeHash.size()); - return hashes; + return inodeHash; } -void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHash & hashes) +Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHash & inodeHash, OptimiseStats & stats) +{ + Strings names; + + AutoCloseDir dir = opendir(path.c_str()); + if (!dir) throw SysError(format("opening directory `%1%'") % path); + + struct dirent * dirent; + while (errno = 0, dirent = readdir(dir)) { /* sic */ + checkInterrupt(); + + if (inodeHash.count(dirent->d_ino)) { + printMsg(lvlDebug, format("`%1%' is already linked") % dirent->d_name); + stats.totalFiles++; + continue; + } + + string name = dirent->d_name; + if (name == "." || name == "..") continue; + names.push_back(name); + } + if (errno) throw SysError(format("reading directory `%1%'") % path); + + return names; +} + +void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHash & inodeHash) { checkInterrupt(); @@ -69,9 +95,9 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa throw SysError(format("getting attributes of path `%1%'") % path); if (S_ISDIR(st.st_mode)) { - Strings names = readDirectory(path); + Strings names = readDirectoryIgnoringInodes(path, inodeHash, stats); foreach (Strings::iterator, i, names) - optimisePath_(stats, path + "/" + *i, hashes); + optimisePath_(stats, path + "/" + *i, inodeHash); return; } @@ -93,7 +119,8 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa stats.totalFiles++; - if (st.st_nlink > 1 && hashes.count(st.st_ino)) { + /* This can still happen on top-level files */ + if (st.st_nlink > 1 && inodeHash.count(st.st_ino)) { printMsg(lvlDebug, format("`%1%' is already linked, with %2% other file(s).") % path % (st.st_nlink - 2)); return; } @@ -116,7 +143,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa if (!pathExists(linkPath)) { /* Nope, create a hard link in the links directory. */ if (link(path.c_str(), linkPath.c_str()) == 0) { - hashes.insert(st.st_ino); + inodeHash.insert(st.st_ino); return; } if (errno != EEXIST) From 690adeb03de039551c4d8b5b4e7dda21c9c8f9b9 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 15 May 2014 11:19:16 +0200 Subject: [PATCH 59/61] Remove tab --- src/libstore/optimise-store.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index 3615bc300a..39b9e587a4 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -89,7 +89,7 @@ Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHa void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHash & inodeHash) { checkInterrupt(); - + struct stat st; if (lstat(path.c_str(), &st)) throw SysError(format("getting attributes of path `%1%'") % path); @@ -145,7 +145,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa if (link(path.c_str(), linkPath.c_str()) == 0) { inodeHash.insert(st.st_ino); return; - } + } if (errno != EEXIST) throw SysError(format("cannot link `%1%' to `%2%'") % linkPath % path); /* Fall through if another process created ‘linkPath’ before From 84813af5b938246d9a4a785dfb08b86383ef62ae Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 15 May 2014 11:33:46 +0200 Subject: [PATCH 60/61] nix-store --optimise: Remove bogus statistics --- src/libstore/local-store.hh | 6 ++---- src/libstore/optimise-store.cc | 11 +++++------ src/nix-store/nix-store.cc | 6 ++---- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 487bb711ea..54331e448a 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -34,14 +34,12 @@ struct Derivation; struct OptimiseStats { - unsigned long totalFiles; - unsigned long sameContents; unsigned long filesLinked; unsigned long long bytesFreed; unsigned long long blocksFreed; OptimiseStats() { - totalFiles = sameContents = filesLinked = 0; + filesLinked = 0; bytesFreed = blocksFreed = 0; } }; @@ -315,7 +313,7 @@ private: #endif InodeHash loadInodeHash(); - Strings readDirectoryIgnoringInodes(const Path & path, const InodeHash & inodeHash, OptimiseStats & stats); + Strings readDirectoryIgnoringInodes(const Path & path, const InodeHash & inodeHash); void optimisePath_(OptimiseStats & stats, const Path & path, InodeHash & inodeHash); // Internal versions that are not wrapped in retry_sqlite. diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index 39b9e587a4..e43dbf31a8 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -39,6 +39,7 @@ struct MakeReadOnly } }; + LocalStore::InodeHash LocalStore::loadInodeHash() { printMsg(lvlDebug, "loading hash inodes in memory"); @@ -60,7 +61,8 @@ LocalStore::InodeHash LocalStore::loadInodeHash() return inodeHash; } -Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHash & inodeHash, OptimiseStats & stats) + +Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHash & inodeHash) { Strings names; @@ -73,7 +75,6 @@ Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHa if (inodeHash.count(dirent->d_ino)) { printMsg(lvlDebug, format("`%1%' is already linked") % dirent->d_name); - stats.totalFiles++; continue; } @@ -86,6 +87,7 @@ Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHa return names; } + void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHash & inodeHash) { checkInterrupt(); @@ -95,7 +97,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa throw SysError(format("getting attributes of path `%1%'") % path); if (S_ISDIR(st.st_mode)) { - Strings names = readDirectoryIgnoringInodes(path, inodeHash, stats); + Strings names = readDirectoryIgnoringInodes(path, inodeHash); foreach (Strings::iterator, i, names) optimisePath_(stats, path + "/" + *i, inodeHash); return; @@ -117,8 +119,6 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa return; } - stats.totalFiles++; - /* This can still happen on top-level files */ if (st.st_nlink > 1 && inodeHash.count(st.st_ino)) { printMsg(lvlDebug, format("`%1%' is already linked, with %2% other file(s).") % path % (st.st_nlink - 2)); @@ -158,7 +158,6 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa if (lstat(linkPath.c_str(), &stLink)) throw SysError(format("getting attributes of path `%1%'") % linkPath); - stats.sameContents++; if (st.st_ino == stLink.st_ino) { printMsg(lvlDebug, format("`%1%' is already linked to `%2%'") % path % linkPath); return; diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index 341a4f6776..5da401c77f 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -801,11 +801,9 @@ static void opRepairPath(Strings opFlags, Strings opArgs) static void showOptimiseStats(OptimiseStats & stats) { printMsg(lvlError, - format("%1% freed by hard-linking %2% files; there are %3% files with equal contents out of %4% files in total") + format("%1% freed by hard-linking %2% files") % showBytes(stats.bytesFreed) - % stats.filesLinked - % stats.sameContents - % stats.totalFiles); + % stats.filesLinked); } From 8d5f472f2c49c79a0d3ae2e506f4d4d76224b328 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 15 May 2014 11:37:44 +0200 Subject: [PATCH 61/61] lvlInfo -> lvlTalkative --- src/libstore/optimise-store.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index e43dbf31a8..67ee94a4bd 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -56,7 +56,7 @@ LocalStore::InodeHash LocalStore::loadInodeHash() } if (errno) throw SysError(format("reading directory `%1%'") % linksDir); - printMsg(lvlInfo, format("loaded %1% hash inodes") % inodeHash.size()); + printMsg(lvlTalkative, format("loaded %1% hash inodes") % inodeHash.size()); return inodeHash; }