From a43561832fcbdc7745838fd21b75d1f9f22d3ab7 Mon Sep 17 00:00:00 2001 From: Joshua Potter Date: Sat, 8 Jan 2022 16:55:46 -0500 Subject: [PATCH] Copy even if locally our file doesn't exist. --- src/copy.rs | 109 ++++++++++++++++++++++++++++++++++------------------ src/lib.rs | 4 +- src/main.rs | 18 +++++---- src/path.rs | 10 ++--- 4 files changed, 89 insertions(+), 52 deletions(-) diff --git a/src/copy.rs b/src/copy.rs index afcb115..f0bf73a 100644 --- a/src/copy.rs +++ b/src/copy.rs @@ -1,5 +1,5 @@ use super::{config::PathConfig, path, path::ResPathBuf}; -use simplelog::{info, paris}; +use simplelog::{info, paris, warn}; use std::{ collections::HashMap, env::VarError, @@ -58,15 +58,32 @@ impl error::Error for Error {} fn apply_all(pc: &PathConfig) -> Result<()> { let workdir = path::resolve(&pc.config.repos.local)?; - let repo_lookup = get_repo_lookup(workdir.as_ref(), workdir.as_ref())?; + let repo_files = walk_repo(workdir.as_ref())?; let package_lookup = get_package_lookup(pc); - for (repo_unresolved, repo_resolved) in &repo_lookup { - if let Some(package_resolved) = package_lookup.get(repo_unresolved) { - fs::copy(repo_resolved, package_resolved)?; + for repo_file in &repo_files { + let path = match package_lookup.get(repo_file.unresolved()) { + Some(value) => value, + None => continue, + }; + if let Some(value) = path { + fs::copy(repo_file.resolved(), value.resolved())?; info!( "Copied `{}` from local repository.", - repo_unresolved.display(), + repo_file.unresolved().display(), + ); + } else { + let expanded = match path::expand(repo_file.unresolved()) { + Ok(expanded) => expanded, + Err(_) => continue, + }; + if let Some(p) = expanded.parent() { + fs::create_dir_all(p)?; + } + fs::copy(repo_file.resolved(), expanded)?; + info!( + "Copied `{}` from local repository.", + repo_file.unresolved().display(), ); } } @@ -74,25 +91,36 @@ fn apply_all(pc: &PathConfig) -> Result<()> { Ok(()) } -fn apply_one(pc: &PathConfig, target: &Path) -> Result<()> { +fn apply_one(pc: &PathConfig, package: &str) -> Result<()> { let workdir = path::resolve(&pc.config.repos.local)?; - let repo_lookup = get_repo_lookup(workdir.as_ref(), workdir.as_ref())?; - let package_lookup = get_package_lookup(pc); - // The user must specify a path that matches the unresolved one. - if let Some(repo_resolved) = repo_lookup.get(target) { - if let Some(package_resolved) = package_lookup.get(target) { - fs::copy(repo_resolved, package_resolved)?; - info!("Copied `{}` from local repository.", target.display(),); + if let Some(paths) = pc.config.packages.get(package) { + for path in paths { + let mut repo_file = workdir.resolved().to_path_buf(); + repo_file.push(path); + if !repo_file.exists() { + continue; + } + let expanded = match path::expand(path) { + Ok(expanded) => expanded, + Err(_) => continue, + }; + if let Some(p) = expanded.parent() { + fs::create_dir_all(p)?; + } + fs::copy(repo_file, expanded)?; + info!("Copied `{}` from local repository.", path.display()); } + } else { + warn!("Could not find package `{}` in config.", package); } Ok(()) } -pub fn apply(pc: &PathConfig, file: Option<&str>) -> Result<()> { - if let Some(file) = file { - apply_one(pc, Path::new(file)) +pub fn apply(pc: &PathConfig, package: Option<&str>) -> Result<()> { + if let Some(package) = package { + apply_one(pc, package) } else { apply_all(pc) } @@ -104,16 +132,16 @@ pub fn apply(pc: &PathConfig, file: Option<&str>) -> Result<()> { pub fn stage(pc: &PathConfig) -> Result<()> { let workdir = path::resolve(&pc.config.repos.local)?; - let repo_lookup = get_repo_lookup(workdir.as_ref(), workdir.as_ref())?; + let repo_files = walk_repo(workdir.as_ref())?; let package_lookup = get_package_lookup(pc); // Find all files in our repository that are no longer being referenced in // our primary config file. They should be removed from the repository. - for (repo_unresolved, repo_resolved) in &repo_lookup { - if !package_lookup.contains_key(repo_unresolved) { - fs::remove_file(repo_resolved)?; + for repo_file in &repo_files { + if !package_lookup.contains_key(repo_file.unresolved()) { + fs::remove_file(repo_file.resolved())?; } - if let Some(p) = repo_resolved.resolved().parent() { + if let Some(p) = repo_file.resolved().parent() { if p.read_dir()?.next().is_none() { fs::remove_dir(p)?; } @@ -122,13 +150,15 @@ pub fn stage(pc: &PathConfig) -> Result<()> { // Find all resolvable files in our primary config and copy them into the // repository. - for (package_unresolved, package_resolved) in &package_lookup { - let mut copy = package_resolved.resolved().to_path_buf(); - copy.push(package_unresolved); - if let Some(p) = copy.parent() { - fs::create_dir_all(p)?; + for (key, value) in &package_lookup { + if let Some(value) = value { + let mut copy = value.resolved().to_path_buf(); + copy.push(key); + if let Some(p) = copy.parent() { + fs::create_dir_all(p)?; + } + fs::copy(value.resolved(), copy)?; } - fs::copy(package_resolved.resolved(), copy)?; } info!( @@ -143,8 +173,8 @@ pub fn stage(pc: &PathConfig) -> Result<()> { // Utility // ======================================== -fn get_repo_lookup(root: &Path, path: &Path) -> Result> { - let mut seen = HashMap::new(); +fn recursive_walk_repo(root: &Path, path: &Path) -> Result> { + let mut seen = Vec::new(); if path.is_dir() { for entry in fs::read_dir(path)? { let nested = entry?.path(); @@ -152,26 +182,31 @@ fn get_repo_lookup(root: &Path, path: &Path) -> Result HashMap { +fn walk_repo(root: &Path) -> Result> { + recursive_walk_repo(root, root) +} + +fn get_package_lookup(pc: &PathConfig) -> HashMap> { let mut seen = HashMap::new(); for (_, packages) in &pc.config.packages { for path in packages { if let Ok(resolved) = path::resolve(path) { - seen.insert(path.to_path_buf(), resolved); + seen.insert(path.to_path_buf(), Some(resolved)); + } else { + seen.insert(path.to_path_buf(), None); } } } diff --git a/src/lib.rs b/src/lib.rs index deeed14..a00c3f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,8 +9,8 @@ use std::error::Error; type Result = std::result::Result<(), Box>; -pub fn run_apply(config: PathConfig, file: Option<&str>) -> Result { - copy::apply(&config, file)?; +pub fn run_apply(config: PathConfig, package: Option<&str>) -> Result { + copy::apply(&config, package)?; Ok(()) } diff --git a/src/main.rs b/src/main.rs index 1e88baf..e4796b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,10 @@ use clap::{App, AppSettings, Arg}; use homesync::path::ResPathBuf; -use simplelog; -use simplelog::{error, paris}; use std::{error::Error, io, path::PathBuf}; +use { + simplelog, + simplelog::{error, paris}, +}; #[cfg(debug_assertions)] fn log_level() -> simplelog::LevelFilter { @@ -42,18 +44,18 @@ fn main() { App::new("apply") .about("Copy files from local repository to rest of desktop") .arg( - Arg::new("file") - .value_name("FILE") + Arg::new("package") + .value_name("PACKAGE") .conflicts_with("all") .required_unless_present("all") - .help("The file we want to overwrite from the local repository") + .help("The package we want to configure from the local repository") .takes_value(true), ) .arg( Arg::new("all") .long("all") - .conflicts_with("file") - .help("Indicates we want to copy all files from the local repository") + .conflicts_with("package") + .help("Indicates we want to copy all configurations from the local repository") .takes_value(false), ), ) @@ -93,7 +95,7 @@ fn dispatch(matches: clap::ArgMatches) -> Result<(), Box> { let candidates = find_candidates(&matches)?; let config = homesync::config::load(&candidates)?; match matches.subcommand() { - Some(("apply", matches)) => Ok(homesync::run_apply(config, matches.value_of("file"))?), + Some(("apply", matches)) => Ok(homesync::run_apply(config, matches.value_of("package"))?), Some(("daemon", matches)) => { let freq_secs: u64 = match matches.value_of("frequency") { Some(f) => f.parse().unwrap_or(0), diff --git a/src/path.rs b/src/path.rs index 80ff151..28fbc0e 100644 --- a/src/path.rs +++ b/src/path.rs @@ -68,13 +68,13 @@ fn unresolved_error(path: &Path) -> io::Error { } impl ResPathBuf { - pub fn new(path: &Path) -> Result { - if !path.is_absolute() { - Err(unresolved_error(path))?; + pub fn new(inner: &Path, unresolved: &Path) -> Result { + if !inner.is_absolute() { + Err(unresolved_error(inner))?; } Ok(ResPathBuf { - inner: path.to_path_buf(), - unresolved: path.to_path_buf(), + inner: inner.to_path_buf(), + unresolved: unresolved.to_path_buf(), }) }