Skip to content

Commit 560c33a

Browse files
authored
Merge pull request #48 from hush-shell/feat/exec
Implement exec, exec0 and spawn0 builtins
2 parents 6c48794 + 52f9af8 commit 560c33a

File tree

4 files changed

+75
-17
lines changed

4 files changed

+75
-17
lines changed

src/runtime/command/exec/fmt.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ impl Display for Builtin {
7272
let command = match self {
7373
Self::Alias => "alias",
7474
Self::Cd => "cd",
75+
Self::Exec => "exec",
76+
Self::Exec0 => "exec0",
77+
Self::Spawn0 => "spawn0",
7578
};
7679

7780
color::Fg(color::Green, command).fmt(f)

src/runtime/command/exec/mod.rs

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::{
66
ffi::{OsStr, OsString},
77
fs::{File, OpenOptions},
88
io::{self, Write},
9-
os::unix::prelude::{FromRawFd, OsStrExt, ExitStatusExt, IntoRawFd},
9+
os::unix::{prelude::{FromRawFd, OsStrExt, ExitStatusExt, IntoRawFd}, process::CommandExt},
1010
process,
1111
};
1212

@@ -152,6 +152,9 @@ pub enum Redirection {
152152
pub enum Builtin {
153153
Alias,
154154
Cd,
155+
Exec,
156+
Exec0,
157+
Spawn0,
155158
}
156159

157160

@@ -161,36 +164,76 @@ impl Builtin {
161164
arguments: Box<[Argument]>,
162165
pos: SourcePos,
163166
) -> Result<Option<ErrorStatus>, Error> {
164-
let mut arguments = arguments.into_vec();
167+
let io_error = |error| Error::io(error, pos.copy());
168+
let mut args = Self::resolve_args(arguments, pos.copy())?;
165169

166170
match self {
167-
Builtin::Alias => todo!(),
171+
Self::Alias => todo!(),
168172

169-
Builtin::Cd => {
170-
let arg = arguments
171-
.pop()
173+
Self::Cd => {
174+
let dir = args
175+
.next()
172176
.ok_or_else(|| Panic::invalid_args("argument", 0, pos.copy()))?;
173177

174-
if !arguments.is_empty() {
178+
let remaining_args = args.count();
179+
if remaining_args > 0 {
175180
return Err(
176-
Panic::invalid_args("argument", arguments.len() as u32 + 1, pos.copy()).into()
181+
Panic::invalid_args("argument", remaining_args as u32 + 1, pos.copy()).into()
177182
);
178183
}
179184

180-
let args = arg.resolve(pos.copy())?;
181-
182-
match args.as_ref() {
183-
[ dir ] => std::env::set_current_dir(dir.as_ref())
184-
.map_err(|error| Error::io(error, pos.copy()))?,
185-
other => return Err(
186-
Panic::invalid_args("argument", other.len() as u32, pos).into()
187-
),
188-
};
185+
std::env::set_current_dir(dir.as_ref()).map_err(io_error)?;
189186

190187
Ok(None)
191188
}
189+
190+
Self::Exec | Self::Exec0 | Self::Spawn0 => {
191+
let cmd = args
192+
.next()
193+
.ok_or_else(|| Panic::invalid_args("argument", 0, pos.copy()))?;
194+
195+
let mut command = process::Command::new(cmd);
196+
197+
if matches!(self, Self::Exec0 | Self::Spawn0) {
198+
let arg0 = args
199+
.next()
200+
.ok_or_else(|| Panic::invalid_args("arg0", 0, pos.copy()))?;
201+
202+
command.arg0(arg0);
203+
}
204+
205+
for arg in args {
206+
command.arg(arg);
207+
}
208+
209+
if matches!(self, Self::Spawn0) {
210+
let process = command.spawn()
211+
.map_err(io_error)?;
212+
213+
Ok(ErrorStatus::wait_child(Child { process, pos }))
214+
} else {
215+
let error = command.exec();
216+
Err(io_error(error))
217+
}
218+
}
192219
}
193220
}
221+
222+
fn resolve_args(
223+
arguments: Box<[Argument]>,
224+
pos: SourcePos,
225+
) -> Result<impl Iterator<Item = Box<OsStr>>, Error> {
226+
let args = arguments
227+
.into_vec()
228+
.into_iter()
229+
.map(|arg| arg.resolve(pos.copy()))
230+
.collect::<Result<Vec<_>, _>>()?
231+
.into_iter()
232+
.map(<[_]>::into_vec)
233+
.flatten();
234+
235+
Ok(args)
236+
}
194237
}
195238

196239

@@ -199,6 +242,9 @@ impl<'a> From<&'a program::command::Builtin> for Builtin {
199242
match builtin {
200243
program::command::Builtin::Alias => Self::Alias,
201244
program::command::Builtin::Cd => Self::Cd,
245+
program::command::Builtin::Exec => Self::Exec,
246+
program::command::Builtin::Exec0 => Self::Exec0,
247+
program::command::Builtin::Spawn0 => Self::Spawn0,
202248
}
203249
}
204250
}

src/semantic/program/command.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ pub enum Redirection {
7474
pub enum Builtin {
7575
Alias,
7676
Cd,
77+
Exec,
78+
Exec0,
79+
Spawn0,
7780
}
7881

7982

@@ -91,6 +94,9 @@ impl<'a> TryFrom<&'a [u8]> for Builtin {
9194
match value {
9295
b"alias" => Ok(Self::Alias),
9396
b"cd" => Ok(Self::Cd),
97+
b"exec" => Ok(Self::Exec),
98+
b"exec0" => Ok(Self::Exec0),
99+
b"spawn0" => Ok(Self::Spawn0),
94100
_ => Err(InvalidBuiltin)
95101
}
96102
}

src/semantic/program/fmt.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,9 @@ impl std::fmt::Display for command::Builtin {
530530
let command = match self {
531531
command::Builtin::Alias => "alias",
532532
command::Builtin::Cd => "cd",
533+
command::Builtin::Exec => "exec",
534+
command::Builtin::Exec0 => "exec0",
535+
command::Builtin::Spawn0 => "spawn0",
533536
};
534537

535538
color::Fg(color::Green, command).fmt(f)

0 commit comments

Comments
 (0)