From 922f40163a6b66da76794dde39866108ed506360 Mon Sep 17 00:00:00 2001 From: Jake Deichert Date: Sat, 27 Jul 2019 14:36:39 -0400 Subject: [PATCH 01/13] Add $MASK and $MASKFILE_DIR utility env variables --- src/executor.rs | 33 +++++++++++++++- src/main.rs | 8 ++-- tests/env_vars_test.rs | 89 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 tests/env_vars_test.rs diff --git a/src/executor.rs b/src/executor.rs index b9b9076..a8cef7b 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -1,10 +1,12 @@ +use std::fs::canonicalize; use std::io::Result; +use std::path::{Path, PathBuf}; use std::process; use std::process::ExitStatus; use crate::command::Command; -pub fn execute_command(cmd: Command) -> Result { +pub fn execute_command(cmd: Command, maskfile_path: String) -> Result { let mut child = match cmd.executor.as_ref() { "js" | "javascript" => { let mut child = process::Command::new("node"); @@ -38,6 +40,8 @@ pub fn execute_command(cmd: Command) -> Result { } }; + child = add_utility_variables(child, maskfile_path); + // Add all required args as environment variables for arg in cmd.required_args { child.env(arg.name, arg.val); @@ -52,3 +56,30 @@ pub fn execute_command(cmd: Command) -> Result { child.spawn()?.wait() } + +// Add some useful environment variables that scripts can use +fn add_utility_variables(mut child: process::Command, maskfile_path: String) -> process::Command { + let maskfile_path = PathBuf::from(maskfile_path); + + // Find the absolute path to the maskfile + let absolute_path = canonicalize(&maskfile_path) + .expect("canonicalize maskfile path failed") + .to_str() + .unwrap() + .to_string(); + let absolute_path = Path::new(&absolute_path); + let absolute_path_str = absolute_path.to_str().unwrap(); + + // Find the absolute path to the maskfile's parent directory + let parent_dir = absolute_path.parent().unwrap().to_str().unwrap(); + + // This allows us to call "$MASK command" instead of "mask --maskfile command" + // inside scripts so that they can be location-agnostic (not care where they are + // called from). This is useful for global maskfiles especially. + child.env("MASK", format!("mask --maskfile {}", absolute_path_str)); + // This allows us to refer to the directory the maskfile lives in which can be handy + // for loading relative files to it. + child.env("MASKFILE_DIR", parent_dir); + + child +} diff --git a/src/main.rs b/src/main.rs index d3609b2..e91ed45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,7 @@ fn main() { .about(crate_description!()) .arg(custom_maskfile_path_arg()); - let maskfile = find_maskfile(); + let (maskfile, maskfile_path) = find_maskfile(); if maskfile.is_err() { // If the maskfile can't be found, at least parse for --version or --help cli_app.get_matches(); @@ -31,7 +31,7 @@ fn main() { std::process::exit(1); } - match mask::executor::execute_command(chosen_cmd.unwrap()) { + match mask::executor::execute_command(chosen_cmd.unwrap(), maskfile_path) { Ok(status) => match status.code() { Some(code) => std::process::exit(code), None => return, @@ -40,7 +40,7 @@ fn main() { } } -fn find_maskfile() -> Result { +fn find_maskfile() -> (Result, String) { let args: Vec = env::args().collect(); let maybe_maskfile = args.get(1); @@ -68,7 +68,7 @@ fn find_maskfile() -> Result { } } - maskfile + (maskfile, maskfile_path.to_str().unwrap().to_string()) } fn custom_maskfile_path_arg<'a, 'b>() -> Arg<'a, 'b> { diff --git a/tests/env_vars_test.rs b/tests/env_vars_test.rs new file mode 100644 index 0000000..1e80b07 --- /dev/null +++ b/tests/env_vars_test.rs @@ -0,0 +1,89 @@ +use assert_cmd::prelude::*; +use predicates::str::contains; + +mod common; +use common::MaskCommandExt; + +// Using current_dir(".github") to make sure the default maskfile.md can't be found +mod env_var_mask { + use super::*; + + #[test] + fn works_from_any_dir() { + let (_temp, maskfile_path) = common::maskfile( + r#" +## ci + +~~~bash +$MASK test +~~~ + +## test + +~~~bash +echo "tests passed" +~~~ +"#, + ); + + common::run_mask(&maskfile_path) + .current_dir(".github") + .command("ci") + .assert() + .stdout(contains("tests passed")) + .success(); + } + + #[test] + fn set_to_the_correct_value() { + let (temp, maskfile_path) = common::maskfile( + r#" +## run + +~~~bash +echo "mask = $MASK" +~~~ +"#, + ); + + common::run_mask(&maskfile_path) + .current_dir(".github") + .command("run") + .assert() + // Needs "/private" because the temp dir is "/var" which is a symlink to "/private/var". + .stdout(contains(format!( + "mask = mask --maskfile /private{}/maskfile.md", + temp.path().to_str().unwrap().to_string() + ))) + .success(); + } +} + +// Using current_dir(".github") to make sure the default maskfile.md can't be found +mod env_var_maskfile_dir { + use super::*; + + #[test] + fn set_to_the_correct_value() { + let (temp, maskfile_path) = common::maskfile( + r#" +## run + +~~~bash +echo "maskfile_dir = $MASKFILE_DIR" +~~~ +"#, + ); + + common::run_mask(&maskfile_path) + .current_dir(".github") + .command("run") + .assert() + // Needs "/private" because the temp dir is "/var" which is a symlink to "/private/var". + .stdout(contains(format!( + "maskfile_dir = /private{}", + temp.path().to_str().unwrap().to_string() + ))) + .success(); + } +} From f46adc0fdf261d3d1f868206d74e0d32bbe51a3b Mon Sep 17 00:00:00 2001 From: Jake Deichert Date: Sat, 27 Jul 2019 15:46:39 -0400 Subject: [PATCH 02/13] Update docs on running mask from within scripts --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7ef3f56..4bca302 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ -

- + [![build status](https://img.shields.io/circleci/build/github/jakedeichert/mask/master.svg)][circleci] [![mask version](https://img.shields.io/crates/v/mask.svg)][crate] @@ -263,7 +262,7 @@ ARGS: ### Running mask from within a script -You can easily call `mask` within scripts if you need to chain commands together. +You can easily call `mask` within scripts if you need to chain commands together. However, if you plan on [running mask with a different maskfile](#running-mask-with-a-different-maskfile), you should consider using the `$MASK` utility instead which allows your scripts to be location-agnostic. **Example:** @@ -276,8 +275,10 @@ You can easily call `mask` within scripts if you need to chain commands together mask install mask build mask link -mask db migrate -mask start +# $MASK also works. It's an alias variable for `mask --maskfile ` +# which allows an externally referenced maskfile to be called from anywhere. +$MASK db migrate +$MASK start ~~~ ``` From 60604c214e76d72700d5764cea6b2fd4c4f876fd Mon Sep 17 00:00:00 2001 From: Jake Deichert Date: Sat, 27 Jul 2019 15:47:33 -0400 Subject: [PATCH 03/13] Update comment --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4bca302..4836159 100644 --- a/README.md +++ b/README.md @@ -276,7 +276,8 @@ mask install mask build mask link # $MASK also works. It's an alias variable for `mask --maskfile ` -# which allows an externally referenced maskfile to be called from anywhere. +# which guarantees your scripts will still work even if they are called from +# another directory. $MASK db migrate $MASK start ~~~ From b65b8b7e346a5745f22b38111732290605372ced Mon Sep 17 00:00:00 2001 From: Jake Deichert Date: Sat, 27 Jul 2019 15:49:48 -0400 Subject: [PATCH 04/13] Use crate_name!() instead of hardcoded name --- src/executor.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/executor.rs b/src/executor.rs index a8cef7b..0dca826 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -4,6 +4,8 @@ use std::path::{Path, PathBuf}; use std::process; use std::process::ExitStatus; +use clap::crate_name; + use crate::command::Command; pub fn execute_command(cmd: Command, maskfile_path: String) -> Result { @@ -76,7 +78,7 @@ fn add_utility_variables(mut child: process::Command, maskfile_path: String) -> // This allows us to call "$MASK command" instead of "mask --maskfile command" // inside scripts so that they can be location-agnostic (not care where they are // called from). This is useful for global maskfiles especially. - child.env("MASK", format!("mask --maskfile {}", absolute_path_str)); + child.env("MASK", format!("{} --maskfile {}", crate_name!(), absolute_path_str)); // This allows us to refer to the directory the maskfile lives in which can be handy // for loading relative files to it. child.env("MASKFILE_DIR", parent_dir); From f9c9d7e72e00a1c123be72ca8910c87cc56003e3 Mon Sep 17 00:00:00 2001 From: Jake Deichert Date: Sat, 27 Jul 2019 15:50:34 -0400 Subject: [PATCH 05/13] Format --- src/executor.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/executor.rs b/src/executor.rs index 0dca826..6e945c6 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -78,7 +78,10 @@ fn add_utility_variables(mut child: process::Command, maskfile_path: String) -> // This allows us to call "$MASK command" instead of "mask --maskfile command" // inside scripts so that they can be location-agnostic (not care where they are // called from). This is useful for global maskfiles especially. - child.env("MASK", format!("{} --maskfile {}", crate_name!(), absolute_path_str)); + child.env( + "MASK", + format!("{} --maskfile {}", crate_name!(), absolute_path_str), + ); // This allows us to refer to the directory the maskfile lives in which can be handy // for loading relative files to it. child.env("MASKFILE_DIR", parent_dir); From 896632fde9ef6857fb9390077eec846348ce8905 Mon Sep 17 00:00:00 2001 From: Jake Deichert Date: Sat, 27 Jul 2019 16:03:09 -0400 Subject: [PATCH 06/13] Try setting alias to fix certain test suites that depend on mask being available --- .circleci/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1347d2c..6e15fdb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -48,6 +48,9 @@ jobs: - run: name: Install other runtimes command: apt-get update && apt-get install -y ruby-full php + - run: + name: Set mask alias for certain test suites that depend on it + command: alias mask="./target/debug/mask" - run: name: Run tests command: cargo test --verbose --frozen From 0da669655e5589ee6fca23df3ab712c458676dbe Mon Sep 17 00:00:00 2001 From: Jake Deichert Date: Sat, 27 Jul 2019 16:24:51 -0400 Subject: [PATCH 07/13] Try to make tests more environment-agnostic --- .circleci/config.yml | 6 ++---- tests/env_vars_test.rs | 20 ++++++++------------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6e15fdb..3506258 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -48,12 +48,10 @@ jobs: - run: name: Install other runtimes command: apt-get update && apt-get install -y ruby-full php - - run: - name: Set mask alias for certain test suites that depend on it - command: alias mask="./target/debug/mask" - run: name: Run tests - command: cargo test --verbose --frozen + # Set mask alias for certain test suites that depend on it + command: alias mask="./target/debug/mask" && cargo test --verbose --frozen workflows: pr_test: diff --git a/tests/env_vars_test.rs b/tests/env_vars_test.rs index 1e80b07..f50aaba 100644 --- a/tests/env_vars_test.rs +++ b/tests/env_vars_test.rs @@ -36,7 +36,7 @@ echo "tests passed" #[test] fn set_to_the_correct_value() { - let (temp, maskfile_path) = common::maskfile( + let (_temp, maskfile_path) = common::maskfile( r#" ## run @@ -50,11 +50,10 @@ echo "mask = $MASK" .current_dir(".github") .command("run") .assert() - // Needs "/private" because the temp dir is "/var" which is a symlink to "/private/var". - .stdout(contains(format!( - "mask = mask --maskfile /private{}/maskfile.md", - temp.path().to_str().unwrap().to_string() - ))) + // Absolute maskfile path starts with / + .stdout(contains("mask = mask --maskfile /")) + // And ends with maskfile.md + .stdout(contains("maskfile.md")) .success(); } } @@ -65,7 +64,7 @@ mod env_var_maskfile_dir { #[test] fn set_to_the_correct_value() { - let (temp, maskfile_path) = common::maskfile( + let (_temp, maskfile_path) = common::maskfile( r#" ## run @@ -79,11 +78,8 @@ echo "maskfile_dir = $MASKFILE_DIR" .current_dir(".github") .command("run") .assert() - // Needs "/private" because the temp dir is "/var" which is a symlink to "/private/var". - .stdout(contains(format!( - "maskfile_dir = /private{}", - temp.path().to_str().unwrap().to_string() - ))) + // Absolute maskfile path starts with / + .stdout(contains("maskfile_dir = /")) .success(); } } From 4189880c5bd69c449b384e497dfd01974a992ce9 Mon Sep 17 00:00:00 2001 From: Jake Deichert Date: Sat, 27 Jul 2019 16:33:22 -0400 Subject: [PATCH 08/13] Try bash func instead of alias --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3506258..c1cd94c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -50,8 +50,8 @@ jobs: command: apt-get update && apt-get install -y ruby-full php - run: name: Run tests - # Set mask alias for certain test suites that depend on it - command: alias mask="./target/debug/mask" && cargo test --verbose --frozen + # Set a mask alias/func for certain test suites that depend on it + command: mask() { ./target/debug/mask; } && cargo test --verbose --frozen workflows: pr_test: From b13b3729fab43dcc50d095e78f65086d949edfff Mon Sep 17 00:00:00 2001 From: Jake Deichert Date: Sat, 27 Jul 2019 17:38:10 -0400 Subject: [PATCH 09/13] Try PATH env to make mask available --- .circleci/config.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c1cd94c..416a9ce 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -50,8 +50,10 @@ jobs: command: apt-get update && apt-get install -y ruby-full php - run: name: Run tests - # Set a mask alias/func for certain test suites that depend on it - command: mask() { ./target/debug/mask; } && cargo test --verbose --frozen + command: cargo test --verbose --frozen + environment: + # mask needs to be available for certain test suites that depend on it + PATH: "$PATH:~/repo/target/debug" workflows: pr_test: From b3e4a1ebc131838969e972a3ce62ac1bac7b7ac5 Mon Sep 17 00:00:00 2001 From: Jake Deichert Date: Sat, 27 Jul 2019 17:39:11 -0400 Subject: [PATCH 10/13] Fix circleci config indent --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 416a9ce..ff59d8d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -51,9 +51,9 @@ jobs: - run: name: Run tests command: cargo test --verbose --frozen - environment: # mask needs to be available for certain test suites that depend on it - PATH: "$PATH:~/repo/target/debug" + environment: + PATH: "$PATH:~/repo/target/debug" workflows: pr_test: From 6cd87ffd329620a6c7d0f157a54a4337bd0b83e7 Mon Sep 17 00:00:00 2001 From: Jake Deichert Date: Sat, 27 Jul 2019 17:44:44 -0400 Subject: [PATCH 11/13] Try setting PATH again --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ff59d8d..5eb32af 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -42,6 +42,9 @@ jobs: steps: - *attach_workspace - *restore_cache + - run: + name: Make mask available for certain test suites that depend on it + command: export PATH="$PATH:~/repo/target/debug" - run: name: Install latest node from PPA command: apt-get update && apt-get install -y curl software-properties-common && curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt-get install nodejs @@ -51,9 +54,6 @@ jobs: - run: name: Run tests command: cargo test --verbose --frozen - # mask needs to be available for certain test suites that depend on it - environment: - PATH: "$PATH:~/repo/target/debug" workflows: pr_test: From 928615cc62ecd5527fb0bf0951087bce595896bc Mon Sep 17 00:00:00 2001 From: Jake Deichert Date: Sat, 27 Jul 2019 17:51:34 -0400 Subject: [PATCH 12/13] Maybe this will work --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5eb32af..93c9476 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -44,7 +44,7 @@ jobs: - *restore_cache - run: name: Make mask available for certain test suites that depend on it - command: export PATH="$PATH:~/repo/target/debug" + command: echo 'export PATH="$PATH:~/repo/target/debug"' >> $BASH_ENV - run: name: Install latest node from PPA command: apt-get update && apt-get install -y curl software-properties-common && curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt-get install nodejs From 422bacf4c89592d861b618b1114b124193669ec5 Mon Sep 17 00:00:00 2001 From: Jake Deichert Date: Sat, 27 Jul 2019 18:04:58 -0400 Subject: [PATCH 13/13] Add note about mask bin dependency --- tests/env_vars_test.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/env_vars_test.rs b/tests/env_vars_test.rs index f50aaba..48ed484 100644 --- a/tests/env_vars_test.rs +++ b/tests/env_vars_test.rs @@ -4,6 +4,8 @@ use predicates::str::contains; mod common; use common::MaskCommandExt; +// NOTE: This test suite depends on the mask binary being available in the current shell + // Using current_dir(".github") to make sure the default maskfile.md can't be found mod env_var_mask { use super::*;