Skip to content

Commit b2c752b

Browse files
authored
feat: implement source (#102)
1 parent 2d2124a commit b2c752b

File tree

3 files changed

+88
-44
lines changed

3 files changed

+88
-44
lines changed

crates/shell/src/commands.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
use std::ffi::OsString;
1+
use std::{ffi::OsString, fs};
22

33
use deno_task_shell::{EnvChange, ExecuteResult, ShellCommand, ShellCommandContext};
4-
use futures::future::LocalBoxFuture;
4+
use futures::{future::LocalBoxFuture, FutureExt};
55

66
use uu_ls::uumain as uu_ls;
7+
8+
use crate::execute;
79
pub struct LsCommand;
810

911
pub struct AliasCommand;
1012

1113
pub struct UnAliasCommand;
1214

15+
pub struct SourceCommand;
16+
1317
impl ShellCommand for AliasCommand {
1418
fn execute(&self, context: ShellCommandContext) -> LocalBoxFuture<'static, ExecuteResult> {
1519
if context.args.len() != 1 {
@@ -61,3 +65,33 @@ fn execute_ls(context: ShellCommandContext) -> ExecuteResult {
6165
let exit_code = uu_ls(args.into_iter());
6266
ExecuteResult::from_exit_code(exit_code)
6367
}
68+
69+
impl ShellCommand for SourceCommand {
70+
fn execute(&self, context: ShellCommandContext) -> LocalBoxFuture<'static, ExecuteResult> {
71+
if context.args.len() != 1 {
72+
return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(1)));
73+
}
74+
75+
let script = context.args[0].clone();
76+
let script_file = context.state.cwd().join(script);
77+
match fs::read_to_string(&script_file) {
78+
Ok(content) => {
79+
let state = context.state.clone();
80+
async move {
81+
execute::execute_inner(&content, state)
82+
.await
83+
.unwrap_or_else(|e| {
84+
eprintln!("Could not source script: {:?}", script_file);
85+
eprintln!("Error: {}", e);
86+
ExecuteResult::from_exit_code(1)
87+
})
88+
}
89+
.boxed_local()
90+
}
91+
Err(e) => {
92+
eprintln!("Could not read file: {:?} ({})", script_file, e);
93+
Box::pin(futures::future::ready(ExecuteResult::from_exit_code(1)))
94+
}
95+
}
96+
}
97+
}

crates/shell/src/execute.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use anyhow::Context;
2+
use deno_task_shell::{
3+
execute_sequential_list, AsyncCommandBehavior, ExecuteResult, ShellPipeReader, ShellPipeWriter,
4+
ShellState,
5+
};
6+
7+
pub async fn execute_inner(text: &str, state: ShellState) -> anyhow::Result<ExecuteResult> {
8+
let list = deno_task_shell::parser::parse(text);
9+
10+
let stderr = ShellPipeWriter::stderr();
11+
let stdout = ShellPipeWriter::stdout();
12+
let stdin = ShellPipeReader::stdin();
13+
14+
if let Err(e) = list {
15+
anyhow::bail!("Syntax error: {}", e);
16+
}
17+
18+
// spawn a sequential list and pipe its output to the environment
19+
let result = execute_sequential_list(
20+
list.unwrap(),
21+
state,
22+
stdin,
23+
stdout,
24+
stderr,
25+
AsyncCommandBehavior::Wait,
26+
)
27+
.await;
28+
29+
Ok(result)
30+
}
31+
32+
pub async fn execute(text: &str, state: &mut ShellState) -> anyhow::Result<i32> {
33+
let result = execute_inner(text, state.clone()).await?;
34+
35+
match result {
36+
ExecuteResult::Continue(exit_code, changes, _) => {
37+
// set CWD to the last command's CWD
38+
state.apply_changes(&changes);
39+
std::env::set_current_dir(state.cwd()).context("Failed to set CWD")?;
40+
Ok(exit_code)
41+
}
42+
ExecuteResult::Exit(_, _) => Ok(0),
43+
}
44+
}

crates/shell/src/main.rs

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ use std::rc::Rc;
55
use anyhow::Context;
66
use clap::Parser;
77
use deno_task_shell::parser::debug_parse;
8-
use deno_task_shell::{
9-
execute_sequential_list, AsyncCommandBehavior, ExecuteResult, ShellCommand, ShellPipeReader,
10-
ShellPipeWriter, ShellState,
11-
};
8+
use deno_task_shell::{ShellCommand, ShellState};
129
use rustyline::error::ReadlineError;
1310
use rustyline::{CompletionType, Config, Editor};
1411

1512
mod commands;
1613
mod completion;
14+
mod execute;
1715
mod helper;
1816

17+
pub use execute::execute;
18+
1919
fn commands() -> HashMap<String, Rc<dyn ShellCommand>> {
2020
HashMap::from([
2121
(
@@ -30,43 +30,13 @@ fn commands() -> HashMap<String, Rc<dyn ShellCommand>> {
3030
"unalias".to_string(),
3131
Rc::new(commands::AliasCommand) as Rc<dyn ShellCommand>,
3232
),
33+
(
34+
"source".to_string(),
35+
Rc::new(commands::SourceCommand) as Rc<dyn ShellCommand>,
36+
),
3337
])
3438
}
3539

36-
async fn execute(text: &str, state: &mut ShellState) -> anyhow::Result<i32> {
37-
let list = deno_task_shell::parser::parse(text);
38-
39-
let mut stderr = ShellPipeWriter::stderr();
40-
let stdout = ShellPipeWriter::stdout();
41-
let stdin = ShellPipeReader::stdin();
42-
43-
if let Err(e) = list {
44-
let _ = stderr.write_line(&format!("Syntax error: {}", e));
45-
return Ok(1);
46-
}
47-
48-
// spawn a sequential list and pipe its output to the environment
49-
let result = execute_sequential_list(
50-
list.unwrap(),
51-
state.clone(),
52-
stdin,
53-
stdout,
54-
stderr,
55-
AsyncCommandBehavior::Wait,
56-
)
57-
.await;
58-
59-
match result {
60-
ExecuteResult::Continue(exit_code, changes, _) => {
61-
// set CWD to the last command's CWD
62-
state.apply_changes(&changes);
63-
std::env::set_current_dir(state.cwd()).context("Failed to set CWD")?;
64-
Ok(exit_code)
65-
}
66-
ExecuteResult::Exit(_, _) => Ok(0),
67-
}
68-
}
69-
7040
#[derive(Parser)]
7141
struct Options {
7242
/// The path to the file that should be executed
@@ -93,10 +63,6 @@ async fn interactive() -> anyhow::Result<()> {
9363
let helper = helper::ShellPromptHelper::default();
9464
rl.set_helper(Some(helper));
9565

96-
// let h = ShellCompleter {};
97-
98-
// rl.set_helper(Some(h));
99-
10066
let mut state = init_state();
10167

10268
let home = dirs::home_dir().context("Couldn't get home directory")?;

0 commit comments

Comments
 (0)