Merge branch 'master' into testing

This commit is contained in:
Jonathan Turner
2019-06-03 05:51:11 +12:00
committed by GitHub
20 changed files with 599 additions and 134 deletions

View File

@ -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 {

View File

@ -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_;

View File

@ -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 {

View File

@ -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()))),
})

View File

@ -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()))),
})

View File

@ -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
View 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())
}

View File

@ -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
View 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
}
}

View File

@ -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;

View File

@ -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 {

View File

@ -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
View 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");
}
}