Projects STRLCPY dum Commits b9ea35d0
🤬
  • fix: Support node_modules in parent directories, closes #19

  • Loading...
  • EGOIST committed 2 years ago
    b9ea35d0
    1 parent 5e37d376
  • ■ ■ ■ ■
    .gitignore
    1 1  /target
    2  - 
     2 +node_modules
  • ■ ■ ■ ■ ■
    src/args.rs
    skipped 6 lines
    7 7   pub script_name: String,
    8 8   pub forwared: String,
    9 9   pub change_dir: PathBuf,
     10 + pub command: String,
    10 11  }
    11 12   
    12 13  pub fn parse_args(args_vec: &[String]) -> AppArgs {
    skipped 3 lines
    16 17   script_name: "".to_string(),
    17 18   change_dir: PathBuf::from(env::current_dir().as_ref().unwrap()),
    18 19   forwared: "".to_string(),
     20 + command: "".to_string(),
    19 21   };
    20 22   
    21 23   loop {
    skipped 35 lines
    57 59   args.forwared.push_str(" ");
    58 60   args.forwared.push_str(&v);
    59 61   }
     62 + } else if v == "run" {
     63 + args.command = v.to_string();
    60 64   } else if args.script_name.is_empty() {
    61 65   args.script_name = match v.as_ref() {
    62 66   "t" => "test".to_string(),
    skipped 16 lines
    79 83   env!("CARGO_PKG_VERSION").to_string()
    80 84  }
    81 85   
    82  -fn get_help() -> String {
     86 +pub fn get_help() -> String {
    83 87   format!(
    84 88   "\
    85 89  dum v{}
    skipped 2 lines
    88 92   dum [OUR_FLAGS] [SCRIPT_NAME] [SCRIPT_ARGS]
    89 93   
    90 94  COMMANDS:
     95 + run Show a list of available scripts
     96 + run <script_name> Run a script
    91 97   add <packages> Add packages to the current project
    92 98   i, install Install dependencies
    93 99   remove <packages> Remove packages from the current project
    skipped 41 lines
  • ■ ■ ■ ■ ■ ■
    src/lib.rs
    skipped 11 lines
    12 12  use std::process::{exit, Command};
    13 13   
    14 14  // Get PATH env and join it with bin_dir
    15  -fn get_path_env(bin_dir: &str) -> String {
     15 +fn get_path_env(bin_dirs: Vec<PathBuf>) -> String {
    16 16   let mut path = env::var("PATH").unwrap_or_default();
    17  - path.push_str(":");
    18  - path.push_str(bin_dir);
     17 + for dir in bin_dirs {
     18 + path.push_str(":");
     19 + path.push_str(dir.to_str().unwrap());
     20 + }
    19 21   path
    20 22  }
    21 23   
    22 24  // A function to find the closest file
    23 25  // Starting from current directory
    24 26  // Recusively until it finds the file or reach root directory `/`
    25  -fn find_closest_file(_current_dir: &PathBuf, name: &str) -> Option<PathBuf> {
    26  - let mut closest_file = None;
     27 +fn find_closest_files(_current_dir: &PathBuf, name: &str, stop_on_first: bool) -> Vec<PathBuf> {
     28 + let mut closest_file: Vec<PathBuf> = Vec::new();
    27 29   let stop_dir = "/".to_string();
    28 30   let mut current_dir = _current_dir.clone();
    29 31   
    30 32   loop {
    31 33   let path = current_dir.join(name);
    32 34   if path.exists() {
    33  - closest_file = Some(PathBuf::from(path.to_str().unwrap()));
    34  - break;
     35 + closest_file.push(path);
     36 + if stop_on_first {
     37 + break;
     38 + }
    35 39   }
    36 40   
    37 41   if current_dir.to_str().unwrap() == stop_dir {
    skipped 29 lines
    67 71   exit(status.code().unwrap_or(1));
    68 72  }
    69 73   
    70  -pub fn dum(args: &args::AppArgs) {
    71  - let pkg_path = find_closest_file(&args.change_dir, "package.json").expect("no package.json");
     74 +fn resolve_bin_path(bin_name: &str, dirs: &Vec<PathBuf>) -> Option<PathBuf> {
     75 + for dir in dirs {
     76 + let path = dir.join(bin_name);
     77 + if path.exists() {
     78 + return Some(path);
     79 + }
     80 + }
     81 + 
     82 + None
     83 +}
     84 + 
     85 +pub fn dum(app_args: &args::AppArgs) {
     86 + let pkg_paths = find_closest_files(&app_args.change_dir, "package.json", true);
     87 + let pkg_path = if pkg_paths.is_empty() {
     88 + println!("No package.json found");
     89 + exit(1);
     90 + } else {
     91 + pkg_paths[0].clone()
     92 + };
     93 + 
    72 94   // The current_dir to execute npm scripts
    73 95   let execute_dir = PathBuf::from(pkg_path.parent().unwrap());
    74  - // bin_dir is the dirname of pkg_data followed by node_modules/.bin
    75  - let bin_dir = PathBuf::from(execute_dir.join("node_modules").join(".bin"));
     96 + 
     97 + let node_modules_dirs = find_closest_files(&app_args.change_dir, "node_modules", false);
     98 + let bin_dirs = node_modules_dirs
     99 + .iter()
     100 + .map(|dir| dir.join(".bin"))
     101 + .collect::<Vec<PathBuf>>();
    76 102   
    77 103   let contents = read_to_string(pkg_path).expect("failed to read package.json");
    78 104   let v: Value = serde_json::from_str(&contents).expect("failed to parse package.json");
    79 105   
    80  - if args.script_name.is_empty() {
     106 + if app_args.command == "run" && app_args.script_name.is_empty() {
    81 107   if let Some(scripts) = v["scripts"].as_object() {
    82 108   println!("\nAvailable scripts:\n");
    83 109   for (name, value) in scripts {
    skipped 6 lines
    90 116   return;
    91 117   }
    92 118   
     119 + if app_args.script_name.is_empty() {
     120 + println!("No script name specified.\n");
     121 + println!("{}", args::get_help());
     122 + return;
     123 + }
     124 + 
    93 125   // Run npm install if the script_name is "install"
    94  - if ["install", "add", "remove"].contains(&args.script_name.as_str()) {
     126 + if ["install", "add", "remove"].contains(&app_args.script_name.as_str()) {
    95 127   let pm = install::guess_package_manager(&execute_dir);
    96 128   
    97 129   if pm.is_none() {
    skipped 2 lines
    100 132   }
    101 133   
    102 134   run_command(
    103  - &[&pm.unwrap(), &args.script_name, &args.forwared],
     135 + &[&pm.unwrap(), &app_args.script_name, &app_args.forwared],
    104 136   &RunOptions {
    105 137   current_dir: execute_dir,
    106 138   envs: HashMap::new(),
    skipped 2 lines
    109 141   return;
    110 142   }
    111 143   
    112  - let result = v
    113  - .get("scripts")
    114  - .and_then(|scripts| match scripts.get(&args.script_name) {
    115  - Some(script) => {
    116  - println!("> {}", args.script_name);
    117  - println!("> {}{}", script.as_str().unwrap(), args.forwared);
    118  - script.as_str().map(|script| script.to_string())
    119  - }
    120  - None => {
    121  - let bin_file = bin_dir.join(&args.script_name);
    122  - if bin_file.exists() {
    123  - println!("> {}", bin_file.display());
    124  - Some(bin_file.to_string_lossy().to_string())
    125  - } else {
    126  - None
    127  - }
    128  - }
     144 + let npm_script = v.get("scripts").and_then(|scripts| {
     145 + scripts.as_object().and_then(|scripts| {
     146 + scripts
     147 + .get(app_args.script_name.as_str())
     148 + .and_then(|script| {
     149 + let script = script.as_str().map(|script| script.to_string());
     150 + Some(script.unwrap_or_default())
     151 + })
    129 152   })
    130  - .map(|script| {
    131  - let envs =
    132  - HashMap::from([("PATH".to_string(), get_path_env(&bin_dir.to_str().unwrap()))]);
     153 + });
    133 154   
    134  - run_command(
    135  - &[&script, &args.forwared],
    136  - &RunOptions {
    137  - current_dir: execute_dir,
    138  - envs,
    139  - },
    140  - );
    141  - });
     155 + if npm_script.is_some() {
     156 + let script = npm_script.unwrap();
     157 + println!("> {}", app_args.script_name);
     158 + println!("> {}{}", script, app_args.forwared);
     159 + let envs = HashMap::from([("PATH".to_string(), get_path_env(bin_dirs))]);
     160 + run_command(
     161 + &[&script, &app_args.forwared],
     162 + &RunOptions {
     163 + current_dir: execute_dir,
     164 + envs,
     165 + },
     166 + );
     167 + return;
     168 + }
    142 169   
    143  - if result.is_none() {
    144  - eprintln!("Error: script not found.");
    145  - std::process::exit(1);
     170 + let resolved_bin = resolve_bin_path(app_args.script_name.as_str(), &bin_dirs);
     171 + if resolved_bin.is_some() {
     172 + let bin_path = resolved_bin.unwrap();
     173 + println!("> {}", app_args.script_name);
     174 + println!("> {}{}", bin_path.to_str().unwrap(), app_args.forwared);
     175 + let envs = HashMap::from([("PATH".to_string(), get_path_env(bin_dirs))]);
     176 + run_command(
     177 + &[bin_path.to_str().unwrap(), &app_args.forwared],
     178 + &RunOptions {
     179 + current_dir: execute_dir,
     180 + envs,
     181 + },
     182 + );
     183 + return;
    146 184   }
     185 + 
     186 + println!("No script found.");
     187 + println!("To see a list of scripts, run `dum run`");
     188 + exit(1);
    147 189  }
    148 190   
Please wait...
Page is in error, reload to recover