aoc2022/07/src/main.rs
2022-12-07 22:02:28 -06:00

135 lines
3 KiB
Rust

#[macro_use]
extern crate anyhow;
#[macro_use]
extern crate log;
mod fs;
mod utils;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use anyhow::Result;
use clap::Parser;
use fuse::{BackgroundSession, FileType};
use crate::fs::FakeFs;
#[derive(Debug, Parser)]
struct Opt {
input: PathBuf,
mountpoint: PathBuf,
}
fn main() -> Result<()> {
let opt = Opt::parse();
setup_logger()?;
let fs = read_input(&opt.input)?;
run_with_ctrlc(move || -> Result<BackgroundSession> {
let x = unsafe { fuse::spawn_mount(fs, &opt.mountpoint, &[])? };
Ok(x)
})?;
Ok(())
}
fn read_input(input: impl AsRef<Path>) -> Result<FakeFs> {
let mut fs = FakeFs::new();
// Read input
{
let file = File::open(input.as_ref())?;
let reader = BufReader::new(file);
let mut it = reader.lines().peekable();
let mut current_dir = PathBuf::from("/");
loop {
let line = match it.next() {
Some(Ok(v)) => v,
Some(Err(e)) => return Err(e.into()),
None => break,
};
// Assume line starts with $
let line = line.strip_prefix("$ ").unwrap();
let parts = line.split(" ").collect::<Vec<_>>();
let command = parts[0];
match command {
"cd" => {
let move_path = PathBuf::from(parts[1]);
let dst_path = utils::into_absolute(&move_path, &current_dir);
info!("Moving to {dst_path:?}");
current_dir = dst_path;
}
"ls" => loop {
let line = match it.peek() {
Some(Ok(v)) if !v.starts_with("$") => it.next().unwrap()?,
_ => break,
};
let parts = line.split(" ").collect::<Vec<_>>();
let filename = parts[1];
let (ty, size) = match parts[0] {
"dir" => (FileType::Directory, 0),
s => (FileType::RegularFile, s.parse::<u64>().unwrap()),
};
let ino = fs.ensure_path(current_dir.join(filename), ty)?;
if size > 0 {
fs.set_size(ino, size);
}
},
_ => panic!("Don't know command {command}"),
}
}
}
debug!("Fs contents: {fs:?}");
Ok(fs)
}
fn run_with_ctrlc<F, R>(f: F) -> R
where
F: FnOnce() -> R,
{
let running = Arc::new(AtomicBool::new(true));
let r = running.clone();
ctrlc::set_handler(move || {
r.store(false, Ordering::SeqCst);
})
.expect("Error setting Ctrl-C handler");
debug!("Waiting for Ctrl-C...");
let res = f();
while running.load(Ordering::SeqCst) {}
debug!("Got it! Exiting...");
res
}
fn setup_logger() -> Result<()> {
fern::Dispatch::new()
.format(|out, message, record| {
out.finish(format_args!(
"{}[{}][{}] {}",
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
record.target(),
record.level(),
message
))
})
.level(log::LevelFilter::Debug)
.chain(std::io::stdout())
.chain(fern::log_file("output.log")?)
.apply()
.map_err(|e| e.into())
}