AH4KXL6MWNOCWA4OXBUHNP2GP2AVFC57VVHMHQLZ574ZXXHACXCQC
use globset::GlobSetBuilder;
use relative_path::RelativePathBuf;
use walkdir::WalkDir;
pub struct Module {
name: String,
paths: Vec<(RelativePathBuf, Vec<crate::config::Tag>)>,
target_directory: camino::Utf8PathBuf,
}
impl TryFrom<(crate::config::Config, String)> for Module {
type Error = crate::Error;
fn try_from(
(config, module_name): (crate::config::Config, String),
) -> Result<Self, Self::Error> {
let module = config
.modules
.get(&module_name)
.ok_or_else(|| crate::error::ReadConfig::InvalidModuleName(module_name.clone()))?;
let include = {
let mut gsb = GlobSetBuilder::new();
for entry in &module.include {
gsb.add(entry.glob.clone());
}
gsb.build()?
};
let exclude = {
let mut gsb = GlobSetBuilder::new();
for entry in &module.exclude {
gsb.add(entry.clone());
}
gsb.build()?
};
let paths: Result<Vec<_>, _> = WalkDir::new(".")
.into_iter()
.flatten()
.filter(|entry| include.is_match(entry.path()) && !exclude.is_match(entry.path()))
.map(|entry| {
RelativePathBuf::from_path(entry.path()).map(|relative_path| {
(
relative_path,
include
.matches(entry.path())
.iter()
.enumerate()
.filter_map(|(idx, num_matches)| {
if *num_matches != 0 {
module.include[idx].tag.clone()
} else {
None
}
})
.collect(),
)
})
})
.collect();
Ok(Self {
name: module_name,
paths: paths?,
})
}
}
mod cli;
fn main() {
println!("Hello, world!");
}
pub mod config;
pub mod error;
pub mod module;
pub use error::Error;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
ReadConfig(#[from] ReadConfig),
#[error(transparent)]
RelativePathError(#[from] relative_path::FromPathError),
#[error(transparent)]
ReadConfigFile(#[from] std::io::Error),
#[error(transparent)]
GlobSet(#[from] globset::Error),
}
#[derive(thiserror::Error, Debug)]
pub enum ReadConfig {
#[error("Invalid module name: '{0}'")]
InvalidModuleName(String),
#[error(transparent)]
ParseToml(#[from] toml::de::Error),
#[error(transparent)]
OpenFile(#[from] std::io::Error),
}
use globset::Glob;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::io::prelude::*;
#[derive(Serialize, Deserialize, Debug)]
pub struct Config {
pub modules: BTreeMap<String, Module>,
pub deploy: Vec<Deploy>,
}
impl Config {
fn read_from_file() -> Result<Self, crate::Error> {
let toml = std::fs::read(".fullstop.toml").map_err(crate::error::ReadConfig::OpenFile)?;
Ok(toml::from_slice(&toml).map_err(crate::error::ReadConfig::ParseToml)?)
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Module {
pub include: Vec<Include>,
pub exclude: Vec<Glob>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Include {
pub glob: Glob,
pub tag: Option<Tag>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Tag {
Rename(String),
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Deploy {
pub module: String,
pub directory: String,
}
use clap::{Parser};
#[derive(Parser, Debug)]
pub struct Opts {
#[clap(short, long, parse(from_occurrences))]
verbose: i32,
#[clap(subcommand)]
subcmd: SubCommand,
}
#[derive(Parser, Debug)]
enum SubCommand {
Init,
Sync,
}