monotone

monotone Mtn Source Tree

Root/src/lua_hooks.cc

1// Copyright (C) 2002 Graydon Hoare <graydon@pobox.com>
2// 2008 Stephen Leake <stephen_leake@stephe-leake.org>
3//
4// This program is made available under the GNU GPL version 2.0 or
5// greater. See the accompanying file COPYING for details.
6//
7// This program is distributed WITHOUT ANY WARRANTY; without even the
8// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
9// PURPOSE.
10
11
12#include "base.hh"
13
14#include <set>
15#include <map>
16#include <fstream>
17#include <iostream>
18
19#include "lua.hh"
20
21#include "app_state.hh"
22#include "file_io.hh"
23#include "lua_hooks.hh"
24#include "sanity.hh"
25#include "vocab.hh"
26#include "transforms.hh"
27#include "paths.hh"
28#include "project.hh"
29#include "uri.hh"
30#include "cmd.hh"
31#include "commands.hh"
32#include "globish.hh"
33#include "simplestring_xform.hh"
34
35// defined in std_hooks.c, generated from std_hooks.lua
36extern char const std_hooks_constant[];
37
38using std::make_pair;
39using std::sort;
40
41static int panic_thrower(lua_State * st)
42{
43 throw oops("lua panic");
44}
45
46// this lets the lua callbacks (monotone_*_for_lua) have access to the
47// app_state the're associated with.
48// it was added so that the confdir (normally ~/.monotone) can be specified on
49// the command line (and so known only to the app_state), and still be
50// available to lua
51// please *don't* use it for complex things that can throw errors
52static map<lua_State*, app_state*> map_of_lua_to_app;
53
54extern "C"
55{
56 static int
57 monotone_get_confdir_for_lua(lua_State *LS)
58 {
59 map<lua_State*, app_state*>::iterator i = map_of_lua_to_app.find(LS);
60 if (i != map_of_lua_to_app.end())
61 {
62 if (i->second->opts.conf_dir_given
63 || !i->second->opts.no_default_confdir)
64 {
65 system_path dir = i->second->opts.conf_dir;
66 string confdir = dir.as_external();
67 lua_pushstring(LS, confdir.c_str());
68 }
69 else
70 lua_pushnil(LS);
71 }
72 else
73 lua_pushnil(LS);
74 return 1;
75 }
76 // taken from http://medek.wordpress.com/2009/02/03/wrapping-lua-errors-and-print-function/
77 static int
78 monotone_message(lua_State *LS)
79 {
80 int nArgs = lua_gettop(LS);
81 lua_getglobal(LS, "tostring");
82
83 string ret;
84 for (int i = 1; i <= nArgs; ++i)
85 {
86 const char *s;
87 lua_pushvalue(LS, -1);
88 lua_pushvalue(LS, i);
89 lua_call(LS, 1, 1);
90 s = lua_tostring(LS, -1);
91 if (s == NULL)
92 return luaL_error(
93 LS, LUA_QL("tostring") " must return a string to ", LUA_QL("print")
94 );
95
96 if (i > 1)
97 ret.append("\t");
98
99 ret.append(s);
100 lua_pop(LS, 1);
101 }
102
103 string prefixed;
104 prefix_lines_with(_("lua: "), ret, prefixed);
105 P(F("%s") % prefixed);
106 return 0;
107 }
108}
109
110app_state*
111get_app_state(lua_State *LS)
112{
113 map<lua_State*, app_state*>::iterator i = map_of_lua_to_app.find(LS);
114 if (i != map_of_lua_to_app.end())
115 return i->second;
116 else
117 return NULL;
118}
119
120namespace {
121 Lua & push_key_identity_info(Lua & ll,
122 key_identity_info const & info)
123 {
124 hexenc<id> hexid;
125 encode_hexenc(info.id.inner(), hexid);
126 ll.push_table()
127 .push_str(hexid())
128 .set_field("id")
129 .push_str(info.given_name())
130 .set_field("given_name")
131 .push_str(info.official_name())
132 .set_field("name");
133 return ll;
134 }
135}
136
137lua_hooks::lua_hooks(app_state * app)
138{
139 st = luaL_newstate();
140 I(st);
141
142 lua_atpanic (st, &panic_thrower);
143
144 luaL_openlibs(st);
145
146 lua_register(st, "get_confdir", monotone_get_confdir_for_lua);
147 lua_register(st, "message", monotone_message);
148 add_functions(st);
149
150 // Disable any functions we don't want. This is easiest
151 // to do just by running a lua string.
152 static char const disable_dangerous[] =
153 "os.execute = function(c) "
154 " error(\"os.execute disabled for security reasons. Try spawn().\") "
155 "end "
156 "io.popen = function(c,t) "
157 " error(\"io.popen disabled for security reasons. Try spawn_pipe().\") "
158 "end ";
159
160 if (!run_string(st, disable_dangerous,
161 "<disabled dangerous functions>"))
162 throw oops("lua error while disabling existing functions");
163
164 // redirect output to internal message handler which calls into
165 // our user interface code. Note that we send _everything_ to stderr
166 // or as out-of-band progress stream to keep our stdout clean
167 static char const redirect_output[] =
168 "io.write = function(...) "
169 " message(...) "
170 "end "
171 "print = function(...) "
172 " message(...) "
173 "end ";
174
175 if (!run_string(st, redirect_output,
176 "<redirect output>"))
177 throw oops("lua error while redirecting output");
178
179 map_of_lua_to_app.insert(make_pair(st, app));
180}
181
182lua_hooks::~lua_hooks()
183{
184 map<lua_State*, app_state*>::iterator i = map_of_lua_to_app.find(st);
185 if (st)
186 lua_close (st);
187 if (i != map_of_lua_to_app.end())
188 map_of_lua_to_app.erase(i);
189}
190
191bool
192lua_hooks::check_lua_state(lua_State * p_st) const
193{
194 return (p_st == st);
195}
196
197void
198lua_hooks::add_std_hooks()
199{
200 if (!run_string(st, std_hooks_constant, "<std hooks>"))
201 throw oops("lua error while setting up standard hooks");
202}
203
204void
205lua_hooks::load_rcfile(utf8 const & rc)
206{
207 I(st);
208 if (rc() != "-" && directory_exists(system_path(rc)))
209 run_directory(st, system_path(rc).as_external().c_str(), "*");
210 else
211 {
212 data dat;
213 L(FL("opening rcfile '%s'") % rc);
214 read_data_for_command_line(rc, dat);
215 E(run_string(st, dat().c_str(), rc().c_str()), origin::user,
216 F("lua error while loading rcfile '%s'") % rc);
217 L(FL("'%s' is ok") % rc);
218 }
219}
220
221void
222lua_hooks::load_rcfile(any_path const & rc, bool required)
223{
224 I(st);
225 bool exists;
226 try
227 {
228 exists = path_exists(rc);
229 }
230 catch (recoverable_failure & e)
231 {
232 if (!required)
233 {
234 L(FL("skipping rcfile '%s': %s") % rc % e.what());
235 return;
236 }
237 else
238 throw;
239 }
240
241 if (exists)
242 {
243 L(FL("opening rcfile '%s'") % rc);
244 E(run_file(st, rc.as_external().c_str()), origin::user,
245 F("lua error while loading '%s'") % rc);
246 L(FL("'%s' is ok") % rc);
247 }
248 else
249 {
250 E(!required, origin::user, F("rcfile '%s' does not exist") % rc);
251 L(FL("skipping nonexistent rcfile '%s'") % rc);
252 }
253}
254
255void
256lua_hooks::load_rcfiles(options const & opts)
257{
258 // Built-in rc settings are defaults.
259 if (!opts.nostd)
260 add_std_hooks();
261
262 // ~/.monotone/monotonerc overrides that, and
263 // _MTN/monotonerc overrides *that*.
264
265 if (!opts.norc)
266 {
267 if (opts.conf_dir_given || !opts.no_default_confdir)
268 {
269 load_rcfile(opts.conf_dir / "monotonerc", false);
270 }
271 load_rcfile(bookkeeping_root / "monotonerc", false);
272 }
273
274 // Command-line rcfiles override even that.
275
276 for (args_vector::const_iterator i = opts.extra_rcfiles.begin();
277 i != opts.extra_rcfiles.end(); ++i)
278 load_rcfile(*i);
279}
280
281bool
282lua_hooks::hook_exists(string const & func_name)
283{
284 return Lua(st)
285 .func(func_name)
286 .ok();
287}
288
289// concrete hooks
290
291// nb: if you're hooking lua to return your passphrase, you don't care if we
292// keep a couple extra temporaries of your passphrase around.
293bool
294lua_hooks::hook_get_passphrase(key_identity_info const & identity,
295 string & phrase)
296{
297 Lua ll(st);
298 ll.func("get_passphrase");
299 push_key_identity_info(ll, identity);
300 ll.call(1,1)
301 .extract_classified_str(phrase);
302 return ll.ok();
303}
304
305bool
306lua_hooks::hook_get_local_key_name(key_identity_info & info)
307{
308 string local_name;
309 Lua ll(st);
310 ll.func("get_local_key_name");
311 push_key_identity_info(ll, info);
312 ll.call(1, 1)
313 .extract_str(local_name);
314 if (ll.ok())
315 {
316 info.official_name = key_name(local_name, origin::user);
317 return true;
318 }
319 else
320 return false;
321}
322
323bool
324lua_hooks::hook_persist_phrase_ok()
325{
326 bool persist_ok = false;
327 bool executed_ok = Lua(st)
328 .func("persist_phrase_ok")
329 .call(0,1)
330 .extract_bool(persist_ok)
331 .ok();
332 return executed_ok && persist_ok;
333}
334
335bool
336lua_hooks::hook_expand_selector(string const & sel,
337 string & exp)
338{
339 return Lua(st)
340 .func("expand_selector")
341 .push_str(sel)
342 .call(1,1)
343 .extract_str(exp)
344 .ok();
345}
346
347bool
348lua_hooks::hook_expand_date(string const & sel,
349 string & exp)
350{
351 exp.clear();
352 bool res= Lua(st)
353 .func("expand_date")
354 .push_str(sel)
355 .call(1,1)
356 .extract_str(exp)
357 .ok();
358 return res && exp.size();
359}
360
361bool
362lua_hooks::hook_get_branch_key(branch_name const & branchname,
363 key_store & keys,
364 project_t & project,
365 key_id & k)
366{
367 string key;
368 bool ok = Lua(st)
369 .func("get_branch_key")
370 .push_str(branchname())
371 .call(1,1)
372 .extract_str(key)
373 .ok();
374
375 if (!ok || key.empty())
376 return false;
377 else
378 {
379 key_identity_info identity;
380 project.get_key_identity(keys, *this, external_key_name(key, origin::user), identity);
381 k = identity.id;
382 return true;
383 }
384}
385
386bool
387lua_hooks::hook_get_author(branch_name const & branchname,
388 key_identity_info const & identity,
389 string & author)
390{
391 Lua ll(st);
392 ll.func("get_author")
393 .push_str(branchname());
394 push_key_identity_info(ll, identity);
395 return ll.call(2,1)
396 .extract_str(author)
397 .ok();
398}
399
400bool
401lua_hooks::hook_edit_comment(external const & user_log_message,
402 external & result)
403{
404 string result_str;
405 bool is_ok = Lua(st)
406 .func("edit_comment")
407 .push_str(user_log_message())
408 .call(1,1)
409 .extract_str(result_str)
410 .ok();
411 result = external(result_str, origin::user);
412 return is_ok;
413}
414
415bool
416lua_hooks::hook_ignore_file(file_path const & p)
417{
418 bool ignore_it = false;
419 bool exec_ok = Lua(st)
420 .func("ignore_file")
421 .push_str(p.as_external())
422 .call(1,1)
423 .extract_bool(ignore_it)
424 .ok();
425 return exec_ok && ignore_it;
426}
427
428bool
429lua_hooks::hook_ignore_branch(branch_name const & branch)
430{
431 bool ignore_it = false;
432 bool exec_ok = Lua(st)
433 .func("ignore_branch")
434 .push_str(branch())
435 .call(1,1)
436 .extract_bool(ignore_it)
437 .ok();
438 return exec_ok && ignore_it;
439}
440
441namespace {
442 template<typename ID>
443 Lua & push_key_ident(Lua & ll, ID const & ident)
444 {
445 enum dummp { d = ( sizeof(struct not_a_key_id_type) == sizeof(ID))};
446 return ll;
447 }
448 template<>
449 Lua & push_key_ident(Lua & ll, key_identity_info const & ident)
450 {
451 return push_key_identity_info(ll, ident);
452 }
453 template<>
454 Lua & push_key_ident(Lua & ll, key_name const & ident)
455 {
456 return ll.push_str(ident());
457 }
458 template<typename ID>
459 bool
460 shared_trust_function_body(Lua & ll,
461 std::set<ID> const & signers,
462 id const & hash,
463 cert_name const & name,
464 cert_value const & val)
465 {
466 ll.push_table();
467
468 int k = 1;
469 for (typename std::set<ID>::const_iterator v = signers.begin();
470 v != signers.end(); ++v)
471 {
472 ll.push_int(k);
473 push_key_ident(ll, *v);
474 ll.set_table();
475 ++k;
476 }
477
478 hexenc<id> hid(encode_hexenc(hash(), hash.made_from), hash.made_from);
479 bool ok;
480 bool exec_ok = ll
481 .push_str(hid())
482 .push_str(name())
483 .push_str(val())
484 .call(4, 1)
485 .extract_bool(ok)
486 .ok();
487
488 return exec_ok && ok;
489 }
490}
491
492bool
493lua_hooks::hook_get_revision_cert_trust(std::set<key_identity_info> const & signers,
494 id const & hash,
495 cert_name const & name,
496 cert_value const & val)
497{
498 Lua ll(st);
499 ll.func("get_revision_cert_trust");
500 return shared_trust_function_body(ll, signers, hash, name, val);
501}
502
503bool
504lua_hooks::hook_get_manifest_cert_trust(std::set<key_name> const & signers,
505 id const & hash,
506 cert_name const & name,
507 cert_value const & val)
508{
509 Lua ll(st);
510 ll.func("get_manifest_cert_trust");
511 return shared_trust_function_body(ll, signers, hash, name, val);
512}
513
514bool
515lua_hooks::hook_accept_testresult_change(map<key_id, bool> const & old_results,
516 map<key_id, bool> const & new_results)
517{
518 Lua ll(st);
519 ll
520 .func("accept_testresult_change")
521 .push_table();
522
523 for (map<key_id, bool>::const_iterator i = old_results.begin();
524 i != old_results.end(); ++i)
525 {
526 ll.push_str(i->first.inner()());
527 ll.push_bool(i->second);
528 ll.set_table();
529 }
530
531 ll.push_table();
532
533 for (map<key_id, bool>::const_iterator i = new_results.begin();
534 i != new_results.end(); ++i)
535 {
536 ll.push_str(i->first.inner()());
537 ll.push_bool(i->second);
538 ll.set_table();
539 }
540
541 bool ok;
542 bool exec_ok = ll
543 .call(2, 1)
544 .extract_bool(ok)
545 .ok();
546
547 return exec_ok && ok;
548}
549
550
551
552bool
553lua_hooks::hook_merge3(file_path const & anc_path,
554 file_path const & left_path,
555 file_path const & right_path,
556 file_path const & merged_path,
557 data const & ancestor,
558 data const & left,
559 data const & right,
560 data & result)
561{
562 string res;
563 bool ok = Lua(st)
564 .func("merge3")
565 .push_str(anc_path.as_external())
566 .push_str(left_path.as_external())
567 .push_str(right_path.as_external())
568 .push_str(merged_path.as_external())
569 .push_str(ancestor())
570 .push_str(left())
571 .push_str(right())
572 .call(7,1)
573 .extract_str(res)
574 .ok();
575 result = data(res, origin::user);
576 return ok;
577}
578
579bool
580lua_hooks::hook_external_diff(file_path const & path,
581 data const & data_old,
582 data const & data_new,
583 bool is_binary,
584 bool diff_args_provided,
585 string const & diff_args,
586 string const & oldrev,
587 string const & newrev)
588{
589 Lua ll(st);
590
591 ll
592 .func("external_diff")
593 .push_str(path.as_external());
594
595 if (oldrev.length() != 0)
596 ll.push_str(data_old());
597 else
598 ll.push_nil();
599
600 ll.push_str(data_new());
601
602 ll.push_bool(is_binary);
603
604 if (diff_args_provided)
605 ll.push_str(diff_args);
606 else
607 ll.push_nil();
608
609 ll.push_str(oldrev);
610 ll.push_str(newrev);
611
612 return ll.call(7,0).ok();
613}
614
615bool
616lua_hooks::hook_get_encloser_pattern(file_path const & path,
617 string & pattern)
618{
619 bool exec_ok
620 = Lua(st)
621 .func("get_encloser_pattern")
622 .push_str(path.as_external())
623 .call(1, 1)
624 .extract_str(pattern)
625 .ok();
626
627 // If the hook fails, make sure pattern is set to something sane
628 // (the empty string, which will disable enclosers for this file).
629 if (!exec_ok)
630 pattern = "";
631 return exec_ok;
632}
633
634bool
635lua_hooks::hook_get_default_command_options(commands::command_id const & cmd,
636 args_vector & args)
637{
638 Lua ll(st);
639 ll.func("get_default_command_options");
640
641 ll.push_table();
642 int k = 1;
643
644 // skip the first ID part, the command group, since this is mostly
645 // useless for the hook implementor
646 vector<utf8>::const_iterator i = cmd.begin();
647 i++;
648
649 for ( ; i != cmd.end(); ++i)
650 {
651 ll.push_int(k);
652 ll.push_str((*i)());
653 ll.set_table();
654 k++;
655 }
656
657 ll.call(1, 1);
658
659 ll.begin();
660 while (ll.next())
661 {
662 string arg;
663 ll.extract_str(arg).pop();
664 args.push_back(arg_type(arg, origin::user));
665 }
666 return ll.ok() && !args.empty();
667}
668
669bool
670lua_hooks::hook_get_date_format_spec(date_format_spec in, string & out)
671{
672 string in_spec;
673 switch (in)
674 {
675 case date_long: in_spec = "date_long"; break;
676 case date_short: in_spec = "date_short"; break;
677 case time_long: in_spec = "time_long"; break;
678 case time_short: in_spec = "time_short"; break;
679 case date_time_long: in_spec = "date_time_long"; break;
680 case date_time_short: in_spec = "date_time_short"; break;
681 default: I(false);
682 }
683
684 bool exec_ok
685 = Lua(st)
686 .func("get_date_format_spec")
687 .push_str(in_spec)
688 .call(1, 1)
689 .extract_str(out)
690 .ok();
691
692 // If the hook fails, disable date formatting.
693 if (!exec_ok)
694 out = "";
695 return exec_ok;
696}
697
698bool lua_hooks::hook_get_default_database_alias(string & alias)
699{
700 bool exec_ok
701 = Lua(st)
702 .func("get_default_database_alias")
703 .call(0, 1)
704 .extract_str(alias)
705 .ok();
706
707 return exec_ok;
708}
709
710bool lua_hooks::hook_get_default_database_locations(vector<system_path> & out)
711{
712 Lua ll(st);
713 ll.func("get_default_database_locations");
714 ll.call(0, 1);
715
716 ll.begin();
717 while (ll.next())
718 {
719 string path;
720 ll.extract_str(path).pop();
721 out.push_back(system_path(path, origin::user));
722 }
723 return ll.ok();
724}
725
726bool lua_hooks::hook_get_default_database_glob(globish & out)
727{
728 string glob;
729 bool exec_ok
730 = Lua(st)
731 .func("get_default_database_glob")
732 .call(0, 1)
733 .extract_str(glob)
734 .ok();
735
736 out = globish(glob, origin::user);
737 return exec_ok;
738}
739
740bool lua_hooks::hook_hook_wrapper(string const & func_name,
741 vector<string> const & args,
742 string & out)
743{
744 Lua ll(st);
745 ll.func("hook_wrapper")
746 .push_str(func_name);
747
748 for (vector<string>::const_iterator i = args.begin();
749 i != args.end(); ++i)
750 {
751 ll.push_str(*i);
752 }
753
754 ll.call(args.size() + 1, 1);
755 ll.extract_str_nolog(out);
756 return ll.ok();
757}
758
759bool
760lua_hooks::hook_get_man_page_formatter_command(string & command)
761{
762 bool exec_ok
763 = Lua(st)
764 .func("get_man_page_formatter_command")
765 .call(0, 1)
766 .extract_str(command)
767 .ok();
768
769 return exec_ok;
770}
771
772bool
773lua_hooks::hook_use_inodeprints()
774{
775 bool use = false, exec_ok = false;
776
777 exec_ok = Lua(st)
778 .func("use_inodeprints")
779 .call(0, 1)
780 .extract_bool(use)
781 .ok();
782 return use && exec_ok;
783}
784
785bool
786lua_hooks::hook_get_netsync_client_key(utf8 const & server_address,
787 globish const & include,
788 globish const & exclude,
789 key_store & keys,
790 project_t & project,
791 key_id & k)
792{
793 string name;
794 bool exec_ok
795 = Lua(st)
796 .func("get_netsync_client_key")
797 .push_str(server_address())
798 .push_str(include())
799 .push_str(exclude())
800 .call(3, 1)
801 .extract_str(name)
802 .ok();
803
804 if (!exec_ok || name.empty())
805 return false;
806 else
807 {
808 key_identity_info identity;
809 project.get_key_identity(keys, *this, external_key_name(name, origin::user), identity);
810 k = identity.id;
811 return true;
812 }
813}
814
815bool
816lua_hooks::hook_get_netsync_server_key(vector<utf8> const & server_ports,
817 key_store & keys,
818 project_t & project,
819 key_id & k)
820{
821 string name;
822 Lua ll(st);
823 ll.func("get_netsync_server_key");
824
825 ll.push_table();
826 vector<utf8>::const_iterator i;
827 int j;
828 for (i = server_ports.begin(), j = 1; i != server_ports.end(); ++i, ++j)
829 {
830 ll.push_int(j);
831 ll.push_str((*i)());
832 ll.set_table();
833 }
834
835 bool exec_ok = ll.call(1, 1)
836 .extract_str(name)
837 .ok();
838
839 if (!exec_ok || name.empty())
840 return false;
841 else
842 {
843 key_identity_info identity;
844 project.get_key_identity(keys, *this, external_key_name(name, origin::user), identity);
845 k = identity.id;
846 return true;
847 }
848}
849
850static void
851push_uri(uri_t const & uri, Lua & ll)
852{
853 ll.push_table();
854
855 if (!uri.scheme.empty())
856 {
857 ll.push_str("scheme");
858 ll.push_str(uri.scheme);
859 ll.set_table();
860 }
861
862 if (!uri.user.empty())
863 {
864 ll.push_str("user");
865 ll.push_str(uri.user);
866 ll.set_table();
867 }
868
869 if (!uri.host.empty())
870 {
871 ll.push_str("host");
872 ll.push_str(uri.host);
873 ll.set_table();
874 }
875
876 if (!uri.port.empty())
877 {
878 ll.push_str("port");
879 ll.push_str(uri.port);
880 ll.set_table();
881 }
882
883 if (!uri.path.empty())
884 {
885 ll.push_str("path");
886 ll.push_str(uri.path);
887 ll.set_table();
888 }
889
890 if (!uri.query.empty())
891 {
892 ll.push_str("query");
893 ll.push_str(uri.query);
894 ll.set_table();
895 }
896
897 if (!uri.fragment.empty())
898 {
899 ll.push_str("fragment");
900 ll.push_str(uri.fragment);
901 ll.set_table();
902 }
903}
904
905bool
906lua_hooks::hook_get_netsync_connect_command(uri_t const & uri,
907 globish const & include_pattern,
908 globish const & exclude_pattern,
909 bool debug,
910 vector<string> & argv)
911{
912 bool cmd = false, exec_ok = false;
913 Lua ll(st);
914 ll.func("get_netsync_connect_command");
915
916 push_uri(uri, ll);
917
918 ll.push_table();
919
920 if (!include_pattern().empty())
921 {
922 ll.push_str("include");
923 ll.push_str(include_pattern());
924 ll.set_table();
925 }
926
927 if (!exclude_pattern().empty())
928 {
929 ll.push_str("exclude");
930 ll.push_str(exclude_pattern());
931 ll.set_table();
932 }
933
934 if (debug)
935 {
936 ll.push_str("debug");
937 ll.push_bool(debug);
938 ll.set_table();
939 }
940
941 ll.call(2,1);
942
943 ll.begin();
944
945 argv.clear();
946 while(ll.next())
947 {
948 string s;
949 ll.extract_str(s).pop();
950 argv.push_back(s);
951 }
952 return ll.ok() && !argv.empty();
953}
954
955
956bool
957lua_hooks::hook_use_transport_auth(uri_t const & uri)
958{
959 bool use_auth = true;
960 Lua ll(st);
961 ll.func("use_transport_auth");
962 push_uri(uri, ll);
963 ll.call(1,1);
964 ll.extract_bool(use_auth);
965
966 // NB: we want to return *true* here if there's a failure.
967 return use_auth;
968}
969
970
971bool
972lua_hooks::hook_get_netsync_read_permitted(string const & branch,
973 key_identity_info const & identity)
974{
975 bool permitted = false, exec_ok = false;
976
977 Lua ll(st);
978 ll.func("get_netsync_read_permitted")
979 .push_str(branch);
980 push_key_identity_info(ll, identity);
981 exec_ok = ll.call(2,1)
982 .extract_bool(permitted)
983 .ok();
984
985 return exec_ok && permitted;
986}
987
988// Anonymous no-key version
989bool
990lua_hooks::hook_get_netsync_read_permitted(string const & branch)
991{
992 bool permitted = false, exec_ok = false;
993
994 exec_ok = Lua(st)
995 .func("get_netsync_read_permitted")
996 .push_str(branch)
997 .push_nil()
998 .call(2,1)
999 .extract_bool(permitted)
1000 .ok();
1001
1002 return exec_ok && permitted;
1003}
1004
1005bool
1006lua_hooks::hook_get_netsync_write_permitted(key_identity_info const & identity)
1007{
1008 bool permitted = false, exec_ok = false;
1009
1010 Lua ll(st);
1011 ll.func("get_netsync_write_permitted");
1012 push_key_identity_info(ll, identity);
1013 exec_ok = ll.call(1,1)
1014 .extract_bool(permitted)
1015 .ok();
1016
1017 return exec_ok && permitted;
1018}
1019
1020bool
1021lua_hooks::hook_get_remote_automate_permitted(key_identity_info const & identity,
1022 vector<string> const & command_line,
1023 vector<pair<string, string> > const & command_opts)
1024{
1025 Lua ll(st);
1026 ll.func("get_remote_automate_permitted");
1027 push_key_identity_info(ll, identity);
1028
1029 int k = 1;
1030
1031 ll.push_table();
1032 vector<string>::const_iterator l;
1033 for (l = command_line.begin(), k = 1; l != command_line.end(); ++l, ++k)
1034 {
1035 ll.push_int(k);
1036 ll.push_str(*l);
1037 ll.set_table();
1038 }
1039 ll.push_table();
1040 k = 1;
1041 vector<pair<string, string> >::const_iterator o;
1042 for (o = command_opts.begin(), k = 1; o != command_opts.end(); ++o, ++k)
1043 {
1044 ll.push_int(k);
1045
1046 {
1047 ll.push_table();
1048
1049 ll.push_str("name");
1050 ll.push_str(o->first);
1051 ll.set_table();
1052
1053 ll.push_str("value");
1054 ll.push_str(o->second);
1055 ll.set_table();
1056 }
1057
1058 ll.set_table();
1059 }
1060
1061 ll.call(3, 1);
1062
1063 bool permitted(false);
1064 ll.extract_bool(permitted);
1065 return ll.ok() && permitted;
1066}
1067
1068bool
1069lua_hooks::hook_init_attributes(file_path const & filename,
1070 map<string, string> & attrs)
1071{
1072 Lua ll(st);
1073
1074 ll
1075 .push_str("attr_init_functions")
1076 .get_tab();
1077
1078 L(FL("calling attr_init_function for %s") % filename);
1079 ll.begin();
1080 while (ll.next())
1081 {
1082 L(FL(" calling an attr_init_function for %s") % filename);
1083 ll.push_str(filename.as_external());
1084 ll.call(1, 1);
1085
1086 if (lua_isstring(st, -1))
1087 {
1088 string key, value;
1089
1090 ll.extract_str(value);
1091 ll.pop();
1092 ll.extract_str(key);
1093
1094 attrs[key] = value;
1095 L(FL(" added attr %s = %s") % key % value);
1096 }
1097 else
1098 {
1099 L(FL(" no attr added"));
1100 ll.pop();
1101 }
1102 }
1103
1104 return ll.pop().ok();
1105}
1106
1107bool
1108lua_hooks::hook_set_attribute(string const & attr,
1109 file_path const & filename,
1110 string const & value)
1111{
1112 return Lua(st)
1113 .push_str("attr_functions")
1114 .get_tab()
1115 .push_str(attr)
1116 .get_fn(-2)
1117 .push_str(filename.as_external())
1118 .push_str(value)
1119 .call(2,0)
1120 .ok();
1121}
1122
1123bool
1124lua_hooks::hook_clear_attribute(string const & attr,
1125 file_path const & filename)
1126{
1127 return Lua(st)
1128 .push_str("attr_functions")
1129 .get_tab()
1130 .push_str(attr)
1131 .get_fn(-2)
1132 .push_str(filename.as_external())
1133 .push_nil()
1134 .call(2,0)
1135 .ok();
1136}
1137
1138bool
1139lua_hooks::hook_validate_changes(revision_data const & new_rev,
1140 branch_name const & branchname,
1141 bool & validated,
1142 string & reason)
1143{
1144 validated = true;
1145 return Lua(st)
1146 .func("validate_changes")
1147 .push_str(new_rev.inner()())
1148 .push_str(branchname())
1149 .call(2, 2)
1150 .extract_str(reason)
1151 // XXX When validated, the extra returned string is superfluous.
1152 .pop()
1153 .extract_bool(validated)
1154 .ok();
1155}
1156
1157bool
1158lua_hooks::hook_validate_commit_message(utf8 const & message,
1159 revision_data const & new_rev,
1160 branch_name const & branchname,
1161 bool & validated,
1162 string & reason)
1163{
1164 validated = true;
1165 return Lua(st)
1166 .func("validate_commit_message")
1167 .push_str(message())
1168 .push_str(new_rev.inner()())
1169 .push_str(branchname())
1170 .call(3, 2)
1171 .extract_str(reason)
1172 // XXX When validated, the extra returned string is superfluous.
1173 .pop()
1174 .extract_bool(validated)
1175 .ok();
1176}
1177
1178bool
1179lua_hooks::hook_note_commit(revision_id const & new_id,
1180 revision_data const & rdat,
1181 map<cert_name, cert_value> const & certs)
1182{
1183 Lua ll(st);
1184 ll
1185 .func("note_commit")
1186 .push_str(encode_hexenc(new_id.inner()(), new_id.inner().made_from))
1187 .push_str(rdat.inner()());
1188
1189 ll.push_table();
1190
1191 for (map<cert_name, cert_value>::const_iterator i = certs.begin();
1192 i != certs.end(); ++i)
1193 {
1194 ll.push_str(i->first());
1195 ll.push_str(i->second());
1196 ll.set_table();
1197 }
1198
1199 ll.call(3, 0);
1200 return ll.ok();
1201}
1202
1203bool
1204lua_hooks::hook_note_netsync_start(size_t session_id, string my_role,
1205 int sync_type, string remote_host,
1206 key_identity_info const & remote_key,
1207 globish include_pattern,
1208 globish exclude_pattern)
1209{
1210 string type;
1211 switch (sync_type)
1212 {
1213 case 1:
1214 type = "push";
1215 break;
1216 case 2:
1217 type = "pull";
1218 break;
1219 case 3:
1220 type = "sync";
1221 break;
1222 default:
1223 type = "unknown";
1224 break;
1225 }
1226 Lua ll(st);
1227 ll.func("note_netsync_start")
1228 .push_int(session_id)
1229 .push_str(my_role)
1230 .push_str(type)
1231 .push_str(remote_host);
1232 push_key_identity_info(ll, remote_key);
1233 return ll.push_str(include_pattern())
1234 .push_str(exclude_pattern())
1235 .call(7, 0)
1236 .ok();
1237}
1238
1239bool
1240lua_hooks::hook_note_netsync_revision_received(revision_id const & new_id,
1241 revision_data const & rdat,
1242 std::set<pair<key_identity_info,
1243 pair<cert_name,
1244 cert_value> > > const & certs,
1245 size_t session_id)
1246{
1247 Lua ll(st);
1248 ll
1249 .func("note_netsync_revision_received")
1250 .push_str(encode_hexenc(new_id.inner()(), new_id.inner().made_from))
1251 .push_str(rdat.inner()());
1252
1253 ll.push_table();
1254
1255 typedef std::set<pair<key_identity_info, pair<cert_name, cert_value> > > cdat;
1256
1257 int n = 1;
1258 for (cdat::const_iterator i = certs.begin(); i != certs.end(); ++i)
1259 {
1260 ll.push_int(n++);
1261 ll.push_table();
1262 push_key_identity_info(ll, i->first);
1263 ll.set_field("key");
1264 ll.push_str(i->second.first());
1265 ll.set_field("name");
1266 ll.push_str(i->second.second());
1267 ll.set_field("value");
1268 ll.set_table();
1269 }
1270
1271 ll.push_int(session_id);
1272 ll.call(4, 0);
1273 return ll.ok();
1274}
1275
1276bool
1277lua_hooks::hook_note_netsync_revision_sent(revision_id const & new_id,
1278 revision_data const & rdat,
1279 std::set<pair<key_identity_info,
1280 pair<cert_name,
1281 cert_value> > > const & certs,
1282 size_t session_id)
1283{
1284 Lua ll(st);
1285 ll
1286 .func("note_netsync_revision_sent")
1287 .push_str(encode_hexenc(new_id.inner()(), new_id.inner().made_from))
1288 .push_str(rdat.inner()());
1289
1290 ll.push_table();
1291
1292 typedef std::set<pair<key_identity_info, pair<cert_name, cert_value> > > cdat;
1293
1294 int n = 1;
1295 for (cdat::const_iterator i = certs.begin(); i != certs.end(); ++i)
1296 {
1297 ll.push_int(n++);
1298 ll.push_table();
1299 push_key_identity_info(ll, i->first);
1300 ll.set_field("key");
1301 ll.push_str(i->second.first());
1302 ll.set_field("name");
1303 ll.push_str(i->second.second());
1304 ll.set_field("value");
1305 ll.set_table();
1306 }
1307
1308 ll.push_int(session_id);
1309 ll.call(4, 0);
1310 return ll.ok();
1311}
1312
1313bool
1314lua_hooks::hook_note_netsync_pubkey_received(key_identity_info const & identity,
1315 size_t session_id)
1316{
1317 Lua ll(st);
1318 ll
1319 .func("note_netsync_pubkey_received");
1320 push_key_identity_info(ll, identity);
1321 ll.push_int(session_id);
1322
1323 ll.call(2, 0);
1324 return ll.ok();
1325}
1326
1327bool
1328lua_hooks::hook_note_netsync_pubkey_sent(key_identity_info const & identity,
1329 size_t session_id)
1330{
1331 Lua ll(st);
1332 ll
1333 .func("note_netsync_pubkey_sent");
1334 push_key_identity_info(ll, identity);
1335 ll.push_int(session_id);
1336
1337 ll.call(2, 0);
1338 return ll.ok();
1339}
1340
1341bool
1342lua_hooks::hook_note_netsync_cert_received(revision_id const & rid,
1343 key_identity_info const & identity,
1344 cert_name const & name,
1345 cert_value const & value,
1346 size_t session_id)
1347{
1348 Lua ll(st);
1349 ll
1350 .func("note_netsync_cert_received")
1351 .push_str(encode_hexenc(rid.inner()(), rid.inner().made_from));
1352 push_key_identity_info(ll, identity);
1353 ll.push_str(name())
1354 .push_str(value())
1355 .push_int(session_id);
1356
1357 ll.call(5, 0);
1358 return ll.ok();
1359}
1360
1361bool
1362lua_hooks::hook_note_netsync_cert_sent(revision_id const & rid,
1363 key_identity_info const & identity,
1364 cert_name const & name,
1365 cert_value const & value,
1366 size_t session_id)
1367{
1368 Lua ll(st);
1369 ll
1370 .func("note_netsync_cert_sent")
1371 .push_str(encode_hexenc(rid.inner()(), rid.inner().made_from));
1372 push_key_identity_info(ll, identity);
1373 ll.push_str(name())
1374 .push_str(value())
1375 .push_int(session_id);
1376
1377 ll.call(5, 0);
1378 return ll.ok();
1379}
1380
1381bool
1382lua_hooks::hook_note_netsync_end(size_t session_id, int status,
1383 size_t bytes_in, size_t bytes_out,
1384 size_t certs_in, size_t certs_out,
1385 size_t revs_in, size_t revs_out,
1386 size_t keys_in, size_t keys_out)
1387{
1388 Lua ll(st);
1389 return ll
1390 .func("note_netsync_end")
1391 .push_int(session_id)
1392 .push_int(status)
1393 .push_int(bytes_in)
1394 .push_int(bytes_out)
1395 .push_int(certs_in)
1396 .push_int(certs_out)
1397 .push_int(revs_in)
1398 .push_int(revs_out)
1399 .push_int(keys_in)
1400 .push_int(keys_out)
1401 .call(10, 0)
1402 .ok();
1403}
1404
1405bool
1406lua_hooks::hook_note_mtn_startup(args_vector const & args)
1407{
1408 Lua ll(st);
1409
1410 ll.func("note_mtn_startup");
1411
1412 for (args_vector::const_iterator i = args.begin(); i != args.end(); ++i)
1413 ll.push_str((*i)());
1414
1415 ll.call(args.size(), 0);
1416 return ll.ok();
1417}
1418
1419bool
1420lua_hooks::hook_unmapped_git_author(string const & unmapped_author, string & fixed_author)
1421{
1422 return Lua(st)
1423 .func("unmapped_git_author")
1424 .push_str(unmapped_author)
1425 .call(1,1)
1426 .extract_str(fixed_author)
1427 .ok();
1428}
1429
1430bool
1431lua_hooks::hook_validate_git_author(string const & author)
1432{
1433 bool valid = false, exec_ok = false;
1434 exec_ok = Lua(st)
1435 .func("validate_git_author")
1436 .push_str(author)
1437 .call(1,1)
1438 .extract_bool(valid)
1439 .ok();
1440 return valid && exec_ok;
1441}
1442
1443// Local Variables:
1444// mode: C++
1445// fill-column: 76
1446// c-file-style: "gnu"
1447// indent-tabs-mode: nil
1448// End:
1449// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

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