From 399bdecaef9b5b3691249db2abc1899d67585943 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Wed, 20 Aug 2014 14:58:58 -0700 Subject: [PATCH] feature: added new command-line utility, "resty", to run Lua code or Lua files (for OpenResty) directly from the command-line. it is installed into the "/bin" directory. prodded by Vitaly Kosenko. --- util/configure | 6 +- util/mirror-tarballs | 1 + util/resty | 206 +++++++++++++++++++++++++++++++++++++++++++ util/ver | 2 +- 4 files changed, 212 insertions(+), 3 deletions(-) create mode 100755 util/resty diff --git a/util/configure b/util/configure index ced81cc..61045c6 100755 --- a/util/configure +++ b/util/configure @@ -312,6 +312,8 @@ push @make_cmds, "cd $root_dir/build/$ngx_dir && " push @make_install_cmds, "cd $root_dir/build/$ngx_dir && " . "\$(MAKE) install DESTDIR=\$(DESTDIR)"; +push @make_install_cmds, "cd $root_dir/build && ./install resty \$(DESTDIR)/$prefix/bin/"; + cd '../..'; # to the root #die "pwd: " .. `pwd`; @@ -468,8 +470,8 @@ _END_ die "failed to remove directory build/.\n"; } - if (-f 'build') { - die "file \"build\" already exists. please remove it first.\n"; + if (-e 'build') { + die "file or directory \"build\" already exists. please remove it first.\n"; } shell "cp -rp bundle/ build"; diff --git a/util/mirror-tarballs b/util/mirror-tarballs index 0db00d5..046d58f 100755 --- a/util/mirror-tarballs +++ b/util/mirror-tarballs @@ -585,6 +585,7 @@ cd .. cp $root/util/configure ./ cp $root/README.markdown ./ cp $root/util/install bundle/ +cp $root/util/resty bundle/ find bundle -name '*~' -delete cd $root diff --git a/util/resty b/util/resty new file mode 100755 index 0000000..2a19cdf --- /dev/null +++ b/util/resty @@ -0,0 +1,206 @@ +#!/usr/bin/env perl + +# Copyright (C) Yichun Zhang (agentzh) + +# TODO: port this script into the nginx core for greater flexibility +# and better performance. + +use strict; +use warnings; + +use File::Spec (); +use FindBin (); +use Getopt::Std qw( getopts ); +use File::Temp qw( tempdir ); +use POSIX qw( WNOHANG ); + +my %opts; +getopts("he:c:", \%opts) + or usage(1); + +if ($opts{h}) { + usage(0); +} + +my $luafile; +if (!defined $opts{e}) { + $luafile = shift + or die qq{No Lua input file nor -e "" option specified.\n}; +} + +if (@ARGV) { + die "unknown arguments: @ARGV\n"; +} + +my $conns = $opts{c} || 64; + +my $nginx_path = File::Spec->catfile($FindBin::Bin, "..", "nginx", "sbin", "nginx"); +#warn $nginx_path; +if (!-f $nginx_path) { + $nginx_path = "nginx"; # find in PATH +} + +my $prefix_dir = tempdir(CLEANUP => 1); +#warn "prefix dir: $prefix_dir\n"; + +my $logs_dir = File::Spec->catfile($prefix_dir, "logs"); +mkdir $logs_dir or die "failed to mkdir $logs_dir: $!"; + +my $conf_dir = File::Spec->catfile($prefix_dir, "conf"); +mkdir $conf_dir or die "failed to mkdir $conf_dir: $!"; + +my $chunk_name; +if (defined $opts{e}) { + $luafile = File::Spec->catfile($conf_dir, "a.lua"); + open my $out, ">$luafile" + or die "Cannot open $luafile for writing: $!\n"; + print $out $opts{e}; + close $out; + $chunk_name = "=(command line -e)"; + +} else { + $chunk_name = "\@$luafile"; +} + +my $loader = <<_EOC_; + local gen + do + local fname = "$luafile" + local f = assert(io.open(fname, "r")) + local chunk = f:read("*a") + gen = assert(loadstring(chunk, "$chunk_name")) + end +_EOC_ + +my $conf_file = File::Spec->catfile($conf_dir, "nginx.conf"); +open my $out, ">$conf_file" + or die "Cannot open $conf_file for writing: $!\n"; + +print $out <<_EOC_; +daemon off; +master_process off; + +error_log /dev/stderr warn; +#error_log /dev/stderr debug; + +events { + worker_connections $conns; +} + +http { + access_log off; + lua_socket_log_errors off; + + init_by_lua ' + local stdout = io.stdout + print = function (...) stdout:write(...) end + ngx.print = print + ngx.say = function (...) print(...) print("\\\\n") end + '; + + init_worker_by_lua ' + local exit = os.exit + local stderr = io.stderr + + local function handle_err(err) + if err then + err = string.gsub(err, "^init_worker_by_lua:%d+: ", "") + stderr:write(err) + end + return exit(1) + end + + local ok, err = pcall(function () +$loader + -- print("calling timer.at...") + local ok, err = ngx.timer.at(0, function () + -- io.stderr:write("timer firing") + local ok, err = pcall(gen) + if not ok then + return handle_err(err) + end + local rc = err + if rc and type(rc) ~= "number" then + return handle_err("bad return value of type " .. type(rc)) + end + return exit(rc) + end) + if not ok then + return handle_err(err) + end + -- print("timer created") + end) + + if not ok then + return handle_err(err) + end + '; +} +_EOC_ + +close $out; + +my $cmd = "$nginx_path -p $prefix_dir/"; + +my $child_pid; + +sub reaper { + $SIG{CHLD} = \&reaper; + if ($child_pid) { + my ($pid, $status); + do { + $pid = waitpid(-1, WNOHANG); + if ($child_pid == $pid) { + $status = $?; + undef $child_pid; + last; + } + } while $pid > 0; + exit($status || 0); + } +} + +$SIG{CHLD}=\&reaper; + +sub sigint { + $SIG{INT} = \&sigint; + if ($child_pid) { + kill INT => $child_pid; + } +} +$SIG{INT} = \&sigint; + +my $pid = fork(); + +if (!defined $pid) { + die "fork() failed: $!\n"; +} + +if ($pid == 0) { # child process + #warn "exec $cmd..."; + exec $cmd; + +} else { + $child_pid = $pid; + waitpid($child_pid, 0); + exit($? || 0); +} + +sub usage { + my $rc = shift; + my $msg = <<_EOC_; +$0 [-h] [-c num] [-e prog] [lua-file] + +Options: + -c num set maximal connection count (default: 64). + -e prog run the inlined Lua code in "prog". + -h print this help. +_EOC_ + if ($rc == 0) { + print $msg; + exit(0); + } + + warn $msg; + exit($rc); +} diff --git a/util/ver b/util/ver index 65db7c6..0e32d29 100755 --- a/util/ver +++ b/util/ver @@ -1,7 +1,7 @@ #!/bin/bash main_ver=1.7.4 -minor_ver=1rc1 +minor_ver=1rc1.1 version=$main_ver.$minor_ver echo $version