Merge branch 'master' into light_tables

This commit is contained in:
Jonathan Turner 2019-09-10 05:11:11 +12:00
commit aea11cf742
9 changed files with 472 additions and 104 deletions

View File

@ -9,21 +9,16 @@ version: 2.1
commands:
check_token:
description: Check that QUAY_TOKEN is provided in environment
steps:
- run:
if [[ -z "${QUAY_TOKEN}" ]]; then
echo "QUAY_TOKEN is undefined. Add to CircleCI environment to continue."
exit 1;
fi
pull_cache:
description: Pulls Quay.io docker images usable for our cache
description: Pulls Quay.io docker images (latest) for our cache
parameters:
tag:
type: string
default: "devel"
steps:
- run: docker pull quay.io/nushell/nu:latest
- run: docker pull quay.io/nushell/nu-base:latest
- run: echo "Tag is << parameters.tag >>"
- run: docker pull quay.io/nushell/nu:<< parameters.tag >>
- run: docker pull quay.io/nushell/nu-base:<< parameters.tag >>
orbs:
# https://circleci.com/orbs/registry/orb/circleci/docker
@ -40,13 +35,12 @@ workflows:
image: nushell/nu-base
tag: latest
dockerfile: docker/Dockerfile.nu-base
extra_build_args: --cache-from=quay.io/nushell/nu-base:latest,quay.io/nushell/nu:latest
extra_build_args: --cache-from=quay.io/nushell/nu-base:devel
filters:
branches:
ignore:
- master
before_build:
- check_token
- pull_cache
after_build:
- run:
@ -63,21 +57,21 @@ workflows:
build_with_deploy:
jobs:
# Deploy versioned and latest images on tags (releases) only.
# Deploy versioned and latest images on tags (releases) only - builds --release.
- docker/publish:
image: nushell/nu-base
registry: quay.io
tag: latest
dockerfile: docker/Dockerfile.nu-base
extra_build_args: --cache-from=quay.io/nushell/nu-base:latest,quay.io/nushell/nu:latest
extra_build_args: --cache-from=quay.io/nushell/nu-base:latest,quay.io/nushell/nu:latest --build-arg RELEASE=true
filters:
branches:
ignore: /.*/
tags:
only: /^v.*/
before_build:
- check_token
- pull_cache
- run: docker pull quay.io/nushell/nu:latest
- run: docker pull quay.io/nushell/nu-base:latest
after_build:
- run:
name: Build Multistage (smaller) container
@ -90,12 +84,11 @@ workflows:
echo "Version for Docker tag is ${DOCKER_TAG}"
docker tag quay.io/nushell/nu-base:latest quay.io/nushell/nu-base:${DOCKER_TAG}
docker tag quay.io/nushell/nu:latest quay.io/nushell/nu:${DOCKER_TAG}
docker login -u="nushell+circleci" -p="${QUAY_TOKEN}" quay.io
docker push quay.io/nushell/nu-base
docker push quay.io/nushell/nu
# publish devel to Docker Hub on merge to master
# publish devel to Docker Hub on merge to master (doesn't build --release)
build_with_deploy_devel:
jobs:
@ -105,9 +98,8 @@ workflows:
registry: quay.io
tag: devel
dockerfile: docker/Dockerfile.nu-base
extra_build_args: --cache-from=quay.io/nushell/nu-base:latest,quay.io/nushell/nu:latest
extra_build_args: --cache-from=quay.io/nushell/nu-base:devel
before_build:
- check_token
- pull_cache
filters:
branches:
@ -120,6 +112,38 @@ workflows:
- run:
name: Publish Development Docker Tags
command: |
docker login -u="nushell+circleci" -p="${QUAY_TOKEN}" quay.io
docker push quay.io/nushell/nu-base:devel
docker push quay.io/nushell/nu:devel
nightly:
jobs:
- docker/publish:
image: nushell/nu-base
registry: quay.io
tag: nightly
dockerfile: docker/Dockerfile.nu-base
extra_build_args: --cache-from=quay.io/nushell/nu-base:nightly --build-arg RELEASE=true
filters:
branches:
only: master
before_build:
- run: docker pull quay.io/nushell/nu:nightly
- run: docker pull quay.io/nushell/nu-base:nightly
after_build:
- run:
name: Build Multistage (smaller) container
command: |
docker build -f docker/Dockerfile -t quay.io/nushell/nu:nightly .
- run:
name: Publish Nightly Nushell Containers
command: |
docker push quay.io/nushell/nu-base:nightly
docker push quay.io/nushell/nu:nightly
triggers:
- schedule:
cron: "0 22 * * *"
filters:
branches:
only:
- master

View File

@ -11,7 +11,7 @@ A modern shell for the GitHub era
# Status
This project has reached a minimum-viable product level of quality. While contributors dogfood it as their daily driver, it may be instable for some commands. Future releases will work fill out missing features and improve stability. Its design is also subject to change as it matures.
This project has reached a minimum-viable product level of quality. While contributors dogfood it as their daily driver, it may be unstable for some commands. Future releases will work fill out missing features and improve stability. Its design is also subject to change as it matures.
Nu comes with a set of built-in commands (listed below). If a command is unknown, the command will shell-out and execute it (using cmd on Windows or bash on Linux and MacOS), correctly passing through stdin, stdout and stderr, so things like your daily git workflows and even `vim` will work just fine.

View File

@ -3,3 +3,4 @@ FROM quay.io/nushell/nu-base:${FROMTAG} as base
FROM rust:1.37-slim
COPY --from=base /usr/local/bin/nu /usr/local/bin/nu
ENTRYPOINT ["nu"]
CMD ["-l", "info"]

View File

@ -1,4 +1,4 @@
FROM rust:1.37-slim
FROM ubuntu:16.04
# docker build -f docker/Dockerfile.nu-base -t nushell/nu-base .
# docker run -it nushell/nu-base
@ -7,12 +7,20 @@ ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && apt-get install -y libssl-dev \
libxcb-composite0-dev \
libx11-dev \
pkg-config
RUN USER=root cargo new --bin /code
pkg-config \
curl
ARG RELEASE=false
WORKDIR /code
ADD . /code
RUN cargo build --release && cargo run --release
RUN cp target/release/nu /usr/local/bin
COPY ./rust-toolchain ./rust-toolchain
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --no-modify-path --default-toolchain `cat rust-toolchain`
ENV PATH=/root/.cargo/bin:$PATH
COPY . /code
RUN echo "##vso[task.prependpath]/root/.cargo/bin" && \
rustc -Vv && \
if $RELEASE; then cargo build --release && cargo run --release; \
cp target/release/nu /usr/local/bin; \
else cargo build; \
cp target/debug/nu /usr/local/bin; fi;
ENTRYPOINT ["nu"]
CMD ["-l", "info"]

View File

@ -328,7 +328,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut ConfigDeserializer<'de> {
let type_name = std::any::type_name::<V::Value>();
let tagged_val_name = std::any::type_name::<Tagged<Value>>();
if name == tagged_val_name {
if type_name == tagged_val_name {
return visit::<Tagged<Value>, _>(value.val, name, fields, visitor);
}
@ -467,3 +467,27 @@ impl<'a, 'de: 'a> de::SeqAccess<'de> for StructDeserializer<'a, 'de> {
return Some(self.fields.len());
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::any::type_name;
#[test]
fn check_type_name_properties() {
// This ensures that certain properties for the
// std::any::type_name function hold, that
// this code relies on. The type_name docs explicitly
// mention that the actual format of the output
// is unspecified and change is likely.
// This test makes sure that such change is detected
// by this test failing, and not things silently breaking.
// Specifically, we rely on this behaviour further above
// in the file to special case Tagged<Value> parsing.
let tuple = type_name::<()>();
let tagged_tuple = type_name::<Tagged<()>>();
let tagged_value = type_name::<Tagged<Value>>();
assert!(tuple != tagged_tuple);
assert!(tuple != tagged_value);
assert!(tagged_tuple != tagged_value);
}
}

View File

@ -15,7 +15,7 @@ use std::path::{Path, PathBuf};
pub struct FilesystemShell {
pub(crate) path: String,
last_path: String,
pub(crate) last_path: String,
completer: NuCompleter,
hinter: HistoryHinter,
}
@ -185,29 +185,20 @@ impl Shell for FilesystemShell {
},
Some(v) => {
let target = v.as_path()?;
let path = PathBuf::from(self.path());
match dunce::canonicalize(path.join(&target).as_path()) {
Ok(p) => p,
Err(_) => {
let error = Err(ShellError::labeled_error(
"Can not change to directory",
"directory not found",
v.span().clone(),
));
if let Some(t) = target.to_str() {
if t == "-" {
match dunce::canonicalize(PathBuf::from(self.last_path.clone()).as_path()) {
Ok(p) => p,
Err(_) => {
return error;
}
}
} else {
return error;
}
} else {
return error;
if PathBuf::from("-") == target {
PathBuf::from(&self.last_path)
} else {
let path = PathBuf::from(self.path());
match dunce::canonicalize(path.join(&target)) {
Ok(p) => p,
Err(_) => {
return Err(ShellError::labeled_error(
"Can not change to directory",
"directory not found",
v.span().clone(),
))
}
}
}
@ -215,23 +206,12 @@ impl Shell for FilesystemShell {
};
let mut stream = VecDeque::new();
match std::env::set_current_dir(&path) {
Ok(_) => {}
Err(_) => {
if let Some(directory) = args.nth(0) {
return Err(ShellError::labeled_error(
"Can not change to directory",
"directory not found",
directory.span(),
));
} else {
return Err(ShellError::string("Can not change to directory"));
}
}
}
stream.push_back(ReturnSuccess::change_cwd(
stream.push_back(
ReturnSuccess::change_cwd(
path.to_string_lossy().to_string(),
));
Ok(stream.into())
}

View File

@ -10,16 +10,24 @@ use crate::utils::ValueStructure;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct ValueShell {
pub(crate) path: String,
pub(crate) last_path: String,
pub(crate) value: Tagged<Value>,
}
impl std::fmt::Debug for ValueShell {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ValueShell @ {}", self.path)
}
}
impl ValueShell {
pub fn new(value: Tagged<Value>) -> ValueShell {
ValueShell {
path: "/".to_string(),
last_path: "/".to_string(),
value,
}
}
@ -76,7 +84,7 @@ impl Shell for ValueShell {
}
fn homedir(&self) -> Option<PathBuf> {
dirs::home_dir()
Some(PathBuf::from("/"))
}
fn ls(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
@ -126,6 +134,8 @@ impl Shell for ValueShell {
if target == PathBuf::from("..") {
cwd.pop();
} else if target == PathBuf::from("-") {
cwd = PathBuf::from(&self.last_path);
} else {
match target.to_str() {
Some(target) => match target.chars().nth(0) {
@ -200,19 +210,16 @@ impl Shell for ValueShell {
}
fn pwd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
let path = PathBuf::from(&self.path());
let mut stream = VecDeque::new();
stream.push_back(ReturnSuccess::value(
Value::Primitive(Primitive::String(path.to_string_lossy().to_string()))
.simple_spanned(args.call_info.name_span),
));
stream.push_back(ReturnSuccess::value(Tagged::from_item(
Value::string(self.path()),
args.call_info.name_span,
)));
Ok(stream.into())
}
fn set_path(&mut self, path: String) {
let _ = std::env::set_current_dir(&path);
self.last_path = self.path.clone();
self.path = path.clone();
}

View File

@ -1,9 +1,124 @@
mod helpers;
use helpers::Playground;
use helpers::{Playground, Stub::*};
use std::path::PathBuf;
#[test]
fn cd_directory_not_found() {
fn filesystem_change_from_current_directory_using_relative_path() {
Playground::setup("cd_test_1", |dirs, _| {
let actual = nu!(
cwd: dirs.root(),
r#"
cd cd_test_1
pwd | echo $it
"#
);
assert_eq!(PathBuf::from(actual), *dirs.test());
})
}
#[test]
fn filesystem_change_from_current_directory_using_absolute_path() {
Playground::setup("cd_test_2", |dirs, _| {
let actual = nu!(
cwd: dirs.test(),
r#"
cd {}
pwd | echo $it
"#,
dirs.formats()
);
assert_eq!(PathBuf::from(actual), dirs.formats());
})
}
#[test]
fn filesystem_switch_back_to_previous_working_directory() {
Playground::setup("cd_test_3", |dirs, sandbox| {
sandbox.mkdir("odin");
let actual = nu!(
cwd: dirs.test().join("odin"),
r#"
cd {}
cd -
pwd | echo $it
"#,
dirs.test()
);
assert_eq!(PathBuf::from(actual), dirs.test().join("odin"));
})
}
#[test]
fn filesytem_change_from_current_directory_using_relative_path_and_dash() {
Playground::setup("cd_test_4", |dirs, sandbox| {
sandbox.within("odin").mkdir("-");
let actual = nu!(
cwd: dirs.test(),
r#"
cd odin/-
pwd | echo $it
"#
);
assert_eq!(PathBuf::from(actual), dirs.test().join("odin").join("-"));
})
}
#[test]
fn filesystem_change_current_directory_to_parent_directory() {
Playground::setup("cd_test_5", |dirs, _| {
let actual = nu!(
cwd: dirs.test(),
r#"
cd ..
pwd | echo $it
"#
);
assert_eq!(PathBuf::from(actual), *dirs.root());
})
}
#[test]
fn filesystem_change_to_home_directory() {
Playground::setup("cd_test_6", |dirs, _| {
let actual = nu!(
cwd: dirs.test(),
r#"
cd ~
pwd | echo $it
"#
);
assert_eq!(PathBuf::from(actual), dirs::home_dir().unwrap());
})
}
#[test]
fn filesystem_change_to_a_directory_containing_spaces() {
Playground::setup("cd_test_7", |dirs, sandbox| {
sandbox.mkdir("robalino turner katz");
let actual = nu!(
cwd: dirs.test(),
r#"
cd "robalino turner katz"
pwd | echo $it
"#
);
assert_eq!(PathBuf::from(actual), dirs.test().join("robalino turner katz"));
})
}
#[test]
fn filesystem_directory_not_found() {
let actual = nu_error!(
cwd: "tests/fixtures",
"cd dir_that_does_not_exist"
@ -13,34 +128,237 @@ fn cd_directory_not_found() {
assert!(actual.contains("directory not found"));
}
#[test]
fn cd_back() {
Playground::setup("cd_test_back", |dirs, sandbox| {
fn valuesystem_change_from_current_path_using_relative_path() {
Playground::setup("cd_test_8", |dirs, sandbox| {
sandbox
.mkdir("andres")
.mkdir("odin");
.with_files(vec![FileWithContent(
"sample.toml",
r#"
[[bin]]
path = "src/plugins/turner.rs"
let odin = dirs.test().join("odin");
let andres = dirs.test().join("andres");
[[bin]]
path = "src/plugins/robalino.rs"
nu!(
[[bin]]
path = "src/plugins/katz.rs"
"#
)]);
let actual = nu!(
cwd: dirs.test(),
r#"
cd odin
mkdir a
cd ../andres
mkdir b
cd -
mkdir c
mkdir -
cd -
mkdir d
enter sample.toml
cd bin
pwd | echo $it
exit
"#
);
assert!(odin.join("a").exists());
assert!(andres.join("b").exists());
assert!(odin.join("c").exists());
assert!(odin.join("-").join("d").exists());
assert_eq!(PathBuf::from(actual), PathBuf::from("/bin"));
})
}
#[test]
fn valuesystem_change_from_current_path_using_absolute_path() {
Playground::setup("cd_test_9", |dirs, sandbox| {
sandbox
.with_files(vec![FileWithContent(
"sample.toml",
r#"
[dependencies]
turner-ts = "0.1.1"
robalino-tkd = "0.0.1"
katz-ember = "0.2.3"
[[bin]]
path = "src/plugins/arepa.rs"
[[bin]]
path = "src/plugins/bbq.rs"
"#
)]);
let actual = nu!(
cwd: dirs.test(),
r#"
enter sample.toml
cd bin
cd /dependencies
pwd | echo $it
exit
"#
);
assert_eq!(PathBuf::from(actual), PathBuf::from("/dependencies"));
})
}
#[test]
fn valuesystem_switch_back_to_previous_working_path() {
Playground::setup("cd_test_10", |dirs, sandbox| {
sandbox
.with_files(vec![FileWithContent(
"sample.toml",
r#"
[dependencies]
turner-ts = "0.1.1"
robalino-tkd = "0.0.1"
katz-ember = "0.2.3"
odin-gf = "0.2.1"
[[bin]]
path = "src/plugins/arepa.rs"
[[bin]]
path = "src/plugins/bbq.rs"
"#
)]);
let actual = nu!(
cwd: dirs.test(),
r#"
enter sample.toml
cd dependencies
cd /bin
cd -
pwd | echo $it
exit
"#
);
assert_eq!(PathBuf::from(actual), PathBuf::from("/dependencies"));
})
}
#[test]
fn valuesystem_change_from_current_path_using_relative_path_and_dash() {
Playground::setup("cd_test_11", |dirs, sandbox| {
sandbox
.with_files(vec![FileWithContent(
"sample.toml",
r#"
[package]
- = ["Yehuda Katz <wycats@gmail.com>", "Jonathan Turner <jonathan.d.turner@gmail.com>", "Andrés N. Robalino <andres@androbtech.com>"]
[[bin]]
path = "src/plugins/arepa.rs"
[[bin]]
path = "src/plugins/bbq.rs"
"#
)]);
let actual = nu!(
cwd: dirs.test(),
r#"
enter sample.toml
cd package/-
cd /bin
cd -
pwd | echo $it
exit
"#
);
assert_eq!(PathBuf::from(actual), PathBuf::from("/package/-"));
})
}
#[test]
fn valuesystem_change_current_path_to_parent_path() {
Playground::setup("cd_test_12", |dirs, sandbox| {
sandbox
.with_files(vec![FileWithContent(
"sample.toml",
r#"
[package]
emberenios = ["Yehuda Katz <wycats@gmail.com>", "Jonathan Turner <jonathan.d.turner@gmail.com>", "Andrés N. Robalino <andres@androbtech.com>"]
"#
)]);
let actual = nu!(
cwd: dirs.test(),
r#"
enter sample.toml
cd package/emberenios
cd ..
pwd | echo $it
exit
"#
);
assert_eq!(PathBuf::from(actual), PathBuf::from("/package"));
})
}
#[test]
fn valuesystem_change_to_home_directory() {
Playground::setup("cd_test_13", |dirs, sandbox| {
sandbox
.with_files(vec![FileWithContent(
"sample.toml",
r#"
[paquete]
el = "pollo loco"
"#
)]);
let actual = nu!(
cwd: dirs.test(),
r#"
enter sample.toml
cd paquete
cd ~
pwd | echo $it
exit
"#
);
assert_eq!(PathBuf::from(actual), PathBuf::from("/"));
})
}
#[test]
fn valuesystem_change_to_a_path_containing_spaces() {
Playground::setup("cd_test_14", |dirs, sandbox| {
sandbox
.with_files(vec![FileWithContent(
"sample.toml",
r#"
["pa que te"]
el = "pollo loco"
"#
)]);
let actual = nu!(
cwd: dirs.test(),
r#"
enter sample.toml
cd "pa que te"
pwd | echo $it
exit
"#
);
assert_eq!(PathBuf::from(actual), PathBuf::from("/").join("pa que te"));
})
}
#[test]
fn valuesystem_path_not_found() {
let actual = nu_error!(
cwd: "tests/fixtures/formats",
r#"
enter cargo_sample.toml
cd im_a_path_that_does_not_exist
exit
"#
);
assert!(actual.contains("Can not change to path inside"));
assert!(actual.contains("No such path exists"));
}

View File

@ -227,8 +227,14 @@ impl Playground {
playground_root.join(topic).display()
));
let root =
dunce::canonicalize(playground_root).expect(&format!(
"Couldn't canonicalize tests root path {}",
playground_root.display()
));
let dirs = Dirs {
root: PathBuf::from(playground_root),
root,
test,
fixtures,
};