monotone

monotone Mtn Source Tree

Root/lua_hooks.cc

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