feat: Add Filesystem to wrap fs operations
This commit is contained in:
parent
d341647d7d
commit
1207bbcff3
5 changed files with 158 additions and 32 deletions
|
@ -14,9 +14,15 @@ console-subscriber = "0.2"
|
|||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
|
||||
# fs
|
||||
tempfile = "3.10"
|
||||
|
||||
[dev-dependencies]
|
||||
# Conventional commits githook
|
||||
cc-cli = "0.1.5"
|
||||
|
||||
# Testing
|
||||
test-log = "0.2"
|
||||
|
||||
[package.metadata.bin]
|
||||
cc-cli = { version = "0.1" }
|
||||
|
|
128
src/filesystem.rs
Normal file
128
src/filesystem.rs
Normal file
|
@ -0,0 +1,128 @@
|
|||
#![allow(unused)]
|
||||
|
||||
use std::{
|
||||
ops::Deref,
|
||||
path::PathBuf,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use tempfile::{tempdir, TempDir};
|
||||
use tracing::{event, Level};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum FileSystem {
|
||||
Real(RealFileSystemEnv),
|
||||
Temp(TempFileSystemEnv),
|
||||
}
|
||||
impl FileSystem {
|
||||
pub fn new_real(cwd: Option<PathBuf>) -> Self {
|
||||
let cwd = cwd.unwrap_or_default();
|
||||
Self::Real(RealFileSystemEnv::new(cwd))
|
||||
}
|
||||
pub fn new_temp() -> std::io::Result<Self> {
|
||||
TempFileSystemEnv::new().map(Self::Temp)
|
||||
}
|
||||
}
|
||||
impl Deref for FileSystem {
|
||||
type Target = dyn FileSystemEnv;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
Self::Real(env) => env,
|
||||
Self::Temp(env) => env,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FileSystemEnv: Sync + Send + std::fmt::Debug {
|
||||
fn cwd(&self) -> &PathBuf;
|
||||
|
||||
fn in_cwd(&self, name: &str) -> PathBuf {
|
||||
self.cwd().join(name)
|
||||
}
|
||||
|
||||
fn write_file(&self, file_name: &str, content: &str) -> std::io::Result<PathBuf> {
|
||||
use std::fs::File;
|
||||
use std::io::{LineWriter, Write};
|
||||
|
||||
let path = self.in_cwd(file_name);
|
||||
event!(Level::INFO, "writing to {:?}", path);
|
||||
let file = File::create(path.clone())?;
|
||||
let mut file = LineWriter::new(file);
|
||||
file.write_all(content.as_bytes())?;
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
fn file_exists(&self, name: &PathBuf) -> bool {
|
||||
use std::fs::File;
|
||||
File::open(name).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct RealFileSystemEnv {
|
||||
cwd: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TempFileSystemEnv {
|
||||
cwd: PathBuf,
|
||||
temp_dir: Arc<Mutex<TempDir>>,
|
||||
}
|
||||
|
||||
impl FileSystemEnv for TempFileSystemEnv {
|
||||
fn cwd(&self) -> &PathBuf {
|
||||
&self.cwd
|
||||
}
|
||||
}
|
||||
|
||||
impl FileSystemEnv for RealFileSystemEnv {
|
||||
fn cwd(&self) -> &PathBuf {
|
||||
&self.cwd
|
||||
}
|
||||
}
|
||||
|
||||
impl RealFileSystemEnv {
|
||||
const fn new(cwd: PathBuf) -> Self {
|
||||
Self { cwd }
|
||||
}
|
||||
}
|
||||
|
||||
impl TempFileSystemEnv {
|
||||
fn new() -> std::io::Result<Self> {
|
||||
let temp_dir = tempdir()?;
|
||||
event!(Level::INFO, "temp dir: {:?}", temp_dir.path());
|
||||
let cwd = temp_dir.path().to_path_buf();
|
||||
let temp_dir = Arc::new(Mutex::new(temp_dir));
|
||||
Ok(Self { cwd, temp_dir })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test_log::test]
|
||||
fn test_cwd() {
|
||||
let cwd = PathBuf::from("/tmp");
|
||||
let env = RealFileSystemEnv::new(cwd.clone());
|
||||
assert_eq!(env.cwd(), &cwd);
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn test_create_on_temp_fs() -> std::io::Result<()> {
|
||||
let env = TempFileSystemEnv::new()?;
|
||||
assert!(env.cwd().exists());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn test_create_on_real_fs() {
|
||||
let cwd = PathBuf::from("/tmp");
|
||||
let env = RealFileSystemEnv::new(cwd.clone());
|
||||
assert_eq!(env.cwd(), &cwd);
|
||||
}
|
||||
}
|
22
src/init.rs
22
src/init.rs
|
@ -1,26 +1,22 @@
|
|||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub(crate) fn run() {
|
||||
use crate::filesystem::FileSystem;
|
||||
|
||||
pub(crate) fn run(fs: FileSystem) {
|
||||
let file_name = ".git-next.toml";
|
||||
let path = std::path::Path::new(file_name);
|
||||
if path.exists() {
|
||||
let path = PathBuf::from(file_name);
|
||||
if fs.file_exists(&path) {
|
||||
eprintln!(
|
||||
"The configuration file already exists at {} - not overwritting it.",
|
||||
file_name
|
||||
);
|
||||
} else {
|
||||
match std::fs::File::create(file_name) {
|
||||
Ok(mut file) => {
|
||||
match fs.write_file(file_name, include_str!("../default.toml")) {
|
||||
Ok(_) => {
|
||||
println!("Created a default configuration file at {}", file_name);
|
||||
match file.write_all(include_bytes!("../default.toml")) {
|
||||
Ok(_) => println!("Wrote to the configuration file successfully."),
|
||||
Err(e) => {
|
||||
eprintln!("Failed to write to the configuration file: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to create a default configuration file: {}", e);
|
||||
eprintln!("Failed to write to the configuration file: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
mod filesystem;
|
||||
mod init;
|
||||
mod server;
|
||||
|
||||
|
@ -21,18 +22,19 @@ enum Server {
|
|||
Start,
|
||||
}
|
||||
fn main() {
|
||||
let fs = filesystem::FileSystem::new_real(None);
|
||||
let commands = Commands::parse();
|
||||
|
||||
match commands.command {
|
||||
Command::Init => {
|
||||
init::run();
|
||||
init::run(fs);
|
||||
}
|
||||
Command::Server(server) => match server {
|
||||
Server::Init => {
|
||||
server::init();
|
||||
server::init(fs);
|
||||
}
|
||||
Server::Start => {
|
||||
server::start();
|
||||
server::start(fs);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,34 +1,28 @@
|
|||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use tracing::info;
|
||||
|
||||
pub(crate) fn init() {
|
||||
use crate::filesystem::FileSystem;
|
||||
|
||||
pub(crate) fn init(fs: FileSystem) {
|
||||
let file_name = "git-next-server.toml";
|
||||
let path = std::path::Path::new(file_name);
|
||||
if path.exists() {
|
||||
let path = PathBuf::from(file_name);
|
||||
if fs.file_exists(&path) {
|
||||
eprintln!(
|
||||
"The configuration file already exists at {} - not overwritting it.",
|
||||
file_name
|
||||
);
|
||||
} else {
|
||||
match std::fs::File::create(file_name) {
|
||||
Ok(mut file) => {
|
||||
println!("Created a default configuration file at {}", file_name);
|
||||
match file.write_all(include_bytes!("../server-default.toml")) {
|
||||
Ok(_) => println!("Wrote to the configuration file successfully."),
|
||||
Err(e) => {
|
||||
eprintln!("Failed to write to the configuration file: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
match fs.write_file(file_name, include_str!("../server-default.toml")) {
|
||||
Ok(_) => println!("Created a default configuration file at {}", file_name),
|
||||
Err(e) => {
|
||||
eprintln!("Failed to create a default configuration file: {}", e);
|
||||
eprintln!("Failed to write to the configuration file: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn start() {
|
||||
pub(crate) fn start(_fs: FileSystem) {
|
||||
let Ok(_) = init_logging() else {
|
||||
eprintln!("Failed to initialize logging.");
|
||||
return;
|
||||
|
|
Loading…
Reference in a new issue