monotone-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Monotone-devel] [Patch] mtn automate lua


From: Thomas Keller
Subject: [Monotone-devel] [Patch] mtn automate lua
Date: Sat, 06 Dec 2008 01:59:06 +0100
User-agent: Thunderbird 2.0.0.18 (Macintosh/20081105)

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

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]