Skip to content

Instantly share code, notes, and snippets.

@Artoria2e5
Last active July 4, 2020 20:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Artoria2e5/d398dcbbde037ea115566855860e053a to your computer and use it in GitHub Desktop.
Save Artoria2e5/d398dcbbde037ea115566855860e053a to your computer and use it in GitHub Desktop.
Copy a minecraft directory with some symlinks
#!/bin/bash
# duplicate-minecraft-dir: copies a minecraft directory with some symlinks.
# Requires uname and GNU coreutils.
# Requires admin priv under Windows.
# Dedicated to the public domain under Creative Commons Zero. Do what the heck you wanna do with it.
SELF=$0
die(){ printf '%s: %s\n' "$SELF" "$1">&2; exit "${2-2}"; }
log() { local level=$1; if ((VERBOSE >= level)); then printf '%s: %s\n' "$SELF" "$2">&2; fi; }
nolink=(config options\*.txt launcher_profiles.json servers.dat config baritone Impact mods)
is_windows_admin() { id -G | grep -qE '\<(114|544)\>'; }
case $(uname -o) in
Cygwin)
is_windows_admin || die "Gonna need admin privs. Run cygwin as admin!"
export CYGWIN+=' winsymlinks:nativestrict';;
Msys)
is_windows_admin || die "Gonna need admin privs. Run msys as admin!"
export MSYS+=' winsymlinks:nativestrict';;
esac
usage="Usage: $0 [options] [--] SOURCE TARGET
Copy the minecraft profile in SOURCE to TARGET, allowing for sharing jars and assets by symlinking"
help="Options:
-h Displays this help.
-a FILE Remove exclusion (a glob).
-e FILE Add exclusion (a glob).
-v Be verbose.
Default exclusions: ${nolink[*]}."
VERBOSE=0
while getopts ':haev' opt; do
case $opt in
(v) ((VERBOSE++));;
(a) for i in "${!nolink[@]}"; do
if [[ ${nolink[i]} = "$OPTARG" ]]; then
unset 'nolink[i]'
fi
done;;
(e) nolink+=("$OPTARG");;
(h) printf '%s\n\n%s\n' "$usage" "$help"
exit 0;;
(*) printf '%s: Invalid option -%s\n%s\n' "$0" "$OPTARG" "$usage">&2
exit 2;;
esac
done
shift "$((OPTIND - 1))"
SOURCE=$1
TARGET=$2
assert_is_directory() {
if [[ ! -d $1 ]]; then
die "$(printf '%q is not a directory' "$1")" 1
fi
}
assert_is_directory "$SOURCE"
mkdir -p -- "$TARGET"
printf '%q ' "$@"
# find GNU cp
declare CP LN
is_gnu_command() { "$1" --version &>/dev/null; }
find_gnu_command() {
declare -n VAR=${1^^}
local i
for i in "$1" g"$1"; do
if is_gnu_command "$i"; then
VAR=$i
return 0;
fi
done
die "Cannot find GNU $1"
}
find_gnu_command cp
find_gnu_command ln
is_nolink() {
local needle=$1 i
for i in "${nolink[@]}"; do
if [[ $needle == */$i ]]; then
return 0;
fi
done
return 1
}
trouble() {
local ret=$?
if ((ret > 0)); then
log 0 "Trouble -- $1 returned $ret."
fi
}
shopt -s dotglob nullglob
for i in "$SOURCE"/*; do
basename="${i#*/}"
if is_nolink "$i"; then
log 1 "Copying $basename..."
# When on Windows, try replacing --reflink=auto with -l. A bit unsafe tho.
"$CP" -a --reflink=auto -t "$TARGET" -- "$i"
trouble "$CP"
else
log 1 "Symlinking $basename..."
"$LN" -rsf -t "$TARGET" -- "$i"
trouble "$LN"
fi
done
log 0 "Done, I think! Check your mods, delete old ones and stuff."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment