mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 10:25:42 +02:00
Merge branch 'master' into testing
This commit is contained in:
10
src/cli.rs
10
src/cli.rs
@ -11,6 +11,7 @@ crate use crate::format::{EntriesListView, GenericView};
|
||||
use crate::object::Value;
|
||||
use crate::parser::{ParsedCommand, Pipeline};
|
||||
use crate::stream::empty_stream;
|
||||
use crate::git::current_branch;
|
||||
|
||||
use log::debug;
|
||||
use rustyline::error::ReadlineError;
|
||||
@ -60,6 +61,7 @@ pub async fn cli() -> Result<(), Box<Error>> {
|
||||
command("trim", trim::trim),
|
||||
command("to-array", to_array::to_array),
|
||||
command("to-json", to_json::to_json),
|
||||
command("to-toml", to_toml::to_toml),
|
||||
Arc::new(Where),
|
||||
Arc::new(Config),
|
||||
command("sort-by", sort_by::sort_by),
|
||||
@ -82,8 +84,12 @@ pub async fn cli() -> Result<(), Box<Error>> {
|
||||
|
||||
loop {
|
||||
let readline = rl.readline(&format!(
|
||||
"{}> ",
|
||||
context.env.lock().unwrap().cwd().display().to_string()
|
||||
"{}{}> ",
|
||||
context.env.lock().unwrap().cwd().display().to_string(),
|
||||
match current_branch() {
|
||||
Some(s) => format!("({})", s),
|
||||
None => "".to_string()
|
||||
}
|
||||
));
|
||||
|
||||
match process_line(readline, &mut context).await {
|
||||
|
@ -19,6 +19,7 @@ crate mod split_row;
|
||||
crate mod take;
|
||||
crate mod to_array;
|
||||
crate mod to_json;
|
||||
crate mod to_toml;
|
||||
crate mod trim;
|
||||
crate mod view;
|
||||
crate mod where_;
|
||||
|
@ -133,28 +133,59 @@ impl ExternalCommand {
|
||||
arg_string.push_str(" ");
|
||||
arg_string.push_str(&arg);
|
||||
}
|
||||
let mut process = Exec::shell(&self.name);
|
||||
|
||||
if arg_string.contains("$it") {
|
||||
let mut first = true;
|
||||
for i in &inputs {
|
||||
if !first {
|
||||
process = process.arg("&&");
|
||||
process = process.arg(&self.name);
|
||||
} else {
|
||||
first = false;
|
||||
let mut process;
|
||||
#[cfg(windows)]
|
||||
{
|
||||
process = Exec::shell(&self.name);
|
||||
|
||||
if arg_string.contains("$it") {
|
||||
let mut first = true;
|
||||
for i in &inputs {
|
||||
if !first {
|
||||
process = process.arg("&&");
|
||||
process = process.arg(&self.name);
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
for arg in &self.args {
|
||||
process = process.arg(&arg.replace("$it", &i.as_string().unwrap()));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for arg in &self.args {
|
||||
process = process.arg(&arg.replace("$it", &i.as_string().unwrap()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for arg in &self.args {
|
||||
process = process.arg(arg);
|
||||
process = process.arg(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let mut new_arg_string = self.name.to_string();
|
||||
|
||||
if arg_string.contains("$it") {
|
||||
let mut first = true;
|
||||
for i in &inputs {
|
||||
if !first {
|
||||
new_arg_string.push_str(" && ");
|
||||
new_arg_string.push_str(&self.name);
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
for arg in &self.args {
|
||||
new_arg_string.push_str(" ");
|
||||
new_arg_string.push_str(&arg.replace("$it", &i.as_string().unwrap()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for arg in &self.args {
|
||||
new_arg_string.push_str(" ");
|
||||
new_arg_string.push_str(&arg);
|
||||
}
|
||||
}
|
||||
process = Exec::shell(new_arg_string);
|
||||
}
|
||||
process = process.cwd(context.env.lock().unwrap().cwd());
|
||||
|
||||
let mut process = match stream_next {
|
||||
|
@ -18,13 +18,17 @@ fn convert_json_value_to_nu_value(v: &serde_json::Value) -> Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_json_string_to_value(s: String) -> Value {
|
||||
let v: serde_json::Value = serde_json::from_str(&s).unwrap();
|
||||
convert_json_value_to_nu_value(&v)
|
||||
}
|
||||
|
||||
pub fn from_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
Ok(out
|
||||
.map(|a| match a {
|
||||
Value::Primitive(Primitive::String(s)) => {
|
||||
let v: serde_json::Value = serde_json::from_str(&s).unwrap();
|
||||
ReturnValue::Value(convert_json_value_to_nu_value(&v))
|
||||
ReturnValue::Value(from_json_string_to_value(s))
|
||||
}
|
||||
_ => ReturnValue::Value(Value::Primitive(Primitive::String("".to_string()))),
|
||||
})
|
||||
|
@ -20,13 +20,17 @@ fn convert_toml_value_to_nu_value(v: &toml::Value) -> Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_toml_string_to_value(s: String) -> Value {
|
||||
let v: toml::Value = s.parse::<toml::Value>().unwrap();
|
||||
convert_toml_value_to_nu_value(&v)
|
||||
}
|
||||
|
||||
pub fn from_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
Ok(out
|
||||
.map(|a| match a {
|
||||
Value::Primitive(Primitive::String(s)) => {
|
||||
let v: toml::Value = s.parse::<toml::Value>().unwrap();
|
||||
ReturnValue::Value(convert_toml_value_to_nu_value(&v))
|
||||
ReturnValue::Value(from_toml_string_to_value(s))
|
||||
}
|
||||
_ => ReturnValue::Value(Value::Primitive(Primitive::String("".to_string()))),
|
||||
})
|
||||
|
@ -14,9 +14,25 @@ pub fn open(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let contents = std::fs::read_to_string(&full_path).unwrap();
|
||||
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(ReturnValue::Value(Value::Primitive(Primitive::String(
|
||||
contents,
|
||||
))));
|
||||
|
||||
let open_raw = match args.positional.get(1) {
|
||||
Some(Value::Primitive(Primitive::String(s))) if s == "--raw" => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
match full_path.extension() {
|
||||
Some(x) if x == "toml" && !open_raw => {
|
||||
stream.push_back(ReturnValue::Value(crate::commands::from_toml::from_toml_string_to_value(contents)));
|
||||
}
|
||||
Some(x) if x == "json" && !open_raw => {
|
||||
stream.push_back(ReturnValue::Value(crate::commands::from_json::from_json_string_to_value(contents)));
|
||||
}
|
||||
_ => {
|
||||
stream.push_back(ReturnValue::Value(Value::Primitive(Primitive::String(
|
||||
contents,
|
||||
))));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(stream.boxed())
|
||||
}
|
||||
|
9
src/commands/to_toml.rs
Normal file
9
src/commands/to_toml.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use crate::object::{Primitive, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn to_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
Ok(out
|
||||
.map(|a| ReturnValue::Value(Value::Primitive(Primitive::String(toml::to_string(&a).unwrap()))))
|
||||
.boxed())
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
use crate::parser::ast;
|
||||
use crate::prelude::*;
|
||||
use crate::object::Primitive;
|
||||
use derive_new::new;
|
||||
|
||||
#[derive(new)]
|
||||
@ -20,10 +21,7 @@ crate fn evaluate_expr(expr: &ast::Expression, scope: &Scope) -> Result<Value, S
|
||||
match expr {
|
||||
Expression::Leaf(l) => Ok(evaluate_leaf(l)),
|
||||
Expression::Parenthesized(p) => evaluate_expr(&p.expr, scope),
|
||||
Expression::Flag(f) => Err(ShellError::string(format!(
|
||||
"can't evaluate the flag {}",
|
||||
f.print()
|
||||
))),
|
||||
Expression::Flag(f) => Ok(Value::Primitive(Primitive::String(f.print()))),
|
||||
Expression::Block(b) => evaluate_block(&b, scope),
|
||||
Expression::Path(p) => evaluate_path(&p, scope),
|
||||
Expression::Binary(b) => evaluate_binary(b, scope),
|
||||
|
21
src/git.rs
Normal file
21
src/git.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use git2::{Repository, RepositoryOpenFlags};
|
||||
use std::ffi::OsString;
|
||||
|
||||
pub fn current_branch() -> Option<String> {
|
||||
let v: Vec<OsString> = vec![];
|
||||
match Repository::open_ext(".", RepositoryOpenFlags::empty(), v) {
|
||||
Ok(repo) => {
|
||||
let r = repo.head();
|
||||
match r {
|
||||
Ok(r) => {
|
||||
match r.shorthand() {
|
||||
Some(s) => Some(s.to_string()),
|
||||
None => None,
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
}
|
@ -11,11 +11,13 @@ mod env;
|
||||
mod errors;
|
||||
mod evaluate;
|
||||
mod format;
|
||||
mod git;
|
||||
mod object;
|
||||
mod parser;
|
||||
mod prelude;
|
||||
mod shell;
|
||||
mod stream;
|
||||
mod tests;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use log::LevelFilter;
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::object::types::Type;
|
||||
use derive_new::new;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
|
||||
pub enum DescriptorName {
|
||||
@ -31,13 +32,29 @@ impl DescriptorName {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash, new)]
|
||||
#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, new)]
|
||||
pub struct DataDescriptor {
|
||||
crate name: DescriptorName,
|
||||
crate readonly: bool,
|
||||
crate ty: Type,
|
||||
}
|
||||
|
||||
impl Serialize for DataDescriptor {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match self.name {
|
||||
DescriptorName::String(ref s) => {
|
||||
serializer.serialize_str(s)
|
||||
}
|
||||
DescriptorName::ValueOf => {
|
||||
serializer.serialize_str("value")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for DataDescriptor {
|
||||
fn from(input: &str) -> DataDescriptor {
|
||||
DataDescriptor {
|
||||
|
@ -4,10 +4,11 @@ use crate::object::DataDescriptor;
|
||||
use crate::object::{Primitive, Value};
|
||||
use derive_new::new;
|
||||
use indexmap::IndexMap;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde_derive::Deserialize;
|
||||
use serde::ser::{Serialize, Serializer, SerializeMap};
|
||||
use std::cmp::{Ordering, PartialOrd};
|
||||
|
||||
#[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, new)]
|
||||
#[derive(Debug, Default, Eq, PartialEq, Deserialize, Clone, new)]
|
||||
pub struct Dictionary {
|
||||
entries: IndexMap<DataDescriptor, Value>,
|
||||
}
|
||||
@ -19,6 +20,28 @@ impl PartialOrd for Dictionary {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Dictionary {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut map = serializer.serialize_map(Some(self.entries.len()))?;
|
||||
for (k, v) in self.entries.iter() {
|
||||
match v {
|
||||
Value::Object(_) => {},
|
||||
_ => map.serialize_entry(k, v)?
|
||||
}
|
||||
}
|
||||
for (k, v) in self.entries.iter() {
|
||||
match v {
|
||||
Value::Object(_) => map.serialize_entry(k, v)?,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IndexMap<String, Value>> for Dictionary {
|
||||
fn from(input: IndexMap<String, Value>) -> Dictionary {
|
||||
let mut out = IndexMap::default();
|
||||
|
61
src/tests.rs
Normal file
61
src/tests.rs
Normal file
@ -0,0 +1,61 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::PathBuf;
|
||||
use std::io::prelude::*;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::error::Error;
|
||||
|
||||
fn test_helper(test_name: &str) {
|
||||
let mut baseline_path = PathBuf::new();
|
||||
baseline_path.push("tests");
|
||||
baseline_path.push(test_name);
|
||||
baseline_path.set_extension("out");
|
||||
|
||||
let mut txt_path = PathBuf::new();
|
||||
txt_path.push("tests");
|
||||
txt_path.push(test_name);
|
||||
txt_path.set_extension("txt");
|
||||
|
||||
let executable = {
|
||||
let mut buf = PathBuf::new();
|
||||
buf.push("target");
|
||||
buf.push("debug");
|
||||
buf.push("nu");
|
||||
buf
|
||||
};
|
||||
|
||||
let process = match Command::new(executable)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn() {
|
||||
|
||||
Ok(process) => process,
|
||||
Err(why) => panic!("Can't run test {}", why.description())
|
||||
};
|
||||
|
||||
let baseline_out = std::fs::read_to_string(baseline_path).unwrap();
|
||||
let baseline_out = baseline_out.replace("\r\n", "\n");
|
||||
let input_commands = std::fs::read_to_string(txt_path).unwrap();
|
||||
|
||||
match process.stdin.unwrap().write_all(input_commands.as_bytes()) {
|
||||
Err(why) => panic!("couldn't write to wc stdin: {}",
|
||||
why.description()),
|
||||
Ok(_) => println!("sent pangram to wc"),
|
||||
}
|
||||
|
||||
let mut s = String::new();
|
||||
match process.stdout.unwrap().read_to_string(&mut s) {
|
||||
Err(why) => panic!("couldn't read stdout: {}",
|
||||
why.description()),
|
||||
Ok(_) => {
|
||||
let s = s.replace("\r\n", "\n");
|
||||
assert_eq!(s, baseline_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_toml() {
|
||||
test_helper("open_toml");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user