changeset 652:3e6f43ab7e22

mod_inotify_reload: Reload modules when their code changes
author Matthew Wild <mwild1@gmail.com>
date Sun, 29 Apr 2012 16:57:21 +0100
parents 78a23a7dc613
children c08b0e4b7b38
files mod_inotify_reload/mod_inotify_reload.lua
diffstat 1 files changed, 85 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_inotify_reload/mod_inotify_reload.lua	Sun Apr 29 16:57:21 2012 +0100
@@ -0,0 +1,85 @@
+-- mod_inotify_reload
+-- Reloads modules when their files change
+-- Depends on linotify: https://github.com/hoelzro/linotify
+
+module:set_global();
+
+local inotify = require "inotify";
+local modulemanager = require "core.modulemanager";
+
+local inh = inotify.init();
+
+local watches = {};
+local watch_ids = {};
+
+-- Fake socket object around inotify
+local inh_conn = {
+	getfd = function () return inh:fileno(); end;
+	dirty = function (self) return false; end;
+	settimeout = function () end;
+	send = function (_, d) return #d, 0; end;
+	close = function () end;
+	receive = function ()
+		local events = inh:read();
+		for _, event in ipairs(events) do
+			local mod = watches[watch_ids[event.wd]];
+			if mod then
+				local host, name = mod.host, mod.name;
+				module:log("debug", "Reloading changed module mod_%s on %s", name, host);
+				modulemanager.reload(host, name);
+			else
+				module:log("warn", "no watch for %d", event.wd);
+			end
+		end
+		return "";
+	end
+};
+require "net.server".wrapclient(inh_conn, "inotify", inh:fileno(), {
+	onincoming = function () end, ondisconnect = function () end
+}, "*a");
+
+function watch_module(name, host, path)
+	local id, err = inh:addwatch(path, inotify.IN_CLOSE_WRITE);
+	if not id then return nil, err; end
+	local k = host.."\0"..name;
+	watches[k] = { id = id, path = path, name = name, host = host };
+	watch_ids[id] = k;
+	return true;
+end
+
+function unwatch_module(name, host)
+	local k = host.."\0"..name;
+	if not watches[k] then
+		return nil, "not-watching";
+	end
+	local id = watches[k].id;
+	local ok, err = inh:rmwatch(id);
+	watches[k] = nil;
+	watch_ids[id] = nil;
+	return ok, err;
+end
+
+function module_loaded(event)
+	local host, name = event.host, event.module;
+	local path = modulemanager.get_module(host, name).module.path;
+	if not path then
+		module:log("warn", "Couldn't watch mod_%s, no path", name);
+		return;
+	end
+	if watch_module(name, host, path) then
+		module:log("debug", "Watching mod_%s", name);
+	end
+end
+
+function module_unloaded(event)
+	unwatch_module(event.module, event.host);
+end
+
+function module.add_host(module)
+	module:hook("module-loaded", module_loaded);
+	module:hook("module-unloaded", module_unloaded);
+end
+
+module:hook("module-loaded", module_loaded);
+module:hook("module-unloaded", module_unloaded);
+