From dc76183cd535d44eb184d6e428a5a9f33c88dfc4 Mon Sep 17 00:00:00 2001 From: Sang-Heon Jeon Date: Mon, 10 Jun 2024 11:43:17 +0900 Subject: [PATCH 01/14] fix wrong casting with into filesize (#13110) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Fix wrong casting which is related to https://github.com/nushell/nushell/pull/12974#discussion_r1618598336 # User-Facing Changes AS-IS (before fixing) ``` $ "-10000PiB" | into filesize 6.2 EiB <--- Wrong casted value $ "10000PiB" | into filesize -6.2 EiB <--- Wrong casted value ``` TO-BE (after fixing) ``` $ "-10000PiB" | into filesize Error: nu::shell::cant_convert × Can't convert to filesize. ╭─[entry #6:1:1] 1 │ "-10000PiB" | into filesize · ─────┬───── · ╰── can't convert string to filesize ╰──── $ "10000PiB" | into filesize Error: nu::shell::cant_convert × Can't convert to filesize. ╭─[entry #7:1:1] 1 │ "10000PiB" | into filesize · ─────┬──── · ╰── can't convert string to filesize ╰──── ``` --- .../src/conversions/into/filesize.rs | 21 ++++++++++++++----- .../tests/commands/into_filesize.rs | 14 +++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/crates/nu-command/src/conversions/into/filesize.rs b/crates/nu-command/src/conversions/into/filesize.rs index 101a9fe6f0..010c031b2a 100644 --- a/crates/nu-command/src/conversions/into/filesize.rs +++ b/crates/nu-command/src/conversions/into/filesize.rs @@ -122,7 +122,7 @@ pub fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value { Value::Filesize { .. } => input.clone(), Value::Int { val, .. } => Value::filesize(*val, value_span), Value::Float { val, .. } => Value::filesize(*val as i64, value_span), - Value::String { val, .. } => match int_from_string(val, value_span) { + Value::String { val, .. } => match i64_from_string(val, value_span) { Ok(val) => Value::filesize(val, value_span), Err(error) => Value::error(error, value_span), }, @@ -139,7 +139,7 @@ pub fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value { } } -fn int_from_string(a_string: &str, span: Span) -> Result { +fn i64_from_string(a_string: &str, span: Span) -> Result { // Get the Locale so we know what the thousands separator is let locale = get_system_locale(); @@ -151,24 +151,35 @@ fn int_from_string(a_string: &str, span: Span) -> Result { // Hadle negative file size if let Some(stripped_negative_string) = clean_string.strip_prefix('-') { match stripped_negative_string.parse::() { - Ok(n) => Ok(-(n.as_u64() as i64)), + Ok(n) => i64_from_byte_size(n, true, span), Err(_) => Err(string_convert_error(span)), } } else if let Some(stripped_positive_string) = clean_string.strip_prefix('+') { match stripped_positive_string.parse::() { Ok(n) if stripped_positive_string.starts_with(|c: char| c.is_ascii_digit()) => { - Ok(n.as_u64() as i64) + i64_from_byte_size(n, false, span) } _ => Err(string_convert_error(span)), } } else { match clean_string.parse::() { - Ok(n) => Ok(n.as_u64() as i64), + Ok(n) => i64_from_byte_size(n, false, span), Err(_) => Err(string_convert_error(span)), } } } +fn i64_from_byte_size( + byte_size: bytesize::ByteSize, + is_negative: bool, + span: Span, +) -> Result { + match i64::try_from(byte_size.as_u64()) { + Ok(n) => Ok(if is_negative { -n } else { n }), + Err(_) => Err(string_convert_error(span)), + } +} + fn string_convert_error(span: Span) -> ShellError { ShellError::CantConvert { to_type: "filesize".into(), diff --git a/crates/nu-command/tests/commands/into_filesize.rs b/crates/nu-command/tests/commands/into_filesize.rs index d8ba88021c..6a72c76b5d 100644 --- a/crates/nu-command/tests/commands/into_filesize.rs +++ b/crates/nu-command/tests/commands/into_filesize.rs @@ -76,6 +76,13 @@ fn into_filesize_wrong_negative_str_filesize() { assert!(actual.err.contains("can't convert string to filesize")); } +#[test] +fn into_filesize_large_negative_str_filesize() { + let actual = nu!("'-10000PiB' | into filesize"); + + assert!(actual.err.contains("can't convert string to filesize")); +} + #[test] fn into_filesize_negative_str() { let actual = nu!("'-1' | into filesize"); @@ -104,6 +111,13 @@ fn into_filesize_wrong_positive_str_filesize() { assert!(actual.err.contains("can't convert string to filesize")); } +#[test] +fn into_filesize_large_positive_str_filesize() { + let actual = nu!("'+10000PiB' | into filesize"); + + assert!(actual.err.contains("can't convert string to filesize")); +} + #[test] fn into_filesize_positive_str() { let actual = nu!("'+1' | into filesize"); From 650ae537c3a7346e9ce899e41634f611786399dd Mon Sep 17 00:00:00 2001 From: Jack Wright <56345+ayax79@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:44:04 -0700 Subject: [PATCH 02/14] Fix the use of right hand expressions in operations (#13096) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As reported by @maxim-uvarov and pyz in the dataframes discord channel: ```nushell [[a b]; [1 1] [1 2] [2 1] [2 2] [3 1] [3 2]] | polars into-df | polars with-column ((polars col a) / (polars col b)) --name c × Type mismatch. ╭─[entry #45:1:102] 1 │ [[a b]; [1 1] [1 2] [2 1] [2 2] [3 1] [3 2]] | polars into-df | polars with-column ((polars col a) / (polars col b)) --name c · ───────┬────── · ╰── Right hand side not a dataframe expression ╰──── ``` This pull request corrects the type casting on the right hand side and allows more than just polars literal expressions. --- .../values/nu_expression/custom_value.rs | 49 ++++--------------- 1 file changed, 10 insertions(+), 39 deletions(-) diff --git a/crates/nu_plugin_polars/src/dataframe/values/nu_expression/custom_value.rs b/crates/nu_plugin_polars/src/dataframe/values/nu_expression/custom_value.rs index ea751b0255..a9371f03f2 100644 --- a/crates/nu_plugin_polars/src/dataframe/values/nu_expression/custom_value.rs +++ b/crates/nu_plugin_polars/src/dataframe/values/nu_expression/custom_value.rs @@ -63,45 +63,16 @@ fn compute_with_value( op: Span, right: &Value, ) -> Result { - let rhs_span = right.span(); - match right { - Value::Custom { val: rhs, .. } => { - let rhs = rhs.as_any().downcast_ref::().ok_or_else(|| { - ShellError::TypeMismatch { - err_message: "Right hand side not a dataframe expression".into(), - span: rhs_span, - } - })?; - - match rhs.as_ref() { - polars::prelude::Expr::Literal(..) => with_operator( - (plugin, engine), - operator, - left, - rhs, - lhs_span, - right.span(), - op, - ), - _ => Err(ShellError::TypeMismatch { - err_message: "Only literal expressions or number".into(), - span: right.span(), - }), - } - } - _ => { - let rhs = NuExpression::try_from_value(plugin, right)?; - with_operator( - (plugin, engine), - operator, - left, - &rhs, - lhs_span, - right.span(), - op, - ) - } - } + let rhs = NuExpression::try_from_value(plugin, right)?; + with_operator( + (plugin, engine), + operator, + left, + &rhs, + lhs_span, + right.span(), + op, + ) } fn with_operator( From 021b8633cb8f776ca1a30db2597d107aa92fbf6f Mon Sep 17 00:00:00 2001 From: Jack Wright <56345+ayax79@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:45:25 -0700 Subject: [PATCH 03/14] Allow the addition of an index column to be optional (#13097) Per discussion on discord dataframes channel with @maxim-uvarov and pyz. When converting a dataframe to an nushell value via `polars into-nu`, the index column should not be added by default and should only be added when specifying `--index` --- .../src/dataframe/eager/to_nu.rs | 14 ++++---- .../src/dataframe/values/nu_dataframe/mod.rs | 32 +++++++++++++------ 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/crates/nu_plugin_polars/src/dataframe/eager/to_nu.rs b/crates/nu_plugin_polars/src/dataframe/eager/to_nu.rs index 8e3cdffa24..72aff7a728 100644 --- a/crates/nu_plugin_polars/src/dataframe/eager/to_nu.rs +++ b/crates/nu_plugin_polars/src/dataframe/eager/to_nu.rs @@ -35,6 +35,7 @@ impl PluginCommand for ToNu { Some('n'), ) .switch("tail", "shows tail rows", Some('t')) + .switch("index", "add an index column", Some('i')) .input_output_types(vec![ (Type::Custom("expression".into()), Type::Any), (Type::Custom("dataframe".into()), Type::table()), @@ -62,18 +63,18 @@ impl PluginCommand for ToNu { vec![ Example { description: "Shows head rows from dataframe", - example: "[[a b]; [1 2] [3 4]] | polars into-df | polars into-nu", + example: "[[a b]; [1 2] [3 4]] | polars into-df | polars into-nu --index", result: Some(Value::list(vec![rec_1, rec_2], Span::test_data())), }, Example { description: "Shows tail rows from dataframe", example: - "[[a b]; [1 2] [5 6] [3 4]] | polars into-df | polars into-nu --tail --rows 1", + "[[a b]; [1 2] [5 6] [3 4]] | polars into-df | polars into-nu --tail --rows 1 --index", result: Some(Value::list(vec![rec_3], Span::test_data())), }, Example { description: "Convert a col expression into a nushell value", - example: "polars col a | polars into-nu", + example: "polars col a | polars into-nu --index", result: Some(Value::test_record(record! { "expr" => Value::test_string("column"), "value" => Value::test_string("a"), @@ -106,17 +107,18 @@ fn dataframe_command( ) -> Result { let rows: Option = call.get_flag("rows")?; let tail: bool = call.has_flag("tail")?; + let index: bool = call.has_flag("index")?; let df = NuDataFrame::try_from_value_coerce(plugin, &input, call.head)?; let values = if tail { - df.tail(rows, call.head)? + df.tail(rows, index, call.head)? } else { // if rows is specified, return those rows, otherwise return everything if rows.is_some() { - df.head(rows, call.head)? + df.head(rows, index, call.head)? } else { - df.head(Some(df.height()), call.head)? + df.head(Some(df.height()), index, call.head)? } }; diff --git a/crates/nu_plugin_polars/src/dataframe/values/nu_dataframe/mod.rs b/crates/nu_plugin_polars/src/dataframe/values/nu_dataframe/mod.rs index 1c322579dd..89a8c862e7 100644 --- a/crates/nu_plugin_polars/src/dataframe/values/nu_dataframe/mod.rs +++ b/crates/nu_plugin_polars/src/dataframe/values/nu_dataframe/mod.rs @@ -326,22 +326,22 @@ impl NuDataFrame { } // Print is made out a head and if the dataframe is too large, then a tail - pub fn print(&self, span: Span) -> Result, ShellError> { + pub fn print(&self, include_index: bool, span: Span) -> Result, ShellError> { let df = &self.df; let size: usize = 20; if df.height() > size { let sample_size = size / 2; - let mut values = self.head(Some(sample_size), span)?; + let mut values = self.head(Some(sample_size), include_index, span)?; conversion::add_separator(&mut values, df, self.has_index(), span); let remaining = df.height() - sample_size; let tail_size = remaining.min(sample_size); - let mut tail_values = self.tail(Some(tail_size), span)?; + let mut tail_values = self.tail(Some(tail_size), include_index, span)?; values.append(&mut tail_values); Ok(values) } else { - Ok(self.head(Some(size), span)?) + Ok(self.head(Some(size), include_index, span)?) } } @@ -349,26 +349,38 @@ impl NuDataFrame { self.df.height() } - pub fn head(&self, rows: Option, span: Span) -> Result, ShellError> { + pub fn head( + &self, + rows: Option, + include_index: bool, + span: Span, + ) -> Result, ShellError> { let to_row = rows.unwrap_or(5); - let values = self.to_rows(0, to_row, span)?; + let values = self.to_rows(0, to_row, include_index, span)?; Ok(values) } - pub fn tail(&self, rows: Option, span: Span) -> Result, ShellError> { + pub fn tail( + &self, + rows: Option, + include_index: bool, + span: Span, + ) -> Result, ShellError> { let df = &self.df; let to_row = df.height(); let size = rows.unwrap_or(DEFAULT_ROWS); let from_row = to_row.saturating_sub(size); - let values = self.to_rows(from_row, to_row, span)?; + let values = self.to_rows(from_row, to_row, include_index, span)?; Ok(values) } + /// Converts the dataframe to a nushell list of values pub fn to_rows( &self, from_row: usize, to_row: usize, + include_index: bool, span: Span, ) -> Result, ShellError> { let df = &self.df; @@ -400,7 +412,7 @@ impl NuDataFrame { .map(|i| { let mut record = Record::new(); - if !has_index { + if !has_index && include_index { record.push("index", Value::int((i + from_row) as i64, span)); } @@ -602,7 +614,7 @@ impl CustomValueSupport for NuDataFrame { } fn base_value(self, span: Span) -> Result { - let vals = self.print(span)?; + let vals = self.print(true, span)?; Ok(Value::list(vals, span)) } From 5b7e8bf1d8022b2aef50d8a0ad7cbd8e3c65f707 Mon Sep 17 00:00:00 2001 From: NotTheDr01ds <32344964+NotTheDr01ds@users.noreply.github.com> Date: Sun, 9 Jun 2024 23:01:22 -0400 Subject: [PATCH 04/14] Deprecate `--numbered` from `for` (#13112) # Description #7777 removed the `--numbered` flag from `each`, `par-each`, `reduce`, and `each while`. It was suggested at the time that it should be removed from `for` as well, but for several reasons it wasn't. This PR deprecates `--numbered` in anticipation of removing it in 0.96. Note: Please review carefully, as this is my first "real" Rust/Nushell code. I was hoping that some prior commit would be useful as a template, but since this was an argument on a parser keyword, I didn't find too much useful. So I had to actually find the relevant helpers in the code and `nu_protocol` doc and learn how to use them - oh darn ;-) But please make sure I did it correctly. # User-Facing Changes * Use of `--numbered` will result in a deprecation warning. * Changed help example to demonstrate the new syntax. * Help shows deprecation notice on the flag --- crates/nu-cmd-lang/src/core_commands/for_.rs | 20 ++++++++++++++++--- .../nu-protocol/src/errors/parse_warning.rs | 2 +- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/crates/nu-cmd-lang/src/core_commands/for_.rs b/crates/nu-cmd-lang/src/core_commands/for_.rs index 387af45282..0f2434d162 100644 --- a/crates/nu-cmd-lang/src/core_commands/for_.rs +++ b/crates/nu-cmd-lang/src/core_commands/for_.rs @@ -1,5 +1,6 @@ use nu_engine::{command_prelude::*, get_eval_block, get_eval_expression}; use nu_protocol::engine::CommandType; +use nu_protocol::ParseWarning; #[derive(Clone)] pub struct For; @@ -30,7 +31,7 @@ impl Command for For { .required("block", SyntaxShape::Block, "The block to run.") .switch( "numbered", - "return a numbered item ($it.index and $it.item)", + "DEPRECATED: return a numbered item ($it.index and $it.item)", Some('n'), ) .creates_scope() @@ -78,6 +79,20 @@ impl Command for For { let value = eval_expression(engine_state, stack, keyword_expr)?; let numbered = call.has_flag(engine_state, stack, "numbered")?; + if numbered { + nu_protocol::report_error_new( + engine_state, + &ParseWarning::DeprecatedWarning { + old_command: "--numbered/-n".into(), + new_suggestion: "use `enumerate`".into(), + span: call + .get_named_arg("numbered") + .expect("`get_named_arg` found `--numbered` but still failed") + .span, + url: "See `help for` examples".into(), + }, + ); + } let ctrlc = engine_state.ctrlc.clone(); let engine_state = engine_state.clone(); @@ -198,8 +213,7 @@ impl Command for For { }, Example { description: "Number each item and print a message", - example: - "for $it in ['bob' 'fred'] --numbered { print $\"($it.index) is ($it.item)\" }", + example: r#"for $it in (['bob' 'fred'] | enumerate) { print $"($it.index) is ($it.item)" }"#, result: None, }, ] diff --git a/crates/nu-protocol/src/errors/parse_warning.rs b/crates/nu-protocol/src/errors/parse_warning.rs index 0213d6889f..a30bc731d8 100644 --- a/crates/nu-protocol/src/errors/parse_warning.rs +++ b/crates/nu-protocol/src/errors/parse_warning.rs @@ -10,7 +10,7 @@ pub enum ParseWarning { DeprecatedWarning { old_command: String, new_suggestion: String, - #[label("`{old_command}` is deprecated and will be removed in 0.94. Please {new_suggestion} instead")] + #[label("`{old_command}` is deprecated and will be removed in a future release. Please {new_suggestion} instead")] span: Span, url: String, }, From af22bb8d52a3e011cff9f0fb5766749206822dc3 Mon Sep 17 00:00:00 2001 From: Ian Manske Date: Mon, 10 Jun 2024 11:31:47 +0000 Subject: [PATCH 05/14] Remove old `sys` command behavior (#13114) # Description Removes the old, deprecated behavior of the `sys` command. That is, it will no longer return the full system information record. # User-Facing Changes Breaking change: `sys` no longer outputs anything and will instead display help text. --- crates/nu-command/src/system/sys/cpu.rs | 43 ++++- crates/nu-command/src/system/sys/disks.rs | 28 ++- crates/nu-command/src/system/sys/host.rs | 56 +++++- crates/nu-command/src/system/sys/mem.rs | 20 ++- crates/nu-command/src/system/sys/mod.rs | 198 +--------------------- crates/nu-command/src/system/sys/net.rs | 21 ++- crates/nu-command/src/system/sys/sys_.rs | 32 +--- crates/nu-command/src/system/sys/temp.rs | 24 ++- crates/nu-command/src/system/sys/users.rs | 26 ++- 9 files changed, 215 insertions(+), 233 deletions(-) diff --git a/crates/nu-command/src/system/sys/cpu.rs b/crates/nu-command/src/system/sys/cpu.rs index b2f6d6afa6..d24197bf70 100644 --- a/crates/nu-command/src/system/sys/cpu.rs +++ b/crates/nu-command/src/system/sys/cpu.rs @@ -1,4 +1,6 @@ +use super::trim_cstyle_null; use nu_engine::command_prelude::*; +use sysinfo::{CpuRefreshKind, System, MINIMUM_CPU_UPDATE_INTERVAL}; #[derive(Clone)] pub struct SysCpu; @@ -26,7 +28,7 @@ impl Command for SysCpu { call: &Call, _input: PipelineData, ) -> Result { - Ok(super::cpu(call.head).into_pipeline_data()) + Ok(cpu(call.head).into_pipeline_data()) } fn examples(&self) -> Vec { @@ -37,3 +39,42 @@ impl Command for SysCpu { }] } } + +fn cpu(span: Span) -> Value { + let mut sys = System::new(); + sys.refresh_cpu_specifics(CpuRefreshKind::everything()); + // We must refresh the CPU twice a while apart to get valid usage data. + // In theory we could just sleep MINIMUM_CPU_UPDATE_INTERVAL, but I've noticed that + // that gives poor results (error of ~5%). Decided to wait 2x that long, somewhat arbitrarily + std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL * 2); + sys.refresh_cpu_specifics(CpuRefreshKind::new().with_cpu_usage()); + + let cpus = sys + .cpus() + .iter() + .map(|cpu| { + // sysinfo CPU usage numbers are not very precise unless you wait a long time between refreshes. + // Round to 1DP (chosen somewhat arbitrarily) so people aren't misled by high-precision floats. + let rounded_usage = (cpu.cpu_usage() * 10.0).round() / 10.0; + + let load_avg = System::load_average(); + let load_avg = format!( + "{:.2}, {:.2}, {:.2}", + load_avg.one, load_avg.five, load_avg.fifteen + ); + + let record = record! { + "name" => Value::string(trim_cstyle_null(cpu.name()), span), + "brand" => Value::string(trim_cstyle_null(cpu.brand()), span), + "freq" => Value::int(cpu.frequency() as i64, span), + "cpu_usage" => Value::float(rounded_usage.into(), span), + "load_average" => Value::string(load_avg, span), + "vendor_id" => Value::string(trim_cstyle_null(cpu.vendor_id()), span), + }; + + Value::record(record, span) + }) + .collect(); + + Value::list(cpus, span) +} diff --git a/crates/nu-command/src/system/sys/disks.rs b/crates/nu-command/src/system/sys/disks.rs index 66991c9087..0d9ce09db3 100644 --- a/crates/nu-command/src/system/sys/disks.rs +++ b/crates/nu-command/src/system/sys/disks.rs @@ -1,4 +1,6 @@ +use super::trim_cstyle_null; use nu_engine::command_prelude::*; +use sysinfo::Disks; #[derive(Clone)] pub struct SysDisks; @@ -26,7 +28,7 @@ impl Command for SysDisks { call: &Call, _input: PipelineData, ) -> Result { - Ok(super::disks(call.head).into_pipeline_data()) + Ok(disks(call.head).into_pipeline_data()) } fn examples(&self) -> Vec { @@ -37,3 +39,27 @@ impl Command for SysDisks { }] } } + +fn disks(span: Span) -> Value { + let disks = Disks::new_with_refreshed_list() + .iter() + .map(|disk| { + let device = trim_cstyle_null(disk.name().to_string_lossy()); + let typ = trim_cstyle_null(disk.file_system().to_string_lossy()); + + let record = record! { + "device" => Value::string(device, span), + "type" => Value::string(typ, span), + "mount" => Value::string(disk.mount_point().to_string_lossy(), span), + "total" => Value::filesize(disk.total_space() as i64, span), + "free" => Value::filesize(disk.available_space() as i64, span), + "removable" => Value::bool(disk.is_removable(), span), + "kind" => Value::string(disk.kind().to_string(), span), + }; + + Value::record(record, span) + }) + .collect(); + + Value::list(disks, span) +} diff --git a/crates/nu-command/src/system/sys/host.rs b/crates/nu-command/src/system/sys/host.rs index 969f59ef99..64dd43424d 100644 --- a/crates/nu-command/src/system/sys/host.rs +++ b/crates/nu-command/src/system/sys/host.rs @@ -1,4 +1,7 @@ +use super::trim_cstyle_null; +use chrono::{DateTime, FixedOffset, Local}; use nu_engine::command_prelude::*; +use sysinfo::System; #[derive(Clone)] pub struct SysHost; @@ -26,8 +29,7 @@ impl Command for SysHost { call: &Call, _input: PipelineData, ) -> Result { - let host = super::host(call.head); - Ok(Value::record(host, call.head).into_pipeline_data()) + Ok(host(call.head).into_pipeline_data()) } fn examples(&self) -> Vec { @@ -38,3 +40,53 @@ impl Command for SysHost { }] } } + +fn host(span: Span) -> Value { + let mut record = Record::new(); + + if let Some(name) = System::name() { + record.push("name", Value::string(trim_cstyle_null(name), span)); + } + if let Some(version) = System::os_version() { + record.push("os_version", Value::string(trim_cstyle_null(version), span)); + } + if let Some(long_version) = System::long_os_version() { + record.push( + "long_os_version", + Value::string(trim_cstyle_null(long_version), span), + ); + } + if let Some(version) = System::kernel_version() { + record.push( + "kernel_version", + Value::string(trim_cstyle_null(version), span), + ); + } + if let Some(hostname) = System::host_name() { + record.push("hostname", Value::string(trim_cstyle_null(hostname), span)); + } + + let uptime = System::uptime() + .saturating_mul(1_000_000_000) + .try_into() + .unwrap_or(i64::MAX); + + record.push("uptime", Value::duration(uptime, span)); + + let boot_time = boot_time() + .map(|time| Value::date(time, span)) + .unwrap_or(Value::nothing(span)); + + record.push("boot_time", boot_time); + + Value::record(record, span) +} + +fn boot_time() -> Option> { + // Broken systems can apparently return really high values. + // See: https://github.com/nushell/nushell/issues/10155 + // First, try to convert u64 to i64, and then try to create a `DateTime`. + let secs = System::boot_time().try_into().ok()?; + let time = DateTime::from_timestamp(secs, 0)?; + Some(time.with_timezone(&Local).fixed_offset()) +} diff --git a/crates/nu-command/src/system/sys/mem.rs b/crates/nu-command/src/system/sys/mem.rs index e5dc36e1b7..89527807d7 100644 --- a/crates/nu-command/src/system/sys/mem.rs +++ b/crates/nu-command/src/system/sys/mem.rs @@ -1,4 +1,5 @@ use nu_engine::command_prelude::*; +use sysinfo::System; #[derive(Clone)] pub struct SysMem; @@ -26,7 +27,7 @@ impl Command for SysMem { call: &Call, _input: PipelineData, ) -> Result { - Ok(super::mem(call.head).into_pipeline_data()) + Ok(mem(call.head).into_pipeline_data()) } fn examples(&self) -> Vec { @@ -37,3 +38,20 @@ impl Command for SysMem { }] } } + +fn mem(span: Span) -> Value { + let mut sys = System::new(); + sys.refresh_memory(); + + let record = record! { + "total" => Value::filesize(sys.total_memory() as i64, span), + "free" => Value::filesize(sys.free_memory() as i64, span), + "used" => Value::filesize(sys.used_memory() as i64, span), + "available" => Value::filesize(sys.available_memory() as i64, span), + "swap total" => Value::filesize(sys.total_swap() as i64, span), + "swap free" => Value::filesize(sys.free_swap() as i64, span), + "swap used" => Value::filesize(sys.used_swap() as i64, span), + }; + + Value::record(record, span) +} diff --git a/crates/nu-command/src/system/sys/mod.rs b/crates/nu-command/src/system/sys/mod.rs index fcb40fd37d..02d271537e 100644 --- a/crates/nu-command/src/system/sys/mod.rs +++ b/crates/nu-command/src/system/sys/mod.rs @@ -16,202 +16,6 @@ pub use sys_::Sys; pub use temp::SysTemp; pub use users::SysUsers; -use chrono::{DateTime, FixedOffset, Local}; -use nu_protocol::{record, Record, Span, Value}; -use sysinfo::{ - Components, CpuRefreshKind, Disks, Networks, System, Users, MINIMUM_CPU_UPDATE_INTERVAL, -}; - -pub fn trim_cstyle_null(s: impl AsRef) -> String { +fn trim_cstyle_null(s: impl AsRef) -> String { s.as_ref().trim_matches('\0').into() } - -pub fn disks(span: Span) -> Value { - let disks = Disks::new_with_refreshed_list() - .iter() - .map(|disk| { - let device = trim_cstyle_null(disk.name().to_string_lossy()); - let typ = trim_cstyle_null(disk.file_system().to_string_lossy()); - - let record = record! { - "device" => Value::string(device, span), - "type" => Value::string(typ, span), - "mount" => Value::string(disk.mount_point().to_string_lossy(), span), - "total" => Value::filesize(disk.total_space() as i64, span), - "free" => Value::filesize(disk.available_space() as i64, span), - "removable" => Value::bool(disk.is_removable(), span), - "kind" => Value::string(disk.kind().to_string(), span), - }; - - Value::record(record, span) - }) - .collect(); - - Value::list(disks, span) -} - -pub fn net(span: Span) -> Value { - let networks = Networks::new_with_refreshed_list() - .iter() - .map(|(iface, data)| { - let record = record! { - "name" => Value::string(trim_cstyle_null(iface), span), - "sent" => Value::filesize(data.total_transmitted() as i64, span), - "recv" => Value::filesize(data.total_received() as i64, span), - }; - - Value::record(record, span) - }) - .collect(); - - Value::list(networks, span) -} - -pub fn cpu(span: Span) -> Value { - let mut sys = System::new(); - sys.refresh_cpu_specifics(CpuRefreshKind::everything()); - // We must refresh the CPU twice a while apart to get valid usage data. - // In theory we could just sleep MINIMUM_CPU_UPDATE_INTERVAL, but I've noticed that - // that gives poor results (error of ~5%). Decided to wait 2x that long, somewhat arbitrarily - std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL * 2); - sys.refresh_cpu_specifics(CpuRefreshKind::new().with_cpu_usage()); - - let cpus = sys - .cpus() - .iter() - .map(|cpu| { - // sysinfo CPU usage numbers are not very precise unless you wait a long time between refreshes. - // Round to 1DP (chosen somewhat arbitrarily) so people aren't misled by high-precision floats. - let rounded_usage = (cpu.cpu_usage() * 10.0).round() / 10.0; - - let load_avg = System::load_average(); - let load_avg = format!( - "{:.2}, {:.2}, {:.2}", - load_avg.one, load_avg.five, load_avg.fifteen - ); - - let record = record! { - "name" => Value::string(trim_cstyle_null(cpu.name()), span), - "brand" => Value::string(trim_cstyle_null(cpu.brand()), span), - "freq" => Value::int(cpu.frequency() as i64, span), - "cpu_usage" => Value::float(rounded_usage.into(), span), - "load_average" => Value::string(load_avg, span), - "vendor_id" => Value::string(trim_cstyle_null(cpu.vendor_id()), span), - }; - - Value::record(record, span) - }) - .collect(); - - Value::list(cpus, span) -} - -pub fn mem(span: Span) -> Value { - let mut sys = System::new(); - sys.refresh_memory(); - - let record = record! { - "total" => Value::filesize(sys.total_memory() as i64, span), - "free" => Value::filesize(sys.free_memory() as i64, span), - "used" => Value::filesize(sys.used_memory() as i64, span), - "available" => Value::filesize(sys.available_memory() as i64, span), - "swap total" => Value::filesize(sys.total_swap() as i64, span), - "swap free" => Value::filesize(sys.free_swap() as i64, span), - "swap used" => Value::filesize(sys.used_swap() as i64, span), - }; - - Value::record(record, span) -} - -pub fn users(span: Span) -> Value { - let users = Users::new_with_refreshed_list() - .iter() - .map(|user| { - let groups = user - .groups() - .iter() - .map(|group| Value::string(trim_cstyle_null(group.name()), span)) - .collect(); - - let record = record! { - "name" => Value::string(trim_cstyle_null(user.name()), span), - "groups" => Value::list(groups, span), - }; - - Value::record(record, span) - }) - .collect(); - - Value::list(users, span) -} - -pub fn host(span: Span) -> Record { - let mut record = Record::new(); - - if let Some(name) = System::name() { - record.push("name", Value::string(trim_cstyle_null(name), span)); - } - if let Some(version) = System::os_version() { - record.push("os_version", Value::string(trim_cstyle_null(version), span)); - } - if let Some(long_version) = System::long_os_version() { - record.push( - "long_os_version", - Value::string(trim_cstyle_null(long_version), span), - ); - } - if let Some(version) = System::kernel_version() { - record.push( - "kernel_version", - Value::string(trim_cstyle_null(version), span), - ); - } - if let Some(hostname) = System::host_name() { - record.push("hostname", Value::string(trim_cstyle_null(hostname), span)); - } - - let uptime = System::uptime() - .saturating_mul(1_000_000_000) - .try_into() - .unwrap_or(i64::MAX); - - record.push("uptime", Value::duration(uptime, span)); - - let boot_time = boot_time() - .map(|time| Value::date(time, span)) - .unwrap_or(Value::nothing(span)); - - record.push("boot_time", boot_time); - - record -} - -fn boot_time() -> Option> { - // Broken systems can apparently return really high values. - // See: https://github.com/nushell/nushell/issues/10155 - // First, try to convert u64 to i64, and then try to create a `DateTime`. - let secs = System::boot_time().try_into().ok()?; - let time = DateTime::from_timestamp(secs, 0)?; - Some(time.with_timezone(&Local).fixed_offset()) -} - -pub fn temp(span: Span) -> Value { - let components = Components::new_with_refreshed_list() - .iter() - .map(|component| { - let mut record = record! { - "unit" => Value::string(component.label(), span), - "temp" => Value::float(component.temperature().into(), span), - "high" => Value::float(component.max().into(), span), - }; - - if let Some(critical) = component.critical() { - record.push("critical", Value::float(critical.into(), span)); - } - - Value::record(record, span) - }) - .collect(); - - Value::list(components, span) -} diff --git a/crates/nu-command/src/system/sys/net.rs b/crates/nu-command/src/system/sys/net.rs index 98dca1bc2f..ef1c595800 100644 --- a/crates/nu-command/src/system/sys/net.rs +++ b/crates/nu-command/src/system/sys/net.rs @@ -1,4 +1,6 @@ +use super::trim_cstyle_null; use nu_engine::command_prelude::*; +use sysinfo::Networks; #[derive(Clone)] pub struct SysNet; @@ -26,7 +28,7 @@ impl Command for SysNet { call: &Call, _input: PipelineData, ) -> Result { - Ok(super::net(call.head).into_pipeline_data()) + Ok(net(call.head).into_pipeline_data()) } fn examples(&self) -> Vec { @@ -37,3 +39,20 @@ impl Command for SysNet { }] } } + +fn net(span: Span) -> Value { + let networks = Networks::new_with_refreshed_list() + .iter() + .map(|(iface, data)| { + let record = record! { + "name" => Value::string(trim_cstyle_null(iface), span), + "sent" => Value::filesize(data.total_transmitted() as i64, span), + "recv" => Value::filesize(data.total_received() as i64, span), + }; + + Value::record(record, span) + }) + .collect(); + + Value::list(networks, span) +} diff --git a/crates/nu-command/src/system/sys/sys_.rs b/crates/nu-command/src/system/sys/sys_.rs index 2886836be9..5369064f50 100644 --- a/crates/nu-command/src/system/sys/sys_.rs +++ b/crates/nu-command/src/system/sys/sys_.rs @@ -1,4 +1,4 @@ -use nu_engine::command_prelude::*; +use nu_engine::{command_prelude::*, get_full_help}; #[derive(Clone)] pub struct Sys; @@ -20,41 +20,17 @@ impl Command for Sys { } fn extra_usage(&self) -> &str { - "Note that this command may take a noticeable amount of time to run. To reduce the time taken, you can use the various `sys` sub commands to get the subset of information you are interested in." + "You must use one of the following subcommands. Using this command as-is will only produce this help message." } fn run( &self, engine_state: &EngineState, - _stack: &mut Stack, + stack: &mut Stack, call: &Call, _input: PipelineData, ) -> Result { - nu_protocol::report_error_new( - engine_state, - &ShellError::GenericError { - error: "Deprecated command".into(), - msg: "the `sys` command is deprecated, please use the new subcommands (`sys host`, `sys mem`, etc.)." - .into(), - span: Some(call.head), - help: None, - inner: vec![], - }, - ); - - let head = call.head; - - let mut host = super::host(head); - host.push("sessions", super::users(head)); - let record = record! { - "host" => Value::record(host, head), - "cpu" => super::cpu(head), - "disks" => super::disks(head), - "mem" => super::mem(head), - "temp" => super::temp(head), - "net" => super::net(head), - }; - Ok(Value::record(record, head).into_pipeline_data()) + Ok(Value::string(get_full_help(self, engine_state, stack), call.head).into_pipeline_data()) } fn examples(&self) -> Vec { diff --git a/crates/nu-command/src/system/sys/temp.rs b/crates/nu-command/src/system/sys/temp.rs index eaf1ed05db..088471f0fd 100644 --- a/crates/nu-command/src/system/sys/temp.rs +++ b/crates/nu-command/src/system/sys/temp.rs @@ -1,4 +1,5 @@ use nu_engine::command_prelude::*; +use sysinfo::Components; #[derive(Clone)] pub struct SysTemp; @@ -30,7 +31,7 @@ impl Command for SysTemp { call: &Call, _input: PipelineData, ) -> Result { - Ok(super::temp(call.head).into_pipeline_data()) + Ok(temp(call.head).into_pipeline_data()) } fn examples(&self) -> Vec { @@ -41,3 +42,24 @@ impl Command for SysTemp { }] } } + +fn temp(span: Span) -> Value { + let components = Components::new_with_refreshed_list() + .iter() + .map(|component| { + let mut record = record! { + "unit" => Value::string(component.label(), span), + "temp" => Value::float(component.temperature().into(), span), + "high" => Value::float(component.max().into(), span), + }; + + if let Some(critical) = component.critical() { + record.push("critical", Value::float(critical.into(), span)); + } + + Value::record(record, span) + }) + .collect(); + + Value::list(components, span) +} diff --git a/crates/nu-command/src/system/sys/users.rs b/crates/nu-command/src/system/sys/users.rs index 9aab2b9b7b..7d4a43cae5 100644 --- a/crates/nu-command/src/system/sys/users.rs +++ b/crates/nu-command/src/system/sys/users.rs @@ -1,4 +1,6 @@ +use super::trim_cstyle_null; use nu_engine::command_prelude::*; +use sysinfo::Users; #[derive(Clone)] pub struct SysUsers; @@ -25,7 +27,7 @@ impl Command for SysUsers { call: &Call, _input: PipelineData, ) -> Result { - Ok(super::users(call.head).into_pipeline_data()) + Ok(users(call.head).into_pipeline_data()) } fn examples(&self) -> Vec { @@ -36,3 +38,25 @@ impl Command for SysUsers { }] } } + +fn users(span: Span) -> Value { + let users = Users::new_with_refreshed_list() + .iter() + .map(|user| { + let groups = user + .groups() + .iter() + .map(|group| Value::string(trim_cstyle_null(group.name()), span)) + .collect(); + + let record = record! { + "name" => Value::string(trim_cstyle_null(user.name()), span), + "groups" => Value::list(groups, span), + }; + + Value::record(record, span) + }) + .collect(); + + Value::list(users, span) +} From a55a48529d57868b4ccc3ca7e19299289bca9b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=BD=C3=A1dn=C3=ADk?= Date: Mon, 10 Jun 2024 22:33:22 +0300 Subject: [PATCH 06/14] Fix delta not being merged when evaluating menus (#13120) # Description After parsing menu code, the changes weren't merged into the engine state, which didn't produce any errors (somehow?) until the recent span ID refactors. With this PR, menus get a new cloned engine state with the parsed changes correctly merged in. Hopefully fixes https://github.com/nushell/nushell/issues/13118 # User-Facing Changes # Tests + Formatting # After Submitting --- crates/nu-cli/src/reedline_config.rs | 37 +++++++++++++++++++++------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/crates/nu-cli/src/reedline_config.rs b/crates/nu-cli/src/reedline_config.rs index 9c08265dfa..dd5a3199dc 100644 --- a/crates/nu-cli/src/reedline_config.rs +++ b/crates/nu-cli/src/reedline_config.rs @@ -75,7 +75,7 @@ const DEFAULT_HELP_MENU: &str = r#" // Adds all menus to line editor pub(crate) fn add_menus( mut line_editor: Reedline, - engine_state: Arc, + engine_state_ref: Arc, stack: &Stack, config: &Config, ) -> Result { @@ -83,7 +83,7 @@ pub(crate) fn add_menus( line_editor = line_editor.clear_menus(); for menu in &config.menus { - line_editor = add_menu(line_editor, menu, engine_state.clone(), stack, config)? + line_editor = add_menu(line_editor, menu, engine_state_ref.clone(), stack, config)? } // Checking if the default menus have been added from the config file @@ -93,13 +93,16 @@ pub(crate) fn add_menus( ("help_menu", DEFAULT_HELP_MENU), ]; + let mut engine_state = (*engine_state_ref).clone(); + let mut menu_eval_results = vec![]; + for (name, definition) in default_menus { if !config .menus .iter() .any(|menu| menu.name.to_expanded_string("", config) == name) { - let (block, _) = { + let (block, delta) = { let mut working_set = StateWorkingSet::new(&engine_state); let output = parse( &mut working_set, @@ -111,15 +114,31 @@ pub(crate) fn add_menus( (output, working_set.render()) }; + engine_state.merge_delta(delta)?; + let mut temp_stack = Stack::new().capture(); let input = PipelineData::Empty; - let res = eval_block::(&engine_state, &mut temp_stack, &block, input)?; + menu_eval_results.push(eval_block::( + &engine_state, + &mut temp_stack, + &block, + input, + )?); + } + } - if let PipelineData::Value(value, None) = res { - for menu in create_menus(&value)? { - line_editor = - add_menu(line_editor, &menu, engine_state.clone(), stack, config)?; - } + let new_engine_state_ref = Arc::new(engine_state); + + for res in menu_eval_results.into_iter() { + if let PipelineData::Value(value, None) = res { + for menu in create_menus(&value)? { + line_editor = add_menu( + line_editor, + &menu, + new_engine_state_ref.clone(), + stack, + config, + )?; } } } From 944d941dec0459a910a6cbf0f6f60688e94554e6 Mon Sep 17 00:00:00 2001 From: Ian Manske Date: Mon, 10 Jun 2024 21:40:09 +0000 Subject: [PATCH 07/14] `path type` error and not found changes (#13007) # Description Instead of an empty string, this PR changes `path type` to return null if the path does not exist. If some other IO error is encountered, then that error is bubbled up instead of treating it as a "not found" case. # User-Facing Changes - `path type` will now return null instead of an empty string, which is technically a breaking change. In most cases though, I think this shouldn't affect the behavior of scripts too much. - `path type` can now error instead of returning an empty string if some other IO error besides a "not found" error occurs. Since this PR introduces breaking changes, it should be merged after the 0.94.1 patch. --- crates/nu-command/src/path/type.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/nu-command/src/path/type.rs b/crates/nu-command/src/path/type.rs index 0897593109..e58e697604 100644 --- a/crates/nu-command/src/path/type.rs +++ b/crates/nu-command/src/path/type.rs @@ -1,7 +1,10 @@ use super::PathSubcommandArguments; use nu_engine::command_prelude::*; use nu_protocol::engine::StateWorkingSet; -use std::path::{Path, PathBuf}; +use std::{ + io, + path::{Path, PathBuf}, +}; struct Arguments { pwd: PathBuf, @@ -36,7 +39,7 @@ impl Command for SubCommand { fn extra_usage(&self) -> &str { r#"This checks the file system to confirm the path's object type. -If nothing is found, an empty string will be returned."# +If the path does not exist, null will be returned."# } fn is_const(&self) -> bool { @@ -104,9 +107,11 @@ If nothing is found, an empty string will be returned."# fn path_type(path: &Path, span: Span, args: &Arguments) -> Value { let path = nu_path::expand_path_with(path, &args.pwd, true); - let meta = path.symlink_metadata(); - let ty = meta.as_ref().map(get_file_type).unwrap_or(""); - Value::string(ty, span) + match path.symlink_metadata() { + Ok(metadata) => Value::string(get_file_type(&metadata), span), + Err(err) if err.kind() == io::ErrorKind::NotFound => Value::nothing(span), + Err(err) => Value::error(err.into_spanned(span).into(), span), + } } fn get_file_type(md: &std::fs::Metadata) -> &str { From c09488f51580ac4208e300b27365ff3c4095ba4a Mon Sep 17 00:00:00 2001 From: NotTheDr01ds <32344964+NotTheDr01ds@users.noreply.github.com> Date: Mon, 10 Jun 2024 20:12:54 -0400 Subject: [PATCH 08/14] Fix multiple issues with `def --wrapped` help example (#13123) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description I've noticed this several times but kept forgetting to fix it: The example given for `help def` for the `--wrapped` flag is: ```nu Define a custom wrapper for an external command > def --wrapped my-echo [...rest] { echo $rest }; my-echo spam ╭───┬──────╮ │ 0 │ spam │ ╰───┴──────╯ ``` That's ... odd, since (a) it specifically says *"for an external"* command, and yet uses (and shows the output from) the builtin `echo`. Also, (b) I believe `--wrapped` is *only* applicable to external commands. Finally, (c) the `my-echo spam` doesn't even demonstrate a wrapped argument. Unless I'm truly missing something, the example just makes no sense. This updates the example to really demonstrate `def --wrapped` with the *external* version of `^echo`. It uses the `-e` command to interpret the escape-tab character in the string. ```nu > def --wrapped my-echo [...rest] { ^echo ...$rest }; my-echo -e 'spam\tspam' spam spam ``` # User-Facing Changes Help example only. # Tests + Formatting - :green_circle: `toolkit fmt` - :green_circle: `toolkit clippy` - :green_circle: `toolkit test` - :green_circle: `toolkit test stdlib` # After Submitting --- crates/nu-cmd-lang/src/core_commands/def.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/nu-cmd-lang/src/core_commands/def.rs b/crates/nu-cmd-lang/src/core_commands/def.rs index e4a169ffcc..913f74803c 100644 --- a/crates/nu-cmd-lang/src/core_commands/def.rs +++ b/crates/nu-cmd-lang/src/core_commands/def.rs @@ -67,8 +67,8 @@ impl Command for Def { }, Example { description: "Define a custom wrapper for an external command", - example: r#"def --wrapped my-echo [...rest] { echo $rest }; my-echo spam"#, - result: Some(Value::test_list(vec![Value::test_string("spam")])), + example: r#"def --wrapped my-echo [...rest] { ^echo ...$rest }; my-echo -e 'spam\tspam'"#, + result: Some(Value::test_string("spam\tspam")), }, ] } From a8376fad4093ce957ee6cef32d5793d1599811b8 Mon Sep 17 00:00:00 2001 From: Darren Schroeder <343840+fdncred@users.noreply.github.com> Date: Tue, 11 Jun 2024 13:44:13 -0500 Subject: [PATCH 09/14] update uutils crates (#13130) # Description This PR updates the uutils/coreutils crates to the latest released version. # User-Facing Changes # Tests + Formatting # After Submitting --- Cargo.lock | 54 +++++++++---------------- Cargo.toml | 14 +++---- crates/nu-command/tests/commands/ucp.rs | 2 +- 3 files changed, 27 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c95f0d1435..e0c8b048ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3011,7 +3011,7 @@ dependencies = [ "uu_mv", "uu_uname", "uu_whoami", - "uucore 0.0.25", + "uucore", "uuid", "v_htmlescape", "wax", @@ -6352,93 +6352,77 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uu_cp" -version = "0.0.25" +version = "0.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcbe045dc92209114afdfd366bd18f7b95dbf999f3eaa85ad6dca910b0be3d56" +checksum = "c31fc5c95f7668999e129464a29e9080f69ba01ccf7a0ae43ff2cfdb15baa340" dependencies = [ "clap", "filetime", "indicatif", "libc", "quick-error 2.0.1", - "uucore 0.0.26", + "uucore", "walkdir", "xattr", ] [[package]] name = "uu_mkdir" -version = "0.0.25" +version = "0.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "040aa4584036b2f65e05387b0ea9ac468afce1db325743ce5f350689fd9ce4ae" +checksum = "496d95e0e3121e4d424ba62019eb84a6f1102213ca8ca16c0a2f8c652c7236c3" dependencies = [ "clap", - "uucore 0.0.26", + "uucore", ] [[package]] name = "uu_mktemp" -version = "0.0.25" +version = "0.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f240a99c36d768153874d198c43605a45c86996b576262689a0f18248cc3bc57" +checksum = "a28a0d9744bdc28ceaf13f70b959bacded91aedfd008402d72fa1e3224158653" dependencies = [ "clap", "rand", "tempfile", - "uucore 0.0.26", + "uucore", ] [[package]] name = "uu_mv" -version = "0.0.25" +version = "0.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c99fd7c75e6e85553c92537314be3d9a64b4927051aa1608513feea2f933022" +checksum = "53680908b01c5ac3cc0ee8a376de3e51a36dde2c5a5227a115a3d0977cc4539b" dependencies = [ "clap", "fs_extra", "indicatif", - "uucore 0.0.26", + "uucore", ] [[package]] name = "uu_uname" -version = "0.0.25" +version = "0.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5951832d73199636bde6c0d61cf960932b3c4450142c290375bc10c7abed6db5" +checksum = "a7f4125fb4f286313bca8f222abaefe39db54d65179ea788c91ebd3162345f4e" dependencies = [ "clap", "platform-info", - "uucore 0.0.26", + "uucore", ] [[package]] name = "uu_whoami" -version = "0.0.25" +version = "0.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b44166eb6335aeac42744ea368cc4c32d3f2287a4ff765a5ce44d927ab8bb4" +checksum = "7f7b313901a15cfde2d88f434fcd077903d690f73cc36d1cec20f47906960aec" dependencies = [ "clap", "libc", - "uucore 0.0.26", + "uucore", "windows-sys 0.48.0", ] -[[package]] -name = "uucore" -version = "0.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23994a722acb43dbc56877e271c9723f167ae42c4c089f909b2d7dd106c3a9b4" -dependencies = [ - "clap", - "glob", - "libc", - "nix", - "once_cell", - "os_display", - "uucore_procs", - "wild", -] - [[package]] name = "uucore" version = "0.0.26" diff --git a/Cargo.toml b/Cargo.toml index 7e5f436bbf..f7f911a0ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -159,13 +159,13 @@ unicode-segmentation = "1.11" unicode-width = "0.1" ureq = { version = "2.9", default-features = false } url = "2.2" -uu_cp = "0.0.25" -uu_mkdir = "0.0.25" -uu_mktemp = "0.0.25" -uu_mv = "0.0.25" -uu_whoami = "0.0.25" -uu_uname = "0.0.25" -uucore = "0.0.25" +uu_cp = "0.0.26" +uu_mkdir = "0.0.26" +uu_mktemp = "0.0.26" +uu_mv = "0.0.26" +uu_whoami = "0.0.26" +uu_uname = "0.0.26" +uucore = "0.0.26" uuid = "1.8.0" v_htmlescape = "0.15.0" wax = "0.6" diff --git a/crates/nu-command/tests/commands/ucp.rs b/crates/nu-command/tests/commands/ucp.rs index 453786ad4e..728cf1dcb2 100644 --- a/crates/nu-command/tests/commands/ucp.rs +++ b/crates/nu-command/tests/commands/ucp.rs @@ -906,7 +906,7 @@ fn test_cp_debug_default() { #[cfg(any(target_os = "linux", target_os = "freebsd"))] if !actual .out - .contains("copy offload: unknown, reflink: unsupported, sparse detection: no") + .contains("copy offload: yes, reflink: unsupported, sparse detection: no") { panic!("{}", format!("Failure: stdout was \n{}", actual.out)); } From b0d1b4b1827d3d90867ca22d6095a009a7c7ae52 Mon Sep 17 00:00:00 2001 From: Ian Manske Date: Tue, 11 Jun 2024 19:00:00 +0000 Subject: [PATCH 10/14] Remove deprecated `--not` flag on `str contains` (#13124) # Description Removes the `str contains --not` flag that was deprecated in the last minor release. # User-Facing Changes Breaking change since a flag was removed. --- .../nu-command/src/strings/str_/contains.rs | 41 +++---------------- 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/crates/nu-command/src/strings/str_/contains.rs b/crates/nu-command/src/strings/str_/contains.rs index 63b9366b09..ff9cb85fcb 100644 --- a/crates/nu-command/src/strings/str_/contains.rs +++ b/crates/nu-command/src/strings/str_/contains.rs @@ -10,7 +10,6 @@ struct Arguments { substring: String, cell_paths: Option>, case_insensitive: bool, - not_contain: bool, } impl CmdArgument for Arguments { @@ -40,7 +39,6 @@ impl Command for SubCommand { "For a data structure input, check strings at the given cell paths, and replace with result.", ) .switch("ignore-case", "search is case insensitive", Some('i')) - .switch("not", "DEPRECATED OPTION: does not contain", Some('n')) .category(Category::Strings) } @@ -63,27 +61,12 @@ impl Command for SubCommand { call: &Call, input: PipelineData, ) -> Result { - if call.has_flag(engine_state, stack, "not")? { - nu_protocol::report_error_new( - engine_state, - &ShellError::GenericError { - error: "Deprecated option".into(), - msg: "`str contains --not {string}` is deprecated and will be removed in 0.95." - .into(), - span: Some(call.head), - help: Some("Please use the `not` operator instead.".into()), - inner: vec![], - }, - ); - } - let cell_paths: Vec = call.rest(engine_state, stack, 1)?; let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths); let args = Arguments { substring: call.req::(engine_state, stack, 0)?, cell_paths, case_insensitive: call.has_flag(engine_state, stack, "ignore-case")?, - not_contain: call.has_flag(engine_state, stack, "not")?, }; operate(action, args, input, call.head, engine_state.ctrlc.clone()) } @@ -114,7 +97,6 @@ impl Command for SubCommand { substring: call.req_const::(working_set, 0)?, cell_paths, case_insensitive: call.has_flag_const(working_set, "ignore-case")?, - not_contain: call.has_flag_const(working_set, "not")?, }; operate( action, @@ -183,7 +165,6 @@ fn action( input: &Value, Arguments { case_insensitive, - not_contain, substring, .. }: &Arguments, @@ -191,23 +172,11 @@ fn action( ) -> Value { match input { Value::String { val, .. } => Value::bool( - match case_insensitive { - true => { - if *not_contain { - !val.to_folded_case() - .contains(substring.to_folded_case().as_str()) - } else { - val.to_folded_case() - .contains(substring.to_folded_case().as_str()) - } - } - false => { - if *not_contain { - !val.contains(substring) - } else { - val.contains(substring) - } - } + if *case_insensitive { + val.to_folded_case() + .contains(substring.to_folded_case().as_str()) + } else { + val.contains(substring) }, head, ), From 0372e8c53c085d4e7d9109fda104cfa68d846e71 Mon Sep 17 00:00:00 2001 From: Darren Schroeder <343840+fdncred@users.noreply.github.com> Date: Tue, 11 Jun 2024 14:10:31 -0500 Subject: [PATCH 11/14] add `$nu.data-dir` for completions and `$nu.cache-dir` for other uses (#13122) # Description This PR is an attempt to add a standard location for people to put completions in. I saw this topic come up again recently and IIRC we decided to create a standard location. I used the dirs-next crate to dictate where these locations are. I know some people won't like that but at least this gets the ball rolling in a direction that has a standard directory. This is what the default NU_LIB_DIRS looks like now in the default_env.nu. It should also be like this when starting nushell with `nu -n` ```nushell $env.NU_LIB_DIRS = [ ($nu.default-config-dir | path join 'scripts') # add /scripts ($nu.data-dir | path join 'completions') # default home for nushell completions ] ``` I also added these default folders to the `$nu` variable so now there is `$nu.data-path` and `$nu.cache-path`. ## Data Dir Default ![image](https://github.com/nushell/nushell/assets/343840/aeeb7cd6-17b4-43e8-bb6f-986a0c7fce23) While I was in there, I also decided to add a cache dir ## Cache Dir Default ![image](https://github.com/nushell/nushell/assets/343840/87dead66-4911-4f67-bfb2-acb16f386674) ### This is what the default looks like in Ubuntu. ![image](https://github.com/nushell/nushell/assets/343840/bca8eae8-8c18-47e8-b64f-3efe34f0004f) ### This is what it looks like with XDG_CACHE_HOME and XDG_DATA_HOME overridden ```nushell XDG_DATA_HOME=/tmp/data_home XDG_CACHE_HOME=/tmp/cache_home cargo r ``` ![image](https://github.com/nushell/nushell/assets/343840/fae86d50-9821-41f1-868e-3814eca3730b) ### This is what the defaults look like in Windows (username scrubbed to protect the innocent) ![image](https://github.com/nushell/nushell/assets/343840/3ebdb5cd-0150-448c-aff5-c57053e4788a) How my NU_LIB_DIRS is set in the images above ```nushell $env.NU_LIB_DIRS = [ ($nu.default-config-dir | path join 'scripts') # add /scripts '/Users/fdncred/src/nu_scripts' ($nu.config-path | path dirname) ($nu.data-dir | path join 'completions') # default home for nushell completions ] ``` Let the debate begin. # User-Facing Changes # Tests + Formatting # After Submitting --- Cargo.toml | 1 + crates/nu-cli/tests/completions/mod.rs | 4 ++- crates/nu-path/src/helpers.rs | 26 ++++++++++++--- crates/nu-path/src/lib.rs | 2 +- crates/nu-protocol/src/eval_const.rs | 32 +++++++++++++++++++ .../nu-utils/src/sample_config/default_env.nu | 1 + src/main.rs | 19 ++++++++--- 7 files changed, 75 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f7f911a0ed..3442e96ff5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -195,6 +195,7 @@ reedline = { workspace = true, features = ["bashisms", "sqlite"] } crossterm = { workspace = true } ctrlc = { workspace = true } +dirs-next = { workspace = true } log = { workspace = true } miette = { workspace = true, features = ["fancy-no-backtrace", "fancy"] } mimalloc = { version = "0.1.42", default-features = false, optional = true } diff --git a/crates/nu-cli/tests/completions/mod.rs b/crates/nu-cli/tests/completions/mod.rs index a5b0b13aa8..107de98c80 100644 --- a/crates/nu-cli/tests/completions/mod.rs +++ b/crates/nu-cli/tests/completions/mod.rs @@ -763,11 +763,13 @@ fn variables_completions() { // Test completions for $nu let suggestions = completer.complete("$nu.", 4); - assert_eq!(15, suggestions.len()); + assert_eq!(17, suggestions.len()); let expected: Vec = vec![ + "cache-dir".into(), "config-path".into(), "current-exe".into(), + "data-dir".into(), "default-config-dir".into(), "env-path".into(), "history-enabled".into(), diff --git a/crates/nu-path/src/helpers.rs b/crates/nu-path/src/helpers.rs index aaa53eab71..5b389410e4 100644 --- a/crates/nu-path/src/helpers.rs +++ b/crates/nu-path/src/helpers.rs @@ -6,18 +6,36 @@ pub fn home_dir() -> Option { dirs_next::home_dir() } +/// Return the data directory for the current platform or XDG_DATA_HOME if specified. +pub fn data_dir() -> Option { + match std::env::var("XDG_DATA_HOME").map(PathBuf::from) { + Ok(xdg_data) if xdg_data.is_absolute() => Some(canonicalize(&xdg_data).unwrap_or(xdg_data)), + _ => get_canonicalized_path(dirs_next::data_dir()), + } +} + +/// Return the cache directory for the current platform or XDG_CACHE_HOME if specified. +pub fn cache_dir() -> Option { + match std::env::var("XDG_CACHE_HOME").map(PathBuf::from) { + Ok(xdg_cache) if xdg_cache.is_absolute() => { + Some(canonicalize(&xdg_cache).unwrap_or(xdg_cache)) + } + _ => get_canonicalized_path(dirs_next::cache_dir()), + } +} + +/// Return the config directory for the current platform or XDG_CONFIG_HOME if specified. pub fn config_dir() -> Option { match std::env::var("XDG_CONFIG_HOME").map(PathBuf::from) { Ok(xdg_config) if xdg_config.is_absolute() => { Some(canonicalize(&xdg_config).unwrap_or(xdg_config)) } - _ => config_dir_old(), + _ => get_canonicalized_path(dirs_next::config_dir()), } } -/// Get the old default config directory. Outside of Linux, this will ignore `XDG_CONFIG_HOME` -pub fn config_dir_old() -> Option { - let path = dirs_next::config_dir()?; +pub fn get_canonicalized_path(path: Option) -> Option { + let path = path?; Some(canonicalize(&path).unwrap_or(path)) } diff --git a/crates/nu-path/src/lib.rs b/crates/nu-path/src/lib.rs index 6c064d4b57..13640acd2f 100644 --- a/crates/nu-path/src/lib.rs +++ b/crates/nu-path/src/lib.rs @@ -8,6 +8,6 @@ mod trailing_slash; pub use components::components; pub use expansions::{canonicalize_with, expand_path_with, expand_to_real_path, locate_in_dirs}; -pub use helpers::{config_dir, config_dir_old, home_dir}; +pub use helpers::{cache_dir, config_dir, data_dir, get_canonicalized_path, home_dir}; pub use tilde::expand_tilde; pub use trailing_slash::{has_trailing_slash, strip_trailing_slash}; diff --git a/crates/nu-protocol/src/eval_const.rs b/crates/nu-protocol/src/eval_const.rs index 08ff6fa391..9f81a6f38b 100644 --- a/crates/nu-protocol/src/eval_const.rs +++ b/crates/nu-protocol/src/eval_const.rs @@ -149,6 +149,38 @@ pub(crate) fn create_nu_constant(engine_state: &EngineState, span: Span) -> Valu }, ); + record.push( + "data-dir", + if let Some(path) = nu_path::data_dir() { + let mut canon_data_path = canonicalize_path(engine_state, &path); + canon_data_path.push("nushell"); + Value::string(canon_data_path.to_string_lossy(), span) + } else { + Value::error( + ShellError::IOError { + msg: "Could not get data path".into(), + }, + span, + ) + }, + ); + + record.push( + "cache-dir", + if let Some(path) = nu_path::cache_dir() { + let mut canon_cache_path = canonicalize_path(engine_state, &path); + canon_cache_path.push("nushell"); + Value::string(canon_cache_path.to_string_lossy(), span) + } else { + Value::error( + ShellError::IOError { + msg: "Could not get cache path".into(), + }, + span, + ) + }, + ); + record.push("temp-path", { let canon_temp_path = canonicalize_path(engine_state, &std::env::temp_dir()); Value::string(canon_temp_path.to_string_lossy(), span) diff --git a/crates/nu-utils/src/sample_config/default_env.nu b/crates/nu-utils/src/sample_config/default_env.nu index 57e255ed20..effe76c98a 100644 --- a/crates/nu-utils/src/sample_config/default_env.nu +++ b/crates/nu-utils/src/sample_config/default_env.nu @@ -77,6 +77,7 @@ $env.ENV_CONVERSIONS = { # The default for this is $nu.default-config-dir/scripts $env.NU_LIB_DIRS = [ ($nu.default-config-dir | path join 'scripts') # add /scripts + ($nu.data-dir | path join 'completions') # default home for nushell completions ] # Directories to search for plugin binaries when calling register diff --git a/src/main.rs b/src/main.rs index f9fdff3ccf..41d5534bb0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -104,7 +104,9 @@ fn main() -> Result<()> { default: nushell_config_path.display().to_string(), }, ); - } else if let Some(old_config) = nu_path::config_dir_old().map(|p| p.join("nushell")) { + } else if let Some(old_config) = + nu_path::get_canonicalized_path(dirs_next::config_dir()).map(|p| p.join("nushell")) + { let xdg_config_empty = nushell_config_path .read_dir() .map_or(true, |mut dir| dir.next().is_none()); @@ -125,13 +127,22 @@ fn main() -> Result<()> { } } + let default_nushell_completions_path = if let Some(mut path) = nu_path::data_dir() { + path.push("nushell"); + path.push("completions"); + path + } else { + std::path::PathBuf::new() + }; + let mut default_nu_lib_dirs_path = nushell_config_path.clone(); default_nu_lib_dirs_path.push("scripts"); engine_state.add_env_var( "NU_LIB_DIRS".to_string(), - Value::test_list(vec![Value::test_string( - default_nu_lib_dirs_path.to_string_lossy(), - )]), + Value::test_list(vec![ + Value::test_string(default_nu_lib_dirs_path.to_string_lossy()), + Value::test_string(default_nushell_completions_path.to_string_lossy()), + ]), ); let mut default_nu_plugin_dirs_path = nushell_config_path; From 1e430d155ee67f9ffb0944e00b78b3be572e2f6d Mon Sep 17 00:00:00 2001 From: Darren Schroeder <343840+fdncred@users.noreply.github.com> Date: Tue, 11 Jun 2024 14:36:13 -0500 Subject: [PATCH 12/14] make packaging status 3 columns --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0bfb7fc0c3..0f1114c992 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ To use `Nu` in GitHub Action, check [setup-nu](https://github.com/marketplace/ac Detailed installation instructions can be found in the [installation chapter of the book](https://www.nushell.sh/book/installation.html). Nu is available via many package managers: -[![Packaging status](https://repology.org/badge/vertical-allrepos/nushell.svg)](https://repology.org/project/nushell/versions) +[![Packaging status](https://repology.org/badge/vertical-allrepos/nushell.svg?columns=3)](https://repology.org/project/nushell/versions) For details about which platforms the Nushell team actively supports, see [our platform support policy](devdocs/PLATFORM_SUPPORT.md). From 17daf783b266ab121dc9c2bb4ee8c4cab95e49c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 00:04:35 +0000 Subject: [PATCH 13/14] Bump crate-ci/typos from 1.22.1 to 1.22.4 Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.22.1 to 1.22.4. - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/v1.22.1...v1.22.4) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/typos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml index 1142b2dbaf..f81f5c89a5 100644 --- a/.github/workflows/typos.yml +++ b/.github/workflows/typos.yml @@ -10,4 +10,4 @@ jobs: uses: actions/checkout@v4.1.6 - name: Check spelling - uses: crate-ci/typos@v1.22.1 + uses: crate-ci/typos@v1.22.4 From 63c863c81b5eb1f5318c6784bbd5528158cf7675 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 09:37:22 +0800 Subject: [PATCH 14/14] Bump actions-rust-lang/setup-rust-toolchain from 1.8.0 to 1.9.0 (#13132) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions-rust-lang/setup-rust-toolchain](https://github.com/actions-rust-lang/setup-rust-toolchain) from 1.8.0 to 1.9.0.
Release notes

Sourced from actions-rust-lang/setup-rust-toolchain's releases.

v1.9.0

  • Add extra argument cache-on-failure and forward it to Swatinem/rust-cache. (#39 by @​samuelhnrq)
    Set the default the value to true. This will result in more caching than previously. This helps when large dependencies are compiled only for testing to fail.
Changelog

Sourced from actions-rust-lang/setup-rust-toolchain's changelog.

[1.9.0] - 2024-06-08

  • Add extra argument cache-on-failure and forward it to Swatinem/rust-cache. (#39 by @​samuelhnrq)
    Set the default the value to true. This will result in more caching than previously. This helps when large dependencies are compiled only for testing to fail.
Commits
  • 1fbea72 Merge pull request #40 from actions-rust-lang/prepare-release
  • 46dca5d Add changelog entry
  • 1734e14 Switch default of cache-on-failure to true
  • 74e1b40 Merge pull request #39 from samuelhnrq/main
  • d60b90d feat: adds cache-on-failure propagation
  • See full diff in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions-rust-lang/setup-rust-toolchain&package-manager=github_actions&previous-version=1.8.0&new-version=1.9.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/nightly-build.yml | 2 +- .github/workflows/release.yml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9cb92b0902..cb94e5fe8b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: - uses: actions/checkout@v4.1.6 - name: Setup Rust toolchain and cache - uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 + uses: actions-rust-lang/setup-rust-toolchain@v1.9.0 - name: cargo fmt run: cargo fmt --all -- --check @@ -69,7 +69,7 @@ jobs: - uses: actions/checkout@v4.1.6 - name: Setup Rust toolchain and cache - uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 + uses: actions-rust-lang/setup-rust-toolchain@v1.9.0 - name: Tests run: cargo test --workspace --profile ci --exclude nu_plugin_* ${{ matrix.default-flags }} @@ -98,7 +98,7 @@ jobs: - uses: actions/checkout@v4.1.6 - name: Setup Rust toolchain and cache - uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 + uses: actions-rust-lang/setup-rust-toolchain@v1.9.0 - name: Install Nushell run: cargo install --path . --locked --no-default-features @@ -149,7 +149,7 @@ jobs: - uses: actions/checkout@v4.1.6 - name: Setup Rust toolchain and cache - uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 + uses: actions-rust-lang/setup-rust-toolchain@v1.9.0 - name: Clippy run: cargo clippy --package nu_plugin_* -- $CLIPPY_OPTIONS diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml index 251cffd3a1..4f6dccbcf9 100644 --- a/.github/workflows/nightly-build.yml +++ b/.github/workflows/nightly-build.yml @@ -122,7 +122,7 @@ jobs: echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml - name: Setup Rust toolchain and cache - uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 + uses: actions-rust-lang/setup-rust-toolchain@v1.9.0 # WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135` with: rustflags: '' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6aca9578d4..a71792e8c8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -69,7 +69,7 @@ jobs: echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml - name: Setup Rust toolchain - uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 + uses: actions-rust-lang/setup-rust-toolchain@v1.9.0 # WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135` with: cache: false