From c10b2477ef8950476d01a91f6ebabb82966b45a5 Mon Sep 17 00:00:00 2001 From: Michael Martin Date: Mon, 11 Dec 2023 16:46:03 -0800 Subject: [PATCH] wip remove minijinja --- Cargo.lock | 30 ----- Cargo.toml | 1 - src/cli.rs | 14 ++- src/nginx.conf.tpl | 172 --------------------------- src/nginx.rs | 291 +++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 280 insertions(+), 228 deletions(-) delete mode 100644 src/nginx.conf.tpl diff --git a/Cargo.lock b/Cargo.lock index 5642053..358ca1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,15 +26,6 @@ version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" -[[package]] -name = "minijinja" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "208758577ef2c86cf5dd3e85730d161413ec3284e2d73b2ef65d9a24d9971bcb" -dependencies = [ - "serde", -] - [[package]] name = "nix" version = "0.27.1" @@ -75,7 +66,6 @@ name = "rusty-cli" version = "0.1.0-pre-6" dependencies = [ "libc", - "minijinja", "nix", "shlex", "strum", @@ -83,26 +73,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "serde" -version = "1.0.190" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.190" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "shlex" version = "1.2.0" diff --git a/Cargo.toml b/Cargo.toml index bd33a42..99ceb53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ publish = true [dependencies] -minijinja = "1.0.10" shlex = "1.2.0" strum = { version = "0.25", features = ["derive"] } strum_macros = "0.25" diff --git a/src/cli.rs b/src/cli.rs index d6fe14f..26b3297 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -9,6 +9,7 @@ use std::env; use std::fmt::Display; use std::fs; use std::fs::File; +use std::io::prelude::*; use std::process; use std::process::Command; use thiserror::Error as ThisError; @@ -533,14 +534,25 @@ impl Action { http_conf: http_conf(&mut user), events_conf: vec![format!("worker_connections {};", user.worker_connections)], lua_loader, + resty_compat_version: crate::nginx::get_resty_compat_version(), }; let conf_path = prefix.conf.join("nginx.conf"); - if let Err(e) = fs::write(conf_path, render_config(vars)) { + let mut file = match fs::File::create(conf_path) { + Ok(file) => file, + Err(e) => { + eprintln!("failed opening nginx.conf for writing: {}", e); + return 2; + } + }; + + if let Err(e) = render_config(&mut file, vars).and_then(|_| file.flush()) { eprintln!("failed writing nginx.conf file: {}", e); return 2; } + drop(file); + let ngx = NginxExec { bin: find_nginx_bin(user.nginx_bin).to_str().unwrap().to_string(), prefix: prefix.root.to_str().unwrap().to_string(), diff --git a/src/nginx.conf.tpl b/src/nginx.conf.tpl deleted file mode 100644 index b793f84..0000000 --- a/src/nginx.conf.tpl +++ /dev/null @@ -1,172 +0,0 @@ -# generated by rusty-cli -# resty-cli compat: v0.{{ resty_compat_version }} - -daemon off; -master_process off; -worker_processes 1; -pid logs/nginx.pid; - -{% for line in main_conf %} -{{ line }} -{%- endfor %} - -events { - {% for line in events_conf %} - {{ line }} - {%- endfor %} -} - -{% if stream_enabled %} -stream { - access_log off; - lua_socket_log_errors off; - lua_regex_cache_max_entries 40960; - {% for line in stream_conf %} - {{ line }} - {%- endfor %} -} -{% endif %} - -http { - access_log off; - lua_socket_log_errors off; - lua_regex_cache_max_entries 40960; - - {% for line in http_conf %} - {{ line }} - {%- endfor %} - - init_by_lua_block { - ngx.config.is_console = true - - local stdout = io.stdout - local ngx_null = ngx.null - local maxn = table.maxn - local unpack = unpack - local concat = table.concat - - local expand_table - function expand_table(src, inplace) - local n = maxn(src) - local dst = inplace and src or {} - for i = 1, n do - local arg = src[i] - local typ = type(arg) - if arg == nil then - dst[i] = "nil" - - elseif typ == "boolean" then - if arg then - dst[i] = "true" - else - dst[i] = "false" - end - - elseif arg == ngx_null then - dst[i] = "null" - - elseif typ == "table" then - dst[i] = expand_table(arg, false) - - elseif typ ~= "string" then - dst[i] = tostring(arg) - - else - dst[i] = arg - end - end - return concat(dst) - end - - local function output(...) - local args = {...} - - return stdout:write(expand_table(args, true)) - end - - ngx.orig_print = ngx.print - ngx.print = output - - ngx.orig_say = ngx.say - ngx.say = function (...) - local ok, err = output(...) - if ok then - return output("\n") - end - return ok, err - end - print = ngx.say - - ngx.flush = function (...) return stdout:flush() end - -- we cannot close stdout here due to a bug in Lua: - ngx.eof = function (...) return true end - - {% if resty_compat_version >= 29 %} - ngx.orig_exit = ngx.exit - {% endif %} - - ngx.exit = os.exit - } - - init_worker_by_lua_block { - local exit = os.exit - local stderr = io.stderr - local ffi = require "ffi" - - local function handle_err(err) - if err then - err = string.gsub(err, "^init_worker_by_lua:%d+: ", "") - stderr:write("ERROR: ", err, "\n") - end - return exit(1) - end - - local ok, err = pcall(function () - if not ngx.config - or not ngx.config.ngx_lua_version - or ngx.config.ngx_lua_version < 10009 - then - error("at least ngx_lua 0.10.9 is required") - end - - local signal_graceful_exit = - require("ngx.process").signal_graceful_exit - if not signal_graceful_exit then - error("lua-resty-core library is too old; " - .. "missing the signal_graceful_exit() function " - .. "in ngx.process") - end - - {% for line in lua_loader %} - {{ line }} - {%- endfor %} - - -- print("calling timer.at...") - local ok, err = ngx.timer.at(0, function () - -- io.stderr:write("timer firing") - local ok, err = xpcall(gen, function (err) - -- level 3: we skip this function and the - -- error() call itself in our stacktrace - local trace = debug.traceback(err, 3) - return handle_err(trace) - end) - if not ok then - return handle_err(err) - end - if ffi.abi("win") then - return exit(0) - end - signal_graceful_exit() - end) - if not ok then - return handle_err(err) - end - -- print("timer created") - end) - - if not ok then - return handle_err(err) - end - } -} -# vim:set ft=nginx ts=4 sw=4 sts=4 et: diff --git a/src/nginx.rs b/src/nginx.rs index 29f6072..f8d0eb7 100644 --- a/src/nginx.rs +++ b/src/nginx.rs @@ -1,12 +1,12 @@ -use minijinja::{context, Environment}; use std::env; +use std::io; use std::path::PathBuf; const RESTY_COMPAT_VAR: &str = "RESTY_CLI_COMPAT_VERSION"; const RESTY_COMPAT_LATEST: u64 = 30; -const TEMPLATE: &str = include_str!("nginx.conf.tpl"); -const TEMPLATE_NAME: &str = "nginx.conf"; +const BLOCK_OPEN: &str = "{"; +const BLOCK_CLOSE: &str = "}"; pub struct Vars { pub events_conf: Vec, @@ -15,34 +15,277 @@ pub struct Vars { pub stream_conf: Vec, pub http_conf: Vec, pub lua_loader: Vec, + pub resty_compat_version: u64, } -fn init_template<'env, 'source>(env: &'env mut Environment) -> minijinja::Template<'env, 'source> { - env.add_template(TEMPLATE_NAME, TEMPLATE).unwrap(); - env.get_template(TEMPLATE_NAME).unwrap() +fn render_stream(buf: &mut T, vars: &Vars) -> io::Result<()> +where + T: io::Write, +{ + if vars.stream_enabled { + writeln!(buf, "stream {}", BLOCK_OPEN)?; + writeln!( + buf, + r##" + access_log off; + lua_socket_log_errors off; + lua_regex_cache_max_entries 40960; +"## + )?; + + for line in &vars.stream_conf { + writeln!(buf, " {}", line)?; + } + + writeln!(buf, "{}", BLOCK_CLOSE)?; + writeln!(buf)?; + } + + Ok(()) } -#[test] -fn verify_template() { - let mut env = Environment::new(); - init_template(&mut env); +fn render_lua(buf: &mut T, vars: &Vars) -> io::Result<()> +where + T: io::Write, +{ + const INIT_BY_LUA_OPEN: &str = r##" + init_by_lua_block { + ngx.config.is_console = true + + local stdout = io.stdout + local ngx_null = ngx.null + local maxn = table.maxn + local unpack = unpack + local concat = table.concat + + local expand_table + function expand_table(src, inplace) + local n = maxn(src) + local dst = inplace and src or {} + for i = 1, n do + local arg = src[i] + local typ = type(arg) + if arg == nil then + dst[i] = "nil" + + elseif typ == "boolean" then + if arg then + dst[i] = "true" + else + dst[i] = "false" + end + + elseif arg == ngx_null then + dst[i] = "null" + + elseif typ == "table" then + dst[i] = expand_table(arg, false) + + elseif typ ~= "string" then + dst[i] = tostring(arg) + + else + dst[i] = arg + end + end + return concat(dst) + end + + local function output(...) + local args = {...} + + return stdout:write(expand_table(args, true)) + end + + ngx.orig_print = ngx.print + ngx.print = output + + ngx.orig_say = ngx.say + ngx.say = function (...) + local ok, err = output(...) + if ok then + return output("\n") + end + return ok, err + end + print = ngx.say + + ngx.flush = function (...) return stdout:flush() end + -- we cannot close stdout here due to a bug in Lua: + ngx.eof = function (...) return true end +"##; + + const INIT_BY_LUA_CLOSE: &str = " + ngx.exit = os.exit + } +"; + + const INIT_WORKER_BY_LUA_OPEN: &str = r##" + init_worker_by_lua_block { + local exit = os.exit + local stderr = io.stderr + local ffi = require "ffi" + + local function handle_err(err) + if err then + err = string.gsub(err, "^init_worker_by_lua:%d+: ", "") + stderr:write("ERROR: ", err, "\n") + end + return exit(1) + end + + local ok, err = pcall(function () + if not ngx.config + or not ngx.config.ngx_lua_version + or ngx.config.ngx_lua_version < 10009 + then + error("at least ngx_lua 0.10.9 is required") + end + + local signal_graceful_exit = + require("ngx.process").signal_graceful_exit + if not signal_graceful_exit then + error("lua-resty-core library is too old; " + .. "missing the signal_graceful_exit() function " + .. "in ngx.process") + end +"##; + + const INIT_WORKER_BY_LUA_CLOSE: &str = r##" + -- print("calling timer.at...") + local ok, err = ngx.timer.at(0, function () + -- io.stderr:write("timer firing") + local ok, err = xpcall(gen, function (err) + -- level 3: we skip this function and the + -- error() call itself in our stacktrace + local trace = debug.traceback(err, 3) + return handle_err(trace) + end) + if not ok then + return handle_err(err) + end + if ffi.abi("win") then + return exit(0) + end + signal_graceful_exit() + end) + if not ok then + return handle_err(err) + end + -- print("timer created") + end) + + if not ok then + return handle_err(err) + end + } +"##; + + writeln!(buf, "{}", INIT_BY_LUA_OPEN)?; + writeln!(buf)?; + + if vars.resty_compat_version >= 29 { + writeln!(buf, " ngx.orig_exit = ngx.exit")?; + writeln!(buf)?; + } + + writeln!(buf, "{}", INIT_BY_LUA_CLOSE)?; + writeln!(buf)?; + + writeln!(buf, "{}", INIT_WORKER_BY_LUA_OPEN)?; + writeln!(buf)?; + + for line in &vars.lua_loader { + writeln!(buf, " {}", line)?; + } + writeln!(buf)?; + + writeln!(buf, "{}", INIT_WORKER_BY_LUA_CLOSE)?; + writeln!(buf)?; + + Ok(()) } -pub fn render_config(vars: Vars) -> String { - let mut env = Environment::new(); - let template = init_template(&mut env); - - let ctx = context! { - main_conf => vars.main_conf, - http_conf => vars.http_conf, - stream_enabled => vars.stream_enabled, - stream_conf => vars.stream_conf, - lua_loader => vars.lua_loader, - events_conf => vars.events_conf, - resty_compat_version => get_resty_compat_version(), - }; +fn render_http(buf: &mut T, vars: &Vars) -> io::Result<()> +where + T: io::Write, +{ + writeln!(buf, "http {}", BLOCK_OPEN)?; + writeln!( + buf, + r##" + access_log off; + lua_socket_log_errors off; + lua_regex_cache_max_entries 40960; +"## + )?; + + for line in &vars.http_conf { + writeln!(buf, " {}", line)?; + } + writeln!(buf)?; + + render_lua(buf, vars)?; + + writeln!(buf, "{}", BLOCK_CLOSE)?; + + Ok(()) +} + +fn render_events(buf: &mut T, vars: &Vars) -> io::Result<()> +where + T: io::Write, +{ + writeln!(buf, "events {}", BLOCK_OPEN)?; + + for line in &vars.events_conf { + writeln!(buf, " {}", line)?; + } + + writeln!(buf, "{}", BLOCK_CLOSE)?; + + Ok(()) +} + +pub fn render_main(buf: &mut T, vars: &Vars) -> io::Result<()> +where + T: io::Write, +{ + writeln!(buf, "# generated by rusty-cli")?; + writeln!(buf, "# resty-cli compat: v0.{}", vars.resty_compat_version)?; + writeln!(buf)?; + + writeln!( + buf, + r##" +daemon off; +master_process off; +worker_processes 1; +pid logs/nginx.pid; +"## + )?; + + for line in &vars.main_conf { + writeln!(buf, "{}", line)?; + } + + writeln!(buf)?; + + Ok(()) +} + +pub fn render_config(buf: &mut T, vars: Vars) -> io::Result<()> +where + T: io::Write, +{ + let buf = &mut io::BufWriter::new(buf); + + render_main(buf, &vars)?; + render_events(buf, &vars)?; + render_stream(buf, &vars)?; + render_http(buf, &vars)?; - template.render(ctx).unwrap() + Ok(()) } pub fn find_nginx_bin(nginx: Option) -> PathBuf {