json repl script
[scpubgit/Tak.git] / jsonrepl
1 #!/usr/bin/env perl
2
3 use strictures 1;
4 use JSON::PP qw(encode_json decode_json);
5 use Eval::WithLexicals;
6 use Data::Dumper::Concise;
7 use IO::Handle;
8
9 STDOUT->autoflush(1);
10
11 my $eval = Eval::WithLexicals->new;
12
13 sub out {
14   print STDOUT encode_json([ @_ ])."\n"
15     or die "Failed to print to STDOUT: $!";
16 }
17
18 sub run_eval {
19   my ($perl) = @_;
20   unless ($perl) {
21     out(MISTAKE => eval_input => "No code supplied");
22     return;
23   }
24   if (my $ref = ref($perl)) {
25     out(MISTAKE => eval_input => "Code was a ${ref} reference");
26     return;
27   }
28   my ($code, @ret);
29   open my $stdout, '>', \my $output;
30   open my $stderr, '>', \my $errors;
31   if (eval {
32     local *STDOUT = $stdout;
33     local *STDERR = $stderr;
34     @ret = $eval->eval($perl);
35     1
36   }) {
37     $code = 'OK';
38   } else {
39     ($code, @ret) = (FAILURE => $@);
40   }
41   my $dumped_ret;
42   unless (eval { $dumped_ret = Dumper(@ret); 1 }) {
43     $dumped_ret = "Error dumping ${code} result: $@";
44     $code = 'FAILURE';
45   }
46   out($code => { stdout => $output, stderr => $errors, return => $dumped_ret });
47 }
48
49 while (my $line = <STDIN>) {
50   my $data = eval { decode_json($line) };
51   if ($@) {
52     out(MISTAKE => invalid_json => $@);
53     next;
54   }
55   unless (ref($data) eq 'ARRAY') {
56     out(MISTAKE => message_format => "Not an ARRAY");
57     next;
58   }
59   unless (@$data > 0) {
60     out(MISTAKE => message_format => "No message name");
61     next;
62   }
63   if (my $ref = ref($data->[0])) {
64     out(MISTAKE => message_format => "Message name was a ${ref} ref");
65     next;
66   }
67   my ($message, @args) = @{$data};
68   if ($message eq 'EXIT') {
69     exit 0;
70   } elsif ($message eq 'EVAL') {
71     run_eval(@args);
72   } else {
73     out(MISTAKE => message_name => "Unknown message");
74   }
75 }