From 0992c36733f58750da93921041424fd09f0158ed Mon Sep 17 00:00:00 2001 From: diogo464 Date: Tue, 8 Feb 2022 09:19:19 +0000 Subject: snapshot before removal --- dotup/src/depot.rs | 18 +++++++++++++++ dotup_cli/src/commands/mod.rs | 1 + dotup_cli/src/commands/mv.rs | 53 +++++++++++++++++++++++++++++++++++++++++++ dotup_cli/src/config.rs | 3 +++ dotup_cli/src/main.rs | 4 ++++ dotup_cli/src/utils.rs | 20 ++++++++++++++++ 6 files changed, 99 insertions(+) create mode 100644 dotup_cli/src/commands/mv.rs diff --git a/dotup/src/depot.rs b/dotup/src/depot.rs index c8801b9..658c0f6 100644 --- a/dotup/src/depot.rs +++ b/dotup/src/depot.rs @@ -194,6 +194,24 @@ impl Depot { None } + pub fn rename_link(&mut self, link_id: LinkID, origin: &Path) { + // TODO: improve + if let Some(id) = self.get_link_id_by_path(origin) { + if link_id != id { + self.remove_link(id); + } + } + if let Some(link) = self.links.get_mut(link_id) { + let origin_canonical = utils::weakly_canonical(origin); + if !origin_canonical.starts_with(&self.base_path) { + panic!("new origin outside depot"); + } + + link.origin = origin_canonical; + link.origin_canonical = utils::weakly_canonical(&link.origin); + } + } + /// checks if there are any linked files/directories under the path `path` /// if `path` is a path to a file and that file is linked then this function returns true pub fn subpath_has_links(&self, path: &Path) -> bool { diff --git a/dotup_cli/src/commands/mod.rs b/dotup_cli/src/commands/mod.rs index 94dc3fd..bd92599 100644 --- a/dotup_cli/src/commands/mod.rs +++ b/dotup_cli/src/commands/mod.rs @@ -1,6 +1,7 @@ pub mod init; pub mod install; pub mod link; +pub mod mv; pub mod status; pub mod uninstall; pub mod unlink; diff --git a/dotup_cli/src/commands/mv.rs b/dotup_cli/src/commands/mv.rs new file mode 100644 index 0000000..aae2715 --- /dev/null +++ b/dotup_cli/src/commands/mv.rs @@ -0,0 +1,53 @@ +use std::path::{Path, PathBuf}; + +use super::prelude::*; + +/// Install links. (Creates symlinks). +/// +/// Installing a link will create the necessary directories. +/// If a file or directory already exists at the location a link would be installed this command will fail. +#[derive(Parser)] +pub struct Opts { + /// The files/directories to move + #[clap(min_values = 2)] + paths: Vec, +} + +pub fn main(config: Config, opts: Opts) -> anyhow::Result<()> { + let mut depot = utils::read_depot(&config.archive_path)?; + + let (sources, destination) = match opts.paths.as_slice() { + [source, destination] => {} + [sources @ .., destination] => { + let mut curr_destination = destination.to_owned(); + for source in sources { + let filename = match source.file_name() { + Some(filename) => filename, + None => { + log::warn!("Ignoring '{}', unknown file name", source.display()); + continue; + } + }; + curr_destination.push(filename); + std::fs::rename(source, &curr_destination)?; + if let Some(id) = depot.get_link_id_by_path(&source) { + depot.rename_link(id, &curr_destination); + } + curr_destination.pop(); + } + } + _ => unreachable!(), + }; + + utils::write_depot(&depot)?; + + Ok(()) +} + +fn rename(depot: &mut Depot, source: &Path, destination: &Path) -> anyhow::Result<()> { + std::fs::rename(source, &destination)?; + if let Some(id) = depot.get_link_id_by_path(&source) { + depot.rename_link(id, &destination); + } + Ok(()) +} diff --git a/dotup_cli/src/config.rs b/dotup_cli/src/config.rs index 2046ad5..dabaf74 100644 --- a/dotup_cli/src/config.rs +++ b/dotup_cli/src/config.rs @@ -4,4 +4,7 @@ use std::path::PathBuf; pub struct Config { pub archive_path: PathBuf, pub install_path: PathBuf, + pub working_path: PathBuf, } + +impl Config {} diff --git a/dotup_cli/src/main.rs b/dotup_cli/src/main.rs index 6161ca7..0d730da 100644 --- a/dotup_cli/src/main.rs +++ b/dotup_cli/src/main.rs @@ -58,6 +58,7 @@ struct Opts { enum SubCommand { Init(commands::init::Opts), Link(commands::link::Opts), + Mv(commands::mv::Opts), Status(commands::status::Opts), Unlink(commands::unlink::Opts), Install(commands::install::Opts), @@ -89,16 +90,19 @@ fn main() -> anyhow::Result<()> { Some(path) => path, None => utils::home_directory()?, }; + let working_path = std::env::current_dir().expect("Failed to obtain current working directory"); log::debug!("Archive path : {}", archive_path.display()); let config = Config { archive_path, install_path, + working_path, }; match opts.subcmd { SubCommand::Init(opts) => commands::init::main(config, opts), SubCommand::Link(opts) => commands::link::main(config, opts), + SubCommand::Mv(opts) => commands::mv::main(config, opts), SubCommand::Status(opts) => commands::status::main(config, opts), SubCommand::Unlink(opts) => commands::unlink::main(config, opts), SubCommand::Install(opts) => commands::install::main(config, opts), diff --git a/dotup_cli/src/utils.rs b/dotup_cli/src/utils.rs index be9f3a9..b9a76a7 100644 --- a/dotup_cli/src/utils.rs +++ b/dotup_cli/src/utils.rs @@ -160,3 +160,23 @@ pub fn collect_read_dir_split( .map(|e| e.path()) .partition(|p| p.is_dir())) } + +/// Checks if `path` is inside a git repository +pub fn path_is_in_git_repo(path: &Path) -> bool { + let mut path = if !path.is_absolute() { + dbg!(dotup::utils::weakly_canonical(path)) + } else { + path.to_owned() + }; + let recurse = path.pop(); + path.push(".git"); + if path.is_dir() { + return true; + } + if recurse { + path.pop(); + return path_is_in_git_repo(&path); + } else { + return false; + } +} -- cgit