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,}