monotone

monotone Mtn Source Tree

Root/lua.cc

1// -*- mode: C++; c-file-style: "gnu"; indent-tabs-mode: nil -*-
2// copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>
3// all rights reserved.
4// licensed to the public under the terms of the GNU GPL (>= 2)
5// see the file COPYING for details
6
7#include "config.h"
8
9extern "C" {
10#include <lua.h>
11#include <lualib.h>
12#include <lauxlib.h>
13}
14
15#include <errno.h>
16#include <stdlib.h>
17#include <string.h>
18#include <stdarg.h>
19#include <signal.h>
20#include <boost/lexical_cast.hpp>
21#include <boost/filesystem/path.hpp>
22#include <boost/filesystem/operations.hpp>
23#include <boost/regex.hpp>
24
25#include <set>
26#include <map>
27#include <fstream>
28
29#include "app_state.hh"
30#include "file_io.hh"
31#include "lua.hh"
32#include "mkstemp.hh"
33#include "sanity.hh"
34#include "vocab.hh"
35#include "platform.hh"
36#include "transforms.hh"
37#include "paths.hh"
38#include "globish.hh"
39#include "basic_io.hh"
40
41// defined in {std,test}_hooks.lua, converted
42#include "test_hooks.h"
43#include "std_hooks.h"
44
45using namespace std;
46using boost::lexical_cast;
47
48// this lets the lua callbacks (monotone_*_for_lua) have access to the
49// app_state the're associated with.
50// it was added so that the confdir (normally ~/.monotone) can be specified on
51// the command line (and so known only to the app_state), and still be
52// available to lua
53// please *don't* use it for complex things that can throw errors
54static std::map<lua_State*, app_state*> map_of_lua_to_app;
55
56static int panic_thrower(lua_State * st)
57{
58 throw oops("lua panic");
59}
60
61// adapted from "programming in lua", section 24.2.3
62// http://www.lua.org/pil/24.2.3.html
63// output is from bottom (least accessible) to top (most accessible, where
64// push and pop happen).
65static std::string
66dump_stack(lua_State * st)
67{
68 std::string out;
69 int i;
70 int top = lua_gettop(st);
71 for (i = 1; i <= top; i++) { /* repeat for each level */
72 int t = lua_type(st, i);
73 switch (t) {
74 case LUA_TSTRING: /* strings */
75 out += (boost::format("`%s'") % std::string(lua_tostring(st, i), lua_strlen(st, i))).str();
76 break;
77
78 case LUA_TBOOLEAN: /* booleans */
79 out += (lua_toboolean(st, i) ? "true" : "false");
80 break;
81
82 case LUA_TNUMBER: /* numbers */
83 out += (boost::format("%g") % lua_tonumber(st, i)).str();
84 break;
85
86 default: /* other values */
87 out += (boost::format("%s") % lua_typename(st, t)).str();
88 break;
89
90 }
91 out += " "; /* put a separator */
92 }
93 return out;
94}
95
96// This Lua object represents a single imperative transaction with the lua
97// interpreter. if it fails at any point, all further commands in the
98// transaction are ignored. it cleans the lua stack up when it is
99// destructed, so no need to pop values when you're done.
100
101struct
102Lua
103{
104 lua_State * st;
105 bool failed;
106 static std::set<string> missing_functions;
107
108 Lua(lua_State * s) :
109 st(s), failed(false)
110 {}
111
112 ~Lua()
113 {
114 lua_settop(st, 0);
115 }
116
117 void fail(std::string const & reason)
118 {
119 L(F("lua failure: %s; stack = %s\n") % reason % dump_stack(st));
120 failed = true;
121 }
122
123 bool ok()
124 {
125 if (failed)
126 L(F("Lua::ok(): failed"));
127 return !failed;
128 }
129
130 void report_error()
131 {
132 I(lua_isstring(st, -1));
133 string err = string(lua_tostring(st, -1), lua_strlen(st, -1));
134 W(boost::format("%s\n") % err);
135 L(F("lua stack: %s") % dump_stack(st));
136 lua_pop(st, 1);
137 failed = true;
138 }
139
140 // getters
141
142 Lua & get(int idx = LUA_GLOBALSINDEX)
143 {
144 if (failed) return *this;
145 if (!lua_istable (st, idx))
146 {
147 fail("istable() in get");
148 return *this;
149 }
150 if (lua_gettop (st) < 1)
151 {
152 fail("stack top > 0 in get");
153 return *this;
154 }
155 lua_gettable(st, idx);
156 return *this;
157 }
158
159 Lua & get_fn(int idx = LUA_GLOBALSINDEX)
160 {
161 if (failed) return *this;
162 get(idx);
163 if (!lua_isfunction (st, -1))
164 fail("isfunction() in get_fn");
165 return *this;
166 }
167
168 Lua & get_tab(int idx = LUA_GLOBALSINDEX)
169 {
170 if (failed) return *this;
171 get(idx);
172 if (!lua_istable (st, -1))
173 fail("istable() in get_tab");
174 return *this;
175 }
176
177 Lua & get_str(int idx = LUA_GLOBALSINDEX)
178 {
179 if (failed) return *this;
180 get(idx);
181 if (!lua_isstring (st, -1))
182 fail("isstring() in get_str");
183 return *this;
184 }
185
186 Lua & get_num(int idx = LUA_GLOBALSINDEX)
187 {
188 if (failed) return *this;
189 get(idx);
190 if (!lua_isnumber (st, -1))
191 fail("isnumber() in get_num");
192 return *this;
193 }
194
195 Lua & get_bool(int idx = LUA_GLOBALSINDEX)
196 {
197 if (failed) return *this;
198 get(idx);
199 if (!lua_isboolean (st, -1))
200 fail("isboolean() in get_bool");
201 return *this;
202 }
203
204 // extractors
205
206 Lua & extract_str(string & str)
207 {
208 if (failed) return *this;
209 if (!lua_isstring (st, -1))
210 {
211 fail("isstring() in extract_str");
212 return *this;
213 }
214 str = string(lua_tostring(st, -1), lua_strlen(st, -1));
215 L(F("lua: extracted string = %s") % str);
216 return *this;
217 }
218
219 Lua & extract_int(int & i)
220 {
221 if (failed) return *this;
222 if (!lua_isnumber (st, -1))
223 {
224 fail("isnumber() in extract_int");
225 return *this;
226 }
227 i = static_cast<int>(lua_tonumber(st, -1));
228 L(F("lua: extracted int = %i") % i);
229 return *this;
230 }
231
232 Lua & extract_double(double & i)
233 {
234 if (failed) return *this;
235 if (!lua_isnumber (st, -1))
236 {
237 fail("isnumber() in extract_double");
238 return *this;
239 }
240 i = lua_tonumber(st, -1);
241 L(F("lua: extracted double = %i") % i);
242 return *this;
243 }
244
245
246 Lua & extract_bool(bool & i)
247 {
248 if (failed) return *this;
249 if (!lua_isboolean (st, -1))
250 {
251 fail("isboolean() in extract_bool");
252 return *this;
253 }
254 i = (lua_toboolean(st, -1) == 1);
255 L(F("lua: extracted bool = %i") % i);
256 return *this;
257 }
258
259
260 // table iteration
261
262 Lua & begin()
263 {
264 if (failed) return *this;
265 if (!lua_istable(st, -1))
266 {
267 fail("istable() in begin");
268 return *this;
269 }
270 I(lua_checkstack (st, 1));
271 lua_pushnil(st);
272 return *this;
273 }
274
275 bool next()
276 {
277 if (failed) return false;
278 if (!lua_istable(st, -2))
279 {
280 fail("istable() in next");
281 return false;
282 }
283 I(lua_checkstack (st, 1));
284 if (lua_next(st, -2) != 0)
285 {
286 return true;
287 }
288 pop();
289 return false;
290 }
291
292 // pushers
293
294 Lua & push_str(string const & str)
295 {
296 if (failed) return *this;
297 I(lua_checkstack (st, 1));
298 lua_pushlstring(st, str.c_str(), str.size());
299 return *this;
300 }
301
302 Lua & push_int(int num)
303 {
304 if (failed) return *this;
305 I(lua_checkstack (st, 1));
306 lua_pushnumber(st, num);
307 return *this;
308 }
309
310 Lua & push_int(double num)
311 {
312 if (failed) return *this;
313 I(lua_checkstack (st, 1));
314 lua_pushnumber(st, num);
315 return *this;
316 }
317
318 Lua & push_bool(bool b)
319 {
320 if (failed) return *this;
321 I(lua_checkstack (st, 1));
322 lua_pushboolean(st, b);
323 return *this;
324 }
325
326 Lua & push_nil()
327 {
328 if (failed) return *this;
329 I(lua_checkstack (st, 1));
330 lua_pushnil(st);
331 return *this;
332 }
333
334 Lua & push_table()
335 {
336 if (failed) return *this;
337 I(lua_checkstack (st, 1));
338 lua_newtable(st);
339 return *this;
340 }
341
342 Lua & set_table(int idx = -3)
343 {
344 if (failed) return *this;
345 I(lua_checkstack (st, 1));
346 lua_settable(st, idx);
347 return *this;
348 }
349
350 Lua & call(int in, int out)
351 {
352 if (failed) return *this;
353 I(lua_checkstack (st, out));
354 if (lua_pcall(st, in, out, 0) != 0)
355 {
356 report_error();
357 }
358 return *this;
359 }
360
361 Lua & pop(int count = 1)
362 {
363 if (failed) return *this;
364 if (lua_gettop (st) < count)
365 {
366 fail("stack top is not >= count in pop");
367 return *this;
368 }
369 lua_pop(st, count);
370 return *this;
371 }
372
373 Lua & func(string const & fname)
374 {
375 L(F("loading lua hook %s") % fname);
376 if (!failed)
377 {
378 if (missing_functions.find(fname) != missing_functions.end())
379 failed = true;
380 else
381 {
382 push_str(fname);
383 get_fn();
384 if (failed)
385 missing_functions.insert(fname);
386 }
387 }
388 return *this;
389 }
390
391 Lua & loadstring(string const & str, string const & identity)
392 {
393 if (!failed)
394 {
395 if (luaL_loadbuffer(st, str.c_str(), str.size(), identity.c_str()))
396 {
397 report_error();
398 }
399 }
400 return *this;
401 }
402
403 Lua & loadfile(string const & filename)
404 {
405 if (!failed)
406 {
407 if (luaL_loadfile(st, filename.c_str()))
408 {
409 report_error();
410 }
411 }
412 return *this;
413 }
414};
415
416std::set<string> Lua::missing_functions;
417
418
419
420
421extern "C"
422{
423 static int
424 monotone_mkstemp_for_lua(lua_State *L)
425 {
426 int fd = -1;
427 FILE **pf = NULL;
428 char const *filename = lua_tostring (L, -1);
429 std::string dup(filename);
430
431 fd = monotone_mkstemp(dup);
432
433 if (fd == -1)
434 return 0;
435
436 // this magic constructs a lua object which the lua io library
437 // will enjoy working with
438 pf = static_cast<FILE **>(lua_newuserdata(L, sizeof(FILE *)));
439 *pf = fdopen(fd, "r+");
440 lua_pushstring(L, "FILE*");
441 lua_rawget(L, LUA_REGISTRYINDEX);
442 lua_setmetatable(L, -2);
443
444 lua_pushstring(L, dup.c_str());
445
446 if (*pf == NULL)
447 {
448 lua_pushnil(L);
449 lua_pushfstring(L, "%s", strerror(errno));
450 lua_pushnumber(L, errno);
451 return 3;
452 }
453 else
454 return 2;
455 }
456
457 static int
458 monotone_existsonpath_for_lua(lua_State *L)
459 {
460 const char *exe = lua_tostring(L, -1);
461 lua_pushnumber(L, existsonpath(exe));
462 return 1;
463 }
464
465 static int
466 monotone_is_executable_for_lua(lua_State *L)
467 {
468 const char *path = lua_tostring(L, -1);
469 lua_pushboolean(L, is_executable(path));
470 return 1;
471 }
472
473 static int
474 monotone_make_executable_for_lua(lua_State *L)
475 {
476 const char *path = lua_tostring(L, -1);
477 lua_pushnumber(L, make_executable(path));
478 return 1;
479 }
480
481 static int
482 monotone_spawn_for_lua(lua_State *L)
483 {
484 int n = lua_gettop(L);
485 const char *path = lua_tostring(L, -n);
486 char **argv = (char**)malloc((n+1)*sizeof(char*));
487 int i;
488 pid_t ret;
489 if (argv==NULL)
490 return 0;
491 argv[0] = (char*)path;
492 for (i=1; i<n; i++) argv[i] = (char*)lua_tostring(L, -(n - i));
493 argv[i] = NULL;
494 ret = process_spawn(argv);
495 free(argv);
496 lua_pushnumber(L, ret);
497 return 1;
498 }
499
500 static int
501 monotone_wait_for_lua(lua_State *L)
502 {
503 pid_t pid = (pid_t)lua_tonumber(L, -1);
504 int res;
505 int ret;
506 ret = process_wait(pid, &res);
507 lua_pushnumber(L, res);
508 lua_pushnumber(L, ret);
509 return 2;
510 }
511
512 static int
513 monotone_kill_for_lua(lua_State *L)
514 {
515 int n = lua_gettop(L);
516 pid_t pid = (pid_t)lua_tonumber(L, -2);
517 int sig;
518 if (n>1)
519 sig = (int)lua_tonumber(L, -1);
520 else
521 sig = SIGTERM;
522 lua_pushnumber(L, process_kill(pid, sig));
523 return 1;
524 }
525
526 static int
527 monotone_sleep_for_lua(lua_State *L)
528 {
529 int seconds = (int)lua_tonumber(L, -1);
530 lua_pushnumber(L, process_sleep(seconds));
531 return 1;
532 }
533
534 static int
535 monotone_guess_binary_file_contents_for_lua(lua_State *L)
536 {
537 const char *path = lua_tostring(L, -1);
538 N(path, F("%s called with an invalid parameter") % "guess_binary");
539
540 std::ifstream file(path, ios_base::binary);
541 if (!file)
542 {
543 lua_pushnil(L);
544 return 1;
545 }
546 const int bufsize = 8192;
547 char tmpbuf[bufsize];
548 string buf;
549 while (file.read(tmpbuf, sizeof tmpbuf))
550 {
551 I(file.gcount() <= static_cast<int>(sizeof tmpbuf));
552 buf.assign(tmpbuf, file.gcount());
553 if (guess_binary(buf))
554 {
555 lua_pushboolean(L, true);
556 return 1;
557 }
558 }
559 lua_pushboolean(L, false);
560 return 1;
561 }
562
563 static int
564 monotone_include_for_lua(lua_State *L)
565 {
566 const char *path = lua_tostring(L, -1);
567 N(path, F("%s called with an invalid parameter") % "Include");
568
569 bool res =Lua(L)
570 .loadfile(std::string(path, lua_strlen(L, -1)))
571 .call(0,1)
572 .ok();
573
574 lua_pushboolean(L, res);
575 return 1;
576 }
577
578 static int
579 monotone_includedir_for_lua(lua_State *L)
580 {
581 const char *pathstr = lua_tostring(L, -1);
582 N(pathstr, F("%s called with an invalid parameter") % "IncludeDir");
583
584 fs::path locpath(pathstr, fs::native);
585 N(fs::exists(locpath), F("Directory '%s' does not exists") % pathstr);
586 N(fs::is_directory(locpath), F("'%s' is not a directory") % pathstr);
587
588 // directory, iterate over it, skipping subdirs, taking every filename,
589 // sorting them and loading in sorted order
590 fs::directory_iterator it(locpath);
591 std::vector<fs::path> arr;
592 while (it != fs::directory_iterator())
593 {
594 if (!fs::is_directory(*it))
595 arr.push_back(*it);
596 ++it;
597 }
598 std::sort(arr.begin(), arr.end());
599 for (std::vector<fs::path>::iterator i= arr.begin(); i != arr.end(); ++i)
600 {
601 bool res =Lua(L)
602 .loadfile(i->string())
603 .call(0,1)
604 .ok();
605 N(res, F("lua error while loading rcfile '%s'") % i->string());
606 }
607
608 lua_pushboolean(L, true);
609 return 1;
610 }
611
612 static int
613 monotone_regex_search_for_lua(lua_State *L)
614 {
615 const char *re = lua_tostring(L, -2);
616 const char *str = lua_tostring(L, -1);
617 boost::cmatch what;
618
619 bool result = false;
620 try {
621 result = boost::regex_search(str, what, boost::regex(re));
622 } catch (boost::bad_pattern e) {
623 lua_pushstring(L, e.what());
624 lua_error(L);
625 return 0;
626 }
627 lua_pushboolean(L, result);
628 return 1;
629 }
630
631 static int
632 monotone_globish_match_for_lua(lua_State *L)
633 {
634 const char *re = lua_tostring(L, -2);
635 const char *str = lua_tostring(L, -1);
636
637 bool result = false;
638 try {
639 string r(re);
640 string n;
641 string s(str);
642 result = globish_matcher(r, n)(s);
643 } catch (informative_failure & e) {
644 lua_pushstring(L, e.what.c_str());
645 lua_error(L);
646 return 0;
647 } catch (boost::bad_pattern & e) {
648 lua_pushstring(L, e.what());
649 lua_error(L);
650 return 0;
651 } catch (...) {
652 lua_pushstring(L, "Unknown error.");
653 lua_error(L);
654 return 0;
655 }
656 lua_pushboolean(L, result);
657 return 1;
658 }
659
660 static int
661 monotone_gettext_for_lua(lua_State *L)
662 {
663 const char *msgid = lua_tostring(L, -1);
664 lua_pushstring(L, gettext(msgid));
665 return 1;
666 }
667
668 static int
669 monotone_get_confdir_for_lua(lua_State *L)
670 {
671 map<lua_State*, app_state*>::iterator i = map_of_lua_to_app.find(L);
672 if (i != map_of_lua_to_app.end())
673 {
674 system_path dir = i->second->get_confdir();
675 string confdir = dir.as_external();
676 lua_pushstring(L, confdir.c_str());
677 }
678 else
679 lua_pushnil(L);
680 return 1;
681 }
682
683 static int
684 monotone_parse_basic_io_for_lua(lua_State *L)
685 {
686 vector<pair<string, vector<string> > > res;
687 const char *str = lua_tostring(L, -1);
688 std::istringstream iss(str);
689 basic_io::input_source in(iss, "monotone_parse_basic_io_for_lua");
690 basic_io::tokenizer tok(in);
691 try
692 {
693 string got;
694 basic_io::token_type tt;
695 do
696 {
697 tt = tok.get_token(got);
698 switch (tt)
699 {
700 case basic_io::TOK_SYMBOL:
701 res.push_back(make_pair(got, vector<string>()));
702 break;
703 case basic_io::TOK_STRING:
704 case basic_io::TOK_HEX:
705 E(!res.empty(), boost::format("bad input to parse_basic_io"));
706 res.back().second.push_back(got);
707 break;
708 default:
709 break;
710 }
711 }
712 while (tt != basic_io::TOK_NONE);
713 }
714 catch (informative_failure & e)
715 {// there was a syntax error in our string
716 lua_pushnil(L);
717 return 0;
718 }
719 lua_newtable(L);
720 int n = 1;
721 for (vector<pair<string, vector<string> > >::const_iterator i = res.begin();
722 i != res.end(); ++i)
723 {
724 lua_pushnumber(L, n++);
725 lua_newtable(L);
726 lua_pushstring(L, "name");
727 lua_pushstring(L, i->first.c_str());
728 lua_settable(L, -3);
729 lua_pushstring(L, "values");
730 lua_newtable(L);
731 int m = 1;
732 for (vector<string>::const_iterator j = i->second.begin();
733 j != i->second.end(); ++j)
734 {
735 lua_pushnumber(L, m++);
736 lua_pushstring(L, j->c_str());
737 lua_settable(L, -3);
738 }
739 lua_settable(L, -3);
740 lua_settable(L, -3);
741 }
742 return 1;
743 }
744}
745
746
747lua_hooks::lua_hooks()
748{
749 st = lua_open ();
750 I(st);
751
752 lua_atpanic (st, &panic_thrower);
753
754 luaopen_base(st);
755 luaopen_io(st);
756 luaopen_string(st);
757 luaopen_math(st);
758 luaopen_table(st);
759 luaopen_debug(st);
760
761 // add monotone-specific functions
762 lua_register(st, "mkstemp", monotone_mkstemp_for_lua);
763 lua_register(st, "existsonpath", monotone_existsonpath_for_lua);
764 lua_register(st, "is_executable", monotone_is_executable_for_lua);
765 lua_register(st, "make_executable", monotone_make_executable_for_lua);
766 lua_register(st, "spawn", monotone_spawn_for_lua);
767 lua_register(st, "wait", monotone_wait_for_lua);
768 lua_register(st, "kill", monotone_kill_for_lua);
769 lua_register(st, "sleep", monotone_sleep_for_lua);
770 lua_register(st, "guess_binary_file_contents", monotone_guess_binary_file_contents_for_lua);
771 lua_register(st, "include", monotone_include_for_lua);
772 lua_register(st, "includedir", monotone_includedir_for_lua);
773 lua_register(st, "gettext", monotone_gettext_for_lua);
774 lua_register(st, "get_confdir", monotone_get_confdir_for_lua);
775 lua_register(st, "parse_basic_io", monotone_parse_basic_io_for_lua);
776
777 // add regex functions:
778 lua_newtable(st);
779 lua_pushstring(st, "regex");
780 lua_pushvalue(st, -2);
781 lua_settable(st, LUA_GLOBALSINDEX);
782
783 lua_pushstring(st, "search");
784 lua_pushcfunction(st, monotone_regex_search_for_lua);
785 lua_settable(st, -3);
786
787 // add globish functions:
788 lua_newtable(st);
789 lua_pushstring(st, "globish");
790 lua_pushvalue(st, -2);
791 lua_settable(st, LUA_GLOBALSINDEX);
792
793 lua_pushstring(st, "match");
794 lua_pushcfunction(st, monotone_globish_match_for_lua);
795 lua_settable(st, -3);
796
797 lua_pop(st, 1);
798}
799
800lua_hooks::~lua_hooks()
801{
802 map<lua_State*, app_state*>::iterator i = map_of_lua_to_app.find(st);
803 if (st)
804 lua_close (st);
805 if (i != map_of_lua_to_app.end())
806 map_of_lua_to_app.erase(i);
807}
808
809void
810lua_hooks::set_app(app_state *_app)
811{
812 map_of_lua_to_app.insert(make_pair(st, _app));
813}
814
815static bool
816run_string(lua_State * st, string const &str, string const & identity)
817{
818 I(st);
819 return
820 Lua(st)
821 .loadstring(str, identity)
822 .call(0,1)
823 .ok();
824}
825
826static bool
827run_file(lua_State * st, string const &filename)
828{
829 I(st);
830 return
831 Lua(st)
832 .loadfile(filename)
833 .call(0,1)
834 .ok();
835}
836
837
838#ifdef BUILD_UNIT_TESTS
839void
840lua_hooks::add_test_hooks()
841{
842 if (!run_string(st, test_hooks_constant, string("<test hooks>")))
843 throw oops("lua error while setting up testing hooks");
844}
845#endif
846
847void
848lua_hooks::add_std_hooks()
849{
850 if (!run_string(st, std_hooks_constant, string("<std hooks>")))
851 throw oops("lua error while setting up standard hooks");
852}
853
854void
855lua_hooks::default_rcfilename(system_path & file)
856{
857 map<lua_State*, app_state*>::iterator i = map_of_lua_to_app.find(st);
858 I(i != map_of_lua_to_app.end());
859 file = i->second->get_confdir() / "monotonerc";
860}
861
862void
863lua_hooks::working_copy_rcfilename(bookkeeping_path & file)
864{
865 file = bookkeeping_root / "monotonerc";
866}
867
868
869void
870lua_hooks::load_rcfile(utf8 const & rc)
871{
872 I(st);
873 if (rc() != "-")
874 {
875 fs::path locpath(system_path(rc).as_external(), fs::native);
876 if (fs::exists(locpath) && fs::is_directory(locpath))
877 {
878 // directory, iterate over it, skipping subdirs, taking every filename,
879 // sorting them and loading in sorted order
880 fs::directory_iterator it(locpath);
881 std::vector<fs::path> arr;
882 while (it != fs::directory_iterator())
883 {
884 if (!fs::is_directory(*it))
885 arr.push_back(*it);
886 ++it;
887 }
888 std::sort(arr.begin(), arr.end());
889 for (std::vector<fs::path>::iterator i= arr.begin(); i != arr.end(); ++i)
890 {
891 load_rcfile(system_path(i->native_directory_string()), true);
892 }
893 return; // directory read, skip the rest ...
894 }
895 }
896 data dat;
897 L(F("opening rcfile '%s' ...\n") % rc);
898 read_data_for_command_line(rc, dat);
899 N(run_string(st, dat(), rc().c_str()),
900 F("lua error while loading rcfile '%s'") % rc);
901 L(F("'%s' is ok\n") % rc);
902}
903
904void
905lua_hooks::load_rcfile(any_path const & rc, bool required)
906{
907 I(st);
908 if (path_exists(rc))
909 {
910 L(F("opening rcfile '%s' ...\n") % rc);
911 N(run_file(st, rc.as_external()),
912 F("lua error while loading '%s'") % rc);
913 L(F("'%s' is ok\n") % rc);
914 }
915 else
916 {
917 N(!required, F("rcfile '%s' does not exist") % rc);
918 L(F("skipping nonexistent rcfile '%s'\n") % rc);
919 }
920}
921
922
923// concrete hooks
924
925// nb: if you're hooking lua to return your passphrase, you don't care if we
926// keep a couple extra temporaries of your passphrase around.
927bool
928lua_hooks::hook_get_passphrase(rsa_keypair_id const & k, string & phrase)
929{
930 return Lua(st)
931 .func("get_passphrase")
932 .push_str(k())
933 .call(1,1)
934 .extract_str(phrase)
935 .ok();
936}
937
938bool
939lua_hooks::hook_persist_phrase_ok()
940{
941 bool persist_ok = false;
942 bool executed_ok = Lua(st)
943 .func("persist_phrase_ok")
944 .call(0,1)
945 .extract_bool(persist_ok)
946 .ok();
947 return executed_ok && persist_ok;
948}
949
950bool
951lua_hooks::hook_expand_selector(std::string const & sel,
952 std::string & exp)
953{
954 return Lua(st)
955 .func("expand_selector")
956 .push_str(sel)
957 .call(1,1)
958 .extract_str(exp)
959 .ok();
960}
961
962bool
963lua_hooks::hook_expand_date(std::string const & sel,
964 std::string & exp)
965{
966 exp.clear();
967 bool res= Lua(st)
968 .func("expand_date")
969 .push_str(sel)
970 .call(1,1)
971 .extract_str(exp)
972 .ok();
973 return res && exp.size();
974}
975
976bool
977lua_hooks::hook_get_branch_key(cert_value const & branchname,
978 rsa_keypair_id & k)
979{
980 string key;
981 bool ok = Lua(st)
982 .func("get_branch_key")
983 .push_str(branchname())
984 .call(1,1)
985 .extract_str(key)
986 .ok();
987
988 k = key;
989 return ok;
990}
991
992bool
993lua_hooks::hook_get_key_pair(rsa_keypair_id const & k,
994 keypair & kp)
995{
996 string key;
997 bool ok = Lua(st)
998 .func("get_priv_key")
999 .push_str(k())
1000 .call(1,1)
1001 .extract_str(key)
1002 .ok();
1003
1004 size_t pos = key.find("#");
1005 if (pos == std::string::npos)
1006 return false;
1007 kp.pub = key.substr(0, pos);
1008 kp.priv = key.substr(pos+1);
1009 return ok;
1010}
1011
1012bool
1013lua_hooks::hook_get_author(cert_value const & branchname,
1014 string & author)
1015{
1016 return Lua(st)
1017 .func("get_author")
1018 .push_str(branchname())
1019 .call(1,1)
1020 .extract_str(author)
1021 .ok();
1022}
1023
1024bool
1025lua_hooks::hook_edit_comment(string const & commentary,
1026 string const & user_log_message,
1027 string & result)
1028{
1029 return Lua(st)
1030 .func("edit_comment")
1031 .push_str(commentary)
1032 .push_str(user_log_message)
1033 .call(2,1)
1034 .extract_str(result)
1035 .ok();
1036}
1037
1038bool
1039lua_hooks::hook_ignore_file(file_path const & p)
1040{
1041 bool ignore_it = false;
1042 bool exec_ok = Lua(st)
1043 .func("ignore_file")
1044 .push_str(p.as_external())
1045 .call(1,1)
1046 .extract_bool(ignore_it)
1047 .ok();
1048 return exec_ok && ignore_it;
1049}
1050
1051bool
1052lua_hooks::hook_ignore_branch(std::string const & branch)
1053{
1054 bool ignore_it = false;
1055 bool exec_ok = Lua(st)
1056 .func("ignore_branch")
1057 .push_str(branch)
1058 .call(1,1)
1059 .extract_bool(ignore_it)
1060 .ok();
1061 return exec_ok && ignore_it;
1062}
1063
1064bool
1065lua_hooks::hook_non_blocking_rng_ok()
1066{
1067 bool ok = false;
1068 bool exec_ok = Lua(st)
1069 .func("non_blocking_rng_ok")
1070 .call(0,1)
1071 .extract_bool(ok)
1072 .ok();
1073 return exec_ok && ok;
1074}
1075
1076static inline bool
1077shared_trust_function_body(Lua & ll,
1078 std::set<rsa_keypair_id> const & signers,
1079 hexenc<id> const & id,
1080 cert_name const & name,
1081 cert_value const & val)
1082{
1083 ll.push_table();
1084
1085 int k = 0;
1086 for (set<rsa_keypair_id>::const_iterator v = signers.begin();
1087 v != signers.end(); ++v)
1088 {
1089 ll.push_int(k);
1090 ll.push_str((*v)());
1091 ll.set_table();
1092 ++k;
1093 }
1094
1095 bool ok;
1096 bool exec_ok = ll
1097 .push_str(id())
1098 .push_str(name())
1099 .push_str(val())
1100 .call(4, 1)
1101 .extract_bool(ok)
1102 .ok();
1103
1104 return exec_ok && ok;
1105}
1106
1107bool
1108lua_hooks::hook_get_revision_cert_trust(std::set<rsa_keypair_id> const & signers,
1109 hexenc<id> const & id,
1110 cert_name const & name,
1111 cert_value const & val)
1112{
1113 Lua ll(st);
1114 ll.func("get_revision_cert_trust");
1115 return shared_trust_function_body(ll, signers, id, name, val);
1116}
1117
1118bool
1119lua_hooks::hook_get_manifest_cert_trust(std::set<rsa_keypair_id> const & signers,
1120 hexenc<id> const & id,
1121 cert_name const & name,
1122 cert_value const & val)
1123{
1124 Lua ll(st);
1125 ll.func("get_manifest_cert_trust");
1126 return shared_trust_function_body(ll, signers, id, name, val);
1127}
1128
1129bool
1130lua_hooks::hook_accept_testresult_change(map<rsa_keypair_id, bool> const & old_results,
1131 map<rsa_keypair_id, bool> const & new_results)
1132{
1133 Lua ll(st);
1134 ll
1135 .func("accept_testresult_change")
1136 .push_table();
1137
1138 for (map<rsa_keypair_id, bool>::const_iterator i = old_results.begin();
1139 i != old_results.end(); ++i)
1140 {
1141 ll.push_str(i->first());
1142 ll.push_bool(i->second);
1143 ll.set_table();
1144 }
1145
1146 ll.push_table();
1147
1148 for (map<rsa_keypair_id, bool>::const_iterator i = new_results.begin();
1149 i != new_results.end(); ++i)
1150 {
1151 ll.push_str(i->first());
1152 ll.push_bool(i->second);
1153 ll.set_table();
1154 }
1155
1156 bool ok;
1157 bool exec_ok = ll
1158 .call(2, 1)
1159 .extract_bool(ok)
1160 .ok();
1161
1162 return exec_ok && ok;
1163}
1164
1165
1166
1167bool
1168lua_hooks::hook_merge2(file_path const & left_path,
1169 file_path const & right_path,
1170 file_path const & merged_path,
1171 data const & left,
1172 data const & right,
1173 data & result)
1174{
1175 string res;
1176 bool ok = Lua(st)
1177 .func("merge2")
1178 .push_str(left_path.as_external())
1179 .push_str(right_path.as_external())
1180 .push_str(merged_path.as_external())
1181 .push_str(left())
1182 .push_str(right())
1183 .call(5,1)
1184 .extract_str(res)
1185 .ok();
1186 result = res;
1187 return ok;
1188}
1189
1190bool
1191lua_hooks::hook_merge3(file_path const & anc_path,
1192 file_path const & left_path,
1193 file_path const & right_path,
1194 file_path const & merged_path,
1195 data const & ancestor,
1196 data const & left,
1197 data const & right,
1198 data & result)
1199{
1200 string res;
1201 bool ok = Lua(st)
1202 .func("merge3")
1203 .push_str(anc_path.as_external())
1204 .push_str(left_path.as_external())
1205 .push_str(right_path.as_external())
1206 .push_str(merged_path.as_external())
1207 .push_str(ancestor())
1208 .push_str(left())
1209 .push_str(right())
1210 .call(7,1)
1211 .extract_str(res)
1212 .ok();
1213 result = res;
1214 return ok;
1215}
1216
1217bool
1218lua_hooks::hook_resolve_file_conflict(file_path const & anc,
1219 file_path const & a,
1220 file_path const & b,
1221 file_path & res)
1222{
1223 string tmp;
1224 bool ok = Lua(st)
1225 .func("resolve_file_conflict")
1226 .push_str(anc.as_external())
1227 .push_str(a.as_external())
1228 .push_str(b.as_external())
1229 .call(3,1)
1230 .extract_str(tmp)
1231 .ok();
1232 res = file_path_internal(tmp);
1233 return ok;
1234}
1235
1236bool
1237lua_hooks::hook_resolve_dir_conflict(file_path const & anc,
1238 file_path const & a,
1239 file_path const & b,
1240 file_path & res)
1241{
1242 string tmp;
1243 bool ok = Lua(st)
1244 .func("resolve_dir_conflict")
1245 .push_str(anc.as_external())
1246 .push_str(a.as_external())
1247 .push_str(b.as_external())
1248 .call(3,1)
1249 .extract_str(tmp)
1250 .ok();
1251 res = file_path_internal(tmp);
1252 return ok;
1253}
1254
1255bool
1256lua_hooks::hook_external_diff(file_path const & path,
1257 data const & data_old,
1258 data const & data_new,
1259 bool is_binary,
1260 bool diff_args_provided,
1261 std::string const & diff_args,
1262 std::string const & oldrev,
1263 std::string const & newrev)
1264{
1265 Lua ll(st);
1266
1267 ll
1268 .func("external_diff")
1269 .push_str(path.as_external());
1270
1271 if (oldrev.length() != 0)
1272 ll.push_str(data_old());
1273 else
1274 ll.push_nil();
1275
1276 ll.push_str(data_new());
1277
1278 ll.push_bool(is_binary);
1279
1280 if (diff_args_provided)
1281 ll.push_str(diff_args);
1282 else
1283 ll.push_nil();
1284
1285 ll.push_str(oldrev);
1286 ll.push_str(newrev);
1287
1288 return ll.call(7,0).ok();
1289}
1290
1291bool
1292lua_hooks::hook_use_inodeprints()
1293{
1294 bool use = false, exec_ok = false;
1295
1296 exec_ok = Lua(st)
1297 .func("use_inodeprints")
1298 .call(0, 1)
1299 .extract_bool(use)
1300 .ok();
1301 return use && exec_ok;
1302}
1303
1304bool
1305lua_hooks::hook_get_netsync_read_permitted(std::string const & branch,
1306 rsa_keypair_id const & identity)
1307{
1308 bool permitted = false, exec_ok = false;
1309
1310 exec_ok = Lua(st)
1311 .func("get_netsync_read_permitted")
1312 .push_str(branch)
1313 .push_str(identity())
1314 .call(2,1)
1315 .extract_bool(permitted)
1316 .ok();
1317
1318 return exec_ok && permitted;
1319}
1320
1321// Anonymous no-key version
1322bool
1323lua_hooks::hook_get_netsync_read_permitted(std::string const & branch)
1324{
1325 bool permitted = false, exec_ok = false;
1326
1327 exec_ok = Lua(st)
1328 .func("get_netsync_read_permitted")
1329 .push_str(branch)
1330 .push_nil()
1331 .call(2,1)
1332 .extract_bool(permitted)
1333 .ok();
1334
1335 return exec_ok && permitted;
1336}
1337
1338bool
1339lua_hooks::hook_get_netsync_write_permitted(rsa_keypair_id const & identity)
1340{
1341 bool permitted = false, exec_ok = false;
1342
1343 exec_ok = Lua(st)
1344 .func("get_netsync_write_permitted")
1345 .push_str(identity())
1346 .call(1,1)
1347 .extract_bool(permitted)
1348 .ok();
1349
1350 return exec_ok && permitted;
1351}
1352
1353bool
1354lua_hooks::hook_init_attributes(file_path const & filename,
1355 std::map<std::string, std::string> & attrs)
1356{
1357 Lua ll(st);
1358
1359 ll
1360 .push_str("attr_init_functions")
1361 .get_tab();
1362
1363 L(F("calling attr_init_function for %s") % filename);
1364 ll.begin();
1365 while (ll.next())
1366 {
1367 L(F(" calling an attr_init_function for %s") % filename);
1368 ll.push_str(filename.as_external());
1369 ll.call(1, 1);
1370
1371 if (lua_isstring(st, -1))
1372 {
1373 string key, value;
1374
1375 ll.extract_str(value);
1376 ll.pop();
1377 ll.extract_str(key);
1378
1379 attrs[key] = value;
1380 L(F(" added attr %s = %s") % key % value);
1381 }
1382 else
1383 {
1384 L(F(" no attr added"));
1385 ll.pop();
1386 }
1387 }
1388
1389 return ll.pop().ok();
1390}
1391
1392bool
1393lua_hooks::hook_apply_attribute(string const & attr,
1394 file_path const & filename,
1395 string const & value)
1396{
1397 return Lua(st)
1398 .push_str("attr_functions")
1399 .get_tab()
1400 .push_str(attr)
1401 .get_fn(-2)
1402 .push_str(filename.as_external())
1403 .push_str(value)
1404 .call(2,0)
1405 .ok();
1406}
1407
1408
1409bool
1410lua_hooks::hook_get_system_linesep(string & linesep)
1411{
1412 return Lua(st)
1413 .func("get_system_linesep")
1414 .call(0,1)
1415 .extract_str(linesep)
1416 .ok();
1417}
1418
1419bool
1420lua_hooks::hook_get_charset_conv(file_path const & p,
1421 std::string & db,
1422 std::string & ext)
1423{
1424 Lua ll(st);
1425 ll
1426 .func("get_charset_conv")
1427 .push_str(p.as_external())
1428 .call(1,1)
1429 .begin();
1430
1431 ll.next();
1432 ll.extract_str(db).pop();
1433
1434 ll.next();
1435 ll.extract_str(ext).pop();
1436 return ll.ok();
1437}
1438
1439bool
1440lua_hooks::hook_get_linesep_conv(file_path const & p,
1441 std::string & db,
1442 std::string & ext)
1443{
1444 Lua ll(st);
1445 ll
1446 .func("get_linesep_conv")
1447 .push_str(p.as_external())
1448 .call(1,1)
1449 .begin();
1450
1451 ll.next();
1452 ll.extract_str(db).pop();
1453
1454 ll.next();
1455 ll.extract_str(ext).pop();
1456 return ll.ok();
1457}
1458
1459bool
1460lua_hooks::hook_note_commit(revision_id const & new_id,
1461 revision_data const & rdat,
1462 map<cert_name, cert_value> const & certs)
1463{
1464 Lua ll(st);
1465 ll
1466 .func("note_commit")
1467 .push_str(new_id.inner()())
1468 .push_str(rdat.inner()());
1469
1470 ll.push_table();
1471
1472 for (map<cert_name, cert_value>::const_iterator i = certs.begin();
1473 i != certs.end(); ++i)
1474 {
1475 ll.push_str(i->first());
1476 ll.push_str(i->second());
1477 ll.set_table();
1478 }
1479
1480 ll.call(3, 0);
1481 return ll.ok();
1482}
1483
1484bool
1485lua_hooks::hook_note_netsync_revision_received(revision_id const & new_id,
1486 revision_data const & rdat,
1487 set<pair<rsa_keypair_id,
1488 pair<cert_name,
1489 cert_value> > > const & certs)
1490{
1491 Lua ll(st);
1492 ll
1493 .func("note_netsync_revision_received")
1494 .push_str(new_id.inner()())
1495 .push_str(rdat.inner()());
1496
1497 ll.push_table();
1498
1499 typedef set<pair<rsa_keypair_id, pair<cert_name, cert_value> > > cdat;
1500
1501 int n=0;
1502 for (cdat::const_iterator i = certs.begin(); i != certs.end(); ++i)
1503 {
1504 ll.push_int(n++);
1505 ll.push_table();
1506 ll.push_str("key");
1507 ll.push_str(i->first());
1508 ll.set_table();
1509 ll.push_str("name");
1510 ll.push_str(i->second.first());
1511 ll.set_table();
1512 ll.push_str("value");
1513 ll.push_str(i->second.second());
1514 ll.set_table();
1515 ll.set_table();
1516 }
1517
1518 ll.call(3, 0);
1519 return ll.ok();
1520}
1521
1522bool
1523lua_hooks::hook_note_netsync_pubkey_received(rsa_keypair_id const & kid)
1524{
1525 Lua ll(st);
1526 ll
1527 .func("note_netsync_pubkey_received")
1528 .push_str(kid());
1529
1530 ll.call(1, 0);
1531 return ll.ok();
1532}
1533
1534bool
1535lua_hooks::hook_note_netsync_cert_received(revision_id const & rid,
1536 rsa_keypair_id const & kid,
1537 cert_name const & name,
1538 cert_value const & value)
1539{
1540 Lua ll(st);
1541 ll
1542 .func("note_netsync_cert_received")
1543 .push_str(rid.inner()())
1544 .push_str(kid())
1545 .push_str(name())
1546 .push_str(value());
1547
1548 ll.call(4, 0);
1549 return ll.ok();
1550}

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status