|
@@ -65,6 +65,11 @@ file_has_markers() {
|
|
|
grep -qE '@(host|group) ' "$1" 2>/dev/null
|
|
grep -qE '@(host|group) ' "$1" 2>/dev/null
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+# Check if any file in a directory tree contains markers
|
|
|
|
|
+dir_has_markers() {
|
|
|
|
|
+ grep -rqlE '@(host|group) ' "$1" 2>/dev/null
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
# Detect the comment prefix from the first marker line in a file
|
|
# Detect the comment prefix from the first marker line in a file
|
|
|
detect_comment_prefix() {
|
|
detect_comment_prefix() {
|
|
|
local src="$1"
|
|
local src="$1"
|
|
@@ -302,61 +307,104 @@ sub_sync(){
|
|
|
fi
|
|
fi
|
|
|
fi
|
|
fi
|
|
|
|
|
|
|
|
- # Deploy dotfiles (symlink or process markers)
|
|
|
|
|
- log_info "Deploying dotfiles for $hostname_id..."
|
|
|
|
|
- get_sync_list | while IFS= read -r p; do
|
|
|
|
|
- local source
|
|
|
|
|
- source=$(resolve_source "$p")
|
|
|
|
|
- local destination="$HOME/$p"
|
|
|
|
|
-
|
|
|
|
|
- if [[ ! -e "$source" ]]; then
|
|
|
|
|
- log_warn "Source file $source does not exist, skipping"
|
|
|
|
|
- continue
|
|
|
|
|
- fi
|
|
|
|
|
|
|
+ # Deploy a single file: process markers or symlink
|
|
|
|
|
+ deploy_file() {
|
|
|
|
|
+ local src="$1"
|
|
|
|
|
+ local dest="$2"
|
|
|
|
|
|
|
|
- mkdir -p "$(dirname "$destination")"
|
|
|
|
|
|
|
+ mkdir -p "$(dirname "$dest")"
|
|
|
|
|
|
|
|
- if [[ -f "$source" ]] && file_has_markers "$source"; then
|
|
|
|
|
|
|
+ if file_has_markers "$src"; then
|
|
|
# File has markers — process and write (not symlink)
|
|
# File has markers — process and write (not symlink)
|
|
|
- if [[ -L "$destination" ]]; then
|
|
|
|
|
- rm "$destination"
|
|
|
|
|
|
|
+ if [[ -L "$dest" ]]; then
|
|
|
|
|
+ rm "$dest"
|
|
|
fi
|
|
fi
|
|
|
|
|
|
|
|
local comment_prefix
|
|
local comment_prefix
|
|
|
- comment_prefix=$(detect_comment_prefix "$source")
|
|
|
|
|
|
|
+ comment_prefix=$(detect_comment_prefix "$src")
|
|
|
|
|
|
|
|
{
|
|
{
|
|
|
echo "$comment_prefix DO NOT EDIT - Generated by dotsync from:"
|
|
echo "$comment_prefix DO NOT EDIT - Generated by dotsync from:"
|
|
|
- echo "$comment_prefix $source"
|
|
|
|
|
|
|
+ echo "$comment_prefix $src"
|
|
|
echo ""
|
|
echo ""
|
|
|
- process_markers "$source"
|
|
|
|
|
- } > "$destination.dotsync_tmp"
|
|
|
|
|
|
|
+ process_markers "$src"
|
|
|
|
|
+ } > "$dest.dotsync_tmp"
|
|
|
|
|
|
|
|
# Only update if content changed
|
|
# Only update if content changed
|
|
|
- if [[ -f "$destination" ]] && cmp -s "$destination" "$destination.dotsync_tmp"; then
|
|
|
|
|
- rm "$destination.dotsync_tmp"
|
|
|
|
|
|
|
+ if [[ -f "$dest" ]] && cmp -s "$dest" "$dest.dotsync_tmp"; then
|
|
|
|
|
+ rm "$dest.dotsync_tmp"
|
|
|
else
|
|
else
|
|
|
- [[ -e "$destination" ]] && rm "$destination"
|
|
|
|
|
- mv "$destination.dotsync_tmp" "$destination"
|
|
|
|
|
- chmod --reference="$source" "$destination"
|
|
|
|
|
- log_info "Processed: $destination (from $source)"
|
|
|
|
|
|
|
+ [[ -e "$dest" ]] && rm "$dest"
|
|
|
|
|
+ mv "$dest.dotsync_tmp" "$dest"
|
|
|
|
|
+ chmod --reference="$src" "$dest"
|
|
|
|
|
+ log_info "Processed: $dest (from $src)"
|
|
|
fi
|
|
fi
|
|
|
else
|
|
else
|
|
|
- # No markers — symlink as before
|
|
|
|
|
- if [[ -L "$destination" ]] && [[ "$(readlink "$destination")" == "$source" ]]; then
|
|
|
|
|
- continue # Already correctly linked
|
|
|
|
|
|
|
+ # No markers — symlink
|
|
|
|
|
+ if [[ -L "$dest" ]] && [[ "$(readlink "$dest")" == "$src" ]]; then
|
|
|
|
|
+ return # Already correctly linked
|
|
|
fi
|
|
fi
|
|
|
|
|
|
|
|
- if [[ -e "$destination" ]] || [[ -L "$destination" ]]; then
|
|
|
|
|
- log_warn "Removing existing $destination"
|
|
|
|
|
- rm -rf "$destination"
|
|
|
|
|
|
|
+ if [[ -e "$dest" ]] || [[ -L "$dest" ]]; then
|
|
|
|
|
+ log_warn "Removing existing $dest"
|
|
|
|
|
+ rm -rf "$dest"
|
|
|
fi
|
|
fi
|
|
|
|
|
|
|
|
- if ln -s "$source" "$destination"; then
|
|
|
|
|
- log_info "Linked: $destination -> $source"
|
|
|
|
|
|
|
+ if ln -s "$src" "$dest"; then
|
|
|
|
|
+ log_info "Linked: $dest -> $src"
|
|
|
|
|
+ else
|
|
|
|
|
+ log_error "Failed to create symlink for $(basename "$dest")"
|
|
|
|
|
+ fi
|
|
|
|
|
+ fi
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # Deploy dotfiles (symlink or process markers)
|
|
|
|
|
+ log_info "Deploying dotfiles for $hostname_id..."
|
|
|
|
|
+ get_sync_list | while IFS= read -r p; do
|
|
|
|
|
+ local source
|
|
|
|
|
+ source=$(resolve_source "$p")
|
|
|
|
|
+ local destination="$HOME/$p"
|
|
|
|
|
+
|
|
|
|
|
+ if [[ ! -e "$source" ]]; then
|
|
|
|
|
+ log_warn "Source $source does not exist, skipping"
|
|
|
|
|
+ continue
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ if [[ -d "$source" ]]; then
|
|
|
|
|
+ if dir_has_markers "$source"; then
|
|
|
|
|
+ # Directory contains markers — expand into per-file operations
|
|
|
|
|
+ # Remove directory-level symlink if present
|
|
|
|
|
+ if [[ -L "$destination" ]]; then
|
|
|
|
|
+ log_warn "Replacing directory symlink $destination with expanded files"
|
|
|
|
|
+ rm "$destination"
|
|
|
|
|
+ fi
|
|
|
|
|
+ mkdir -p "$destination"
|
|
|
|
|
+
|
|
|
|
|
+ # Walk all files in the source directory
|
|
|
|
|
+ while IFS= read -r src_file; do
|
|
|
|
|
+ local rel="${src_file#"$source/"}"
|
|
|
|
|
+ deploy_file "$src_file" "$destination/$rel"
|
|
|
|
|
+ done < <(find "$source" -type f | sort)
|
|
|
else
|
|
else
|
|
|
- log_error "Failed to create symlink for $p"
|
|
|
|
|
|
|
+ # No markers in directory — symlink the whole directory
|
|
|
|
|
+ if [[ -L "$destination" ]] && [[ "$(readlink "$destination")" == "$source" ]]; then
|
|
|
|
|
+ continue # Already correctly linked
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ if [[ -e "$destination" ]] || [[ -L "$destination" ]]; then
|
|
|
|
|
+ log_warn "Removing existing $destination"
|
|
|
|
|
+ rm -rf "$destination"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ if ln -s "$source" "$destination"; then
|
|
|
|
|
+ log_info "Linked: $destination -> $source"
|
|
|
|
|
+ else
|
|
|
|
|
+ log_error "Failed to create symlink for $p"
|
|
|
|
|
+ fi
|
|
|
fi
|
|
fi
|
|
|
|
|
+ else
|
|
|
|
|
+ # Single file entry
|
|
|
|
|
+ deploy_file "$source" "$destination"
|
|
|
fi
|
|
fi
|
|
|
done
|
|
done
|
|
|
|
|
|