Skip to content

Commit

Permalink
feat: #10 ✨ Prepare completely new task call parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
ddanier committed Apr 17, 2024
1 parent 26fb0d4 commit f8e8bd6
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 70 deletions.
71 changes: 46 additions & 25 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@ use nu_protocol::{
};
use nu_utils::stdout_write_all_and_flush;

pub(crate) fn gather_commandline_args(args: Vec<String>) -> (Vec<String>, String, Vec<String>) {
pub(crate) fn gather_commandline_args(args: Vec<String>) -> (Vec<String>, bool, Vec<String>) {
let mut args_to_nur = Vec::from([String::from(NUR_NAME)]);
let mut task_name = String::new();
let mut task_and_args = Vec::from([String::from(NUR_NAME)]);
let mut has_task_call = false;
let mut args_iter = args.iter();

args_iter.next(); // Ignore own name
#[allow(clippy::while_let_on_iterator)]
while let Some(arg) = args_iter.next() {
if !arg.starts_with('-') {
task_name = arg.clone();
has_task_call = true;
task_and_args.push(arg.clone());
break;
}

Expand All @@ -36,12 +38,18 @@ pub(crate) fn gather_commandline_args(args: Vec<String>) -> (Vec<String>, String
// }
}

let args_to_task = if !task_name.is_empty() {
args_iter.map(|arg| escape_for_script_arg(arg)).collect()
if has_task_call {
// Consume remaining elements in iterator
#[allow(clippy::while_let_on_iterator)]
while let Some(arg) = args_iter.next() {
task_and_args.push(escape_for_script_arg(arg));
}
} else {
Vec::default()
};
(args_to_nur, task_name, args_to_task)
// Also remove "nur" from task_and_args
task_and_args.clear();
}

(args_to_nur, has_task_call, task_and_args)
}

pub(crate) fn parse_commandline_args(
Expand Down Expand Up @@ -133,12 +141,17 @@ mod tests {
String::from("--task-option"),
String::from("task-value"),
];
let (nur_args, task_name, task_args) = gather_commandline_args(args);
let (nur_args, has_task_call, task_and_args) = gather_commandline_args(args);
assert_eq!(nur_args, vec![String::from("nur"), String::from("--quiet")]);
assert_eq!(task_name, "some_task_name");
assert_eq!(has_task_call, true);
assert_eq!(
task_args,
vec![String::from("--task-option"), String::from("task-value")]
task_and_args,
vec![
String::from("nur"),
String::from("some_task_name"),
String::from("--task-option"),
String::from("task-value")
]
);
}

Expand All @@ -150,22 +163,27 @@ mod tests {
String::from("--task-option"),
String::from("task-value"),
];
let (nur_args, task_name, task_args) = gather_commandline_args(args);
let (nur_args, has_task_call, task_and_args) = gather_commandline_args(args);
assert_eq!(nur_args, vec![String::from("nur")]);
assert_eq!(task_name, "some_task_name");
assert_eq!(has_task_call, true);
assert_eq!(
task_args,
vec![String::from("--task-option"), String::from("task-value")]
task_and_args,
vec![
String::from("nur"),
String::from("some_task_name"),
String::from("--task-option"),
String::from("task-value")
]
);
}

#[test]
fn test_gather_commandline_args_handles_missing_task_name() {
let args = vec![String::from("nur"), String::from("--help")];
let (nur_args, task_name, task_args) = gather_commandline_args(args);
let (nur_args, has_task_call, task_and_args) = gather_commandline_args(args);
assert_eq!(nur_args, vec![String::from("nur"), String::from("--help")]);
assert_eq!(task_name, "");
assert_eq!(task_args, vec![] as Vec<String>);
assert_eq!(has_task_call, false);
assert_eq!(task_and_args, vec![] as Vec<String>);
}

#[test]
Expand All @@ -175,19 +193,22 @@ mod tests {
String::from("--quiet"),
String::from("some_task_name"),
];
let (nur_args, task_name, task_args) = gather_commandline_args(args);
let (nur_args, has_task_call, task_and_args) = gather_commandline_args(args);
assert_eq!(nur_args, vec![String::from("nur"), String::from("--quiet")]);
assert_eq!(task_name, "some_task_name");
assert_eq!(task_args, vec![] as Vec<String>);
assert_eq!(has_task_call, true);
assert_eq!(
task_and_args,
vec![String::from("nur"), String::from("some_task_name")]
);
}

#[test]
fn test_gather_commandline_args_handles_no_args_at_all() {
let args = vec![String::from("nur")];
let (nur_args, task_name, task_args) = gather_commandline_args(args);
let (nur_args, has_task_call, task_and_args) = gather_commandline_args(args);
assert_eq!(nur_args, vec![String::from("nur")]);
assert_eq!(task_name, "");
assert_eq!(task_args, vec![] as Vec<String>);
assert_eq!(has_task_call, false);
assert_eq!(task_and_args, vec![] as Vec<String>);
}

fn _create_minimal_engine_for_erg_parsing() -> EngineState {
Expand Down
8 changes: 4 additions & 4 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ impl NurEngine {
Span::unknown(),
),
);
nur_record.push(
NUR_VAR_TASK_NAME,
Value::string(&self.state.task_name, Span::unknown()),
);
// nur_record.push(
// NUR_VAR_TASK_NAME,
// Value::string(&self.state.task_name, Span::unknown()),
// );
nur_record.push(
NUR_VAR_CONFIG_DIR,
Value::string(
Expand Down
58 changes: 26 additions & 32 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use crate::compat::show_nurscripts_hint;
use crate::engine::init_engine_state;
use crate::engine::NurEngine;
use crate::errors::NurError;
use crate::names::NUR_NAME;
use crate::state::NurState;
use miette::Result;
use nu_ansi_term::Color;
Expand Down Expand Up @@ -45,8 +44,7 @@ fn main() -> Result<ExitCode, miette::ErrReport> {
eprintln!("project path: {:?}", nur_engine.state.project_path);
eprintln!();
eprintln!("nur args: {:?}", parsed_nur_args);
eprintln!("task name: {:?}", nur_engine.state.task_name);
eprintln!("task args: {:?}", nur_engine.state.args_to_task);
eprintln!("task call: {:?}", nur_engine.state.task_and_args);
eprintln!();
eprintln!("nur config dir: {:?}", nur_engine.state.config_dir);
eprintln!(
Expand Down Expand Up @@ -101,33 +99,33 @@ fn main() -> Result<ExitCode, miette::ErrReport> {
}

// Initialize internal data
let task_def_name = format!("{} {}", NUR_NAME, nur_engine.state.task_name);
#[cfg(feature = "debug")]
if parsed_nur_args.debug_output {
eprintln!("task def name: {}", task_def_name);
}
// let task_def_name = format!("{} {}", NUR_NAME, nur_engine.state.task_name);
// #[cfg(feature = "debug")]
// if parsed_nur_args.debug_output {
// eprintln!("task def name: {}", task_def_name);
// }

// Handle help
if parsed_nur_args.show_help || nur_engine.state.task_name.is_empty() {
if nur_engine.state.task_name.is_empty() {
nur_engine.print_help(&Nur);
} else if let Some(command) = nur_engine.get_def(task_def_name) {
nur_engine.clone().print_help(command);
} else {
return Err(miette::ErrReport::from(NurError::TaskNotFound(
nur_engine.state.task_name,
)));
}

std::process::exit(0);
}
// if parsed_nur_args.show_help || nur_engine.state.task_name.is_empty() {
// if nur_engine.state.task_name.is_empty() {
// nur_engine.print_help(&Nur);
// } else if let Some(command) = nur_engine.get_def(task_def_name) {
// nur_engine.clone().print_help(command);
// } else {
// return Err(miette::ErrReport::from(NurError::TaskNotFound(
// nur_engine.state.task_name,
// )));
// }
//
// std::process::exit(0);
// }

// Check if requested task exists
if !nur_engine.has_def(&task_def_name) {
return Err(miette::ErrReport::from(NurError::TaskNotFound(
nur_engine.state.task_name,
)));
}
// if !nur_engine.has_def(&task_def_name) {
// return Err(miette::ErrReport::from(NurError::TaskNotFound(
// nur_engine.state.task_and_args[1].clone(), // TODO: Use real task name
// )));
// }

// Prepare input data - if requested
let input = if parsed_nur_args.attach_stdin {
Expand All @@ -153,11 +151,7 @@ fn main() -> Result<ExitCode, miette::ErrReport> {

// Execute the task
let exit_code: i64;
let full_task_call = format!(
"{} {}",
task_def_name,
nur_engine.state.args_to_task.join(" ")
);
let full_task_call = nur_engine.state.task_and_args.join(" ");
#[cfg(feature = "debug")]
if parsed_nur_args.debug_output {
eprintln!("full task call: {}", full_task_call);
Expand All @@ -172,7 +166,7 @@ fn main() -> Result<ExitCode, miette::ErrReport> {
} else {
println!("nur version {}", env!("CARGO_PKG_VERSION"));
println!("Project path {:?}", nur_engine.state.project_path);
println!("Executing task {}", nur_engine.state.task_name);
println!("Executing task {}", nur_engine.state.task_and_args[1]); // TODO: Use real task name
println!();
exit_code = nur_engine.eval_and_print(full_task_call, input)?;
#[cfg(feature = "debug")]
Expand Down
65 changes: 56 additions & 9 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ pub(crate) struct NurState {
pub(crate) local_nurfile_path: PathBuf,

pub(crate) args_to_nur: Vec<String>,
pub(crate) task_name: String,
pub(crate) args_to_task: Vec<String>,
pub(crate) has_task_call: bool,
pub(crate) task_and_args: Vec<String>,
}

impl NurState {
Expand All @@ -43,7 +43,7 @@ impl NurState {
let local_nurfile_path = project_path.join(NUR_LOCAL_FILE);

// Parse args into bits
let (args_to_nur, task_name, args_to_task) = gather_commandline_args(args);
let (args_to_nur, has_task_call, task_and_args) = gather_commandline_args(args);

NurState {
run_path,
Expand All @@ -59,8 +59,8 @@ impl NurState {
local_nurfile_path,

args_to_nur,
task_name,
args_to_task,
has_task_call,
task_and_args,
}
}
}
Expand Down Expand Up @@ -107,8 +107,15 @@ mod tests {
state.args_to_nur,
vec![String::from("nur"), String::from("--quiet"),]
);
assert_eq!(state.task_name, "some_task");
assert_eq!(state.args_to_task, vec![String::from("task_arg"),]);
assert_eq!(state.has_task_call, true);
assert_eq!(
state.task_and_args,
vec![
String::from("nur"),
String::from("some_task"),
String::from("task_arg")
]
);

// Clean up
std::fs::remove_file(nurfile_path).unwrap();
Expand Down Expand Up @@ -148,7 +155,47 @@ mod tests {
state.args_to_nur,
vec![String::from("nur"), String::from("--quiet"),]
);
assert_eq!(state.task_name, "some_task");
assert_eq!(state.args_to_task, vec![String::from("task_arg"),]);
assert_eq!(state.has_task_call, true);
assert_eq!(
state.task_and_args,
vec![
String::from("nur"),
String::from("some_task"),
String::from("task_arg")
]
);
}

#[test]
fn test_nur_state_without_task() {
let temp_dir = tempdir().unwrap();
let temp_dir_path = temp_dir.path().to_path_buf();

// Setup test
let args = vec![String::from("nur"), String::from("--help")];
let state = NurState::new(temp_dir_path.clone(), args);

// Check everything works out
assert_eq!(state.run_path, temp_dir_path);
assert_eq!(state.project_path, temp_dir_path); // same as run_path, as this is the fallback
assert_eq!(state.has_project_path, false);

assert_eq!(state.config_dir, temp_dir_path.join(".nur"));
assert_eq!(state.lib_dir_path, temp_dir_path.join(".nur/scripts"));
assert_eq!(state.env_path, temp_dir_path.join(".nur/env.nu"));
assert_eq!(state.config_path, temp_dir_path.join(".nur/config.nu"));

assert_eq!(state.nurfile_path, temp_dir_path.join("nurfile"));
assert_eq!(
state.local_nurfile_path,
temp_dir_path.join("nurfile.local")
);

assert_eq!(
state.args_to_nur,
vec![String::from("nur"), String::from("--help"),]
);
assert_eq!(state.has_task_call, false);
assert_eq!(state.task_and_args, vec![] as Vec<String>);
}
}

0 comments on commit f8e8bd6

Please sign in to comment.