monotone

monotone Mtn Source Tree

Root/lua_hooks.cc

1// Copyright (C) 2008 Stephen Leake <stephen_leake@stephe-leake.org>
2// Copyright (C) 2002 Graydon Hoare <graydon@pobox.com>
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#include "lua.h"
14#include "lualib.h"
15#include "lauxlib.h"
16
17#include <set>
18#include <map>
19#include <fstream>
20#include <iostream>
21
22#include "lua.hh"
23
24#include "app_state.hh"
25#include "file_io.hh"
26#include "lua_hooks.hh"
27#include "sanity.hh"
28#include "vocab.hh"
29#include "transforms.hh"
30#include "paths.hh"
31#include "uri.hh"
32#include "cmd.hh"
33#include "commands.hh"
34#include "globish.hh"
35
36// defined in std_hooks.c, generated from std_hooks.lua
37extern char const std_hooks_constant[];
38
39using std::make_pair;
40using std::map;
41using std::pair;
42using std::set;
43using std::sort;
44using std::string;
45using std::vector;
46
47static int panic_thrower(lua_State * st)
48{
49 throw oops("lua panic");
50}
51
52// this lets the lua callbacks (monotone_*_for_lua) have access to the
53// app_state the're associated with.
54// it was added so that the confdir (normally ~/.monotone) can be specified on
55// the command line (and so known only to the app_state), and still be
56// available to lua
57// please *don't* use it for complex things that can throw errors
58static map<lua_State*, app_state*> map_of_lua_to_app;
59
60extern "C"
61{
62 static int
63 monotone_get_confdir_for_lua(lua_State *L)
64 {
65 map<lua_State*, app_state*>::iterator i = map_of_lua_to_app.find(L);
66 if (i != map_of_lua_to_app.end())
67 {
68 if (i->second->opts.conf_dir_given
69 || !i->second->opts.no_default_confdir)
70 {
71 system_path dir = i->second->opts.conf_dir;
72 string confdir = dir.as_external();
73 lua_pushstring(L, confdir.c_str());
74 }
75 else
76 lua_pushnil(L);
77 }
78 else
79 lua_pushnil(L);
80 return 1;
81 }
82}
83
84app_state*
85get_app_state(lua_State *L)
86{
87 map<lua_State*, app_state*>::iterator i = map_of_lua_to_app.find(L);
88 if (i != map_of_lua_to_app.end())
89 return i->second;
90 else
91 return NULL;
92}
93
94lua_hooks::lua_hooks(app_state * app)
95{
96 st = luaL_newstate();
97 I(st);
98
99 lua_atpanic (st, &panic_thrower);
100
101 luaL_openlibs(st);
102
103 lua_register(st, "get_confdir", monotone_get_confdir_for_lua);
104 add_functions(st);
105
106 // Disable any functions we don't want. This is easiest
107 // to do just by running a lua string.
108 static char const disable_dangerous[] =
109 "os.execute = function(c) "
110 " error(\"os.execute disabled for security reasons. Try spawn().\") "
111 "end "
112 "io.popen = function(c,t) "
113 " error(\"io.popen disabled for security reasons. Try spawn_pipe().\") "
114 "end ";
115
116 if (!run_string(st, disable_dangerous,
117 "<disabled dangerous functions>"))
118 throw oops("lua error while disabling existing functions");
119
120 map_of_lua_to_app.insert(make_pair(st, app));
121}
122
123lua_hooks::~lua_hooks()
124{
125 map<lua_State*, app_state*>::iterator i = map_of_lua_to_app.find(st);
126 if (st)
127 lua_close (st);
128 if (i != map_of_lua_to_app.end())
129 map_of_lua_to_app.erase(i);
130}
131
132bool
133lua_hooks::check_lua_state(lua_State * p_st) const
134{
135 return (p_st == st);
136}
137
138void
139lua_hooks::add_std_hooks()
140{
141 if (!run_string(st, std_hooks_constant, "<std hooks>"))
142 throw oops("lua error while setting up standard hooks");
143}
144
145void
146lua_hooks::load_rcfile(utf8 const & rc)
147{
148 I(st);
149 if (rc() != "-" && directory_exists(system_path(rc)))
150 run_directory(st, system_path(rc).as_external().c_str(), "*");
151 else
152 {
153 data dat;
154 L(FL("opening rcfile '%s'") % rc);
155 read_data_for_command_line(rc, dat);
156 N(run_string(st, dat().c_str(), rc().c_str()),
157 F("lua error while loading rcfile '%s'") % rc);
158 L(FL("'%s' is ok") % rc);
159 }
160}
161
162void
163lua_hooks::load_rcfile(any_path const & rc, bool required)
164{
165 I(st);
166 bool exists;
167 try
168 {
169 exists = path_exists(rc);
170 }
171 catch (informative_failure & e)
172 {
173 if (!required)
174 {
175 L(FL("skipping rcfile '%s': %s") % rc % e.what());
176 return;
177 }
178 else
179 throw;
180 }
181
182 if (exists)
183 {
184 L(FL("opening rcfile '%s'") % rc);
185 N(run_file(st, rc.as_external().c_str()),
186 F("lua error while loading '%s'") % rc);
187 L(FL("'%s' is ok") % rc);
188 }
189 else
190 {
191 N(!required, F("rcfile '%s' does not exist") % rc);
192 L(FL("skipping nonexistent rcfile '%s'") % rc);
193 }
194}
195
196void
197lua_hooks::load_rcfiles(options & opts)
198{
199 // Built-in rc settings are defaults.
200 if (!opts.nostd)
201 add_std_hooks();
202
203 // ~/.monotone/monotonerc overrides that, and
204 // _MTN/monotonerc overrides *that*.
205
206 if (!opts.norc)
207 {
208 if (opts.conf_dir_given || !opts.no_default_confdir)
209 {
210 load_rcfile(opts.conf_dir / "monotonerc", false);
211 }
212 load_rcfile(bookkeeping_root / "monotonerc", false);
213 }
214
215 // Command-line rcfiles override even that.
216
217 for (args_vector::const_iterator i = opts.extra_rcfiles.begin();
218 i != opts.extra_rcfiles.end(); ++i)
219 load_rcfile(*i);
220}
221
222bool
223lua_hooks::hook_exists(std::string const & func_name)
224{
225 return Lua(st)
226 .func(func_name)
227 .ok();
228}
229
230// concrete hooks
231
232// nb: if you're hooking lua to return your passphrase, you don't care if we
233// keep a couple extra temporaries of your passphrase around.
234bool
235lua_hooks::hook_get_passphrase(rsa_keypair_id const & k, string & phrase)
236{
237 return Lua(st)
238 .func("get_passphrase")
239 .push_str(k())
240 .call(1,1)
241 .extract_classified_str(phrase)
242 .ok();
243}
244
245bool
246lua_hooks::hook_persist_phrase_ok()
247{
248 bool persist_ok = false;
249 bool executed_ok = Lua(st)
250 .func("persist_phrase_ok")
251 .call(0,1)
252 .extract_bool(persist_ok)
253 .ok();
254 return executed_ok && persist_ok;
255}
256
257bool
258lua_hooks::hook_expand_selector(string const & sel,
259 string & exp)
260{
261 return Lua(st)
262 .func("expand_selector")
263 .push_str(sel)
264 .call(1,1)
265 .extract_str(exp)
266 .ok();
267}
268
269bool
270lua_hooks::hook_expand_date(string const & sel,
271 string & exp)
272{
273 exp.clear();
274 bool res= Lua(st)
275 .func("expand_date")
276 .push_str(sel)
277 .call(1,1)
278 .extract_str(exp)
279 .ok();
280 return res && exp.size();
281}
282
283bool
284lua_hooks::hook_get_branch_key(branch_name const & branchname,
285 rsa_keypair_id & k)
286{
287 string key;
288 bool ok = Lua(st)
289 .func("get_branch_key")
290 .push_str(branchname())
291 .call(1,1)
292 .extract_str(key)
293 .ok();
294
295 k = rsa_keypair_id(key);
296 return ok;
297}
298
299bool
300lua_hooks::hook_get_author(branch_name const & branchname,
301 rsa_keypair_id const & k,
302 string & author)
303{
304 return Lua(st)
305 .func("get_author")
306 .push_str(branchname())
307 .push_str(k())
308 .call(2,1)
309 .extract_str(author)
310 .ok();
311}
312
313bool
314lua_hooks::hook_edit_comment(external const & commentary,
315 external const & user_log_message,
316 external & result)
317{
318 string result_str;
319 bool is_ok = Lua(st)
320 .func("edit_comment")
321 .push_str(commentary())
322 .push_str(user_log_message())
323 .call(2,1)
324 .extract_str(result_str)
325 .ok();
326 result = external(result_str);
327 return is_ok;
328}
329
330bool
331lua_hooks::hook_ignore_file(file_path const & p)
332{
333 bool ignore_it = false;
334 bool exec_ok = Lua(st)
335 .func("ignore_file")
336 .push_str(p.as_external())
337 .call(1,1)
338 .extract_bool(ignore_it)
339 .ok();
340 return exec_ok && ignore_it;
341}
342
343bool
344lua_hooks::hook_ignore_branch(branch_name const & branch)
345{
346 bool ignore_it = false;
347 bool exec_ok = Lua(st)
348 .func("ignore_branch")
349 .push_str(branch())
350 .call(1,1)
351 .extract_bool(ignore_it)
352 .ok();
353 return exec_ok && ignore_it;
354}
355
356static inline bool
357shared_trust_function_body(Lua & ll,
358 set<rsa_keypair_id> const & signers,
359 hexenc<id> const & hash,
360 cert_name const & name,
361 cert_value const & val)
362{
363 ll.push_table();
364
365 int k = 1;
366 for (set<rsa_keypair_id>::const_iterator v = signers.begin();
367 v != signers.end(); ++v)
368 {
369 ll.push_int(k);
370 ll.push_str((*v)());
371 ll.set_table();
372 ++k;
373 }
374
375 bool ok;
376 bool exec_ok = ll
377 .push_str(hash())
378 .push_str(name())
379 .push_str(val())
380 .call(4, 1)
381 .extract_bool(ok)
382 .ok();
383
384 return exec_ok && ok;
385}
386
387static inline bool
388shared_trust_function_body(Lua & ll,
389 set<rsa_keypair_id> const & signers,
390 id const & hash,
391 cert_name const & name,
392 cert_value const & val)
393{
394 hexenc<id> hid(encode_hexenc(hash()));
395 return shared_trust_function_body(ll, signers, hid, name, val);
396};
397
398bool
399lua_hooks::hook_get_revision_cert_trust(set<rsa_keypair_id> const & signers,
400 hexenc<id> const & id,
401 cert_name const & name,
402 cert_value const & val)
403{
404 Lua ll(st);
405 ll.func("get_revision_cert_trust");
406 return shared_trust_function_body(ll, signers, id, name, val);
407}
408
409bool
410lua_hooks::hook_get_revision_cert_trust(set<rsa_keypair_id> const & signers,
411 revision_id const & id,
412 cert_name const & name,
413 cert_value const & val)
414{
415 Lua ll(st);
416 ll.func("get_revision_cert_trust");
417 return shared_trust_function_body(ll, signers, id.inner(), name, val);
418}
419
420bool
421lua_hooks::hook_get_manifest_cert_trust(set<rsa_keypair_id> const & signers,
422 hexenc<id> const & id,
423 cert_name const & name,
424 cert_value const & val)
425{
426 Lua ll(st);
427 ll.func("get_manifest_cert_trust");
428 return shared_trust_function_body(ll, signers, id, name, val);
429}
430
431bool
432lua_hooks::hook_get_manifest_cert_trust(set<rsa_keypair_id> const & signers,
433 manifest_id const & id,
434 cert_name const & name,
435 cert_value const & val)
436{
437 Lua ll(st);
438 ll.func("get_manifest_cert_trust");
439 return shared_trust_function_body(ll, signers, id.inner(), name, val);
440}
441
442bool
443lua_hooks::hook_accept_testresult_change(map<rsa_keypair_id, bool> const & old_results,
444 map<rsa_keypair_id, bool> const & new_results)
445{
446 Lua ll(st);
447 ll
448 .func("accept_testresult_change")
449 .push_table();
450
451 for (map<rsa_keypair_id, bool>::const_iterator i = old_results.begin();
452 i != old_results.end(); ++i)
453 {
454 ll.push_str(i->first());
455 ll.push_bool(i->second);
456 ll.set_table();
457 }
458
459 ll.push_table();
460
461 for (map<rsa_keypair_id, bool>::const_iterator i = new_results.begin();
462 i != new_results.end(); ++i)
463 {
464 ll.push_str(i->first());
465 ll.push_bool(i->second);
466 ll.set_table();
467 }
468
469 bool ok;
470 bool exec_ok = ll
471 .call(2, 1)
472 .extract_bool(ok)
473 .ok();
474
475 return exec_ok && ok;
476}
477
478
479
480bool
481lua_hooks::hook_merge3(file_path const & anc_path,
482 file_path const & left_path,
483 file_path const & right_path,
484 file_path const & merged_path,
485 data const & ancestor,
486 data const & left,
487 data const & right,
488 data & result)
489{
490 string res;
491 bool ok = Lua(st)
492 .func("merge3")
493 .push_str(anc_path.as_external())
494 .push_str(left_path.as_external())
495 .push_str(right_path.as_external())
496 .push_str(merged_path.as_external())
497 .push_str(ancestor())
498 .push_str(left())
499 .push_str(right())
500 .call(7,1)
501 .extract_str(res)
502 .ok();
503 result = data(res);
504 return ok;
505}
506
507bool
508lua_hooks::hook_external_diff(file_path const & path,
509 data const & data_old,
510 data const & data_new,
511 bool is_binary,
512 bool diff_args_provided,
513 string const & diff_args,
514 string const & oldrev,
515 string const & newrev)
516{
517 Lua ll(st);
518
519 ll
520 .func("external_diff")
521 .push_str(path.as_external());
522
523 if (oldrev.length() != 0)
524 ll.push_str(data_old());
525 else
526 ll.push_nil();
527
528 ll.push_str(data_new());
529
530 ll.push_bool(is_binary);
531
532 if (diff_args_provided)
533 ll.push_str(diff_args);
534 else
535 ll.push_nil();
536
537 ll.push_str(oldrev);
538 ll.push_str(newrev);
539
540 return ll.call(7,0).ok();
541}
542
543bool
544lua_hooks::hook_get_encloser_pattern(file_path const & path,
545 std::string & pattern)
546{
547 bool exec_ok
548 = Lua(st)
549 .func("get_encloser_pattern")
550 .push_str(path.as_external())
551 .call(1, 1)
552 .extract_str(pattern)
553 .ok();
554
555 // If the hook fails, make sure pattern is set to something sane
556 // (the empty string, which will disable enclosers for this file).
557 if (!exec_ok)
558 pattern = "";
559 return exec_ok;
560}
561
562bool
563lua_hooks::hook_get_default_command_options(commands::command_id const & cmd,
564 args_vector & args)
565{
566 Lua ll(st);
567 ll.func("get_default_command_options");
568
569 ll.push_table();
570 int k = 1;
571
572 // skip the first ID part, the command group, since this is mostly
573 // useless for the hook implementor
574 vector<utf8>::const_iterator i = cmd.begin();
575 i++;
576
577 for ( ; i != cmd.end(); ++i)
578 {
579 ll.push_int(k);
580 ll.push_str((*i)());
581 ll.set_table();
582 k++;
583 }
584
585 ll.call(1, 1);
586
587 ll.begin();
588 while (ll.next())
589 {
590 std::string arg;
591 ll.extract_str(arg).pop();
592 args.push_back(arg_type(arg));
593 }
594 return ll.ok() && !args.empty();
595}
596
597bool
598lua_hooks::hook_use_inodeprints()
599{
600 bool use = false, exec_ok = false;
601
602 exec_ok = Lua(st)
603 .func("use_inodeprints")
604 .call(0, 1)
605 .extract_bool(use)
606 .ok();
607 return use && exec_ok;
608}
609
610bool
611lua_hooks::hook_get_netsync_key(utf8 const & server_address,
612 globish const & include,
613 globish const & exclude,
614 rsa_keypair_id & k)
615{
616 string key_id;
617 bool exec_ok
618 = Lua(st)
619 .func("get_netsync_key")
620 .push_str(server_address())
621 .push_str(include())
622 .push_str(exclude())
623 .call(3, 1)
624 .extract_str(key_id)
625 .ok();
626
627 if (!exec_ok)
628 key_id = "";
629 k = rsa_keypair_id(key_id);
630 return exec_ok;
631}
632
633static void
634push_uri(uri const & u, Lua & ll)
635{
636 ll.push_table();
637
638 if (!u.scheme.empty())
639 {
640 ll.push_str("scheme");
641 ll.push_str(u.scheme);
642 ll.set_table();
643 }
644
645 if (!u.user.empty())
646 {
647 ll.push_str("user");
648 ll.push_str(u.user);
649 ll.set_table();
650 }
651
652 if (!u.host.empty())
653 {
654 ll.push_str("host");
655 ll.push_str(u.host);
656 ll.set_table();
657 }
658
659 if (!u.port.empty())
660 {
661 ll.push_str("port");
662 ll.push_str(u.port);
663 ll.set_table();
664 }
665
666 if (!u.path.empty())
667 {
668 ll.push_str("path");
669 ll.push_str(u.path);
670 ll.set_table();
671 }
672
673 if (!u.query.empty())
674 {
675 ll.push_str("query");
676 ll.push_str(u.query);
677 ll.set_table();
678 }
679
680 if (!u.fragment.empty())
681 {
682 ll.push_str("fragment");
683 ll.push_str(u.fragment);
684 ll.set_table();
685 }
686}
687
688bool
689lua_hooks::hook_get_netsync_connect_command(uri const & u,
690 globish const & include_pattern,
691 globish const & exclude_pattern,
692 bool debug,
693 std::vector<std::string> & argv)
694{
695 bool cmd = false, exec_ok = false;
696 Lua ll(st);
697 ll.func("get_netsync_connect_command");
698
699 push_uri(u, ll);
700
701 ll.push_table();
702
703 if (!include_pattern().empty())
704 {
705 ll.push_str("include");
706 ll.push_str(include_pattern());
707 ll.set_table();
708 }
709
710 if (!exclude_pattern().empty())
711 {
712 ll.push_str("exclude");
713 ll.push_str(exclude_pattern());
714 ll.set_table();
715 }
716
717 if (debug)
718 {
719 ll.push_str("debug");
720 ll.push_bool(debug);
721 ll.set_table();
722 }
723
724 ll.call(2,1);
725
726 ll.begin();
727
728 argv.clear();
729 while(ll.next())
730 {
731 std::string s;
732 ll.extract_str(s).pop();
733 argv.push_back(s);
734 }
735 return ll.ok() && !argv.empty();
736}
737
738
739bool
740lua_hooks::hook_use_transport_auth(uri const & u)
741{
742 bool use_auth = true;
743 Lua ll(st);
744 ll.func("use_transport_auth");
745 push_uri(u, ll);
746 ll.call(1,1);
747 ll.extract_bool(use_auth);
748
749 // NB: we want to return *true* here if there's a failure.
750 return use_auth;
751}
752
753
754bool
755lua_hooks::hook_get_netsync_read_permitted(string const & branch,
756 rsa_keypair_id const & identity)
757{
758 bool permitted = false, exec_ok = false;
759
760 exec_ok = Lua(st)
761 .func("get_netsync_read_permitted")
762 .push_str(branch)
763 .push_str(identity())
764 .call(2,1)
765 .extract_bool(permitted)
766 .ok();
767
768 return exec_ok && permitted;
769}
770
771// Anonymous no-key version
772bool
773lua_hooks::hook_get_netsync_read_permitted(string const & branch)
774{
775 bool permitted = false, exec_ok = false;
776
777 exec_ok = Lua(st)
778 .func("get_netsync_read_permitted")
779 .push_str(branch)
780 .push_nil()
781 .call(2,1)
782 .extract_bool(permitted)
783 .ok();
784
785 return exec_ok && permitted;
786}
787
788bool
789lua_hooks::hook_get_netsync_write_permitted(rsa_keypair_id const & identity)
790{
791 bool permitted = false, exec_ok = false;
792
793 exec_ok = Lua(st)
794 .func("get_netsync_write_permitted")
795 .push_str(identity())
796 .call(1,1)
797 .extract_bool(permitted)
798 .ok();
799
800 return exec_ok && permitted;
801}
802
803bool
804lua_hooks::hook_init_attributes(file_path const & filename,
805 map<string, string> & attrs)
806{
807 Lua ll(st);
808
809 ll
810 .push_str("attr_init_functions")
811 .get_tab();
812
813 L(FL("calling attr_init_function for %s") % filename);
814 ll.begin();
815 while (ll.next())
816 {
817 L(FL(" calling an attr_init_function for %s") % filename);
818 ll.push_str(filename.as_external());
819 ll.call(1, 1);
820
821 if (lua_isstring(st, -1))
822 {
823 string key, value;
824
825 ll.extract_str(value);
826 ll.pop();
827 ll.extract_str(key);
828
829 attrs[key] = value;
830 L(FL(" added attr %s = %s") % key % value);
831 }
832 else
833 {
834 L(FL(" no attr added"));
835 ll.pop();
836 }
837 }
838
839 return ll.pop().ok();
840}
841
842bool
843lua_hooks::hook_apply_attribute(string const & attr,
844 file_path const & filename,
845 string const & value)
846{
847 return Lua(st)
848 .push_str("attr_functions")
849 .get_tab()
850 .push_str(attr)
851 .get_fn(-2)
852 .push_str(filename.as_external())
853 .push_str(value)
854 .call(2,0)
855 .ok();
856}
857
858
859bool
860lua_hooks::hook_validate_commit_message(utf8 const & message,
861 revision_data const & new_rev,
862 branch_name const & branchname,
863 bool & validated,
864 string & reason)
865{
866 validated = true;
867 return Lua(st)
868 .func("validate_commit_message")
869 .push_str(message())
870 .push_str(new_rev.inner()())
871 .push_str(branchname())
872 .call(3, 2)
873 .extract_str(reason)
874 // XXX When validated, the extra returned string is superfluous.
875 .pop()
876 .extract_bool(validated)
877 .ok();
878}
879
880bool
881lua_hooks::hook_note_commit(revision_id const & new_id,
882 revision_data const & rdat,
883 map<cert_name, cert_value> const & certs)
884{
885 Lua ll(st);
886 ll
887 .func("note_commit")
888 .push_str(encode_hexenc(new_id.inner()()))
889 .push_str(rdat.inner()());
890
891 ll.push_table();
892
893 for (map<cert_name, cert_value>::const_iterator i = certs.begin();
894 i != certs.end(); ++i)
895 {
896 ll.push_str(i->first());
897 ll.push_str(i->second());
898 ll.set_table();
899 }
900
901 ll.call(3, 0);
902 return ll.ok();
903}
904
905bool
906lua_hooks::hook_note_netsync_start(size_t session_id, string my_role,
907 int sync_type, string remote_host,
908 rsa_keypair_id remote_keyname,
909 globish include_pattern,
910 globish exclude_pattern)
911{
912 string type;
913 switch (sync_type)
914 {
915 case 1:
916 type = "push";
917 break;
918 case 2:
919 type = "pull";
920 break;
921 case 3:
922 type = "sync";
923 break;
924 default:
925 type = "unknown";
926 break;
927 }
928 Lua ll(st);
929 return ll
930 .func("note_netsync_start")
931 .push_int(session_id)
932 .push_str(my_role)
933 .push_str(type)
934 .push_str(remote_host)
935 .push_str(remote_keyname())
936 .push_str(include_pattern())
937 .push_str(exclude_pattern())
938 .call(7, 0)
939 .ok();
940}
941
942bool
943lua_hooks::hook_note_netsync_revision_received(revision_id const & new_id,
944 revision_data const & rdat,
945 set<pair<rsa_keypair_id,
946 pair<cert_name,
947 cert_value> > > const & certs,
948 size_t session_id)
949{
950 Lua ll(st);
951 ll
952 .func("note_netsync_revision_received")
953 .push_str(encode_hexenc(new_id.inner()()))
954 .push_str(rdat.inner()());
955
956 ll.push_table();
957
958 typedef set<pair<rsa_keypair_id, pair<cert_name, cert_value> > > cdat;
959
960 int n = 1;
961 for (cdat::const_iterator i = certs.begin(); i != certs.end(); ++i)
962 {
963 ll.push_int(n++);
964 ll.push_table();
965 ll.push_str(i->first());
966 ll.set_field("key");
967 ll.push_str(i->second.first());
968 ll.set_field("name");
969 ll.push_str(i->second.second());
970 ll.set_field("value");
971 ll.set_table();
972 }
973
974 ll.push_int(session_id);
975 ll.call(4, 0);
976 return ll.ok();
977}
978
979bool
980lua_hooks::hook_note_netsync_revision_sent(revision_id const & new_id,
981 revision_data const & rdat,
982 set<pair<rsa_keypair_id,
983 pair<cert_name,
984 cert_value> > > const & certs,
985 size_t session_id)
986{
987 Lua ll(st);
988 ll
989 .func("note_netsync_revision_sent")
990 .push_str(encode_hexenc(new_id.inner()()))
991 .push_str(rdat.inner()());
992
993 ll.push_table();
994
995 typedef set<pair<rsa_keypair_id, pair<cert_name, cert_value> > > cdat;
996
997 int n = 1;
998 for (cdat::const_iterator i = certs.begin(); i != certs.end(); ++i)
999 {
1000 ll.push_int(n++);
1001 ll.push_table();
1002 ll.push_str(i->first());
1003 ll.set_field("key");
1004 ll.push_str(i->second.first());
1005 ll.set_field("name");
1006 ll.push_str(i->second.second());
1007 ll.set_field("value");
1008 ll.set_table();
1009 }
1010
1011 ll.push_int(session_id);
1012 ll.call(4, 0);
1013 return ll.ok();
1014}
1015
1016bool
1017lua_hooks::hook_note_netsync_pubkey_received(rsa_keypair_id const & kid,
1018 size_t session_id)
1019{
1020 Lua ll(st);
1021 ll
1022 .func("note_netsync_pubkey_received")
1023 .push_str(kid())
1024 .push_int(session_id);
1025
1026 ll.call(2, 0);
1027 return ll.ok();
1028}
1029
1030bool
1031lua_hooks::hook_note_netsync_pubkey_sent(rsa_keypair_id const & kid,
1032 size_t session_id)
1033{
1034 Lua ll(st);
1035 ll
1036 .func("note_netsync_pubkey_sent")
1037 .push_str(kid())
1038 .push_int(session_id);
1039
1040 ll.call(2, 0);
1041 return ll.ok();
1042}
1043
1044bool
1045lua_hooks::hook_note_netsync_cert_received(revision_id const & rid,
1046 rsa_keypair_id const & kid,
1047 cert_name const & name,
1048 cert_value const & value,
1049 size_t session_id)
1050{
1051 Lua ll(st);
1052 ll
1053 .func("note_netsync_cert_received")
1054 .push_str(encode_hexenc(rid.inner()()))
1055 .push_str(kid())
1056 .push_str(name())
1057 .push_str(value())
1058 .push_int(session_id);
1059
1060 ll.call(5, 0);
1061 return ll.ok();
1062}
1063
1064bool
1065lua_hooks::hook_note_netsync_cert_sent(revision_id const & rid,
1066 rsa_keypair_id const & kid,
1067 cert_name const & name,
1068 cert_value const & value,
1069 size_t session_id)
1070{
1071 Lua ll(st);
1072 ll
1073 .func("note_netsync_cert_sent")
1074 .push_str(encode_hexenc(rid.inner()()))
1075 .push_str(kid())
1076 .push_str(name())
1077 .push_str(value())
1078 .push_int(session_id);
1079
1080 ll.call(5, 0);
1081 return ll.ok();
1082}
1083
1084bool
1085lua_hooks::hook_note_netsync_end(size_t session_id, int status,
1086 size_t bytes_in, size_t bytes_out,
1087 size_t certs_in, size_t certs_out,
1088 size_t revs_in, size_t revs_out,
1089 size_t keys_in, size_t keys_out)
1090{
1091 Lua ll(st);
1092 return ll
1093 .func("note_netsync_end")
1094 .push_int(session_id)
1095 .push_int(status)
1096 .push_int(bytes_in)
1097 .push_int(bytes_out)
1098 .push_int(certs_in)
1099 .push_int(certs_out)
1100 .push_int(revs_in)
1101 .push_int(revs_out)
1102 .push_int(keys_in)
1103 .push_int(keys_out)
1104 .call(10, 0)
1105 .ok();
1106}
1107
1108bool
1109lua_hooks::hook_note_mtn_startup(args_vector const & args)
1110{
1111 Lua ll(st);
1112
1113 ll.func("note_mtn_startup");
1114
1115 for (args_vector::const_iterator i = args.begin(); i != args.end(); ++i)
1116 ll.push_str((*i)());
1117
1118 ll.call(args.size(), 0);
1119 return ll.ok();
1120}
1121
1122namespace commands {
1123 class cmd_lua : public command
1124 {
1125 lua_State *st;
1126 std::string const f_name;
1127 public:
1128 cmd_lua(std::string const & primary_name,
1129 std::string const & params,
1130 std::string const & abstract,
1131 std::string const & desc,
1132 lua_State *L_st,
1133 std::string const & func_name) :
1134 command(primary_name, "", CMD_REF(user), false, false, params,
1135 abstract, desc, true, options::options_type() | options::opts::none, true),
1136 st(L_st), f_name(func_name)
1137 {
1138 // because user commands are inserted after the normal initialisation process
1139 CMD_REF(user)->children().insert(this);
1140 }
1141
1142 void exec(app_state & app, command_id const & execid, args_vector const & args) const;
1143 };
1144}
1145
1146void commands::cmd_lua::exec(app_state & app,
1147 command_id const & execid,
1148 args_vector const & args) const
1149{
1150 I(st);
1151 I(app.lua.check_lua_state(st));
1152
1153 app_state* app_p = get_app_state(st);
1154 I(app_p == & app);
1155
1156 Lua ll(st);
1157 ll.func(f_name);
1158
1159 for (args_vector::const_iterator it = args.begin(); it != args.end(); ++it)
1160 ll.push_str((*it)());
1161
1162 app.mtn_automate_allowed = true;
1163
1164 ll.call(args.size(),0);
1165
1166 app.mtn_automate_allowed = false;
1167
1168 E(ll.ok(), F("Call to user command %s (lua command: %s) failed.") % primary_name() % f_name);
1169}
1170
1171LUAEXT(alias_command, )
1172{
1173 const char *old_cmd = luaL_checkstring(L, -2);
1174 const char *new_cmd = luaL_checkstring(L, -1);
1175 N(old_cmd && new_cmd,
1176 F("%s called with an invalid parameter") % "alias_command");
1177
1178 args_vector args;
1179 args.push_back(arg_type(old_cmd));
1180 commands::command_id id = commands::complete_command(args);
1181 commands::command *old_cmd_p = CMD_REF(__root__)->find_command(id);
1182
1183 old_cmd_p->add_alias(utf8(new_cmd));
1184
1185 lua_pushboolean(L, true);
1186 return 1;
1187}
1188
1189
1190LUAEXT(register_command, )
1191{
1192 const char *cmd_name = luaL_checkstring(L, -5);
1193 const char *cmd_params = luaL_checkstring(L, -4);
1194 const char *cmd_abstract = luaL_checkstring(L, -3);
1195 const char *cmd_desc = luaL_checkstring(L, -2);
1196 const char *cmd_func = luaL_checkstring(L, -1);
1197
1198 N(cmd_name && cmd_params && cmd_abstract && cmd_desc && cmd_func,
1199 F("%s called with an invalid parameter") % "register_command");
1200
1201 new commands::cmd_lua(cmd_name, cmd_params, cmd_abstract, cmd_desc, L, cmd_func); // leak this - commands can't be removed anyway
1202
1203 lua_pushboolean(L, true);
1204 return 1;
1205}
1206
1207// Local Variables:
1208// mode: C++
1209// fill-column: 76
1210// c-file-style: "gnu"
1211// indent-tabs-mode: nil
1212// End:
1213// 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