From 51eae214cc373da601148c269dd51542aed8b653 Mon Sep 17 00:00:00 2001 From: Misaka Company Date: Wed, 28 Jan 2026 13:45:43 +0800 Subject: [PATCH] Add file conflict handling to minio-upload skill Implement comprehensive file conflict detection and resolution: - Check for existing files before upload using mc stat (fixes mc ls bug) - Interactive prompt when conflict detected: overwrite, skip, backup, rename - Command-line options for non-interactive use: --force, --skip, --backup, --rename - Auto-rename with numeric suffix when file exists - Backup existing files with .bak extension before overwriting - Update SKILL.md with conflict handling documentation and examples Co-Authored-By: Claude Sonnet 4.5 --- skills/minio-upload/SKILL.md | 47 ++++- .../scripts/upload_to_obsidian.sh | 173 +++++++++++++++++- 2 files changed, 208 insertions(+), 12 deletions(-) diff --git a/skills/minio-upload/SKILL.md b/skills/minio-upload/SKILL.md index 4a7eb23..8b9f754 100644 --- a/skills/minio-upload/SKILL.md +++ b/skills/minio-upload/SKILL.md @@ -19,6 +19,47 @@ Upload to a specific vault: .claude/skills/minio-upload/scripts/upload_to_obsidian.sh path/to/file.md "journal" ``` +## File Conflict Handling + +**CRITICAL**: When a file with the same name already exists in the target vault, the script will prompt you to choose an action (unless an option is specified). + +### Interactive Prompt (Default) + +If the file exists and no option is provided, you'll see: +``` +âš ī¸ File 'filename.md' already exists in vault 'main' +Choose an action: + [o] Overwrite - Replace existing file + [s] Skip - Cancel upload + [b] Backup - Backup existing file (.bak) then overwrite + [r] Rename - Upload with new name (adds numeric suffix) +``` + +### Command-Line Options + +You can specify the behavior explicitly to skip the prompt: + +- `--force` - Overwrite existing files without prompting +- `--skip` - Skip upload if file already exists +- `--backup` - Backup existing file (creates `.bak` file) before overwriting +- `--rename` - Automatically rename with numeric suffix (e.g., `file-1.md`, `file-2.md`) + +### Examples + +```bash +# Force overwrite without prompting +upload_to_obsidian.sh file.md main --force + +# Skip if file exists +upload_to_obsidian.sh file.md journal --skip + +# Backup before overwriting +upload_to_obsidian.sh file.md work --backup + +# Auto-rename if conflict +upload_to_obsidian.sh file.md personal --rename +``` + ## Vault Configuration **CRITICAL RULE**: When no vault is explicitly specified by the user, files MUST be uploaded to the `main` vault only. Do NOT assume or invent other vault names. @@ -52,8 +93,10 @@ The MinIO obsidian bucket contains Obsidian vaults as top-level directories: 1. **Verify file exists** - Check that the source file is accessible 2. **Determine target vault** - Use specified vault name or default to `main` -3. **Upload with mc** - Execute `mc cp` command to transfer file -4. **Confirm success** - Verify upload completed and report target location +3. **Check for conflicts** - Detect if file already exists in target vault +4. **Resolve conflict** - Prompt user or use specified option to handle conflict +5. **Upload with mc** - Execute `mc cp` command to transfer file +6. **Confirm success** - Verify upload completed and report target location ## Error Handling diff --git a/skills/minio-upload/scripts/upload_to_obsidian.sh b/skills/minio-upload/scripts/upload_to_obsidian.sh index e3ee77c..8514d83 100755 --- a/skills/minio-upload/scripts/upload_to_obsidian.sh +++ b/skills/minio-upload/scripts/upload_to_obsidian.sh @@ -1,28 +1,78 @@ #!/bin/bash # # Upload files to MinIO obsidian bucket -# Usage: upload_to_obsidian.sh [subpath] +# Usage: upload_to_obsidian.sh [subpath] [options] # # Arguments: # file_path - Path to the file to upload -# subpath - Optional subpath within obsidian bucket (default: main) +# subpath - Optional subpath/vault within obsidian bucket (default: main) +# +# Options: +# --force - Overwrite existing files without prompting +# --skip - Skip upload if file already exists +# --backup - Backup existing file before overwriting (.bak extension) +# --rename - Automatically rename if file exists (adds numeric suffix) # # Examples: # upload_to_obsidian.sh temp/file.md -# upload_to_obsidian.sh temp/file.md notes/2024 -# upload_to_obsidian.sh temp/file.md "archive/old projects" +# upload_to_obsidian.sh temp/file.md journal +# upload_to_obsidian.sh temp/file.md main --force +# upload_to_obsidian.sh temp/file.md work --skip set -e -# Check arguments -if [ $# -lt 1 ]; then - echo "Usage: $0 [subpath]" >&2 +# Initialize variables +FORCE=false +SKIP=false +BACKUP=false +RENAME=false +FILE_PATH="" +SUBPATH="main" + +# Parse arguments +while [[ $# -gt 0 ]]; do + case "$1" in + --force) + FORCE=true + shift + ;; + --skip) + SKIP=true + shift + ;; + --backup) + BACKUP=true + shift + ;; + --rename) + RENAME=true + shift + ;; + -*) + echo "Error: Unknown option '$1'" >&2 + echo "Usage: $0 [subpath] [--force|--skip|--backup|--rename]" >&2 + exit 1 + ;; + *) + if [ -z "$FILE_PATH" ]; then + FILE_PATH="$1" + elif [ "$SUBPATH" = "main" ]; then + SUBPATH="$1" + else + echo "Error: Too many arguments" >&2 + exit 1 + fi + shift + ;; + esac +done + +# Check file path argument +if [ -z "$FILE_PATH" ]; then + echo "Usage: $0 [subpath] [--force|--skip|--backup|--rename]" >&2 exit 1 fi -FILE_PATH="$1" -SUBPATH="${2:-main}" # Default to 'main' if not specified - # Validate file exists if [ ! -f "$FILE_PATH" ]; then echo "Error: File '$FILE_PATH' does not exist" >&2 @@ -38,6 +88,109 @@ TARGET_PATH="minio/obsidian/${SUBPATH}/${FILENAME}" # Ensure subpath ends without trailing slash for mc TARGET_PATH=$(echo "$TARGET_PATH" | sed 's://*:/:g') +# Check if file already exists +if mc stat "$TARGET_PATH" >/dev/null 2>&1; then + # User explicitly specified --skip + if [ "$SKIP" = true ]; then + echo "â„šī¸ File already exists, skipping upload: $TARGET_PATH" + exit 0 + fi + + # User explicitly specified --backup + if [ "$BACKUP" = true ]; then + BACKUP_PATH="${TARGET_PATH}.bak" + echo "đŸ“Ļ Backing up existing file: $TARGET_PATH -> $BACKUP_PATH" + mc cp "$TARGET_PATH" "$BACKUP_PATH" + # User explicitly specified --rename + elif [ "$RENAME" = true ]; then + COUNTER=1 + BASE_NAME="${FILENAME%.*}" + EXT="${FILENAME##*.}" + + if [ "$BASE_NAME" = "$EXT" ]; then + # No extension + BASE_NAME="$FILENAME" + EXT="" + else + EXT=".$EXT" + fi + + while true; do + NEW_NAME="${BASE_NAME}-${COUNTER}${EXT}" + NEW_TARGET="minio/obsidian/${SUBPATH}/${NEW_NAME}" + if ! mc stat "$NEW_TARGET" >/dev/null 2>&1; then + TARGET_PATH="$NEW_TARGET" + FILENAME="$NEW_NAME" + echo "📝 Renamed to: $FILENAME" + break + fi + COUNTER=$((COUNTER + 1)) + done + # User explicitly specified --force + elif [ "$FORCE" = true ]; then + echo "âš ī¸ Overwriting existing file: $TARGET_PATH" + else + # No explicit option - prompt user + echo "" + echo "âš ī¸ File '$FILENAME' already exists in vault '${SUBPATH}'" + echo "Target: $TARGET_PATH" + echo "" + echo "Choose an action:" + echo " [o] Overwrite - Replace existing file" + echo " [s] Skip - Cancel upload" + echo " [b] Backup - Backup existing file (.bak) then overwrite" + echo " [r] Rename - Upload with new name (adds numeric suffix)" + echo "" + + while true; do + read -p "Your choice [o/s/b/r]: " choice + case "$choice" in + o|O|overwrite) + echo "Overwriting existing file..." + break + ;; + s|S|skip) + echo "❌ Upload cancelled" + exit 0 + ;; + b|B|backup) + BACKUP_PATH="${TARGET_PATH}.bak" + echo "đŸ“Ļ Backing up existing file: $TARGET_PATH -> $BACKUP_PATH" + mc cp "$TARGET_PATH" "$BACKUP_PATH" + break + ;; + r|R|rename) + COUNTER=1 + BASE_NAME="${FILENAME%.*}" + EXT="${FILENAME##*.}" + + if [ "$BASE_NAME" = "$EXT" ]; then + BASE_NAME="$FILENAME" + EXT="" + else + EXT=".$EXT" + fi + + while true; do + NEW_NAME="${BASE_NAME}-${COUNTER}${EXT}" + NEW_TARGET="minio/obsidian/${SUBPATH}/${NEW_NAME}" + if ! mc stat "$NEW_TARGET" >/dev/null 2>&1; then + TARGET_PATH="$NEW_TARGET" + FILENAME="$NEW_NAME" + echo "📝 Renamed to: $FILENAME" + break 2 + fi + COUNTER=$((COUNTER + 1)) + done + ;; + *) + echo "Invalid choice. Please enter o, s, b, or r" + ;; + esac + done + fi +fi + # Upload file mc cp "$FILE_PATH" "$TARGET_PATH"