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 <noreply@anthropic.com>
This commit is contained in:
Misaka Company
2026-01-28 13:45:43 +08:00
parent cbe3cfccba
commit 51eae214cc
2 changed files with 208 additions and 12 deletions

View File

@@ -19,6 +19,47 @@ Upload to a specific vault:
.claude/skills/minio-upload/scripts/upload_to_obsidian.sh path/to/file.md "journal" .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 ## 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. **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 1. **Verify file exists** - Check that the source file is accessible
2. **Determine target vault** - Use specified vault name or default to `main` 2. **Determine target vault** - Use specified vault name or default to `main`
3. **Upload with mc** - Execute `mc cp` command to transfer file 3. **Check for conflicts** - Detect if file already exists in target vault
4. **Confirm success** - Verify upload completed and report target location 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 ## Error Handling

View File

@@ -1,28 +1,78 @@
#!/bin/bash #!/bin/bash
# #
# Upload files to MinIO obsidian bucket # Upload files to MinIO obsidian bucket
# Usage: upload_to_obsidian.sh <file_path> [subpath] # Usage: upload_to_obsidian.sh <file_path> [subpath] [options]
# #
# Arguments: # Arguments:
# file_path - Path to the file to upload # 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: # Examples:
# upload_to_obsidian.sh temp/file.md # upload_to_obsidian.sh temp/file.md
# upload_to_obsidian.sh temp/file.md notes/2024 # upload_to_obsidian.sh temp/file.md journal
# upload_to_obsidian.sh temp/file.md "archive/old projects" # upload_to_obsidian.sh temp/file.md main --force
# upload_to_obsidian.sh temp/file.md work --skip
set -e set -e
# Check arguments # Initialize variables
if [ $# -lt 1 ]; then FORCE=false
echo "Usage: $0 <file_path> [subpath]" >&2 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 <file_path> [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 <file_path> [subpath] [--force|--skip|--backup|--rename]" >&2
exit 1 exit 1
fi fi
FILE_PATH="$1"
SUBPATH="${2:-main}" # Default to 'main' if not specified
# Validate file exists # Validate file exists
if [ ! -f "$FILE_PATH" ]; then if [ ! -f "$FILE_PATH" ]; then
echo "Error: File '$FILE_PATH' does not exist" >&2 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 # Ensure subpath ends without trailing slash for mc
TARGET_PATH=$(echo "$TARGET_PATH" | sed 's://*:/:g') 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 # Upload file
mc cp "$FILE_PATH" "$TARGET_PATH" mc cp "$FILE_PATH" "$TARGET_PATH"