Merge branch 'plugins' of https://github.com/shlevy/nix
This commit is contained in:
		
						commit
						1c10a74c73
					
				
					 24 changed files with 122 additions and 3 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -38,6 +38,7 @@ perl/Makefile.config | ||||||
| /scripts/nix-copy-closure | /scripts/nix-copy-closure | ||||||
| /scripts/nix-reduce-build | /scripts/nix-reduce-build | ||||||
| /scripts/nix-http-export.cgi | /scripts/nix-http-export.cgi | ||||||
|  | /scripts/nix-profile-daemon.sh | ||||||
| 
 | 
 | ||||||
| # /src/libexpr/ | # /src/libexpr/ | ||||||
| /src/libexpr/lexer-tab.cc | /src/libexpr/lexer-tab.cc | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -24,7 +24,8 @@ makefiles = \ | ||||||
|   misc/launchd/local.mk \
 |   misc/launchd/local.mk \
 | ||||||
|   misc/upstart/local.mk \
 |   misc/upstart/local.mk \
 | ||||||
|   doc/manual/local.mk \
 |   doc/manual/local.mk \
 | ||||||
|   tests/local.mk |   tests/local.mk \
 | ||||||
|  |   tests/plugins/local.mk | ||||||
| 
 | 
 | ||||||
| GLOBAL_CXXFLAGS += -std=c++14 -g -Wall -include config.h | GLOBAL_CXXFLAGS += -std=c++14 -g -Wall -include config.h | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -742,6 +742,33 @@ builtins.fetchurl { | ||||||
|   </varlistentry> |   </varlistentry> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |   <varlistentry xml:id="conf-plugin-files"> | ||||||
|  |     <term><literal>plugin-files</literal></term> | ||||||
|  |     <listitem> | ||||||
|  |       <para> | ||||||
|  |         A list of plugin files to be loaded by Nix. Each of these | ||||||
|  |         files will be dlopened by Nix, allowing them to affect | ||||||
|  |         execution through static initialization. In particular, these | ||||||
|  |         plugins may construct static instances of RegisterPrimOp to | ||||||
|  |         add new primops to the expression language, | ||||||
|  |         RegisterStoreImplementation to add new store implementations, | ||||||
|  |         and RegisterCommand to add new subcommands to the | ||||||
|  |         <literal>nix</literal> command. See the constructors for those | ||||||
|  |         types for more details. | ||||||
|  |       </para> | ||||||
|  |       <para> | ||||||
|  | 	Since these files are loaded into the same address space as | ||||||
|  |         Nix itself, they must be DSOs compatible with the instance of | ||||||
|  |         Nix running at the time (i.e. compiled against the same | ||||||
|  |         headers, not linked to any incompatible libraries). They | ||||||
|  |         should not be linked to any Nix libs directly, as those will | ||||||
|  |         be available already at load time. | ||||||
|  |       </para> | ||||||
|  |     </listitem> | ||||||
|  | 
 | ||||||
|  |   </varlistentry> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| </variablelist> | </variablelist> | ||||||
| 
 | 
 | ||||||
| </para> | </para> | ||||||
|  |  | ||||||
|  | @ -389,6 +389,13 @@ configureFlags = "--prefix=${placeholder "out"} --includedir=${placeholder "dev" | ||||||
|     </para> |     </para> | ||||||
|   </listitem> |   </listitem> | ||||||
| 
 | 
 | ||||||
|  |   <listitem> | ||||||
|  |     <para> | ||||||
|  |       Nix can now be extended with plugins. See the documentation of | ||||||
|  |       the 'plugin-files' option for more details. | ||||||
|  |     </para> | ||||||
|  |   </listitem> | ||||||
|  | 
 | ||||||
| </itemizedlist> | </itemizedlist> | ||||||
| 
 | 
 | ||||||
| <para>Some features were removed:</para> | <para>Some features were removed:</para> | ||||||
|  |  | ||||||
|  | @ -45,6 +45,11 @@ endif | ||||||
| # - $(1)_INSTALL_DIR: the directory where the library will be
 | # - $(1)_INSTALL_DIR: the directory where the library will be
 | ||||||
| #   installed.  Defaults to $(libdir).
 | #   installed.  Defaults to $(libdir).
 | ||||||
| #
 | #
 | ||||||
|  | # - $(1)_EXCLUDE_FROM_LIBRARY_LIST: if defined, the library will not
 | ||||||
|  | #   be automatically marked as a dependency of the top-level all
 | ||||||
|  | #   target andwill not be listed in the make help output. This is
 | ||||||
|  | #   useful for libraries built solely for testing, for example.
 | ||||||
|  | #
 | ||||||
| # - BUILD_SHARED_LIBS: if equal to ‘1’, a dynamic library will be
 | # - BUILD_SHARED_LIBS: if equal to ‘1’, a dynamic library will be
 | ||||||
| #   built, otherwise a static library.
 | #   built, otherwise a static library.
 | ||||||
| define build-library | define build-library | ||||||
|  | @ -149,7 +154,9 @@ define build-library | ||||||
|   $(1)_DEPS := $$(foreach fn, $$($(1)_OBJS), $$(call filename-to-dep, $$(fn))) |   $(1)_DEPS := $$(foreach fn, $$($(1)_OBJS), $$(call filename-to-dep, $$(fn))) | ||||||
|   -include $$($(1)_DEPS) |   -include $$($(1)_DEPS) | ||||||
| 
 | 
 | ||||||
|  |   ifndef $(1)_EXCLUDE_FROM_LIBRARY_LIST | ||||||
|   libs-list += $$($(1)_PATH) |   libs-list += $$($(1)_PATH) | ||||||
|  |   endif | ||||||
|   clean-files += $$(_d)/*.a $$(_d)/*.$(SO_EXT) $$(_d)/*.o $$(_d)/.*.dep $$($(1)_DEPS) $$($(1)_OBJS) |   clean-files += $$(_d)/*.a $$(_d)/*.$(SO_EXT) $$(_d)/*.o $$(_d)/.*.dep $$($(1)_DEPS) $$($(1)_OBJS) | ||||||
|   dist-files += $$(_srcs) |   dist-files += $$(_srcs) | ||||||
| endef | endef | ||||||
|  |  | ||||||
|  | @ -64,6 +64,8 @@ int main (int argc, char * * argv) | ||||||
| 
 | 
 | ||||||
|         settings.maxBuildJobs.set("1"); // hack to make tests with local?root= work
 |         settings.maxBuildJobs.set("1"); // hack to make tests with local?root= work
 | ||||||
| 
 | 
 | ||||||
|  |         initPlugins(); | ||||||
|  | 
 | ||||||
|         auto store = openStore().cast<LocalStore>(); |         auto store = openStore().cast<LocalStore>(); | ||||||
| 
 | 
 | ||||||
|         /* It would be more appropriate to use $XDG_RUNTIME_DIR, since
 |         /* It would be more appropriate to use $XDG_RUNTIME_DIR, since
 | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ public: | ||||||
| 
 | 
 | ||||||
| int handleExceptions(const string & programName, std::function<void()> fun); | int handleExceptions(const string & programName, std::function<void()> fun); | ||||||
| 
 | 
 | ||||||
|  | /* Don't forget to call initPlugins() after settings are initialized! */ | ||||||
| void initNix(); | void initNix(); | ||||||
| 
 | 
 | ||||||
| void parseCmdLine(int argc, char * * argv, | void parseCmdLine(int argc, char * * argv, | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <map> | #include <map> | ||||||
| #include <thread> | #include <thread> | ||||||
|  | #include <dlfcn.h> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| namespace nix { | namespace nix { | ||||||
|  | @ -137,4 +138,18 @@ void MaxBuildJobsSetting::set(const std::string & str) | ||||||
|         throw UsageError("configuration setting '%s' should be 'auto' or an integer", name); |         throw UsageError("configuration setting '%s' should be 'auto' or an integer", name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | void initPlugins() | ||||||
|  | { | ||||||
|  |     for (const auto & pluginFile : settings.pluginFiles.get()) { | ||||||
|  |         /* handle is purposefully leaked as there may be state in the
 | ||||||
|  |            DSO needed by the action of the plugin. */ | ||||||
|  |         void *handle = | ||||||
|  |             dlopen(pluginFile.c_str(), RTLD_LAZY | RTLD_LOCAL); | ||||||
|  |         if (!handle) | ||||||
|  |             throw Error(format("could not dynamically open plugin file '%1%': %2%") % pluginFile % dlerror()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -367,12 +367,19 @@ public: | ||||||
| 
 | 
 | ||||||
|     Setting<Strings> allowedUris{this, {}, "allowed-uris", |     Setting<Strings> allowedUris{this, {}, "allowed-uris", | ||||||
|         "Prefixes of URIs that builtin functions such as fetchurl and fetchGit are allowed to fetch."}; |         "Prefixes of URIs that builtin functions such as fetchurl and fetchGit are allowed to fetch."}; | ||||||
|  | 
 | ||||||
|  |     Setting<Paths> pluginFiles{this, {}, "plugin-files", | ||||||
|  |         "Plugins to dynamically load at nix initialization time."}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // FIXME: don't use a global variable.
 | // FIXME: don't use a global variable.
 | ||||||
| extern Settings settings; | extern Settings settings; | ||||||
| 
 | 
 | ||||||
|  | /* This should be called after settings are initialized, but before
 | ||||||
|  |    anything else */ | ||||||
|  | void initPlugins(); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| extern const string nixVersion; | extern const string nixVersion; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -9,6 +9,9 @@ libstore_SOURCES := $(wildcard $(d)/*.cc) | ||||||
| libstore_LIBS = libutil libformat | libstore_LIBS = libutil libformat | ||||||
| 
 | 
 | ||||||
| libstore_LDFLAGS = $(SQLITE3_LIBS) -lbz2 $(LIBCURL_LIBS) $(SODIUM_LIBS) -pthread | libstore_LDFLAGS = $(SQLITE3_LIBS) -lbz2 $(LIBCURL_LIBS) $(SODIUM_LIBS) -pthread | ||||||
|  | ifneq ($(OS), FreeBSD) | ||||||
|  |  libstore_LDFLAGS += -ldl | ||||||
|  | endif | ||||||
| 
 | 
 | ||||||
| libstore_FILES = sandbox-defaults.sb sandbox-minimal.sb sandbox-network.sb | libstore_FILES = sandbox-defaults.sb sandbox-minimal.sb sandbox-network.sb | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -232,6 +232,8 @@ void mainWrapped(int argc, char * * argv) | ||||||
| 
 | 
 | ||||||
|     myArgs.parseCmdline(args); |     myArgs.parseCmdline(args); | ||||||
| 
 | 
 | ||||||
|  |     initPlugins(); | ||||||
|  | 
 | ||||||
|     if (packages && fromArgs) |     if (packages && fromArgs) | ||||||
|         throw UsageError("'-p' and '-E' are mutually exclusive"); |         throw UsageError("'-p' and '-E' are mutually exclusive"); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -213,6 +213,9 @@ int main(int argc, char ** argv) | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|  | 
 | ||||||
|  |         initPlugins(); | ||||||
|  | 
 | ||||||
|         switch (cmd) { |         switch (cmd) { | ||||||
|             case cNone: |             case cNone: | ||||||
|                 throw UsageError("no command specified"); |                 throw UsageError("no command specified"); | ||||||
|  |  | ||||||
|  | @ -77,6 +77,8 @@ int main(int argc, char * * argv) | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|  |         initPlugins(); | ||||||
|  | 
 | ||||||
|         auto profilesDir = settings.nixStateDir + "/profiles"; |         auto profilesDir = settings.nixStateDir + "/profiles"; | ||||||
|         if (removeOld) removeOldGenerations(profilesDir); |         if (removeOld) removeOldGenerations(profilesDir); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -44,6 +44,8 @@ int main(int argc, char ** argv) | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|  |         initPlugins(); | ||||||
|  | 
 | ||||||
|         if (sshHost.empty()) |         if (sshHost.empty()) | ||||||
|             throw UsageError("no host name specified"); |             throw UsageError("no host name specified"); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1060,6 +1060,8 @@ int main(int argc, char * * argv) | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|  |         initPlugins(); | ||||||
|  | 
 | ||||||
|         if (stdio) { |         if (stdio) { | ||||||
|             if (getStoreType() == tDaemon) { |             if (getStoreType() == tDaemon) { | ||||||
|                 /* Forward on this connection to the real daemon */ |                 /* Forward on this connection to the real daemon */ | ||||||
|  |  | ||||||
|  | @ -1393,6 +1393,8 @@ int main(int argc, char * * argv) | ||||||
| 
 | 
 | ||||||
|         myArgs.parseCmdline(argvToStrings(argc, argv)); |         myArgs.parseCmdline(argvToStrings(argc, argv)); | ||||||
| 
 | 
 | ||||||
|  |         initPlugins(); | ||||||
|  | 
 | ||||||
|         if (!op) throw UsageError("no operation specified"); |         if (!op) throw UsageError("no operation specified"); | ||||||
| 
 | 
 | ||||||
|         auto store = openStore(); |         auto store = openStore(); | ||||||
|  |  | ||||||
|  | @ -151,6 +151,8 @@ int main(int argc, char * * argv) | ||||||
| 
 | 
 | ||||||
|         myArgs.parseCmdline(argvToStrings(argc, argv)); |         myArgs.parseCmdline(argvToStrings(argc, argv)); | ||||||
| 
 | 
 | ||||||
|  |         initPlugins(); | ||||||
|  | 
 | ||||||
|         if (evalOnly && !wantsReadWrite) |         if (evalOnly && !wantsReadWrite) | ||||||
|             settings.readOnlyMode = true; |             settings.readOnlyMode = true; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -89,6 +89,8 @@ int main(int argc, char * * argv) | ||||||
| 
 | 
 | ||||||
|         myArgs.parseCmdline(argvToStrings(argc, argv)); |         myArgs.parseCmdline(argvToStrings(argc, argv)); | ||||||
| 
 | 
 | ||||||
|  |         initPlugins(); | ||||||
|  | 
 | ||||||
|         if (args.size() > 2) |         if (args.size() > 2) | ||||||
|             throw UsageError("too many arguments"); |             throw UsageError("too many arguments"); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1052,6 +1052,8 @@ int main(int argc, char * * argv) | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|  |         initPlugins(); | ||||||
|  | 
 | ||||||
|         if (!op) throw UsageError("no operation specified"); |         if (!op) throw UsageError("no operation specified"); | ||||||
| 
 | 
 | ||||||
|         if (op != opDump && op != opRestore) /* !!! hack */ |         if (op != opDump && op != opRestore) /* !!! hack */ | ||||||
|  |  | ||||||
|  | @ -92,6 +92,8 @@ void mainWrapped(int argc, char * * argv) | ||||||
| 
 | 
 | ||||||
|     args.parseCmdline(argvToStrings(argc, argv)); |     args.parseCmdline(argvToStrings(argc, argv)); | ||||||
| 
 | 
 | ||||||
|  |     initPlugins(); | ||||||
|  | 
 | ||||||
|     if (!args.command) args.showHelpAndExit(); |     if (!args.command) args.showHelpAndExit(); | ||||||
| 
 | 
 | ||||||
|     Finally f([]() { stopProgressBar(); }); |     Finally f([]() { stopProgressBar(); }); | ||||||
|  |  | ||||||
|  | @ -22,7 +22,8 @@ nix_tests = \ | ||||||
|   run.sh \
 |   run.sh \
 | ||||||
|   brotli.sh \
 |   brotli.sh \
 | ||||||
|   pure-eval.sh \
 |   pure-eval.sh \
 | ||||||
|   check.sh |   check.sh \
 | ||||||
|  |   plugins.sh | ||||||
|   # parallel.sh |   # parallel.sh | ||||||
| 
 | 
 | ||||||
| install-tests += $(foreach x, $(nix_tests), tests/$(x)) | install-tests += $(foreach x, $(nix_tests), tests/$(x)) | ||||||
|  | @ -31,4 +32,4 @@ tests-environment = NIX_REMOTE= $(bash) -e | ||||||
| 
 | 
 | ||||||
| clean-files += $(d)/common.sh | clean-files += $(d)/common.sh | ||||||
| 
 | 
 | ||||||
| installcheck: $(d)/common.sh | installcheck: $(d)/common.sh $(d)/plugins/plugintest.so | ||||||
|  |  | ||||||
							
								
								
									
										7
									
								
								tests/plugins.sh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/plugins.sh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | ||||||
|  | source common.sh | ||||||
|  | 
 | ||||||
|  | set -o pipefail | ||||||
|  | 
 | ||||||
|  | res=$(nix eval '(builtins.constNull true)' --option plugin-files $PWD/plugins/plugintest.so) | ||||||
|  | 
 | ||||||
|  | [ "$res"x = "nullx" ] | ||||||
							
								
								
									
										9
									
								
								tests/plugins/local.mk
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/plugins/local.mk
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | libraries += plugintest | ||||||
|  | 
 | ||||||
|  | plugintest_DIR := $(d) | ||||||
|  | 
 | ||||||
|  | plugintest_SOURCES := $(d)/plugintest.cc | ||||||
|  | 
 | ||||||
|  | plugintest_ALLOW_UNDEFINED := 1 | ||||||
|  | 
 | ||||||
|  | plugintest_EXCLUDE_FROM_LIBRARY_LIST := 1 | ||||||
							
								
								
									
										10
									
								
								tests/plugins/plugintest.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								tests/plugins/plugintest.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | #include "primops.hh" | ||||||
|  | 
 | ||||||
|  | using namespace nix; | ||||||
|  | 
 | ||||||
|  | static void prim_constNull (EvalState & state, const Pos & pos, Value ** args, Value & v) | ||||||
|  | { | ||||||
|  |     mkNull(v); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static RegisterPrimOp r("constNull", 1, prim_constNull); | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue