diff --git a/.zetch.lock b/.zetch.lock index 3c245b8..c1102e9 100644 --- a/.zetch.lock +++ b/.zetch.lock @@ -1,16 +1,16 @@ { "version": "0.0.10", "files": { - "setup.zetch.cfg": "ec37422c63513f42feab279eaad528e834dd4480cd9c3e2789b2fd9bea626ed1", - "README.zetch.md": "bf36c066d493db3c44a95ef89989ce310c8905df162d772db21913cc7a113311", - "docs/CODE_OF_CONDUCT.zetch.md": "bf106326ffc75f5167cfde27c997c77c6b97c843a9e392b564355d0e70e50b97", - "docs/CONTRIBUTING.zetch.md": "c1163c54e695dc64174c047f48976e927b6aae4f6fbf4c94ebd06ef56f8ba02f", "CONTRIBUTING.zetch.md": "c1163c54e695dc64174c047f48976e927b6aae4f6fbf4c94ebd06ef56f8ba02f", - "docs/index.zetch.md": "2eda002221d0f22c813a6de54c44a78fc029f516f023c8f7b52bdd437f22c54f", - "docs/LICENSE.zetch.md": "d2c12e539d357957b950a54a5477c3a9f87bd2b3ee707be7a4db7adaf5aacc2b", "CODE_OF_CONDUCT.zetch.md": "bf106326ffc75f5167cfde27c997c77c6b97c843a9e392b564355d0e70e50b97", - "py_rust/README.zetch.md": "2eda002221d0f22c813a6de54c44a78fc029f516f023c8f7b52bdd437f22c54f", + "docs/CONTRIBUTING.zetch.md": "c1163c54e695dc64174c047f48976e927b6aae4f6fbf4c94ebd06ef56f8ba02f", + "docs/LICENSE.zetch.md": "d2c12e539d357957b950a54a5477c3a9f87bd2b3ee707be7a4db7adaf5aacc2b", + "docs/index.zetch.md": "2eda002221d0f22c813a6de54c44a78fc029f516f023c8f7b52bdd437f22c54f", "py_rust/LICENSE.zetch.md": "d2c12e539d357957b950a54a5477c3a9f87bd2b3ee707be7a4db7adaf5aacc2b", - "LICENSE.zetch.md": "d2c12e539d357957b950a54a5477c3a9f87bd2b3ee707be7a4db7adaf5aacc2b" + "LICENSE.zetch.md": "d2c12e539d357957b950a54a5477c3a9f87bd2b3ee707be7a4db7adaf5aacc2b", + "docs/CODE_OF_CONDUCT.zetch.md": "bf106326ffc75f5167cfde27c997c77c6b97c843a9e392b564355d0e70e50b97", + "setup.zetch.cfg": "ec37422c63513f42feab279eaad528e834dd4480cd9c3e2789b2fd9bea626ed1", + "py_rust/README.zetch.md": "2eda002221d0f22c813a6de54c44a78fc029f516f023c8f7b52bdd437f22c54f", + "README.zetch.md": "bf36c066d493db3c44a95ef89989ce310c8905df162d772db21913cc7a113311" } } \ No newline at end of file diff --git a/dev_scripts/py_rust.sh b/dev_scripts/py_rust.sh index caec1a3..d18085d 100755 --- a/dev_scripts/py_rust.sh +++ b/dev_scripts/py_rust.sh @@ -21,10 +21,8 @@ ensure_venv () { source ./py_rust/.venv/bin/activate fi - ./dev_scripts/utils.sh py_install_if_missing typing-extensions - ./dev_scripts/utils.sh py_install_if_missing maturin - ./dev_scripts/utils.sh py_install_if_missing pyright - ./dev_scripts/utils.sh py_install_if_missing pytest + # Install any dev requirements that aren't managed by maturin: + pip install -r ./py_rust/dev_requirements.txt ./dev_scripts/utils.sh py_install_if_missing ruff } diff --git a/py_rust/Cargo.lock b/py_rust/Cargo.lock index 0c6fcdb..b8a66a3 100644 --- a/py_rust/Cargo.lock +++ b/py_rust/Cargo.lock @@ -175,7 +175,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "639f2d11715601ccc0ba383a11209d87f89361736242b3ebf0182c7299a3d682" dependencies = [ "chrono", - "clap", "colored", "comfy-table", "conch-parser", diff --git a/py_rust/Cargo.toml b/py_rust/Cargo.toml index af9d561..30ee760 100644 --- a/py_rust/Cargo.toml +++ b/py_rust/Cargo.toml @@ -17,7 +17,7 @@ path = "src/lib.rs" colored = '2' tracing = "0.1" error-stack = "0.4" -bitbazaar = { version = "0.0.38", features = ["cli", "timing", "clap"] } +bitbazaar = { version = "0.0.38", features = ["cli", "timing"] } pyo3 = { version = '0.20.0', features = ['extension-module', 'chrono', 'generate-import-lib'] } parking_lot = { version = "0.12", features = ['deadlock_detection', 'serde'] } strum = { version = '0.25', features = ['derive'] } diff --git a/py_rust/dev_requirements.txt b/py_rust/dev_requirements.txt new file mode 100644 index 0000000..065f507 --- /dev/null +++ b/py_rust/dev_requirements.txt @@ -0,0 +1,6 @@ +maturin==1.4.0 +typing-extensions==4.9.0 +pyright==1.1.351 +pytest==8.0.1 +pytest-xdist==3.5.0 +pytest-profiling==1.7.0 \ No newline at end of file diff --git a/py_rust/src/args.rs b/py_rust/src/args.rs index cb77e4a..f73e1ae 100644 --- a/py_rust/src/args.rs +++ b/py_rust/src/args.rs @@ -37,7 +37,7 @@ pub fn get_version_info() -> String { } } -#[derive(Debug, Parser)] +#[derive(Clone, Debug, Parser)] #[command( author, name = "zetch", @@ -49,7 +49,7 @@ pub struct Args { #[command(subcommand)] pub command: Command, #[clap(flatten)] - pub log_level_args: bitbazaar::log::ClapLogLevelArgs, + pub log_level_args: ClapLogLevelArgs, /// The config file to use. Note if render command, relative and not found from working directory, will search entered root directory. #[arg( short, @@ -61,7 +61,7 @@ pub struct Args { pub config: PathBuf, } -#[derive(Debug, clap::Subcommand)] +#[derive(Clone, Debug, clap::Subcommand)] pub enum Command { /// Render all templates found whilst traversing the given root (default). Render(RenderCommand), @@ -95,9 +95,19 @@ pub struct RenderCommand { /// The target directory to search and render. #[clap(default_value = ".")] pub root: PathBuf, + + /// No tasks will be run, cli vars will be ignored and treated as empty strings if "light" defaults not specified. + #[arg(short, long, default_value = "false")] + pub light: bool, + + /// Same as light, but user defined custom extensions are also treated as empty strings, pure rust speeds! + #[arg(long, default_value = "false")] + pub superlight: bool, + /// Force write all rendered files, ignore existing lockfile. #[arg(short, long, default_value = "false")] pub force: bool, + /// Comma separated list of env ctx vars to ignore defaults for and raise if not in env. E.g. --ban-defaults FOO,BAR... /// /// If no vars are provided, all defaults will be ignored. @@ -218,3 +228,34 @@ pub enum HelpFormat { Text, Json, } + +/// A simple clap argument group for controlling the log level for cli usage. +#[derive(Clone, Debug, clap::Args)] +pub struct ClapLogLevelArgs { + /// Enable verbose logging. + #[arg( + short, + long, + global = true, + group = "verbosity", + help_heading = "Log levels" + )] + pub verbose: bool, + /// Print diagnostics, but nothing else. + #[arg( + short, + long, + global = true, + group = "verbosity", + help_heading = "Log levels" + )] + /// Disable all logging (but still exit with status code "1" upon detecting diagnostics). + #[arg( + short, + long, + global = true, + group = "verbosity", + help_heading = "Log levels" + )] + pub silent: bool, +} diff --git a/py_rust/src/config/context.rs b/py_rust/src/config/context.rs index 0274d0d..1ef264e 100644 --- a/py_rust/src/config/context.rs +++ b/py_rust/src/config/context.rs @@ -66,7 +66,7 @@ impl CtxEnvVar { pub struct CtxCliVar { pub commands: Vec, pub coerce: Option, - pub initial: Option, + pub light: Option, } impl CtxCliVar { diff --git a/py_rust/src/config/schema.json b/py_rust/src/config/schema.json index 643aec6..fb73e1a 100644 --- a/py_rust/src/config/schema.json +++ b/py_rust/src/config/schema.json @@ -148,8 +148,8 @@ }, "minItems": 1 }, - "initial": { - "description": "You might find one of your commands fails on a fresh build if zetch hasn't run yet due to dependencies on other zetched files, i.e. a circular dependency. When no lockfile is found, or --force is used, if any cli variable has initial set zetch will run twice, on the first run cli vars will use their initials where they have them, on the second render the real commands will compute the values." + "light": { + "description": "The value to use when in rendering in --light or --superlight mode. If not set, the var will be treated as an empty string." }, "coerce": { "type": "string", diff --git a/py_rust/src/custom_exts/py_interface.rs b/py_rust/src/custom_exts/py_interface.rs index 4b5a4e0..d747d20 100644 --- a/py_rust/src/custom_exts/py_interface.rs +++ b/py_rust/src/custom_exts/py_interface.rs @@ -50,6 +50,14 @@ pub fn load_custom_exts(exts: &[String], state: &State) -> Result Result>(()) })?; - // Extract a copy of the user funcs to add to minijinja env: - // Note copying as env might be created multiple times (e.g. initial) - // TODO: instead of this maybe reusing an env? In general need a bit of a refactor! - Ok(PY_USER_FUNCS.lock().clone()) + // Extra the loaded user funcs, this fn is checked to only run once. So no need to clone and maintain global var. + Ok(std::mem::take(&mut *PY_USER_FUNCS.lock())) } pub fn mini_values_to_py_params( diff --git a/py_rust/src/render/debug.rs b/py_rust/src/render/debug.rs index ed015da..72be71f 100644 --- a/py_rust/src/render/debug.rs +++ b/py_rust/src/render/debug.rs @@ -1,8 +1,11 @@ -use crate::state::State; +use std::collections::HashMap; + +use crate::config::conf::Config; #[derive(Debug, serde::Serialize)] pub struct Debug { - pub state: State, + pub conf: Config, + pub ctx: HashMap, pub written: Vec, pub identical: Vec, pub matched_templates: Vec, diff --git a/py_rust/src/render/mini_env.rs b/py_rust/src/render/mini_env.rs index ab6e265..61a0be6 100644 --- a/py_rust/src/render/mini_env.rs +++ b/py_rust/src/render/mini_env.rs @@ -60,33 +60,42 @@ pub fn new_mini_env<'a>(root: &Path, state: &'a State) -> Result| - -> core::result::Result { - let result = - Python::with_gil(|py| -> Result { - let (py_args, py_kwargs) = py_interface::mini_values_to_py_params(py, values)?; - let py_result = py_fn - .call(py, py_args, py_kwargs) - .map_err(|e: PyErr| zerr!(Zerr::CustomPyFunctionError, "{}", e))?; - let rustified: serde_json::Value = - depythonize(py_result.as_ref(py)).change_context(Zerr::CustomPyFunctionError).attach_printable_lazy(|| { - "Failed to convert python result to a rust-like value." - })?; - Ok(rustified) - }); - match result { - Err(e) => Err(minijinja::Error::new( - minijinja::ErrorKind::InvalidOperation, - format!("Failed to call custom filter '{}'. Err: \n{:?}", name, e), - )), - Ok(result) => Ok(minijinja::Value::from_serializable(&result)), - } - }, - ) + // If superlight, add a pseudo fn that returns an empty string + if state.superlight { + let empty_str = minijinja::Value::from_safe_string("".to_string()); + env.add_function( + name.clone(), + move |_values: minijinja::value::Rest| empty_str.clone(), + ); + } else { + // Add the rust-wrapped python fn to the minijinja environment: + env.add_function( + name.clone(), + move | + values: minijinja::value::Rest| + -> core::result::Result { + let result = + Python::with_gil(|py| -> Result { + let (py_args, py_kwargs) = py_interface::mini_values_to_py_params(py, values)?; + let py_result = py_fn + .call(py, py_args, py_kwargs) + .map_err(|e: PyErr| zerr!(Zerr::CustomPyFunctionError, "{}", e))?; + let rustified: serde_json::Value = + depythonize(py_result.as_ref(py)).change_context(Zerr::CustomPyFunctionError).attach_printable_lazy(|| { + "Failed to convert python result to a rust-like value." + })?; + Ok(rustified) + }); + match result { + Err(e) => Err(minijinja::Error::new( + minijinja::ErrorKind::InvalidOperation, + format!("Failed to call custom filter '{}'. Err: \n{:?}", name, e), + )), + Ok(result) => Ok(minijinja::Value::from_serializable(&result)), + } + }, + ) + } } Ok(env) diff --git a/py_rust/src/render/mod.rs b/py_rust/src/render/mod.rs index db362e8..805fdcb 100644 --- a/py_rust/src/render/mod.rs +++ b/py_rust/src/render/mod.rs @@ -23,43 +23,26 @@ pub fn render(args: &crate::args::Args, render_args: &RenderCommand) -> Result