Skip to content

Commit

Permalink
fixed #54: fallback is fully implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
RaphGL committed Jan 29, 2025
1 parent 79b9cbb commit 41528c0
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 50 deletions.
17 changes: 10 additions & 7 deletions src/dotfiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ pub const VALID_TARGETS: &[&str] = &[
"_windows",
];

pub fn get_target_priority(target: impl AsRef<str>) -> usize {
let target = target.as_ref();
match target {
"_unix" | "_windows" => 2,
_ if !group_ends_with_target_name(target) => 0,
_ => 1,
}
}

pub fn get_highest_priority_target_idx(targets: &[impl AsRef<str>]) -> Option<usize> {
if targets.is_empty() {
return None;
Expand All @@ -38,13 +47,7 @@ pub fn get_highest_priority_target_idx(targets: &[impl AsRef<str>]) -> Option<us
let mut highest_idx = 0;

for (idx, target) in targets.iter().enumerate() {
let target = target.as_ref();

let target_priority = match target {
"_unix" | "_windows" => 2,
_ if !group_ends_with_target_name(target) => 0,
_ => 1,
};
let target_priority = get_target_priority(target);

if target_priority >= highest_priority {
highest_priority = target_priority;
Expand Down
115 changes: 72 additions & 43 deletions src/symlinks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,47 @@ impl SymlinkHandler {
}
}

/// returns a cache with files in dotfiles that already exist in $HOME
/// todo: test and somethingsomething group not being marked as conflict when both have $HOME/test file
fn get_conflicts_in_cache(&self) -> HashCache {
let mut conflicts = HashCache::new();

// mark group as conflicting if at least one value already exists in $HOME
for files in self.not_symlinked.values() {
for file in files {
if file.to_target_path().unwrap().exists() && file.is_valid_target() {
conflicts.entry(file.group_name.clone()).or_default();
let curr_entry = conflicts.get_mut(&file.group_name).unwrap();
curr_entry.insert(file.clone());
}
}
}

for files in self.not_owned.values() {
for file in files {
conflicts.entry(file.group_name.clone()).or_default();
let curr_entry = conflicts.get_mut(&file.group_name).unwrap();

let dotfile_source = file.to_target_path().unwrap().read_link().unwrap();
let Ok(dotfile) = Dotfile::try_from(dotfile_source) else {
curr_entry.insert(file.clone());
continue;
};

let target_has_higher_priority = dotfiles::get_target_priority(&dotfile.group_name)
> dotfiles::get_target_priority(&file.group_name);
let not_same_base_group = dotfiles::group_without_target(&file.group_name)
!= dotfiles::group_without_target(&dotfile.group_name);

if dotfile.path != file.path && target_has_higher_priority && not_same_base_group {
curr_entry.insert(file.clone());
}
}
}

conflicts.into_iter().filter(|g| !g.1.is_empty()).collect()
}

/// Symlinks all the files of a group to the user's $HOME
fn add(&self, group: &str) {
let Some(mut groups) =
Expand Down Expand Up @@ -569,26 +610,6 @@ pub fn remove_cmd(
Ok(())
}

/// returns a cache with files in dotfiles that already exist in $HOME
fn get_conflicts_in_cache(cache: &HashCache) -> HashCache {
let mut conflicts = HashCache::new();

// mark group as conflicting if at least one value already exists in $HOME
for files in cache.values() {
for file in files {
if !file.to_target_path().unwrap().exists() || !file.is_valid_target() {
continue;
}

conflicts.entry(file.group_name.clone()).or_default();
let entry = conflicts.get_mut(&file.group_name).unwrap();
entry.insert(file.clone());
}
}

conflicts
}

fn print_global_status(sym: &SymlinkHandler) -> Result<(), ExitCode> {
#[derive(Tabled, Debug)]
struct SymlinkRow<'a> {
Expand Down Expand Up @@ -667,10 +688,10 @@ fn print_global_status(sym: &SymlinkHandler) -> Result<(), ExitCode> {
};

// --- detect conflicts ---
let conflicts = get_conflicts_in_cache(&sym.not_symlinked);
let conflicts = sym.get_conflicts_in_cache();
// whether a conflict is a symlink or a pre-existing file does not matter for global status
// so we just add them together
let conflicts: HashSet<_> = conflicts.keys().chain(sym.not_owned.keys()).collect();
let conflicts: HashSet<_> = conflicts.keys().collect();

// --- Creates all the tables and prints them ---
use tabled::{
Expand Down Expand Up @@ -773,13 +794,6 @@ fn print_groups_status(
let not_symlinked = get_related_groups(sym, None);
let symlinked = get_related_groups(sym, Some(&not_symlinked));

let not_owned: HashCache = sym
.not_owned
.clone()
.into_iter()
.filter(|(group, _)| groups.contains(group))
.collect();

let unsupported = {
let mut unsupported = groups
.iter()
Expand All @@ -793,29 +807,44 @@ fn print_groups_status(
unsupported
};

if !not_symlinked.is_empty() || !not_owned.is_empty() {
let print_conflicts = |conflicts_cache: &HashCache, group: &str, msg: &str| {
let file_conflicts: HashCache = sym
.get_conflicts_in_cache()
.into_iter()
.filter(|(g, _)| groups.contains(g))
.collect();

if !file_conflicts.is_empty() || !not_symlinked.is_empty() {
fn print_conflicts(conflicts_cache: &HashCache, group: &str) {
let Some(conflicts) = conflicts_cache.get(group) else {
return;
};

for file in conflicts {
if file.group_name != group {
continue;
}

let conflict = file.to_target_path().unwrap();
println!("\t\t-> {} ({})", conflict.display(), msg,);
let conflict_dotfile = Dotfile::try_from(conflict.read_link().unwrap());

let msg = match conflict_dotfile {
Ok(conflict) => {
if file.path != conflict.path {
t!("errors.already_exists")
} else {
unreachable!();
}
}
Err(_) => t!("errors.symlinks_elsewhere"),
};
println!("\t\t -> {} ({})", conflict.display(), msg,);
}
};

let file_conflicts = get_conflicts_in_cache(&sym.not_symlinked);
}

println!("{}:", t!("table-column.not_symlinked"));
for group in &not_symlinked {
for group in not_symlinked {
println!("\t{}", group.red());
}

for group in file_conflicts.keys() {
println!("\t{}", group.red());
print_conflicts(&file_conflicts, group, &t!("errors.already_exists"));
print_conflicts(&sym.not_owned, group, &t!("errors.symlinks_elsewhere"));
print_conflicts(&file_conflicts, group);
}

println!();
Expand Down Expand Up @@ -846,7 +875,7 @@ fn print_groups_status(
println!();
}

if !not_symlinked.is_empty() {
if !file_conflicts.is_empty() {
println!(
"{}",
t!("info.learn_how_to_fix_symlinks", cmd = "tuckr help add")
Expand Down

0 comments on commit 41528c0

Please sign in to comment.