Commit 28ecbe7b authored by Wohlgemuth, Jason's avatar Wohlgemuth, Jason
Browse files

feat: Initial local binary module support

parent 64c2576d
Loading
Loading
Loading
Loading
Loading
+363 −337
Original line number Diff line number Diff line
@@ -200,55 +200,46 @@ DA:182,0
DA:184,0
DA:186,0
DA:189,0
DA:190,0
DA:191,0
DA:192,0
DA:193,0
DA:194,0
DA:195,0
DA:196,0
DA:197,0
DA:198,0
DA:199,0
DA:200,0
DA:202,0
DA:204,0
DA:203,0
DA:206,0
DA:208,0
DA:209,0
DA:210,0
DA:212,0
DA:213,0
DA:211,0
DA:214,0
DA:217,0
DA:215,0
DA:216,0
DA:218,0
DA:221,0
DA:220,0
DA:222,0
DA:223,0
DA:224,0
DA:225,0
DA:226,0
DA:228,0
DA:229,0
DA:232,0
DA:227,0
DA:230,0
DA:231,0
DA:233,0
DA:234,0
DA:235,0
DA:236,0
DA:237,0
DA:238,0
DA:239,0
DA:240,0
DA:241,0
DA:244,0
DA:242,0
DA:245,0
DA:246,0
DA:247,0
DA:248,0
DA:249,0
DA:250,0
DA:251,0
DA:252,0
DA:253,0
DA:254,0
DA:256,0
DA:259,0
DA:262,0
DA:265,0
DA:267,0
DA:270,0
DA:272,0
LF:137
DA:255,0
LF:128
LH:0
end_of_record
TN:
@@ -381,58 +372,60 @@ FN:496,EnvironmentValue::from_string
FN:499,EnvironmentValue::from_value
FN:507,EnvironmentValue::prepend_prefix
FN:511,EnvironmentValue::trim_prefix
FN:515,EnvironmentValue::get_from_serde
FN:529,EnvironmentValue::get_all
FN:539,EnvironmentValue::print_all
FN:544,EnvironmentValue::set_variable
FN:554,EnvironmentValue::set_variables
FN:561,Extension::from_string
FN:570,Label::dry_run
FN:574,Label::fail
FN:578,Label::found
FN:582,Label::not_found
FN:586,Label::output
FN:590,Label::read
FN:594,Label::rejected
FN:598,Label::run
FN:602,Label::using
FN:608,ModuleUri<'_>::from
FN:618,ModuleUri<'_>::hash
FN:642,ModuleUri<'_>::get_whitelist
FN:645,ModuleUri<'_>::is_allowed
FN:648,ModuleUri<'_>::test
FN:649,ModuleUri<'_>::test::check
FN:666,ModuleUri<'_>::working_directory
FN:678,SemanticVersion::from_string
FN:701,Script::expand_arguments
FN:736,Script::expand_arguments_from
FN:768,Script::from_template
FN:796,Script::from_path
FN:808,Script::get_command
FN:814,Script::get_arguments
FN:825,Script::maybe_create_conda_environment
FN:858,Script::maybe_git_clone
FN:865,Script::python_default
FN:879,Script::run
FN:950,Script::with_current_dir
FN:988,Script::with_environment
FN:993,Script::with_envs
FN:1002,StringTemplate::new
FN:1011,StringTemplate::expand
FN:1018,StringTemplate::get_variable
FN:1048,StringTemplate::is_handlebars
FN:1083,StringTemplate::remove_spaces
FN:1093,add_forward_slash
FN:1101,get_conda_environment_list
FN:1143,get_conda_environment_name
FN:1175,get_extension
FN:1179,get_parent
FN:1192,has_extension
FN:1196,is_stdin_piped
FN:1204,is_stdout_piped
FN:1222,read_file
FN:1236,to_string
FNF:61
FN:515,EnvironmentValue::get_from_config
FN:522,EnvironmentValue::get_from_serde
FN:536,EnvironmentValue::get_all
FN:546,EnvironmentValue::print_all
FN:551,EnvironmentValue::set_variable
FN:561,EnvironmentValue::set_variables
FN:568,Extension::from_string
FN:577,Label::dry_run
FN:581,Label::fail
FN:585,Label::found
FN:589,Label::not_found
FN:593,Label::output
FN:597,Label::read
FN:601,Label::rejected
FN:605,Label::run
FN:609,Label::using
FN:615,ModuleUri<'_>::from
FN:625,ModuleUri<'_>::hash
FN:649,ModuleUri<'_>::get_whitelist
FN:652,ModuleUri<'_>::is_allowed
FN:655,ModuleUri<'_>::test
FN:656,ModuleUri<'_>::test::check
FN:673,ModuleUri<'_>::working_directory
FN:685,SemanticVersion::from_string
FN:708,Script::expand_arguments
FN:743,Script::expand_arguments_from
FN:778,Script::from_module
FN:836,Script::from_path
FN:859,Script::from_template
FN:876,Script::get_command
FN:882,Script::get_arguments
FN:893,Script::maybe_create_conda_environment
FN:926,Script::maybe_git_clone
FN:933,Script::python_default
FN:947,Script::run
FN:1018,Script::with_current_dir
FN:1056,Script::with_environment
FN:1061,Script::with_envs
FN:1070,StringTemplate::new
FN:1079,StringTemplate::expand
FN:1086,StringTemplate::get_variable
FN:1116,StringTemplate::is_handlebars
FN:1151,StringTemplate::remove_spaces
FN:1161,add_forward_slash
FN:1169,get_conda_environment_list
FN:1211,get_conda_environment_name
FN:1243,get_extension
FN:1247,get_parent
FN:1260,has_extension
FN:1264,is_stdin_piped
FN:1272,is_stdout_piped
FN:1290,read_file
FN:1304,to_string
FNF:63
FNDA:1,Command::test
FNDA:1,Config::read
FNDA:1,Config::read_json
@@ -443,6 +436,7 @@ FNDA:0,EnvironmentValue::from_string
FNDA:0,EnvironmentValue::from_value
FNDA:0,EnvironmentValue::prepend_prefix
FNDA:1,EnvironmentValue::trim_prefix
FNDA:0,EnvironmentValue::get_from_config
FNDA:0,EnvironmentValue::get_from_serde
FNDA:1,EnvironmentValue::get_all
FNDA:0,EnvironmentValue::print_all
@@ -468,9 +462,10 @@ FNDA:0,ModuleUri<'_>::working_directory
FNDA:1,SemanticVersion::from_string
FNDA:1,Script::expand_arguments
FNDA:1,Script::expand_arguments_from
FNDA:1,Script::from_template
FNDA:0,Script::from_module
FNDA:1,Script::from_path
FNDA:2,Script::get_command
FNDA:1,Script::from_template
FNDA:1,Script::get_command
FNDA:2,Script::get_arguments
FNDA:0,Script::maybe_create_conda_environment
FNDA:1,Script::maybe_git_clone
@@ -567,316 +562,347 @@ DA:517,0
DA:518,0
DA:519,0
DA:520,0
DA:521,0
DA:522,0
DA:523,0
DA:524,0
DA:525,0
DA:526,0
DA:527,0
DA:529,1
DA:530,1
DA:531,2
DA:532,2
DA:533,2
DA:534,2
DA:535,1
DA:539,0
DA:540,0
DA:541,0
DA:544,0
DA:545,0
DA:528,0
DA:529,0
DA:530,0
DA:532,0
DA:534,0
DA:536,1
DA:537,1
DA:538,2
DA:539,2
DA:540,2
DA:541,2
DA:542,1
DA:546,0
DA:547,0
DA:548,0
DA:549,0
DA:550,0
DA:551,0
DA:552,0
DA:553,0
DA:554,0
DA:555,0
DA:556,0
DA:557,0
DA:561,1
DA:562,2
DA:563,2
DA:564,3
DA:565,0
DA:570,0
DA:571,0
DA:561,0
DA:562,0
DA:564,0
DA:568,1
DA:569,2
DA:570,2
DA:571,3
DA:572,0
DA:574,0
DA:575,0
DA:576,0
DA:577,0
DA:578,0
DA:579,0
DA:580,0
DA:581,0
DA:582,0
DA:583,0
DA:584,0
DA:586,1
DA:587,3
DA:588,3
DA:585,0
DA:586,0
DA:587,0
DA:589,0
DA:590,0
DA:591,0
DA:592,0
DA:594,0
DA:595,0
DA:596,0
DA:593,1
DA:594,3
DA:595,3
DA:597,0
DA:598,0
DA:599,0
DA:600,0
DA:601,0
DA:602,0
DA:603,0
DA:604,0
DA:608,1
DA:609,1
DA:610,2
DA:611,1
DA:612,2
DA:613,0
DA:605,0
DA:606,0
DA:607,0
DA:609,0
DA:610,0
DA:611,0
DA:615,1
DA:616,1
DA:617,2
DA:618,1
DA:619,1
DA:620,1
DA:621,1
DA:619,2
DA:620,0
DA:622,1
DA:623,0
DA:625,3
DA:629,4
DA:630,4
DA:632,4
DA:633,2
DA:635,2
DA:638,0
DA:642,0
DA:643,0
DA:625,1
DA:626,1
DA:627,1
DA:628,1
DA:629,1
DA:630,0
DA:632,3
DA:636,4
DA:637,4
DA:639,4
DA:640,2
DA:642,2
DA:645,0
DA:646,0
DA:648,0
DA:649,0
DA:650,0
DA:652,0
DA:653,0
DA:654,0
DA:655,0
DA:656,0
DA:657,0
DA:658,0
DA:659,0
DA:660,0
DA:661,0
DA:662,0
DA:666,0
DA:663,0
DA:664,0
DA:665,0
DA:667,0
DA:668,0
DA:669,0
DA:670,0
DA:672,0
DA:673,0
DA:678,1
DA:679,1
DA:680,3
DA:681,3
DA:682,3
DA:701,1
DA:702,2
DA:705,2
DA:706,1
DA:707,2
DA:674,0
DA:675,0
DA:676,0
DA:677,0
DA:679,0
DA:680,0
DA:685,1
DA:686,1
DA:687,3
DA:688,3
DA:689,3
DA:708,1
DA:709,1
DA:711,2
DA:709,2
DA:712,2
DA:713,1
DA:714,2
DA:715,1
DA:716,1
DA:736,1
DA:737,2
DA:740,2
DA:741,1
DA:742,2
DA:743,2
DA:746,2
DA:718,2
DA:722,1
DA:723,1
DA:743,1
DA:744,2
DA:747,2
DA:748,1
DA:749,2
DA:750,2
DA:754,1
DA:753,2
DA:755,1
DA:768,1
DA:769,1
DA:770,3
DA:774,2
DA:776,2
DA:778,2
DA:781,1
DA:782,2
DA:783,3
DA:796,1
DA:797,2
DA:798,1
DA:800,0
DA:801,0
DA:804,2
DA:805,1
DA:806,1
DA:808,2
DA:809,2
DA:810,1
DA:811,2
DA:814,2
DA:815,2
DA:816,1
DA:817,1
DA:818,3
DA:819,2
DA:821,2
DA:825,0
DA:826,0
DA:827,0
DA:828,0
DA:830,0
DA:831,0
DA:832,0
DA:833,0
DA:834,0
DA:835,0
DA:837,0
DA:838,0
DA:839,0
DA:757,2
DA:761,1
DA:762,1
DA:778,0
DA:780,0
DA:781,0
DA:782,0
DA:785,0
DA:786,0
DA:787,0
DA:788,0
DA:789,0
DA:791,0
DA:792,0
DA:793,0
DA:796,0
DA:797,0
DA:798,0
DA:799,0
DA:802,0
DA:803,0
DA:804,0
DA:807,0
DA:809,0
DA:810,0
DA:813,0
DA:819,0
DA:820,0
DA:836,1
DA:837,2
DA:838,1
DA:840,0
DA:841,0
DA:842,0
DA:843,0
DA:845,0
DA:846,0
DA:849,0
DA:853,0
DA:854,0
DA:858,1
DA:859,2
DA:860,2
DA:861,2
DA:862,3
DA:863,1
DA:865,0
DA:866,0
DA:867,0
DA:875,0
DA:879,1
DA:880,2
DA:881,2
DA:882,4
DA:883,4
DA:884,5
DA:844,2
DA:845,1
DA:846,1
DA:859,1
DA:860,1
DA:861,3
DA:865,2
DA:867,2
DA:869,2
DA:872,1
DA:873,2
DA:874,3
DA:876,1
DA:877,2
DA:878,1
DA:879,2
DA:882,2
DA:883,2
DA:884,1
DA:885,1
DA:886,13
DA:887,4
DA:888,2
DA:886,3
DA:887,2
DA:889,2
DA:890,2
DA:891,2
DA:896,4
DA:897,2
DA:893,0
DA:894,0
DA:895,0
DA:896,0
DA:898,0
DA:899,0
DA:900,0
DA:903,2
DA:904,2
DA:905,4
DA:906,6
DA:907,4
DA:910,4
DA:911,2
DA:901,0
DA:902,0
DA:903,0
DA:905,0
DA:906,0
DA:907,0
DA:908,0
DA:909,0
DA:910,0
DA:911,0
DA:913,0
DA:914,0
DA:917,2
DA:918,2
DA:919,4
DA:920,0
DA:917,0
DA:921,0
DA:924,4
DA:925,2
DA:926,6
DA:922,0
DA:926,1
DA:927,2
DA:928,6
DA:929,6
DA:930,2
DA:932,3
DA:933,3
DA:934,2
DA:937,0
DA:938,0
DA:939,0
DA:928,2
DA:929,2
DA:930,3
DA:931,1
DA:933,0
DA:934,0
DA:935,0
DA:943,0
DA:944,0
DA:950,1
DA:951,2
DA:952,1
DA:988,2
DA:989,2
DA:990,2
DA:993,0
DA:994,0
DA:995,0
DA:947,1
DA:948,1
DA:949,2
DA:950,4
DA:951,4
DA:952,6
DA:953,2
DA:954,12
DA:955,3
DA:956,2
DA:957,2
DA:958,2
DA:959,2
DA:964,4
DA:965,2
DA:967,0
DA:968,0
DA:971,2
DA:972,2
DA:973,4
DA:974,6
DA:975,4
DA:978,4
DA:979,2
DA:981,0
DA:982,0
DA:985,2
DA:986,2
DA:987,4
DA:988,0
DA:989,0
DA:992,4
DA:993,2
DA:994,6
DA:995,2
DA:996,6
DA:997,6
DA:998,2
DA:1000,3
DA:1001,3
DA:1002,2
DA:1004,2
DA:1011,1
DA:1012,4
DA:1013,3
DA:1005,0
DA:1006,0
DA:1007,0
DA:1011,0
DA:1012,0
DA:1018,1
DA:1019,2
DA:1020,2
DA:1021,1
DA:1022,2
DA:1024,0
DA:1048,1
DA:1049,2
DA:1050,2
DA:1051,1
DA:1052,0
DA:1054,0
DA:1083,1
DA:1084,2
DA:1085,1
DA:1086,0
DA:1088,3
DA:1020,1
DA:1056,2
DA:1057,2
DA:1058,2
DA:1061,0
DA:1062,0
DA:1063,0
DA:1070,2
DA:1072,2
DA:1079,1
DA:1080,4
DA:1081,3
DA:1086,1
DA:1087,2
DA:1088,2
DA:1089,1
DA:1093,1
DA:1094,2
DA:1095,0
DA:1097,2
DA:1101,1
DA:1102,2
DA:1103,2
DA:1104,2
DA:1105,2
DA:1106,5
DA:1109,1
DA:1111,2
DA:1113,4
DA:1116,0
DA:1143,1
DA:1144,1
DA:1145,1
DA:1146,6
DA:1158,1
DA:1160,0
DA:1175,1
DA:1176,1
DA:1179,1
DA:1180,3
DA:1192,1
DA:1193,1
DA:1196,0
DA:1197,0
DA:1198,0
DA:1200,0
DA:1204,0
DA:1205,0
DA:1206,0
DA:1208,0
DA:1222,1
DA:1223,1
DA:1224,6
DA:1225,3
DA:1226,9
DA:1227,7
DA:1229,1
DA:1230,3
DA:1231,1
DA:1234,4
DA:1236,1
DA:1237,4
LF:383
DA:1090,2
DA:1092,0
DA:1116,1
DA:1117,2
DA:1118,2
DA:1119,1
DA:1120,0
DA:1122,0
DA:1151,1
DA:1152,2
DA:1153,1
DA:1154,0
DA:1156,3
DA:1157,1
DA:1161,1
DA:1162,2
DA:1163,0
DA:1165,2
DA:1169,1
DA:1170,2
DA:1171,2
DA:1172,2
DA:1173,2
DA:1174,5
DA:1177,1
DA:1179,2
DA:1181,4
DA:1184,0
DA:1211,1
DA:1212,1
DA:1213,1
DA:1214,6
DA:1226,1
DA:1228,0
DA:1243,1
DA:1244,1
DA:1247,1
DA:1248,3
DA:1260,1
DA:1261,1
DA:1264,0
DA:1265,0
DA:1266,0
DA:1268,0
DA:1272,0
DA:1273,0
DA:1274,0
DA:1276,0
DA:1290,1
DA:1291,1
DA:1292,6
DA:1293,3
DA:1294,9
DA:1295,7
DA:1297,1
DA:1298,3
DA:1299,1
DA:1302,4
DA:1304,1
DA:1305,4
LF:414
LH:224
end_of_record
+17 −1
Original line number Diff line number Diff line
%% Cell type:code id: tags:

``` rust
:dep pipe = { path = "../" }
:dep pipe-lib = { path = "../pipe-lib" }
```

%% Cell type:code id: tags:

``` rust
:dep uriparse

use uriparse::URI;

let uri = URI::try_from("file:///path/to/file").unwrap();
let path = uri.path().clone();
println!("URI: {}", path);
```

%% Output

    URI: /path/to/file

%% Cell type:code id: tags:

``` rust
```
+23 −40
Original line number Diff line number Diff line
@@ -2,14 +2,14 @@ use clap_verbosity_flag::Verbosity;
use color_eyre::eyre::Report;
use exitcode;
use nanoid::nanoid;
use pipe_lib::{
    get_conda_environment_name, Command, Config, EnvironmentValue, Label, ModuleLanguage, ModuleType, ModuleUri, Script, TemplateAttribute,
};
use pipe_lib::{get_conda_environment_name, Command, Config, EnvironmentValue, Label, ModuleLanguage, ModuleType, ModuleUri, Script};
use rayon::prelude::*;
use std::convert::TryFrom;
use std::env;
use std::path::PathBuf;
use tracing::{debug, error, info, warn};
use uriparse::Scheme;
use uriparse::URI;

const DEFAULT_CONFIG_NAME: &str = "config.json";

@@ -187,8 +187,24 @@ pub fn run(
            });
            // Run workflow
            cfg.modules.iter().for_each(|module| match &module.module_type {
                | ModuleType::Binary { .. } => {
                    unimplemented!("Binary modules are not supported yet");
                | ModuleType::Binary { ref uri } => {
                    let envs = EnvironmentValue::get_from_config(&cfg, Some(module.clone()));
                    let parent = PathBuf::from(uri).parent().unwrap().to_string_lossy().to_string();
                    let working_dir = URI::try_from(parent.as_str()).unwrap().clone().path().to_string();
                    let loaded = Script::from_module(module.clone(), Some(PathBuf::from(working_dir.clone())));
                    let script = loaded.expand_arguments_from(envs).with_current_dir(working_dir);
                    if dry_run {
                        EnvironmentValue::print_all();
                        info!(
                            module = module.name,
                            script = script.to_string(),
                            cwd = script.current_dir,
                            "=> {}",
                            Label::dry_run()
                        );
                    } else {
                        script.run();
                    }
                }
                | ModuleType::Script { programming_language, uri } => match programming_language {
                    | ModuleLanguage::Generic => {
@@ -203,37 +219,7 @@ pub fn run(
                            "=> {} Manifest file",
                            Label::using()
                        );
                        let default_template_path = PathBuf::from(&working_dir).join("template.json");
                        // TODO: Abstract loading script from template: fn(module, default_path) -> Script
                        let loaded = match &module.template {
                            | Some(attribute) => match attribute {
                                | TemplateAttribute::Path(value) => match PathBuf::from(value).try_exists() {
                                    | Ok(true) => {
                                        let path = PathBuf::from(&working_dir).join(value);
                                        debug!(module = module.name, path = path.to_str().unwrap(), "=> {} Template file", Label::using());
                                        Script::from_path(path)
                                    }
                                    | _ => {
                                        warn!(module = module.name, "=> {} Default template file", Label::using());
                                        Script::from_path(default_template_path)
                                    }
                                },
                                | TemplateAttribute::Template(value) => {
                                    debug!(module = module.name, "=> {} Template attribute", Label::using());
                                    Script::from_template(value.clone())
                                }
                            },
                            | None => match default_template_path.try_exists() {
                                | Ok(true) => {
                                    warn!(module = module.name, "=> {} Default template file", Label::using());
                                    Script::from_path(default_template_path)
                                }
                                | _ => {
                                    warn!(module = module.name, "=> {} Default Python script", Label::using());
                                    Script::python_default()
                                }
                            },
                        };
                        let loaded = Script::from_module(module.clone(), Some(root.clone()));
                        let environment = match get_conda_environment_name(manifest_path) {
                            | Some(value) => Some(value),
                            | None => match &module.template {
@@ -241,10 +227,7 @@ pub fn run(
                                | None => None,
                            },
                        };
                        let config_vars = cfg.variables.clone().unwrap_or_default();
                        let module_vars = module.variables.clone().unwrap_or_default();
                        let mut envs = EnvironmentValue::get_from_serde(&config_vars);
                        envs.extend(EnvironmentValue::get_from_serde(&module_vars));
                        let envs = EnvironmentValue::get_from_config(&cfg, Some(module.clone()));
                        let script = loaded
                            .expand_arguments_from(envs)
                            .with_current_dir(working_dir)
+95 −27
Original line number Diff line number Diff line
@@ -512,6 +512,13 @@ impl EnvironmentValue {
        let pre = format!("_{}_", EnvironmentValue::PREFIX.to_uppercase());
        key.trim_start_matches(&pre).to_string()
    }
    pub fn get_from_config(config: &Config, module: Option<Module>) -> HashMap<String, String> {
        let config_vars = config.variables.clone().unwrap_or_default();
        let module_vars = module.unwrap().variables.clone().unwrap_or_default();
        let mut envs = EnvironmentValue::get_from_serde(&config_vars);
        envs.extend(EnvironmentValue::get_from_serde(&module_vars));
        envs
    }
    pub fn get_from_serde(values: &Map<String, Value>) -> HashMap<String, String> {
        let mut lookup: HashMap<String, String> = HashMap::new();
        values.iter().for_each(|(key, value)| {
@@ -568,8 +575,8 @@ impl Extension {
}
impl Label {
    pub fn dry_run() -> Styled<&'static &'static str> {
        let style = Style::new().white().on_yellow();
        " DRY_RUN ".style(style)
        let style = Style::new().black().on_yellow();
        " DRY_RUN ".style(style)
    }
    pub fn fail() -> Styled<&'static &'static str> {
        let style = Style::new().white().on_red();
@@ -596,7 +603,7 @@ impl Label {
        " REJECTED ".style(style)
    }
    pub fn run() -> Styled<&'static &'static str> {
        let style = Style::new().white().on_yellow();
        let style = Style::new().black().on_yellow();
        " RUN ▶ ".style(style)
    }
    pub fn using() -> Styled<&'static &'static str> {
@@ -754,6 +761,90 @@ impl Script {
        self.arguments = expanded;
        self
    }
    /// TODO: Factor out root argument?
    /// Create a script from a Module.
    ///
    /// Tries to create script from template interface. Resolves template interface from following:
    ///
    /// - IF `template` attribute exists in workflow configuration file
    ///   - path -> Script::from_path
    ///   - object -> Script::from_template
    ///
    /// - ELSE `template` attribute does NOT exist in workflow configuration file
    ///   - use "template.json", if it exists
    ///   - use default script if "template.json" does not exist
    ///
    /// ```
    pub fn from_module(module: Module, root: Option<PathBuf>) -> Script {
        const DEFAULT_FILENAME: &str = "template.json";
        let module_uri = match module.module_type {
            | ModuleType::Binary { ref uri } => ModuleUri::from(uri),
            | ModuleType::Script { ref uri, .. } => ModuleUri::from(uri),
            | ModuleType::Configuration { .. } => unimplemented!("Configuration module type"),
        };
        let working_dir = module_uri.working_directory(Some(root.unwrap_or_default().clone()));
        let default_template_path = PathBuf::from(&working_dir).join(DEFAULT_FILENAME);
        match &module.template {
            | Some(attribute) => match attribute {
                | TemplateAttribute::Path(value) => match PathBuf::from(&working_dir).join(value).try_exists() {
                    | Ok(true) => {
                        let path = PathBuf::from(&working_dir).join(value);
                        debug!(module = module.name, path = path.to_str().unwrap(), "=> {} Template file", Label::using());
                        Script::from_path(path)
                    }
                    | _ => {
                        let path = PathBuf::from(&working_dir).join(value).into_os_string().into_string().unwrap();
                        warn!(module = module.name, "=> {} {}", Label::not_found(), path);
                        warn!(module = module.name, "=> {} Default template file path", Label::using());
                        Script::from_path(default_template_path)
                    }
                },
                | TemplateAttribute::Template(value) => {
                    debug!(module = module.name, "=> {} Template attribute", Label::using());
                    Script::from_template(value.clone())
                }
            },
            | None => match default_template_path.try_exists() {
                | Ok(true) => {
                    warn!(module = module.name, "=> {} Default template file path", Label::using());
                    Script::from_path(default_template_path)
                }
                | _ => {
                    warn!(
                        module = module.name,
                        "=> {} {}",
                        Label::not_found(),
                        default_template_path.into_os_string().into_string().unwrap()
                    );
                    warn!(module = module.name, "=> {} Default Python script", Label::using());
                    Script::python_default()
                }
            },
        }
    }
    /// Create a script from a template JSON file in [ScriptTemplate] format.
    ///
    /// You can easily import the script with
    /// ```
    /// use pipe_lib::Script;
    /// use std::path::PathBuf;
    ///
    /// let path = PathBuf::from("../tests/fixtures/template.json");
    /// let script = Script::from_path(path);
    /// let output = script.run();
    /// ```
    pub fn from_path(path: PathBuf) -> Script {
        let content = match read_file(path.clone()) {
            | Ok(value) => value,
            | Err(_) => {
                error!("Failed to read file: {:?}", path);
                "".to_owned()
            }
        };
        let json: serde_json::Result<ScriptTemplate> = serde_json::from_str(&content);
        let template = json.expect("=> [ERROR] Failed to parse script template").clone();
        Script::from_template(template)
    }
    /// Create a script from a ScriptTemplate struct.
    ///
    /// You can easily import the script with
@@ -782,29 +873,6 @@ impl Script {
        let command = Command::init().name(template.command).build();
        Script::init().command(command).arguments(arguments).build().with_environment(environment)
    }
    /// Create a script from a template JSON file in [ScriptTemplate] format.
    ///
    /// You can easily import the script with
    /// ```
    /// use pipe_lib::Script;
    /// use std::path::PathBuf;
    ///
    /// let path = PathBuf::from("../tests/fixtures/template.json");
    /// let script = Script::from_path(path);
    /// let output = script.run();
    /// ```
    pub fn from_path(path: PathBuf) -> Script {
        let content = match read_file(path.clone()) {
            | Ok(value) => value,
            | Err(_) => {
                error!("Failed to read config file: {:?}", path);
                "".to_owned()
            }
        };
        let json: serde_json::Result<ScriptTemplate> = serde_json::from_str(&content);
        let template = json.expect("=> [ERROR] Failed to parse script template").clone();
        Script::from_template(template)
    }
    fn get_command(&self) -> String {
        match &self.command.virtual_environment {
            | Some(_) => "conda".to_string(),
@@ -881,7 +949,7 @@ impl Script {
        let arguments = self.get_arguments();
        let current_dir = PathBuf::from(&self.current_dir);
        let envs = self.envs.clone().unwrap_or_default();
        warn!(script = self.to_string(), "=> {}", Label::run());
        warn!(cwd = current_dir.to_str().unwrap(), script = self.to_string(), "=> {}", Label::run());
        let mut output: Vec<String> = vec![];
        if let Ok(mut cmd) = process::Command::new(command)
            .args(arguments.iter())