Extract duplicate rename code from --rename option and interactive 'r' branch into find_unique_filename() function. Reduces code duplication and improves maintainability. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
199 lines
5.8 KiB
Bash
Executable File
199 lines
5.8 KiB
Bash
Executable File
#!/bin/bash
|
||
#
|
||
# Upload files to MinIO obsidian bucket
|
||
# Usage: upload_to_obsidian.sh <file_path> [subpath] [options]
|
||
#
|
||
# Arguments:
|
||
# file_path - Path to the file to upload
|
||
# 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 journal
|
||
# upload_to_obsidian.sh temp/file.md main --force
|
||
# upload_to_obsidian.sh temp/file.md work --skip
|
||
|
||
set -e
|
||
|
||
# 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 <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
|
||
|
||
# Validate mutual exclusion of conflict handling options
|
||
CONFLICT_OPTS_COUNT=0
|
||
[ "$FORCE" = true ] && CONFLICT_OPTS_COUNT=$((CONFLICT_OPTS_COUNT + 1))
|
||
[ "$SKIP" = true ] && CONFLICT_OPTS_COUNT=$((CONFLICT_OPTS_COUNT + 1))
|
||
[ "$BACKUP" = true ] && CONFLICT_OPTS_COUNT=$((CONFLICT_OPTS_COUNT + 1))
|
||
[ "$RENAME" = true ] && CONFLICT_OPTS_COUNT=$((CONFLICT_OPTS_COUNT + 1))
|
||
|
||
if [ $CONFLICT_OPTS_COUNT -gt 1 ]; then
|
||
echo "Error: Conflict handling options are mutually exclusive." >&2
|
||
echo "Use only one of: --force, --skip, --backup, --rename" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# Check file path argument
|
||
if [ -z "$FILE_PATH" ]; then
|
||
echo "Usage: $0 <file_path> [subpath] [--force|--skip|--backup|--rename]" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# Validate file exists
|
||
if [ ! -f "$FILE_PATH" ]; then
|
||
echo "Error: File '$FILE_PATH' does not exist" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# Get filename
|
||
FILENAME=$(basename "$FILE_PATH")
|
||
|
||
# Function to find unique filename by adding numeric suffix
|
||
# Sets global variables: TARGET_PATH, FILENAME
|
||
find_unique_filename() {
|
||
local original_filename="$1"
|
||
local subpath="$2"
|
||
local counter=1
|
||
local base_name="${original_filename%.*}"
|
||
local ext="${original_filename##*.}"
|
||
|
||
# Handle files without extension
|
||
if [ "$base_name" = "$ext" ]; then
|
||
base_name="$original_filename"
|
||
ext=""
|
||
else
|
||
ext=".$ext"
|
||
fi
|
||
|
||
while true; do
|
||
local new_name="${base_name}-${counter}${ext}"
|
||
local 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"
|
||
return 0
|
||
fi
|
||
counter=$((counter + 1))
|
||
done
|
||
}
|
||
|
||
# Construct target path
|
||
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
|
||
find_unique_filename "$FILENAME" "$SUBPATH"
|
||
# 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)
|
||
find_unique_filename "$FILENAME" "$SUBPATH"
|
||
break
|
||
;;
|
||
*)
|
||
echo "Invalid choice. Please enter o, s, b, or r"
|
||
;;
|
||
esac
|
||
done
|
||
fi
|
||
fi
|
||
|
||
# Upload file
|
||
mc cp "$FILE_PATH" "$TARGET_PATH"
|
||
|
||
echo "✅ Uploaded: $FILE_PATH -> $TARGET_PATH"
|