From a6da8ce769edea72abb58bf8c6f58eeaa63c7345 Mon Sep 17 00:00:00 2001 From: nibon7 Date: Sat, 16 Dec 2023 23:56:03 +0800 Subject: [PATCH] Allow `filesize` type as a valid limit value (#11349) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description This pr allow us to use `filesize` type as a valid limit value, which is benefit for some file size based limits. # User-Facing Changes ```console /data/source/nushell> ulimit -f ╭───┬─────────────────────────────────────────────────────┬───────────┬───────────╮ │ # │ description │ soft │ hard │ ├───┼─────────────────────────────────────────────────────┼───────────┼───────────┤ │ 0 │ Maximum size of files created by the shell (kB, -f) │ unlimited │ unlimited │ ╰───┴─────────────────────────────────────────────────────┴───────────┴───────────╯ /data/source/nushell> ulimit -f 10Mib /data/source/nushell> ulimit -f ╭───┬─────────────────────────────────────────────────────┬───────┬───────╮ │ # │ description │ soft │ hard │ ├───┼─────────────────────────────────────────────────────┼───────┼───────┤ │ 0 │ Maximum size of files created by the shell (kB, -f) │ 10240 │ 10240 │ ╰───┴─────────────────────────────────────────────────────┴───────┴───────╯ /data/source/nushell> ulimit -n ╭───┬──────────────────────────────────────────────┬──────┬────────╮ │ # │ description │ soft │ hard │ ├───┼──────────────────────────────────────────────┼──────┼────────┤ │ 0 │ Maximum number of open file descriptors (-n) │ 1024 │ 524288 │ ╰───┴──────────────────────────────────────────────┴──────┴────────╯ /data/source/nushell> ulimit -n 10Mib Error: nu::shell::type_mismatch × Type mismatch. ╭─[entry #5:1:1] 1 │ ulimit -n 10Mib · ─┬─ · ╰── filesize is not compatible with resource RLIMIT_NOFILE ╰──── ``` # Tests + Formatting Make sure you've run and fixed any issues with these commands: - [x] add `commands::ulimit::limit_set_filesize1` - [x] add `commands::ulimit::limit_set_filesize2` - [x] `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to check that you're using the standard code style - [x] `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - [x] `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library --- crates/nu-command/src/platform/ulimit.rs | 33 ++++++++++----- crates/nu-command/tests/commands/ulimit.rs | 49 +++++++++++++++++++++- 2 files changed, 70 insertions(+), 12 deletions(-) diff --git a/crates/nu-command/src/platform/ulimit.rs b/crates/nu-command/src/platform/ulimit.rs index d058393b84..e3ec3f3130 100644 --- a/crates/nu-command/src/platform/ulimit.rs +++ b/crates/nu-command/src/platform/ulimit.rs @@ -338,14 +338,7 @@ fn set_limits( call_span: Span, ) -> Result<(), ShellError> { let (mut soft_limit, mut hard_limit) = getrlimit(res.resource)?; - let new_limit = parse_limit( - limit_value, - res.multiplier, - soft, - soft_limit, - hard_limit, - call_span, - )?; + let new_limit = parse_limit(limit_value, res, soft, soft_limit, hard_limit, call_span)?; if hard { hard_limit = new_limit; @@ -427,7 +420,7 @@ fn getrlimit(res: Resource) -> Result<(rlim_t, rlim_t), ShellError> { /// Parse user input fn parse_limit( limit_value: &Value, - multiplier: rlim_t, + res: &ResourceInfo, soft: bool, soft_limit: rlim_t, hard_limit: rlim_t, @@ -442,13 +435,31 @@ fn parse_limit( help: Some(e.to_string()), })?; - let (limit, overflow) = value.overflowing_mul(multiplier); + let (limit, overflow) = value.overflowing_mul(res.multiplier); if overflow { Ok(RLIM_INFINITY) } else { Ok(limit) } } + Value::Filesize { val, internal_span } => { + if res.multiplier != 1024 { + return Err(ShellError::TypeMismatch { + err_message: format!( + "filesize is not compatible with resource {:?}", + res.resource + ), + span: *internal_span, + }); + } + + rlim_t::try_from(*val).map_err(|e| ShellError::CantConvert { + to_type: "rlim_t".into(), + from_type: "i64".into(), + span: *internal_span, + help: Some(e.to_string()), + }) + } Value::String { val, internal_span } => { if val == "unlimited" { Ok(RLIM_INFINITY) @@ -470,7 +481,7 @@ fn parse_limit( } _ => Err(ShellError::TypeMismatch { err_message: format!( - "string or int required, you provide {}", + "string, int or filesize required, you provide {}", limit_value.get_type() ), span: limit_value.span(), diff --git a/crates/nu-command/tests/commands/ulimit.rs b/crates/nu-command/tests/commands/ulimit.rs index 50bc532241..51d2dafeb7 100644 --- a/crates/nu-command/tests/commands/ulimit.rs +++ b/crates/nu-command/tests/commands/ulimit.rs @@ -134,7 +134,7 @@ fn limit_set_invalid4() { " ); - assert!(actual.err.contains("string or int required")); + assert!(actual.err.contains("string, int or filesize required")); }); } @@ -168,3 +168,50 @@ fn limit_set_invalid5() { assert!(actual.out.eq("unlimited")); }); } + +#[test] +fn limit_set_filesize1() { + Playground::setup("limit_set_filesize1", |dirs, _sandbox| { + let actual = nu!( + cwd: dirs.test(), pipeline( + " + let hard = (ulimit -c | first | get hard); + match $hard { + \"unlimited\" => { + ulimit -c 1Mib; + ulimit -c + | first + | get soft + }, + $x if $x >= 1024 * 1024 => { + ulimit -c 1Mib; + ulimit -c + | first + | get soft + } + _ => { + echo \"hard limit too small\" + } + } + " + )); + + assert!(actual.out.eq("1024") || actual.out.eq("hard limit too small")); + }); +} + +#[test] +fn limit_set_filesize2() { + Playground::setup("limit_set_filesize2", |dirs, _sandbox| { + let actual = nu!( + cwd: dirs.test(), + " + ulimit -n 10Kib + " + ); + + assert!(actual + .err + .contains("filesize is not compatible with resource RLIMIT_NOFILE")); + }); +}