Skip to content

Commit

Permalink
Merge pull request #26 from jakedeichert/utility-env-vars
Browse files Browse the repository at this point in the history
Add $MASK and $MASKFILE_DIR utility env variables
  • Loading branch information
jacobdeichert authored Jul 27, 2019
2 parents fbba139 + 422bacf commit e12344c
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 10 deletions.
3 changes: 3 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ jobs:
steps:
- *attach_workspace
- *restore_cache
- run:
name: Make mask available for certain test suites that depend on it
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
Expand Down
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@

<p align="center">
<img height="180" width="210" src="https://user-images.githubusercontent.com/1631044/61989571-aae27580-afff-11e9-8f8a-c9768ed7a6b8.png">
</p>


[![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]
Expand Down Expand Up @@ -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:**

Expand All @@ -276,8 +275,11 @@ 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 <path_to_maskfile>`
# which guarantees your scripts will still work even if they are called from
# another directory.
$MASK db migrate
$MASK start
~~~
```

Expand Down
38 changes: 37 additions & 1 deletion src/executor.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use std::fs::canonicalize;
use std::io::Result;
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) -> Result<ExitStatus> {
pub fn execute_command(cmd: Command, maskfile_path: String) -> Result<ExitStatus> {
let mut child = match cmd.executor.as_ref() {
"js" | "javascript" => {
let mut child = process::Command::new("node");
Expand Down Expand Up @@ -38,6 +42,8 @@ pub fn execute_command(cmd: Command) -> Result<ExitStatus> {
}
};

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);
Expand All @@ -52,3 +58,33 @@ pub fn execute_command(cmd: Command) -> Result<ExitStatus> {

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 <path> 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),
);
// 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
}
8 changes: 4 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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,
Expand All @@ -40,7 +40,7 @@ fn main() {
}
}

fn find_maskfile() -> Result<String, String> {
fn find_maskfile() -> (Result<String, String>, String) {
let args: Vec<String> = env::args().collect();

let maybe_maskfile = args.get(1);
Expand Down Expand Up @@ -68,7 +68,7 @@ fn find_maskfile() -> Result<String, String> {
}
}

maskfile
(maskfile, maskfile_path.to_str().unwrap().to_string())
}

fn custom_maskfile_path_arg<'a, 'b>() -> Arg<'a, 'b> {
Expand Down
87 changes: 87 additions & 0 deletions tests/env_vars_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use assert_cmd::prelude::*;
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::*;

#[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()
// Absolute maskfile path starts with /
.stdout(contains("mask = mask --maskfile /"))
// And ends with maskfile.md
.stdout(contains("maskfile.md"))
.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()
// Absolute maskfile path starts with /
.stdout(contains("maskfile_dir = /"))
.success();
}
}

0 comments on commit e12344c

Please sign in to comment.