monotone

monotone Mtn Source Tree

Root/lua.cc

1// copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>
2// all rights reserved.
3// licensed to the public under the terms of the GNU GPL (>= 2)
4// see the file COPYING for details
5
6#include "config.h"
7
8extern "C" {
9#include "lua/lua.h"
10#include "lua/lualib.h"
11}
12
13#include <stdlib.h>
14#include <string.h>
15#include <stdarg.h>
16#include <boost/lexical_cast.hpp>
17#include <boost/filesystem/path.hpp>
18#include <boost/filesystem/operations.hpp>
19
20#include <set>
21#include <map>
22
23#include "lua.hh"
24#include "sanity.hh"
25#include "vocab.hh"
26#include "file_io.hh"
27#include "app_state.hh"
28
29// defined in {std,test}_hooks.lua, converted
30#include "test_hooks.h"
31#include "std_hooks.h"
32
33using namespace std;
34using boost::lexical_cast;
35
36/*
37static int panic_thrower(lua_State * st)
38{
39 throw oops("lua panic");
40}
41*/
42
43lua_hooks::lua_hooks()
44{
45 st = lua_open ();
46 I(st);
47
48 // no atpanic support in 4.x
49 // lua_atpanic (st, &panic_thrower);
50
51 lua_baselibopen(st);
52 lua_iolibopen(st);
53 lua_strlibopen(st);
54 lua_mathlibopen(st);
55 lua_tablibopen(st);
56 lua_dblibopen(st);
57}
58
59lua_hooks::~lua_hooks()
60{
61 if (st)
62 lua_close (st);
63}
64
65
66// This Lua object represents a single imperative transaction with the lua
67// interpreter. if it fails at any point, all further commands in the
68// transaction are ignored. it cleans the lua stack up when it is
69// destructed, so no need to pop values when you're done.
70
71struct Lua
72{
73 lua_State * st;
74 bool failed;
75
76 Lua(lua_State * s) :
77 st(s), failed(false)
78 {}
79
80 ~Lua()
81 {
82 lua_settop(st, 0);
83 }
84
85 bool ok()
86 {
87 return !failed;
88 }
89
90 // getters
91
92 Lua & get(int idx = LUA_GLOBALSINDEX)
93 {
94 if (failed) return *this;
95 if (!lua_istable (st, idx))
96 {
97L(F("lua istable() failed\n"));
98failed = true;
99return *this;
100 }
101 if (lua_gettop (st) < 1)
102 {
103L(F("lua stack top > 0 failed\n"));
104failed = true;
105return *this;
106 }
107 lua_gettable(st, idx);
108 return *this;
109 }
110
111 Lua & get_fn(int idx = LUA_GLOBALSINDEX)
112 {
113 if (failed) return *this;
114 get(idx);
115 if (!lua_isfunction (st, -1))
116 {
117L(F("lua isfunction() failed in get_fn\n"));
118failed = true;
119 }
120 return *this;
121 }
122
123 Lua & get_tab(int idx = LUA_GLOBALSINDEX)
124 {
125 if (failed) return *this;
126 get(idx);
127 if (!lua_istable (st, -1))
128 {
129L(F("lua istable() failed in get_tab\n"));
130failed = true;
131 }
132 return *this;
133 }
134
135 Lua & get_str(int idx = LUA_GLOBALSINDEX)
136 {
137 if (failed) return *this;
138 get(idx);
139 if (!lua_isstring (st, -1))
140 {
141L(F("lua isstring() failed in get_str\n"));
142failed = true;
143 }
144 return *this;
145 }
146
147 Lua & get_num(int idx = LUA_GLOBALSINDEX)
148 {
149 if (failed) return *this;
150 get(idx);
151 if (!lua_isnumber (st, -1))
152 {
153L(F("lua isnumber() failed in get_num\n"));
154failed = true;
155 }
156 return *this;
157 }
158
159 Lua & get_bool(int idx = LUA_GLOBALSINDEX)
160 {
161 if (failed) return *this;
162 get(idx);
163 if (!lua_isboolean (st, -1))
164 {
165L(F("lua isboolean() failed in get_bool\n"));
166failed = true;
167 }
168 return *this;
169 }
170
171 // extractors
172
173 Lua & extract_str(string & str)
174 {
175 if (failed) return *this;
176 if (!lua_isstring (st, -1))
177 {
178L(F("lua isstring() failed in extract_str\n"));
179failed = true;
180return *this;
181 }
182 str = string(lua_tostring(st, -1), lua_strlen(st, -1));
183 return *this;
184 }
185
186 Lua & extract_int(int & i)
187 {
188 if (failed) return *this;
189 if (!lua_isnumber (st, -1))
190 {
191L(F("lua isnumber() failed in extract_int\n"));
192failed = true;
193return *this;
194 }
195 i = static_cast<int>(lua_tonumber(st, -1));
196 return *this;
197 }
198
199 Lua & extract_double(double & i)
200 {
201 if (failed) return *this;
202 if (!lua_isnumber (st, -1))
203 {
204L(F("lua isnumber() failed in extract_double\n"));
205failed = true;
206return *this;
207 }
208 i = lua_tonumber(st, -1);
209 return *this;
210 }
211
212
213 Lua & extract_bool(bool & i)
214 {
215 if (failed) return *this;
216 if (!lua_isboolean (st, -1))
217 {
218L(F("lua isboolean() failed in extract_bool\n"));
219failed = true;
220return *this;
221 }
222 i = (lua_toboolean(st, -1) == 1);
223 return *this;
224 }
225
226
227 // table iteration
228
229 Lua & begin()
230 {
231 if (failed) return *this;
232 if (!lua_istable(st, -1))
233 {
234L(F("lua istable() failed in begin\n"));
235failed = true;
236return *this;
237 }
238 I(lua_checkstack (st, 1));
239 lua_pushnil(st);
240 return *this;
241 }
242
243 bool next()
244 {
245 if (failed) return false;
246 if (!lua_istable(st, -2))
247 {
248L(F("lua istable() failed in next\n"));
249failed = true;
250return false;
251 }
252 I(lua_checkstack (st, 1));
253 if (lua_next(st, -2) != 0)
254 {
255return true;
256 }
257 pop();
258 return false;
259 }
260
261 // pushers
262
263 Lua & push_str(string const & str)
264 {
265 if (failed) return *this;
266 I(lua_checkstack (st, 1));
267 lua_pushlstring(st, str.c_str(), str.size());
268 return *this;
269 }
270
271 Lua & push_int(int num)
272 {
273 if (failed) return *this;
274 I(lua_checkstack (st, 1));
275 lua_pushnumber(st, num);
276 return *this;
277 }
278
279 Lua & push_int(double num)
280 {
281 if (failed) return *this;
282 I(lua_checkstack (st, 1));
283 lua_pushnumber(st, num);
284 return *this;
285 }
286
287 Lua & push_bool(bool b)
288 {
289 if (failed) return *this;
290 I(lua_checkstack (st, 1));
291 lua_pushboolean(st, b);
292 return *this;
293 }
294
295 Lua & push_table()
296 {
297 if (failed) return *this;
298 I(lua_checkstack (st, 1));
299 lua_newtable(st);
300 return *this;
301 }
302
303 Lua & set_table(int idx = -3)
304 {
305 if (failed) return *this;
306 I(lua_checkstack (st, 1));
307 lua_settable(st, idx);
308 return *this;
309 }
310
311
312 Lua & call(int in, int out)
313 {
314 if (failed) return *this;
315 I(lua_checkstack (st, out));
316 if (lua_pcall(st, in, out, 0) != 0)
317 {
318I(lua_isstring (st, -1));
319string err = string(lua_tostring(st, -1), lua_strlen(st, -1));
320L(F("lua pcall() failed: %s\n") % err);
321lua_pop(st, 1);
322failed = true;
323 }
324 return *this;
325 }
326
327 Lua & pop(int count = 1)
328 {
329 if (failed) return *this;
330 if (lua_gettop (st) < count)
331 {
332L(F("lua stack top >= count failed\n"));
333failed = true;
334return *this;
335 }
336 lua_pop(st, count);
337 return *this;
338 }
339};
340
341static bool run_string(lua_State * st, string const &str)
342{
343 I(st);
344 return
345 Lua(st)
346 .push_str("loadstring")
347 .get_fn()
348 .push_str(str)
349 .call(1,1)
350 .call(0,0)
351 .ok();
352}
353
354static bool run_file(lua_State * st, string const &filename)
355{
356 I(st);
357 return
358 Lua(st)
359 .push_str("loadfile")
360 .get_fn()
361 .push_str(filename)
362 .call(1,1)
363 .call(0,0)
364 .ok();
365}
366
367
368#ifdef BUILD_UNIT_TESTS
369void lua_hooks::add_test_hooks()
370{
371 if (!run_string(st, test_hooks_constant))
372 throw oops("lua error while setting up testing hooks");
373}
374#endif
375
376void lua_hooks::add_std_hooks()
377{
378 if (!run_string(st, std_hooks_constant))
379 throw oops("lua error while setting up standard hooks");
380}
381
382void lua_hooks::default_rcfilename(fs::path & file)
383{
384 file = mkpath(get_homedir()) / mkpath(".monotonerc");
385}
386
387void lua_hooks::working_copy_rcfilename(fs::path & file)
388{
389 file = mkpath(book_keeping_dir) / mkpath("monotonerc");
390}
391
392
393void lua_hooks::add_rcfile(fs::path const & rc)
394{
395 I(st);
396 if (fs::exists(rc))
397 {
398 L(F("opening rcfile '%s' ... ") % rc.string());
399 if (!run_file(st, rc.string()))
400{
401 L(F("no good\n"));
402 throw oops("lua error while loading " + rc.string());
403}
404 L("ok\n");
405 }
406 else
407 L(F("skipping nonexistent rcfile '%s'\n") % rc.string());
408}
409
410
411// concrete hooks
412
413// nb: if you're hooking lua to return your passphrase, you don't care if we
414// keep a couple extra temporaries of your passphrase around.
415bool lua_hooks::hook_get_passphrase(rsa_keypair_id const & k, string & phrase)
416{
417 return Lua(st)
418 .push_str("get_passphrase")
419 .get_fn()
420 .push_str(k())
421 .call(1,1)
422 .extract_str(phrase)
423 .ok();
424}
425
426bool lua_hooks::hook_persist_phrase_ok()
427{
428 bool persist_ok = false;
429 bool executed_ok = Lua(st)
430 .push_str("persist_phrase_ok")
431 .get_fn()
432 .call(0,1)
433 .extract_bool(persist_ok)
434 .ok();
435 return executed_ok && persist_ok;
436}
437
438
439bool lua_hooks::hook_get_branch_key(cert_value const & branchname, rsa_keypair_id & k)
440{
441 string key;
442 bool ok = Lua(st)
443 .push_str("get_branch_key")
444 .get_fn()
445 .push_str(branchname())
446 .call(1,1)
447 .extract_str(key)
448 .ok();
449
450 k = key;
451 return ok;
452}
453
454bool lua_hooks::hook_get_author(cert_value const & branchname, string & author)
455{
456 return Lua(st)
457 .push_str("get_author")
458 .get_fn()
459 .push_str(branchname())
460 .call(1,1)
461 .extract_str(author)
462 .ok();
463}
464
465bool lua_hooks::hook_edit_comment(string const & commentary, string & result)
466{
467 return Lua(st)
468 .push_str("edit_comment")
469 .get_fn()
470 .push_str(commentary)
471 .call(1,1)
472 .extract_str(result)
473 .ok();
474}
475
476
477bool lua_hooks::hook_get_sorter(string const & certname, string & sort_type)
478{
479 return Lua(st)
480 .push_str("get_sorter")
481 .get_fn()
482 .push_str(certname)
483 .call(1,1)
484 .extract_str(sort_type)
485 .ok();
486}
487
488bool lua_hooks::hook_ignore_file(file_path const & p)
489{
490 bool ignore_it = false;
491 bool exec_ok = Lua(st)
492 .push_str("ignore_file")
493 .get_fn()
494 .push_str(p())
495 .call(1,1)
496 .extract_bool(ignore_it)
497 .ok();
498 return exec_ok && ignore_it;
499}
500
501
502bool lua_hooks::hook_non_blocking_rng_ok()
503{
504 bool ok = false;
505 bool exec_ok = Lua(st)
506 .push_str("non_blocking_rng_ok")
507 .get_fn()
508 .call(0,1)
509 .extract_bool(ok)
510 .ok();
511 return exec_ok && ok;
512}
513
514bool lua_hooks::hook_get_manifest_cert_trust(std::set<rsa_keypair_id> const & signers,
515 hexenc<id> const & id,
516 cert_name const & name,
517 cert_value const & val)
518{
519 Lua ll(st);
520 ll
521 .push_str("get_manifest_cert_trust")
522 .get_fn()
523 .push_table();
524
525 int k = 0;
526 for (set<rsa_keypair_id>::const_iterator v = signers.begin();
527 v != signers.end(); ++v)
528 {
529 ll.push_int(k);
530 ll.push_str((*v)());
531 ll.set_table();
532 ++k;
533 }
534
535 bool ok;
536 bool exec_ok = ll
537 .push_str(id())
538 .push_str(name())
539 .push_str(val())
540 .call(4, 1)
541 .extract_bool(ok)
542 .ok();
543
544 return exec_ok && ok;
545}
546
547bool lua_hooks::hook_get_file_cert_trust(std::set<rsa_keypair_id> const & signers,
548 hexenc<id> const & id,
549 cert_name const & name,
550 cert_value const & val)
551{
552 Lua ll(st);
553 ll
554 .push_str("get_file_cert_trust")
555 .get_fn()
556 .push_table();
557
558 int k = 0;
559 for (set<rsa_keypair_id>::const_iterator v = signers.begin();
560 v != signers.end(); ++v)
561 {
562 ll.push_int(k);
563 ll.push_str((*v)());
564 ll.set_table();
565 ++k;
566 }
567
568 bool ok;
569 bool exec_ok = ll
570 .push_str(id())
571 .push_str(name())
572 .push_str(val())
573 .call(4, 1)
574 .extract_bool(ok)
575 .ok();
576
577 return exec_ok && ok;
578}
579
580bool lua_hooks::hook_accept_testresult_change(map<rsa_keypair_id, bool> const & old_results,
581 map<rsa_keypair_id, bool> const & new_results)
582{
583 Lua ll(st);
584 ll
585 .push_str("accept_testresult_change")
586 .get_fn()
587 .push_table();
588
589 for (map<rsa_keypair_id, bool>::const_iterator i = old_results.begin();
590 i != old_results.end(); ++i)
591 {
592 ll.push_str(i->first());
593 ll.push_bool(i->second);
594 ll.set_table();
595 }
596
597 ll.push_table();
598
599 for (map<rsa_keypair_id, bool>::const_iterator i = new_results.begin();
600 i != new_results.end(); ++i)
601 {
602 ll.push_str(i->first());
603 ll.push_bool(i->second);
604 ll.set_table();
605 }
606
607 bool ok;
608 bool exec_ok = ll
609 .call(2, 1)
610 .extract_bool(ok)
611 .ok();
612
613 return exec_ok && ok;
614}
615
616
617
618bool lua_hooks::hook_merge2(data const & left,
619 data const & right,
620 data & result)
621{
622 string res;
623 bool ok = Lua(st)
624 .push_str("merge2")
625 .get_fn()
626 .push_str(left())
627 .push_str(right())
628 .call(2,1)
629 .extract_str(res)
630 .ok();
631 result = res;
632 return ok;
633}
634
635bool lua_hooks::hook_merge3(data const & ancestor,
636 data const & left,
637 data const & right,
638 data & result)
639{
640 string res;
641 bool ok = Lua(st)
642 .push_str("merge3")
643 .get_fn()
644 .push_str(ancestor())
645 .push_str(left())
646 .push_str(right())
647 .call(3,1)
648 .extract_str(res)
649 .ok();
650 result = res;
651 return ok;
652}
653
654
655bool lua_hooks::hook_get_news_sender(url const & u, string & sender)
656{
657 return Lua(st)
658 .push_str("get_news_sender")
659 .get_fn()
660 .push_str(u())
661 .call(1,1)
662 .extract_str(sender)
663 .ok();
664}
665
666bool lua_hooks::hook_get_mail_sender(url const & u, string & sender)
667{
668 return Lua(st)
669 .push_str("get_mail_sender")
670 .get_fn()
671 .push_str(u())
672 .call(1,1)
673 .extract_str(sender)
674 .ok();
675}
676
677bool lua_hooks::hook_get_mail_hostname(url const & u, string & hostname)
678{
679 return Lua(st)
680 .push_str("get_mail_hostname")
681 .get_fn()
682 .push_str(u())
683 .call(1,1)
684 .extract_str(hostname)
685 .ok();
686}
687
688bool lua_hooks::hook_get_http_auth(url const & u, rsa_keypair_id & pubkey)
689{
690 string res;
691 bool ok = Lua(st)
692 .push_str("get_http_auth")
693 .get_fn()
694 .push_str(u())
695 .call(1,1)
696 .extract_str(res)
697 .ok();
698
699 pubkey = res;
700 return ok;
701}
702
703bool lua_hooks::hook_get_post_targets(cert_value const & branchname,
704 set<url> & targets)
705{
706 targets.clear();
707
708 Lua ll(st);
709 ll
710 .push_str("get_post_targets")
711 .get_fn()
712 .push_str(branchname())
713 .call(1,1)
714 .begin();
715
716 while(ll.next())
717 {
718 string u;
719 ll.extract_str(u).pop();
720 targets.insert(url(u));
721 }
722
723 return ll.ok();
724}
725
726bool lua_hooks::hook_get_fetch_sources(cert_value const & branchname,
727 set<url> & sources)
728{
729 sources.clear();
730
731 Lua ll(st);
732 ll
733 .push_str("get_fetch_sources")
734 .get_fn()
735 .push_str(branchname())
736 .call(1,1)
737 .begin();
738
739 while(ll.next())
740 {
741 string u;
742 ll.extract_str(u).pop();
743 sources.insert(url(u));
744 }
745
746 return ll.ok();
747}
748
749// connect addrs are for *pure tunnels*
750bool lua_hooks::hook_get_connect_addr(string const & proto,
751 string const & host,
752 unsigned long port,
753 string & host_out,
754 unsigned long & port_out)
755{
756 Lua ll(st);
757 ll
758 .push_str("get_connect_addr")
759 .get_fn()
760 .push_str(proto)
761 .push_str(host)
762 .push_int(static_cast<int>(port))
763 .call(3,1)
764 .begin();
765
766 ll.next();
767 ll.extract_str(host_out).pop();
768
769 ll.next();
770 int tmp;
771 ll.extract_int(tmp).pop();
772 if (ll.ok()) port_out = tmp;
773
774 return ll.ok();
775}
776
777// http proxies are a special case, alas
778bool lua_hooks::hook_get_http_proxy(string const & host,
779 unsigned long port,
780 string & host_out,
781 unsigned long & port_out)
782{
783 Lua ll(st);
784 ll
785 .push_str("get_http_proxy")
786 .get_fn()
787 .push_str(host)
788 .push_int(static_cast<int>(port))
789 .call(2,1)
790 .begin();
791
792 ll.next();
793 ll.extract_str(host_out).pop();
794
795 ll.next();
796 int tmp;
797 ll.extract_int(tmp).pop();
798 if (ll.ok()) port_out = tmp;
799
800 return ll.ok();
801}
802
803bool lua_hooks::hook_get_netsync_read_permitted(std::string const & collection,
804rsa_keypair_id const & identity)
805{
806 bool permitted = false, exec_ok = false;
807
808 exec_ok = Lua(st)
809 .push_str("get_netsync_read_permitted")
810 .get_fn()
811 .push_str(collection)
812 .push_str(identity())
813 .call(2,1)
814 .extract_bool(permitted)
815 .ok();
816
817 return exec_ok && permitted;
818}
819
820bool lua_hooks::hook_get_netsync_anonymous_read_permitted(std::string const & collection)
821{
822 bool permitted = false, exec_ok = false;
823
824 exec_ok = Lua(st)
825 .push_str("get_netsync_anonymous_read_permitted")
826 .get_fn()
827 .push_str(collection)
828 .call(1,1)
829 .extract_bool(permitted)
830 .ok();
831
832 return exec_ok && permitted;
833}
834
835bool lua_hooks::hook_get_netsync_write_permitted(std::string const & collection,
836 rsa_keypair_id const & identity)
837{
838 bool permitted = false, exec_ok = false;
839
840 exec_ok = Lua(st)
841 .push_str("get_netsync_write_permitted")
842 .get_fn()
843 .push_str(collection)
844 .push_str(identity())
845 .call(2,1)
846 .extract_bool(permitted)
847 .ok();
848
849 return exec_ok && permitted;
850}
851
852
853bool lua_hooks::hook_apply_attribute(string const & attr,
854 file_path const & filename,
855 string const & value)
856{
857 return Lua(st)
858 .push_str("attr_functions")
859 .get_tab()
860 .push_str(attr)
861 .get_fn(-2)
862 .push_str(filename())
863 .push_str(value)
864 .call(2,0)
865 .ok();
866}
867
868
869bool lua_hooks::hook_get_system_linesep(string & linesep)
870{
871 return Lua(st)
872 .push_str("get_system_linesep")
873 .get_fn()
874 .call(0,1)
875 .extract_str(linesep)
876 .ok();
877}
878
879bool lua_hooks::hook_get_charset_conv(file_path const & p,
880 std::string & db, std::string & ext)
881{
882 Lua ll(st);
883 ll
884 .push_str("get_charset_conv")
885 .get_fn()
886 .push_str(p())
887 .call(1,1)
888 .begin();
889
890 ll.next();
891 ll.extract_str(db).pop();
892
893 ll.next();
894 ll.extract_str(ext).pop();
895 return ll.ok();
896}
897
898bool lua_hooks::hook_get_linesep_conv(file_path const & p,
899 std::string & db, std::string & ext)
900{
901 Lua ll(st);
902 ll
903 .push_str("get_linesep_conv")
904 .get_fn()
905 .push_str(p())
906 .call(1,1)
907 .begin();
908
909 ll.next();
910 ll.extract_str(db).pop();
911
912 ll.next();
913 ll.extract_str(ext).pop();
914 return ll.ok();
915}

Archive Download this file

Branches

Tags

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