From 6ebc0fc3ffd397c5ca6c53eb69ae06ef1e523c28 Mon Sep 17 00:00:00 2001 From: Rikuki IX <52599939+rikukiix@users.noreply.github.com> Date: Wed, 25 Dec 2024 21:35:49 +0800 Subject: [PATCH] Switch from serde_yaml to serde_yml (#14630) # Description This PR fixes #14339. Since [serde_yaml](https://docs.rs/serde_yaml/latest/serde_yaml/) is already deprecated, replaced it with [serde_yml](https://doc.serdeyml.com/serde_yml/). After this change, the `to yaml` boolean parsing issue in #14339 is also fixed. Now the command ``` ['y' 'Y' 'yes' 'Yes' 'YES' 'n' 'N' 'no' 'No' 'No' 'on' 'On' 'ON' 'off' 'Off' 'OFF'] | to yaml ``` will return ``` - 'y' - 'Y' - 'yes' - 'Yes' - 'YES' - 'n' - 'N' - 'no' - 'No' - 'No' - 'on' - 'On' - 'ON' - 'off' - 'Off' - 'OFF' ``` # User-Facing Changes I'm not sure if the yaml spec change is a user-facing change. --- Cargo.lock | 28 ++++++---- Cargo.toml | 2 +- crates/nu-command/Cargo.toml | 2 +- crates/nu-command/src/formats/from/yaml.rs | 48 ++++++++-------- crates/nu-command/src/formats/to/yaml.rs | 55 +++++++++---------- .../tests/format_conversions/yaml.rs | 15 +++++ 6 files changed, 83 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3300716fd5..515d8b0035 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3099,6 +3099,16 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "libyml" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3302702afa434ffa30847a83305f0a69d6abd74293b6554c18ec85c7ef30c980" +dependencies = [ + "anyhow", + "version_check", +] + [[package]] name = "libz-sys" version = "1.1.20" @@ -3810,7 +3820,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "serde_yaml", + "serde_yml", "sha2", "sysinfo 0.32.1", "tabled", @@ -6728,16 +6738,18 @@ dependencies = [ ] [[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" +name = "serde_yml" +version = "0.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +checksum = "59e2dd588bf1597a252c3b920e0143eb99b0f76e4e082f4c92ce34fbc9e71ddd" dependencies = [ "indexmap", "itoa", + "libyml", + "memchr", "ryu", "serde", - "unsafe-libyaml", + "version_check", ] [[package]] @@ -7756,12 +7768,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - [[package]] name = "untrusted" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index c6702371b3..f23e035822 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -151,7 +151,7 @@ scopeguard = { version = "1.2.0" } serde = { version = "1.0" } serde_json = "1.0" serde_urlencoded = "0.7.1" -serde_yaml = "0.9" +serde_yml = "0.0.12" sha2 = "0.10" strip-ansi-escapes = "0.2.0" syn = "2.0" diff --git a/crates/nu-command/Cargo.toml b/crates/nu-command/Cargo.toml index 7e8962d195..98dce2061c 100644 --- a/crates/nu-command/Cargo.toml +++ b/crates/nu-command/Cargo.toml @@ -84,7 +84,7 @@ scopeguard = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["preserve_order"] } serde_urlencoded = { workspace = true } -serde_yaml = { workspace = true } +serde_yml = { workspace = true } sha2 = { workspace = true } sysinfo = { workspace = true } tabled = { workspace = true, features = ["ansi"], default-features = false } diff --git a/crates/nu-command/src/formats/from/yaml.rs b/crates/nu-command/src/formats/from/yaml.rs index 649f7e83ac..fb639802a0 100644 --- a/crates/nu-command/src/formats/from/yaml.rs +++ b/crates/nu-command/src/formats/from/yaml.rs @@ -72,7 +72,7 @@ impl Command for FromYml { } fn convert_yaml_value_to_nu_value( - v: &serde_yaml::Value, + v: &serde_yml::Value, span: Span, val_span: Span, ) -> Result { @@ -83,22 +83,22 @@ fn convert_yaml_value_to_nu_value( input_span: val_span, }; Ok(match v { - serde_yaml::Value::Bool(b) => Value::bool(*b, span), - serde_yaml::Value::Number(n) if n.is_i64() => { + serde_yml::Value::Bool(b) => Value::bool(*b, span), + serde_yml::Value::Number(n) if n.is_i64() => { Value::int(n.as_i64().ok_or(err_not_compatible_number)?, span) } - serde_yaml::Value::Number(n) if n.is_f64() => { + serde_yml::Value::Number(n) if n.is_f64() => { Value::float(n.as_f64().ok_or(err_not_compatible_number)?, span) } - serde_yaml::Value::String(s) => Value::string(s.to_string(), span), - serde_yaml::Value::Sequence(a) => { + serde_yml::Value::String(s) => Value::string(s.to_string(), span), + serde_yml::Value::Sequence(a) => { let result: Result, ShellError> = a .iter() .map(|x| convert_yaml_value_to_nu_value(x, span, val_span)) .collect(); Value::list(result?, span) } - serde_yaml::Value::Mapping(t) => { + serde_yml::Value::Mapping(t) => { // Using an IndexMap ensures consistent ordering let mut collected = IndexMap::new(); @@ -111,19 +111,19 @@ fn convert_yaml_value_to_nu_value( input_span: val_span, }; match (k, v) { - (serde_yaml::Value::Number(k), _) => { + (serde_yml::Value::Number(k), _) => { collected.insert( k.to_string(), convert_yaml_value_to_nu_value(v, span, val_span)?, ); } - (serde_yaml::Value::Bool(k), _) => { + (serde_yml::Value::Bool(k), _) => { collected.insert( k.to_string(), convert_yaml_value_to_nu_value(v, span, val_span)?, ); } - (serde_yaml::Value::String(k), _) => { + (serde_yml::Value::String(k), _) => { collected.insert( k.clone(), convert_yaml_value_to_nu_value(v, span, val_span)?, @@ -132,16 +132,16 @@ fn convert_yaml_value_to_nu_value( // Hard-code fix for cases where "v" is a string without quotations with double curly braces // e.g. k = value // value: {{ something }} - // Strangely, serde_yaml returns + // Strangely, serde_yml returns // "value" -> Mapping(Mapping { map: {Mapping(Mapping { map: {String("something"): Null} }): Null} }) - (serde_yaml::Value::Mapping(m), serde_yaml::Value::Null) => { + (serde_yml::Value::Mapping(m), serde_yml::Value::Null) => { return m .iter() .take(1) .collect_vec() .first() .and_then(|e| match e { - (serde_yaml::Value::String(s), serde_yaml::Value::Null) => { + (serde_yml::Value::String(s), serde_yml::Value::Null) => { Some(Value::string("{{ ".to_owned() + s.as_str() + " }}", span)) } _ => None, @@ -156,22 +156,22 @@ fn convert_yaml_value_to_nu_value( Value::record(collected.into_iter().collect(), span) } - serde_yaml::Value::Tagged(t) => { + serde_yml::Value::Tagged(t) => { let tag = &t.tag; let value = match &t.value { - serde_yaml::Value::String(s) => { + serde_yml::Value::String(s) => { let val = format!("{} {}", tag, s).trim().to_string(); Value::string(val, span) } - serde_yaml::Value::Number(n) => { + serde_yml::Value::Number(n) => { let val = format!("{} {}", tag, n).trim().to_string(); Value::string(val, span) } - serde_yaml::Value::Bool(b) => { + serde_yml::Value::Bool(b) => { let val = format!("{} {}", tag, b).trim().to_string(); Value::string(val, span) } - serde_yaml::Value::Null => { + serde_yml::Value::Null => { let val = format!("{}", tag).trim().to_string(); Value::string(val, span) } @@ -180,7 +180,7 @@ fn convert_yaml_value_to_nu_value( value } - serde_yaml::Value::Null => Value::nothing(span), + serde_yml::Value::Null => Value::nothing(span), x => unimplemented!("Unsupported YAML case: {:?}", x), }) } @@ -188,9 +188,9 @@ fn convert_yaml_value_to_nu_value( pub fn from_yaml_string_to_value(s: &str, span: Span, val_span: Span) -> Result { let mut documents = vec![]; - for document in serde_yaml::Deserializer::from_str(s) { - let v: serde_yaml::Value = - serde_yaml::Value::deserialize(document).map_err(|x| ShellError::UnsupportedInput { + for document in serde_yml::Deserializer::from_str(s) { + let v: serde_yml::Value = + serde_yml::Value::deserialize(document).map_err(|x| ShellError::UnsupportedInput { msg: format!("Could not load YAML: {x}"), input: "value originates from here".into(), msg_span: span, @@ -393,8 +393,8 @@ mod test { ]; for test_case in test_cases { - let doc = serde_yaml::Deserializer::from_str(test_case.input); - let v: serde_yaml::Value = serde_yaml::Value::deserialize(doc.last().unwrap()).unwrap(); + let doc = serde_yml::Deserializer::from_str(test_case.input); + let v: serde_yml::Value = serde_yml::Value::deserialize(doc.last().unwrap()).unwrap(); let result = convert_yaml_value_to_nu_value(&v, Span::test_data(), Span::test_data()); assert!(result.is_ok()); assert!(result.ok().unwrap() == test_case.expected.ok().unwrap()); diff --git a/crates/nu-command/src/formats/to/yaml.rs b/crates/nu-command/src/formats/to/yaml.rs index 4fc4e62319..d6cad362f9 100644 --- a/crates/nu-command/src/formats/to/yaml.rs +++ b/crates/nu-command/src/formats/to/yaml.rs @@ -40,29 +40,24 @@ impl Command for ToYaml { } } -pub fn value_to_yaml_value(v: &Value) -> Result { +pub fn value_to_yaml_value(v: &Value) -> Result { Ok(match &v { - Value::Bool { val, .. } => serde_yaml::Value::Bool(*val), - Value::Int { val, .. } => serde_yaml::Value::Number(serde_yaml::Number::from(*val)), - Value::Filesize { val, .. } => { - serde_yaml::Value::Number(serde_yaml::Number::from(val.get())) - } - Value::Duration { val, .. } => serde_yaml::Value::String(val.to_string()), - Value::Date { val, .. } => serde_yaml::Value::String(val.to_string()), - Value::Range { .. } => serde_yaml::Value::Null, - Value::Float { val, .. } => serde_yaml::Value::Number(serde_yaml::Number::from(*val)), + Value::Bool { val, .. } => serde_yml::Value::Bool(*val), + Value::Int { val, .. } => serde_yml::Value::Number(serde_yml::Number::from(*val)), + Value::Filesize { val, .. } => serde_yml::Value::Number(serde_yml::Number::from(val.get())), + Value::Duration { val, .. } => serde_yml::Value::String(val.to_string()), + Value::Date { val, .. } => serde_yml::Value::String(val.to_string()), + Value::Range { .. } => serde_yml::Value::Null, + Value::Float { val, .. } => serde_yml::Value::Number(serde_yml::Number::from(*val)), Value::String { val, .. } | Value::Glob { val, .. } => { - serde_yaml::Value::String(val.clone()) + serde_yml::Value::String(val.clone()) } Value::Record { val, .. } => { - let mut m = serde_yaml::Mapping::new(); + let mut m = serde_yml::Mapping::new(); for (k, v) in &**val { - m.insert( - serde_yaml::Value::String(k.clone()), - value_to_yaml_value(v)?, - ); + m.insert(serde_yml::Value::String(k.clone()), value_to_yaml_value(v)?); } - serde_yaml::Value::Mapping(m) + serde_yml::Value::Mapping(m) } Value::List { vals, .. } => { let mut out = vec![]; @@ -71,28 +66,28 @@ pub fn value_to_yaml_value(v: &Value) -> Result { out.push(value_to_yaml_value(value)?); } - serde_yaml::Value::Sequence(out) + serde_yml::Value::Sequence(out) } - Value::Closure { .. } => serde_yaml::Value::Null, - Value::Nothing { .. } => serde_yaml::Value::Null, + Value::Closure { .. } => serde_yml::Value::Null, + Value::Nothing { .. } => serde_yml::Value::Null, Value::Error { error, .. } => return Err(*error.clone()), - Value::Binary { val, .. } => serde_yaml::Value::Sequence( + Value::Binary { val, .. } => serde_yml::Value::Sequence( val.iter() - .map(|x| serde_yaml::Value::Number(serde_yaml::Number::from(*x))) + .map(|x| serde_yml::Value::Number(serde_yml::Number::from(*x))) .collect(), ), - Value::CellPath { val, .. } => serde_yaml::Value::Sequence( + Value::CellPath { val, .. } => serde_yml::Value::Sequence( val.members .iter() .map(|x| match &x { - PathMember::String { val, .. } => Ok(serde_yaml::Value::String(val.clone())), + PathMember::String { val, .. } => Ok(serde_yml::Value::String(val.clone())), PathMember::Int { val, .. } => { - Ok(serde_yaml::Value::Number(serde_yaml::Number::from(*val))) + Ok(serde_yml::Value::Number(serde_yml::Number::from(*val))) } }) - .collect::, ShellError>>()?, + .collect::, ShellError>>()?, ), - Value::Custom { .. } => serde_yaml::Value::Null, + Value::Custom { .. } => serde_yml::Value::Null, }) } @@ -105,9 +100,9 @@ fn to_yaml(input: PipelineData, head: Span) -> Result let value = input.into_value(head)?; let yaml_value = value_to_yaml_value(&value)?; - match serde_yaml::to_string(&yaml_value) { - Ok(serde_yaml_string) => { - Ok(Value::string(serde_yaml_string, head) + match serde_yml::to_string(&yaml_value) { + Ok(serde_yml_string) => { + Ok(Value::string(serde_yml_string, head) .into_pipeline_data_with_metadata(Some(metadata))) } _ => Ok(Value::error( diff --git a/crates/nu-command/tests/format_conversions/yaml.rs b/crates/nu-command/tests/format_conversions/yaml.rs index 57e75164ab..146890012e 100644 --- a/crates/nu-command/tests/format_conversions/yaml.rs +++ b/crates/nu-command/tests/format_conversions/yaml.rs @@ -48,3 +48,18 @@ fn convert_dict_to_yaml_with_integer_floats_key() { assert!(actual.out.contains("2.11")); assert!(actual.err.is_empty()); } + +#[test] +fn convert_bool_to_yaml_in_yaml_spec_1_2() { + let actual = nu!(pipeline( + r#" + [y n no On OFF True true false] | to yaml + "# + )); + + assert_eq!( + actual.out, + "- 'y'- 'n'- 'no'- 'On'- 'OFF'- 'True'- true- false" + ); + assert!(actual.err.is_empty()); +}