Compare commits
No commits in common. "982dac721faeeb50dc14b161a60378f114142373" and "ad889622d50064c89e11700462265094df8f6c73" have entirely different histories.
982dac721f
...
ad889622d5
194
src/esh/mod.rs
Normal file
194
src/esh/mod.rs
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
use std::borrow::BorrowMut;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::num::ParseIntError;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use regex::{Captures, Match, Regex};
|
||||||
|
use crate::esh::ExecutionError::DirectoryNotFoundError;
|
||||||
|
|
||||||
|
pub enum ExecutionError {
|
||||||
|
ParseError(CommandError),
|
||||||
|
DirectoryNotFoundError(String),
|
||||||
|
InvalidFileSize(ParseIntError)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CommandError> for ExecutionError {
|
||||||
|
fn from(e: CommandError) -> Self {
|
||||||
|
Self::ParseError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParseIntError> for ExecutionError {
|
||||||
|
fn from(e: ParseIntError) -> Self {
|
||||||
|
Self::InvalidFileSize(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum CommandError {
|
||||||
|
UnknownCommand,
|
||||||
|
ArgumentError,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Command {
|
||||||
|
Ls,
|
||||||
|
CdParent,
|
||||||
|
CdRoot,
|
||||||
|
Cd(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Captures<'_>> for Command {
|
||||||
|
type Error = CommandError;
|
||||||
|
|
||||||
|
fn try_from(s: Captures) -> Result<Self, Self::Error> {
|
||||||
|
match s.name("cmd") {
|
||||||
|
Some(c) if c.as_str() == "ls" => Ok(Command::Ls),
|
||||||
|
Some(c) if c.as_str() == "cd" => match s.name("arg") {
|
||||||
|
None => Err(CommandError::ArgumentError),
|
||||||
|
Some(c) if c.as_str() == "/" => Ok(Command::CdRoot),
|
||||||
|
Some(c) if c.as_str() == ".." => Ok(Command::CdParent),
|
||||||
|
Some(c) => Ok(Command::Cd(c.as_str().into())),
|
||||||
|
},
|
||||||
|
_ => Err(CommandError::UnknownCommand)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Esh<'a> {
|
||||||
|
pub working_directory2: &'a Directory,
|
||||||
|
pub working_directory: RefCell<Directory>,
|
||||||
|
pub total_disk_space: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Esh<'a> {
|
||||||
|
pub fn execute(&mut self, line: &str) -> Result<(), ExecutionError> {
|
||||||
|
lazy_static! {
|
||||||
|
static ref COMMAND_REGEX: Regex = Regex::new(r"\$ (?P<cmd>\w+)( (?P<arg>[\w\.]+))?")
|
||||||
|
.unwrap();
|
||||||
|
static ref FILE_REGEX: Regex = Regex::new(r"(?P<size>\d+) (?P<name>[\w\.]+)")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
if let Some(captures) = COMMAND_REGEX.captures(line) {
|
||||||
|
let command = captures.try_into()?;
|
||||||
|
self.execute_command(command)?;
|
||||||
|
} else if let Some(captures) = FILE_REGEX.captures(line) {
|
||||||
|
let size = captures.name("size").unwrap().as_str().parse()?;
|
||||||
|
let file = DirectoryEntry::File {
|
||||||
|
size,
|
||||||
|
name: captures.name("name").unwrap().as_str().into()
|
||||||
|
};
|
||||||
|
//self.working_directory.entries.push(file);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_command(&mut self, command: Command) -> Result<(), ExecutionError> {
|
||||||
|
match command {
|
||||||
|
Command::Ls => Ok(()),
|
||||||
|
Command::CdRoot => {
|
||||||
|
|
||||||
|
while let Some(wd) = &self.working_directory.borrow().parent {
|
||||||
|
self.working_directory.replace(wd.into_inner());
|
||||||
|
}/*
|
||||||
|
while let Some(wd) = &self.working_directory.into_inner().parent {
|
||||||
|
self.working_directory = wd;
|
||||||
|
}*/
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
Command::CdParent => {
|
||||||
|
/*
|
||||||
|
if let Some(wd) = &self.working_directory.parent {
|
||||||
|
self.working_directory = wd;
|
||||||
|
Ok(())
|
||||||
|
}*/
|
||||||
|
if let Some(wd) = &self.working_directory.borrow().parent {
|
||||||
|
self.working_directory.replace(wd.into_inner());
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(DirectoryNotFoundError(
|
||||||
|
format!("{}/../", self.working_directory.borrow().name)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Command::Cd(dir) => {
|
||||||
|
if let Some(child) = self.working_directory.into_inner().subfolder(&dir) {
|
||||||
|
//self.working_directory = RefCell::from()
|
||||||
|
todo!();
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(DirectoryNotFoundError(
|
||||||
|
format!("{}/{}/", self.working_directory.name, dir)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
impl<'a> Default for Esh<'a> {
|
||||||
|
fn default() -> Self {
|
||||||
|
let d: &'static Directory = &Directory::root();
|
||||||
|
Esh {
|
||||||
|
working_directory: d,
|
||||||
|
total_disk_space: 70000000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
pub enum DirectoryEntry {
|
||||||
|
File { size: usize, name: String },
|
||||||
|
Directory(Directory)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Directory {
|
||||||
|
name: String,
|
||||||
|
entries: Vec<DirectoryEntry>,
|
||||||
|
parent: Option<Rc<RefCell<Directory>>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Directory {
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
self.entries.iter().map(|e|e.size()).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root() -> Self {
|
||||||
|
Self {
|
||||||
|
name: "/".into(),
|
||||||
|
entries: vec![],
|
||||||
|
parent: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subfolder(&self, dir: &str) -> Option<&Directory> {
|
||||||
|
self.entries
|
||||||
|
.iter()
|
||||||
|
.flat_map(|e| {
|
||||||
|
match e {
|
||||||
|
DirectoryEntry::Directory(d) if d.name == dir => Some(d),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Directory {
|
||||||
|
fn default() -> Self { Directory::root() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirectoryEntry {
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
DirectoryEntry::File { size, name } => *size,
|
||||||
|
DirectoryEntry::Directory(d) => d.size()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
match &self {
|
||||||
|
DirectoryEntry::File { size, name } => name.into(),
|
||||||
|
DirectoryEntry::Directory(d) => (*d.name).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user