feat(export): second move method

This commit is contained in:
steven-omaha
2023-06-06 15:30:24 +02:00
parent 0b7fcbbbd4
commit 0610cd0731
+59 -29
View File
@@ -1,6 +1,6 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::env::current_dir; use std::env::current_dir;
use std::fs::{remove_file, rename, File}; use std::fs::{copy, remove_file, rename, File};
use std::os::unix::fs::symlink; use std::os::unix::fs::symlink;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@@ -12,11 +12,11 @@ use crate::backend::{Backend, Backends, ToDoPerBackend};
use crate::cmd::run_edit_command; use crate::cmd::run_edit_command;
use crate::env::get_single_var; use crate::env::get_single_var;
use crate::path::{binary_in_path, get_absolutized_file_paths, get_group_dir}; use crate::path::{binary_in_path, get_absolutized_file_paths, get_group_dir};
use crate::review;
use crate::search; use crate::search;
use crate::ui::get_user_confirmation; use crate::ui::get_user_confirmation;
use crate::Config; use crate::Config;
use crate::Group; use crate::Group;
use crate::{review, Error};
/// Most data that is required during runtime of the program. /// Most data that is required during runtime of the program.
/// `args` is an `Option` so that we can take ownership later without cloning. /// `args` is an `Option` so that we can take ownership later without cloning.
@@ -399,25 +399,17 @@ impl Pacdef {
Ok(()) Ok(())
} }
fn export_groups(&self, groups: &[String]) -> Result<()> { fn export_groups(&self, names: &[String]) -> Result<()> {
let groups: Vec<_> = groups let groups = find_groups_by_name(names, &self.groups)?;
.iter()
.map(|group_name| {
self.groups
.iter()
.find(|group| group.name == *group_name)
.unwrap()
})
.collect();
let output_dir = current_dir()?; let output_dir = current_dir()?;
for group in &groups { for group in &groups {
let mut exported_path = output_dir.clone(); let mut exported_path = output_dir.clone();
exported_path.push(PathBuf::from(&group.name)); exported_path.push(PathBuf::from(&group.name));
// TODO: check if output exists
// TODO: check if this was successful, resort to the other method otherwise ensure!(!exported_path.exists(), "{exported_path:?} already exists");
rename(&group.path, &exported_path)?;
move_file(&group.path, &exported_path)?;
symlink(&exported_path, &group.path)?; symlink(&exported_path, &group.path)?;
} }
@@ -425,6 +417,53 @@ impl Pacdef {
} }
} }
fn move_file<P, Q>(from: P, to: Q) -> Result<()>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
let from = from.as_ref();
let to = to.as_ref();
match rename(from, to) {
Ok(_) => (),
Err(e) => {
// CrossesDevices is nightly. See rust #86442.
// We cannot check that here, so we just assume that
// that would be the error if permisisons are okay.
if e.kind() == std::io::ErrorKind::PermissionDenied {
bail!(e);
}
copy(from, to)?;
remove_file(from)?;
}
};
Ok(())
}
/// For the provided names, get the group with the same name.
///
/// # Errors
///
/// This function will return an error if any of the file names
/// do not match one of group names.
fn find_groups_by_name<'a>(names: &[String], groups: &'a HashSet<Group>) -> Result<Vec<&'a Group>> {
let name_group_map: HashMap<&str, &Group> =
groups.iter().map(|g| (g.name.as_str(), g)).collect();
let mut result = Vec::new();
for file in names {
match name_group_map.get(file.as_str()) {
Some(group) => {
result.push(*group);
}
None => bail!(Error::GroupFileNotFound(file.clone())),
}
}
Ok(result)
}
/// For the provided CLI arguments, get the absolute path to each corresponding /// For the provided CLI arguments, get the absolute path to each corresponding
/// group file. /// group file.
/// ///
@@ -436,19 +475,10 @@ fn get_group_file_paths_matching_args<'a>(
file_names: &[String], file_names: &[String],
groups: &'a HashSet<Group>, groups: &'a HashSet<Group>,
) -> Result<Vec<&'a Path>> { ) -> Result<Vec<&'a Path>> {
let name_group_map: HashMap<&str, &Group> = let result = find_groups_by_name(file_names, groups)?
groups.iter().map(|g| (g.name.as_str(), g)).collect(); .into_iter()
.map(|g| g.path.as_path())
let mut result = Vec::new(); .collect();
for file in file_names {
match name_group_map.get(file.as_str()) {
Some(group) => {
result.push(group.path.as_path());
}
None => bail!(crate::errors::Error::GroupFileNotFound(file.clone())),
}
}
Ok(result) Ok(result)
} }