mirror of
https://github.com/nushell/nushell
synced 2024-12-26 13:03:07 +00:00
Merge pull request #112 from jonathandturner/ini
Add .ini loading/saving
This commit is contained in:
commit
744ae9252e
13 changed files with 160 additions and 0 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -1589,6 +1589,7 @@ dependencies = [
|
|||
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde-hjson 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_ini 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"subprocess 0.1.19 (git+https://github.com/jonathandturner/rust-subprocess.git?branch=is_already_escaped)",
|
||||
|
@ -2267,6 +2268,11 @@ dependencies = [
|
|||
"uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "result"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
version = "0.6.0"
|
||||
|
@ -2447,6 +2453,16 @@ dependencies = [
|
|||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_ini"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"result 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.39"
|
||||
|
@ -3413,6 +3429,7 @@ dependencies = [
|
|||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||
"checksum render-tree 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "68ed587df09cfb7ce1bc6fe8f77e24db219f222c049326ccbfb948ec67e31664"
|
||||
"checksum reqwest 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)" = "00eb63f212df0e358b427f0f40aa13aaea010b470be642ad422bcbca2feff2e4"
|
||||
"checksum result 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "194d8e591e405d1eecf28819740abed6d719d1a2db87fc0bcdedee9a26d55560"
|
||||
"checksum roxmltree 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "53b0200cbfa8b3f6cfd6076592717d697a1ddc57cb2a8fbfd3d133c06011b579"
|
||||
"checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
|
||||
"checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288"
|
||||
|
@ -3436,6 +3453,7 @@ dependencies = [
|
|||
"checksum serde-hjson 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4640cf3168e40c00c874ff1ad436c0f18c37edec101d5d897a4396f617abce29"
|
||||
"checksum serde-value 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7a663f873dedc4eac1a559d4c6bc0d0b2c34dc5ac4702e105014b8281489e44f"
|
||||
"checksum serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "101b495b109a3e3ca8c4cbe44cf62391527cdfb6ba15821c5ce80bcd5ea23f9f"
|
||||
"checksum serde_ini 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eb236687e2bb073a7521c021949be944641e671b8505a94069ca37b656c81139"
|
||||
"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
|
||||
"checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5"
|
||||
"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a"
|
||||
|
|
|
@ -61,6 +61,7 @@ clipboard = "0.5"
|
|||
reqwest = "0.9"
|
||||
roxmltree = "0.6.0"
|
||||
pretty = "0.5.2"
|
||||
serde_ini = "0.2.0"
|
||||
|
||||
[dependencies.pancurses]
|
||||
version = "0.16"
|
||||
|
|
|
@ -55,6 +55,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||
command("skip", skip::skip),
|
||||
command("first", first::first),
|
||||
command("size", size::size),
|
||||
command("from-ini", from_ini::from_ini),
|
||||
command("from-json", from_json::from_json),
|
||||
command("from-toml", from_toml::from_toml),
|
||||
command("from-xml", from_xml::from_xml),
|
||||
|
@ -69,6 +70,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||
command("reject", reject::reject),
|
||||
command("trim", trim::trim),
|
||||
command("to-array", to_array::to_array),
|
||||
command("to-ini", to_ini::to_ini),
|
||||
command("to-json", to_json::to_json),
|
||||
command("to-toml", to_toml::to_toml),
|
||||
Arc::new(Where),
|
||||
|
|
|
@ -8,6 +8,7 @@ crate mod config;
|
|||
crate mod enter;
|
||||
crate mod exit;
|
||||
crate mod first;
|
||||
crate mod from_ini;
|
||||
crate mod from_json;
|
||||
crate mod from_toml;
|
||||
crate mod from_xml;
|
||||
|
@ -25,6 +26,7 @@ crate mod sort_by;
|
|||
crate mod split_column;
|
||||
crate mod split_row;
|
||||
crate mod to_array;
|
||||
crate mod to_ini;
|
||||
crate mod to_json;
|
||||
crate mod to_toml;
|
||||
crate mod tree;
|
||||
|
|
|
@ -102,6 +102,8 @@ pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
Some("json".to_string())
|
||||
} else if s == "--xml" {
|
||||
Some("xml".to_string())
|
||||
} else if s == "--ini" {
|
||||
Some("ini".to_string())
|
||||
} else if s == "--yaml" {
|
||||
Some("yaml".to_string())
|
||||
} else if s == "--toml" {
|
||||
|
@ -157,6 +159,19 @@ pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
)?,
|
||||
)));
|
||||
}
|
||||
Some(x) if x == "ini" => {
|
||||
stream.push_back(ReturnValue::Action(CommandAction::Enter(
|
||||
crate::commands::from_ini::from_ini_string_to_value(contents).map_err(
|
||||
move |_| {
|
||||
ShellError::maybe_labeled_error(
|
||||
"Could not load as INI",
|
||||
"could not load as INI",
|
||||
span,
|
||||
)
|
||||
},
|
||||
)?,
|
||||
)));
|
||||
}
|
||||
Some(x) if x == "yml" => {
|
||||
stream.push_back(ReturnValue::Action(CommandAction::Enter(
|
||||
crate::commands::from_yaml::from_yaml_string_to_value(contents).map_err(
|
||||
|
|
54
src/commands/from_ini.rs
Normal file
54
src/commands/from_ini.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use crate::object::{DataDescriptor, Dictionary, Primitive, Value};
|
||||
use crate::prelude::*;
|
||||
use indexmap::IndexMap;
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn convert_ini_second_to_nu_value(v: &HashMap<String, String>) -> Value {
|
||||
let mut second = Dictionary::new(IndexMap::new());
|
||||
for (key, value) in v.into_iter() {
|
||||
second.add(
|
||||
DataDescriptor::from(key.as_str()),
|
||||
Value::Primitive(Primitive::String(value.clone())),
|
||||
);
|
||||
}
|
||||
Value::Object(second)
|
||||
}
|
||||
fn convert_ini_top_to_nu_value(v: &HashMap<String, HashMap<String, String>>) -> Value {
|
||||
let mut top_level = Dictionary::new(IndexMap::new());
|
||||
for (key, value) in v.iter() {
|
||||
top_level.add(
|
||||
DataDescriptor::from(key.as_str()),
|
||||
convert_ini_second_to_nu_value(value),
|
||||
);
|
||||
}
|
||||
Value::Object(top_level)
|
||||
}
|
||||
|
||||
pub fn from_ini_string_to_value(s: String) -> Result<Value, Box<dyn std::error::Error>> {
|
||||
let v: HashMap<String, HashMap<String, String>> = serde_ini::from_str(&s)?;
|
||||
Ok(convert_ini_top_to_nu_value(&v))
|
||||
}
|
||||
|
||||
pub fn from_ini(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
let span = args.name_span;
|
||||
Ok(out
|
||||
.map(move |a| match a {
|
||||
Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s) {
|
||||
Ok(x) => ReturnValue::Value(x),
|
||||
Err(e) => {
|
||||
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
"Could not parse as INI",
|
||||
format!("{:#?}", e),
|
||||
span,
|
||||
))))
|
||||
}
|
||||
},
|
||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)))),
|
||||
})
|
||||
.boxed())
|
||||
}
|
|
@ -101,6 +101,8 @@ pub fn open(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
Some("json".to_string())
|
||||
} else if s == "--xml" {
|
||||
Some("xml".to_string())
|
||||
} else if s == "--ini" {
|
||||
Some("ini".to_string())
|
||||
} else if s == "--yaml" {
|
||||
Some("yaml".to_string())
|
||||
} else if s == "--toml" {
|
||||
|
@ -143,6 +145,19 @@ pub fn open(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
)?,
|
||||
));
|
||||
}
|
||||
Some(x) if x == "ini" => {
|
||||
stream.push_back(ReturnValue::Value(
|
||||
crate::commands::from_ini::from_ini_string_to_value(contents).map_err(
|
||||
move |_| {
|
||||
ShellError::maybe_labeled_error(
|
||||
"Could not open as INI",
|
||||
"could not open as INI",
|
||||
span,
|
||||
)
|
||||
},
|
||||
)?,
|
||||
));
|
||||
}
|
||||
Some(x) if x == "xml" => {
|
||||
stream.push_back(ReturnValue::Value(
|
||||
crate::commands::from_xml::from_xml_string_to_value(contents).map_err(
|
||||
|
|
|
@ -45,6 +45,14 @@ pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> {
|
|||
}
|
||||
toml::to_string(&args.input[0]).unwrap()
|
||||
}
|
||||
Some(x) if x == "ini" && !save_raw => {
|
||||
if args.input.len() != 1 {
|
||||
return Err(ShellError::string(
|
||||
"saving to ini requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
serde_ini::to_string(&args.input[0]).unwrap()
|
||||
}
|
||||
Some(x) if x == "json" && !save_raw => {
|
||||
if args.input.len() != 1 {
|
||||
return Err(ShellError::string(
|
||||
|
|
17
src/commands/to_ini.rs
Normal file
17
src/commands/to_ini.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use crate::object::{Primitive, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn to_ini(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
let span = args.name_span;
|
||||
Ok(out
|
||||
.map(move |a| match serde_ini::to_string(&a) {
|
||||
Ok(x) => ReturnValue::Value(Value::Primitive(Primitive::String(x))),
|
||||
Err(_) => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
||||
"Can not convert to INI string",
|
||||
"can not convert piped data to INI string",
|
||||
span,
|
||||
)))),
|
||||
})
|
||||
.boxed())
|
||||
}
|
1
tests/open_ini.out
Normal file
1
tests/open_ini.out
Normal file
|
@ -0,0 +1 @@
|
|||
1234
|
3
tests/open_ini.txt
Normal file
3
tests/open_ini.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
cd tests
|
||||
open test.ini | get SectionOne.integer | echo $it
|
||||
exit
|
19
tests/test.ini
Normal file
19
tests/test.ini
Normal file
|
@ -0,0 +1,19 @@
|
|||
[SectionOne]
|
||||
|
||||
key = value
|
||||
integer = 1234
|
||||
real = 3.14
|
||||
string1 = 'Case 1'
|
||||
string2 = "Case 2"
|
||||
|
||||
[SectionTwo]
|
||||
|
||||
; comment line
|
||||
key = new value
|
||||
integer = 1234
|
||||
real = 3.14
|
||||
string1 = 'Case 1'
|
||||
string2 = "Case 2"
|
||||
string3 = 'Case 3'
|
||||
|
||||
|
|
@ -67,6 +67,11 @@ mod tests {
|
|||
test_helper("open_xml");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn open_ini() {
|
||||
test_helper("open_ini");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_roundtrip() {
|
||||
test_helper("json_roundtrip");
|
||||
|
|
Loading…
Reference in a new issue