This adds a small module for examining parts of a commit
from inside a lua interpreter. Eventually you'll be able to
do grep-like filtering and --pretty formatting.

The most naive presentation would be to parse the whole
commit and put it in a lua table. However, instead we build
upon the incremental parsing used by the --format parser,
and lazily parse bits of the commit as the lua code requests
them.

Signed-off-by: Jeff King <p...@peff.net>
---
Set "USE_LUA" in your Makefile to turn it on.

 Makefile     |   7 +++
 lua-commit.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lua-commit.h |   9 ++++
 3 files changed, 182 insertions(+)
 create mode 100644 lua-commit.c
 create mode 100644 lua-commit.h

diff --git a/Makefile b/Makefile
index a49d1db..54473e2 100644
--- a/Makefile
+++ b/Makefile
@@ -636,6 +636,7 @@ LIB_H += log-tree.h
 LIB_H += list-objects.h
 LIB_H += ll-merge.h
 LIB_H += log-tree.h
+LIB_H += lua-commit.h
 LIB_H += mailmap.h
 LIB_H += merge-file.h
 LIB_H += merge-recursive.h
@@ -749,6 +750,7 @@ LIB_OBJS += log-tree.o
 LIB_OBJS += ll-merge.o
 LIB_OBJS += lockfile.o
 LIB_OBJS += log-tree.o
+LIB_OBJS += lua-commit.o
 LIB_OBJS += mailmap.o
 LIB_OBJS += match-trees.o
 LIB_OBJS += merge-file.o
@@ -1818,6 +1820,11 @@ endif
        COMPAT_OBJS += compat/nedmalloc/nedmalloc.o
 endif
 
+ifdef USE_LUA
+       BASIC_CFLAGS += -DUSE_LUA `pkg-config --cflags lua5.2`
+       EXTLIBS += `pkg-config --libs lua5.2`
+endif
+
 ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT
        export GIT_TEST_CMP_USE_COPIED_CONTEXT
 endif
diff --git a/lua-commit.c b/lua-commit.c
new file mode 100644
index 0000000..ce1eeeb
--- /dev/null
+++ b/lua-commit.c
@@ -0,0 +1,166 @@
+#include "cache.h"
+#include "lua-commit.h"
+#include "commit.h"
+
+#ifndef USE_LUA
+
+static const char msg[] = "git was built without lua support";
+
+void lua_commit_init(const char *)
+{
+       die(msg);
+}
+
+void lua_commit_format(struct strbuf *,
+                      struct format_commit_context *)
+{
+       die(msg);
+}
+
+#else
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+static lua_State *lua;
+
+/* XXX
+ * We need to access this from functions called from inside lua. Probably it
+ * would be cleaner use a lua "register" to let each function access it, but I
+ * haven't looked into it.
+ */
+static struct format_commit_context *c;
+
+static int lua_fun_hash(lua_State *lua)
+{
+       lua_pushstring(lua, sha1_to_hex(c->commit->object.sha1));
+       return 1;
+}
+
+static int lua_fun_abbrev(lua_State *lua)
+{
+       const char *hex;
+       unsigned char sha1[20];
+
+       hex = lua_tostring(lua, -1);
+       if (!hex || get_sha1_hex(hex, sha1)) {
+               lua_pushstring(lua, "abbrev requires a sha1");
+               lua_error(lua);
+       }
+
+       lua_pushstring(lua, find_unique_abbrev(sha1, c->pretty_ctx->abbrev));
+       return 1;
+}
+
+static int get_ident(lua_State *lua, const char *line, int len)
+{
+       struct ident_split s;
+
+       if (split_ident_line(&s, line, len) < 0) {
+               lua_pushstring(lua, "unable to parse ident line");
+               lua_error(lua);
+       }
+
+       lua_createtable(lua, 0, 2);
+       lua_pushstring(lua, "name");
+       lua_pushlstring(lua, s.name_begin, s.name_end - s.name_begin);
+       lua_settable(lua, -3);
+       lua_pushstring(lua, "email");
+       lua_pushlstring(lua, s.mail_begin, s.mail_end - s.mail_begin);
+       lua_settable(lua, -3);
+
+       /* XXX should also put date in the table */
+
+       return 1;
+}
+
+static int lua_fun_author(lua_State *lua)
+{
+       if (!c->commit_header_parsed)
+               parse_commit_header(c);
+       return get_ident(lua, c->message + c->author.off, c->author.len);
+}
+
+static int lua_fun_committer(lua_State *lua)
+{
+       if (!c->commit_header_parsed)
+               parse_commit_header(c);
+       return get_ident(lua, c->message + c->committer.off, c->committer.len);
+}
+
+static int lua_fun_message(lua_State *lua)
+{
+       lua_pushstring(lua, c->message + c->message_off + 1);
+       return 1;
+}
+
+static int lua_fun_subject(lua_State *lua)
+{
+       struct strbuf tmp = STRBUF_INIT;
+
+       if (!c->commit_header_parsed)
+               parse_commit_header(c);
+       if (!c->commit_message_parsed)
+               parse_commit_message(c);
+
+       format_subject(&tmp, c->message + c->subject_off, " ");
+       lua_pushlstring(lua, tmp.buf, tmp.len);
+       return 1;
+}
+
+static int lua_fun_body(lua_State *lua)
+{
+       if (!c->commit_header_parsed)
+               parse_commit_header(c);
+       if (!c->commit_message_parsed)
+               parse_commit_message(c);
+
+       lua_pushstring(lua, c->message + c->body_off);
+       return 1;
+}
+
+void lua_commit_init(const char *snippet)
+{
+       if (!lua) {
+               lua = luaL_newstate();
+               if (!lua)
+                       die("unable to open lua interpreter");
+               luaL_openlibs(lua);
+
+#define REG(name) do { \
+       lua_pushcfunction(lua, lua_fun_##name); \
+       lua_setglobal(lua, #name); \
+} while(0)
+
+               REG(hash);
+               REG(abbrev);
+               REG(author);
+               REG(committer);
+               REG(message);
+               REG(subject);
+               REG(body);
+       }
+
+       if (luaL_loadstring(lua, snippet))
+               die("unable to load lua snippet: %s", snippet);
+}
+
+void lua_commit_format(struct strbuf *out,
+                      struct format_commit_context *context)
+{
+       const char *ret;
+       size_t len;
+
+       c = context;
+
+       lua_pushvalue(lua, -1);
+       if (lua_pcall(lua, 0, 1, 0))
+               die("lua failed: %s", lua_tostring(lua, -1));
+
+       ret = lua_tolstring(lua, -1, &len);
+       strbuf_add(out, ret, len);
+       lua_pop(lua, 1);
+}
+
+#endif /* USE_LUA */
diff --git a/lua-commit.h b/lua-commit.h
new file mode 100644
index 0000000..aaffced
--- /dev/null
+++ b/lua-commit.h
@@ -0,0 +1,9 @@
+#ifndef LUA_COMMIT_H
+#define LUA_COMMIT_H
+
+struct format_commit_context;
+
+void lua_commit_init(const char *snippet);
+void lua_commit_format(struct strbuf *out, struct format_commit_context 
*context);
+
+#endif
-- 
1.7.12.1.10.g6537447

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to