It took me some time (and I've learned quite a lot about lua and its C
interface), but especially with the help of the lua community I was
able
to build a general "automate lua" command which lets you call lua
hooks
over automate just as monotone would call them!
Now, what is this good for? Basically, its great for getting the
user's
or system's defaults, like keys, passwords, and many other settings.
My
main purpose was to find out in an elegant way if a certain unknown
file
(path) should be ignored without having to call automate inventory
(which does not recurse into unknown directories anyways) and without
having to implement an "automate ls unknown" or "automate ls ignored"
command just for that purpose. With the new API all I have to do is
net.venge.monotone$ mtn automate lua ignore_file "tester"
[1] = true;
net.venge.monotone$
and voila, there is my result. You can put arbitrary arguments to a
function call (also complex values, encoded in lua syntax) and you
retrieve a string with an arbitrary complex value, like f.e.
[1] = {
["bla"] = {
["foo"] = <function>;
};
[true] = false;
[3,3] = nil;
["foo"] = 3;
};
Functions, userdata, thread and other things which don't make sense in
this string output are enclosed into <> brackets.
So I'd like to include this in mainline (tests and documentation
will be
added, of course) if other people find this useful as well and are ok
with the implementation.
I'm still a bit undecided when it comes to security constraints, like
should a couple of hooks be disabled (i.e. should I maintain a list of
"supported" hooks) or should I just leave this out into the wild as
is?
If people write their passwords into local files I guess its not much
more insecure if I allow a script or program to retrieve this password
through automate; in the end with some clever parsing the user's
monotonerc file could be read as well for this purpose.
However, this might be a completly different cup of tea if we open /
use
the automation interface for networking - of course we do not want to
allow anybody even with write access to a database being able to
retrieve any kind of the local password. Maybe we then need to
introduce
some kind of marking for each automate command, like
"secure_for_local_use" vs. "secure_for_foreign_use" and check if
automate stdio is connected to a socket? I don't know, this is just my
simple understanding... I'm open for other ideas ;)
So long,
Thomas.
--
GPG-Key 0x160D1092 | address@hidden | http://
thomaskeller.biz
Please note that according to the EU law on data retention,
information
on every electronic information exchange might be retained for a
period
of six months or longer: http://www.vorratsdatenspeicherung.de/?
lang=en
#
# old_revision [76251b1a907280f580f3a934fdcb9177a4824729]
#
# patch "automate.cc"
# from [598a04952daffa804d60dde204967b20e17fc37a]
# to [881288755ce94308be92ab8c9e73491640b6a4d2]
#
# patch "lua_hooks.cc"
# from [0476cf2512e471ca31d9a3b185968487fbeb9e8e]
# to [af8016e477fd39f14de53b4c17e16eacb2692bf4]
#
# patch "lua_hooks.hh"
# from [eb7235af2f81fcce2921725bfd150df2ba3bfc65]
# to [a5ac6a6139a2672c9e8d16bb97162ac849179dda]
#
# patch "std_hooks.lua"
# from [c4f02c95a5717f64d0a60251081ff5bd1a8038de]
# to [602ac070879bb429d902af61e65bcf652857af90]
#
============================================================
--- automate.cc 598a04952daffa804d60dde204967b20e17fc37a
+++ automate.cc 881288755ce94308be92ab8c9e73491640b6a4d2
@@ -2276,6 +2276,35 @@ CMD_AUTOMATE(get_workspace_root, "",
output << get_current_working_dir() << '\n';
}
+CMD_AUTOMATE(lua, "LUA_FUNCTION [ARG1 [ARG2 [...]]]",
+ N_("Executes the given lua function and returns the
result"),
+ "",
+ options::opts::none)
+{
+ N(args.size() >= 1,
+ F("wrong argument count"));
+
+ std::string func = idx(args, 0)();
+
+ N(app.lua.hook_exists(func),
+ F("lua function '%s' does not exist") % func);
+
+ std::vector<std::string> func_args;
+ if (args.size() > 1)
+ {
+ for (unsigned int i=1; i<args.size(); i++)
+ {
+ func_args.push_back(idx(args, i)());
+ }
+ }
+
+ std::string out;
+ N(app.lua.hook_hook_wrapper(func, func_args, out),
+ F("lua call '%s' failed") % func);
+
+ output << out << '\n';
+}
+
// Local Variables:
// mode: C++
// fill-column: 76
============================================================
--- lua_hooks.cc 0476cf2512e471ca31d9a3b185968487fbeb9e8e
+++ lua_hooks.cc af8016e477fd39f14de53b4c17e16eacb2692bf4
@@ -594,6 +594,29 @@ lua_hooks::hook_get_default_command_opti
return ll.ok() && !args.empty();
}
+bool lua_hooks::hook_hook_wrapper(std::string const & func_name,
+ std::vector<std::string> const &
args,
+ std::string & out)
+{
+ Lua ll(st);
+ ll.func("hook_wrapper")
+ .push_str(func_name)
+ .push_table();
+
+ int k=0;
+ for (std::vector<std::string>::const_iterator i = args.begin();
+ i != args.end(); ++i)
+ {
+ ll.push_int(++k)
+ .push_str(*i)
+ .set_table();
+ }
+
+ ll.call(2, 1);
+ ll.extract_str_nolog(out);
+ return ll.ok();
+}
+
bool
lua_hooks::hook_use_inodeprints()
{
============================================================
--- lua_hooks.hh eb7235af2f81fcce2921725bfd150df2ba3bfc65
+++ lua_hooks.hh a5ac6a6139a2672c9e8d16bb97162ac849179dda
@@ -138,6 +138,11 @@ public:
bool & validated,
std::string & reason);
+ // meta hooks
+ bool hook_hook_wrapper(std::string const & func_name,
+ std::vector<std::string> const & args,
+ std::string & out);
+
// notification hooks
bool hook_note_commit(revision_id const & new_id,
revision_data const & rdat,
============================================================
--- std_hooks.lua c4f02c95a5717f64d0a60251081ff5bd1a8038de
+++ std_hooks.lua 602ac070879bb429d902af61e65bcf652857af90
@@ -1157,7 +1157,50 @@ end
return default_args
end
+dump = {}
+dump.depth = 0
+dump._string = function(s) return string.format("%q", s) end
+dump._number = function(n) return tonumber(n) end
+dump._boolean = function(b) if (b) then return "true" end
return "false" end
+dump._userdata = function(u) return "<userdata>" end
+dump._function = function(f) return "<function>" end
+dump._nil = function(n) return "nil" end
+dump._thread = function(t) return "<thread>" end
+dump._lightuserdata = function(l) return "<lightuserdata>" end
+dump._table = function(t)
+ local buf = ''
+ if (dump.depth > 0) then
+ buf = buf .. '{\n'
+ end
+ dump.depth = dump.depth + 1;
+ for k,v in pairs(t) do
+ buf = buf..string.format('%s[%s] = %s;\n',
+ string.rep("\t", dump.depth - 1),
+ dump["_" .. type(k)](k),
+ dump["_" .. type(v)](v))
+ end
+ dump.depth = dump.depth - 1;
+ if (dump.depth > 0) then
+ buf = buf .. string.rep("\t", dump.depth - 1) .. '}'
+ end
+ return buf
+end
+
+function hook_wrapper(func_name, ...)
+ -- evaluate each single string argument to resolve types
+ -- like nil's, table's and others - the select('#', ...) syntax
is
+ -- borrowed from http://lua-users.org/wiki/StoringNilsInTables to
+ -- let this code properly work for nil arguments as well
+ local args = {n=select('#',...), ...}
+ for i=2,args.n do
+ args[i] = assert(loadstring("return " .. args[i]))()
+ end
+ local res = { _G[func_name](unpack(unpack(args, 1, args.n))) }
+ return dump._table(res)
+end
+
+
function get_remote_unix_socket_command(host)
return "socat"
end
_______________________________________________
Monotone-devel mailing list
address@hidden
http://lists.nongnu.org/mailman/listinfo/monotone-devel