Last active
April 30, 2021 07:54
-
-
Save b2cc/c312bec251aaecbfedd07e4d4bda512e to your computer and use it in GitHub Desktop.
Find wrong pathnames when running Battletech mods in Linux (check case-sensitivity)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# pathfinder.sh | |
# | |
# Find wrong pathnames when running Battletech mods | |
# in Linux (check case-sensitivity) | |
# | |
# navigate to your BATTLETECH install folder and execute this script, i.e. | |
# | |
# cd /home/$(whoami)/.local/share/Steam/steamapps/common/BATTLETECH | |
# bash ./pathfinder.sh | |
# | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program. If not, see <https://www.gnu.org/licenses/>. | |
set -o pipefail | |
debug="disabled" | |
check=0 | |
checkjson=0 | |
counter="" | |
failedpath="" | |
failedpathcounter="0" | |
fixedmods="" | |
mod="" | |
modmap="" | |
modsymlinkset="" | |
nopaths="" | |
path="" | |
pathmap="" | |
black=$(tput setaf 0) | |
red=$(tput setaf 1) | |
green=$(tput setaf 2) | |
yellow=$(tput setaf 3) | |
blue=$(tput setaf 4) | |
magenta=$(tput setaf 5) | |
cyan=$(tput setaf 6) | |
white=$(tput setaf 7) | |
bold=$(tput bold) | |
reset=$(tput sgr0) | |
LOGGER="$(which logger)" | |
SCRIPTNAME=$(basename $0) | |
log_generic() { | |
logdate=$(date "+%h %d %H:%M:%S") | |
logproc=$(echo $$) | |
logmessage="$logdate ${HOST} ${scriptname}[${logproc}]: (${USER}) ${LOGLEVEL}: $1" | |
echo "${logmessage}" | |
${LOGGER} "$1" | |
} | |
log() { | |
LOGLEVEL="${white}${bold}INFO${reset}" | |
log_generic "$@" | |
} | |
log_debug() { | |
if [[ ${debug} == enabled ]]; then | |
LOGLEVEL="${blue}${bold}DEBUG${reset}" | |
log_generic "$@" | |
fi | |
} | |
log_warn() { | |
LOGLEVEL="${yellow}${bold}WARN${reset}" | |
log_generic "$@" | |
} | |
die() { | |
LOGLEVEL="${red}${bold}ERROR${reset}" | |
log_generic "$@" | |
exit 1 | |
} | |
trap "die 'Program interrupted! Exiting...'" SIGHUP SIGINT SIGQUIT SIGABRT | |
BINARIES=(jq) | |
for binary in "${BINARIES[@]}"; do | |
[[ -x $(which ${binary} 2>/dev/null) ]] || die "${binary} binary not found, exiting." | |
done | |
check_getopt_version() { | |
! getopt --test > /dev/null | |
if [[ ${PIPESTATUS[0]} -ne 4 ]]; then | |
die " installed version of getopt does not support required features. install/update util-linux package." | |
fi | |
} | |
print_help() { | |
echo " | |
- ${SCRIPTNAME} - | |
Find wrong pathnames when running Battletech mods | |
on Linux (check case-sensitivity) | |
Navigate to your BATTLETECH install folder and execute this script, i.e. | |
cd /home/\$(whoami)/.local/share/Steam/steamapps/common/BATTLETECH | |
bash ./pathfinder.sh | |
Options: | |
-h | --help show help | |
-d | --debug enable debug output | |
-c | --check run path check | |
-j | --check-json validate JSON files (Warning: script will abort on invalid JSON, | |
manual intervention will probably be required.) | |
" | |
exit 0 | |
} | |
checkbtfolder() { | |
log " * Checking if we are in the BATTLETECH install folder..." | |
if ! [[ -d ./BattleTech_Data ]] || ! [[ -d ./Mods ]]; then | |
die " ...can't locate either BattleTech_Data (n)or Mods folder, please run this script from the BATTLETECH install directory. exiting." | |
else | |
log " ...found BattleTech_Data and Mods folders, continuing." | |
fi | |
} | |
checkmodsymlink() { | |
log " * Testing if lowercase symlink for Mods folder exists:" | |
if ! [[ $(readlink ./mods) == Mods ]]; then | |
log_warn " Symlink mods to folder Mods doesn't exist - setting it up..." | |
ln -s Mods mods || die " Error while setting up symlink, please check folder permissions! exiting." | |
log " ...done." | |
modsymlinkset=1 | |
else | |
log " mods -> Mods symlink found, continuing." | |
modsymlinkset=0 | |
fi | |
} | |
read_mods() { | |
find -L ./Mods -mindepth 1 -maxdepth 1 -type d -prune -not -path './Mods/.modtek' | sort | |
} | |
read_path(){ | |
jq -r '.Manifest[].Path' "${mod}"/mod.json 2>/dev/null | egrep -v '[Aa]ssets|AssetBundleName' | |
} | |
getlistofmods() { | |
log " * Evaluating mod folders and checking for mod.json files..." | |
readarray -t modmap < <(read_mods) | |
} | |
checkjson() { | |
log " * Validating mod.json files..." | |
for mod in "${modmap[@]}"; do | |
if [[ -r "${mod}"/mod.json ]]; then | |
log_debug " testing ${mod}/mod.json" | |
jq -r . "${mod}"/mod.json > /dev/null 2>&1 || die " ${mod}/mod.json is not valid! Please check/fix JSON syntax and run script again. exiting." | |
fi | |
done | |
log " - all JSON files are valid." | |
} | |
declare -a failedpathlist | |
checkpath() { | |
log_debug " -- start modmap" | |
if [[ ${debug} == enabled ]]; then | |
printf '%s\n' "${modmap[@]}" | |
fi | |
log_debug " -- stop modmap" | |
for mod in "${modmap[@]}"; do | |
log " mod: ${mod}" | |
counter=0 | |
nopaths=0 | |
if [[ -r "${mod}"/mod.json ]]; then | |
log_debug " extracting paths from mod.json" | |
readarray -t pathmap < <(read_path) | |
if [[ -z "${pathmap}" ]]; then | |
log " - mod seems to not define any paths, continuing..." | |
nopaths=1 | |
else | |
log_debug " - testing paths in mod \"${mod}\"..." | |
for path in "${pathmap[@]}"; do | |
log_debug " - testing for existing path \"${path}\" in folder \"${mod}\"" | |
if [[ -d "${mod}/${path}" ]]; then | |
log_debug " - ${mod}/${path} ...${green}${bold}OK${reset}" | |
log_debug "" | |
else | |
modpath="${mod}/${path}" | |
realpath=$(find -iname "$(basename "${modpath}")" -ipath "$(dirname "${modpath}")/*" -print -quit) | |
if [[ ! -z ${realpath} ]]; then | |
cd "$(dirname "${realpath}")" | |
if ln -s "$(basename "${realpath}")" "$(basename "${modpath}")"; then | |
log " - fixed ${modpath} to ${realpath} by ${green}${bold}creating symlink${reset}." | |
failedpathlist+=(${modpath}) | |
failedpathcounter=$((failedpathcounter+1)) | |
else | |
log_warn " - an error occurred while symlinking ${modpath} to ${realpath}, please fix manually!" | |
fi | |
cd - >/dev/null | |
counter=$((counter+1)) | |
fi | |
fi | |
done | |
fi | |
else | |
log_warn " Couldn't find mod.json - possibly not a mod folder? please make your checks." | |
echo "" | |
fi | |
if [[ ${counter} -eq 0 ]] && [[ ${nopaths} -eq 0 ]]; then | |
log " - mod ${green}${bold}OK!${reset}" | |
fi | |
done | |
} | |
printreport() { | |
log " * Paths and mod.json files checked successfully!" | |
if [[ ${failedpathcounter} -gt 0 ]]; then | |
log " * The following paths have been fixed:" | |
for failedpath in "${failedpathlist[@]}"; do | |
log " - ${failedpath}" | |
done | |
fi | |
log " * All done, exiting. Have a nice day :)" | |
echo "" | |
exit 0 | |
} | |
OPTS=cdhj | |
LONGOPTS=check,check-json,debug,help | |
! PARSED=$(getopt --options=${OPTS} \ | |
--longoptions=${LONGOPTS} \ | |
--name "${0}" \ | |
-- "${@}") | |
if [[ ${PIPESTATUS[0]} -ne 0 ]]; then | |
die "getopt parser reported an error parsing arguments, aborting." | |
fi | |
eval set -- "$PARSED" | |
while [[ ( ${discard_opts_after_doubledash} -eq 1 ) || ( $# -gt 0 ) ]]; do | |
case "$1" in | |
-h|--help) | |
print_help | |
;; | |
-c|--check) | |
checkpath=1 | |
;; | |
-d|--debug) | |
debug="enabled" | |
;; | |
-j|--check-json) | |
checkjson=1 | |
;; | |
--) if [[ ${discard_opts_after_doubledash} -eq 1 ]]; then break; fi | |
;; | |
*) extra_args=("${extra_args[@]}" "$1") | |
;; | |
esac | |
shift | |
done | |
extra_args=("${extra_args[@]/${dummy_arg}}") | |
if [[ checkjson -eq 0 ]] && [[ checkpath -eq 0 ]]; then print_help; fi | |
check_getopt_version | |
checkbtfolder | |
getlistofmods | |
if [[ checkjson -eq 1 ]]; then checkjson; fi | |
if [[ checkpath -eq 1 ]]; then checkpath; checkmodsymlink; fi | |
printreport |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@36PopTarts: I tested the script before I uploaded it, and it worked fine. However I'm not at my workstation at the moment and will check again to make sure. The filter is actually the dot after the option (-r):
jq -r .
which basically stands for no filter, as I don't want to filter but only validate the JSON files.It is true that jq is very strict, but it also seems equally true that JSON doesn't allow trailing commas - at least to what I could find out with a quick search (e.g.: SO discussion: https://stackoverflow.com/questions/201782/can-you-use-a-trailing-comma-in-a-json-object ). BATTLETECH seems to be more relaxed when parsing the files, so trailing commas are kind of a false positive I however can't work around in this case. I basically added the option to check JSON for validity after I encountered actually malformed JSON / malfunctioning mods a couple of times and got bored of writing shell loops every time.
If you can supply me with a
mod.json
file where jq misbehaves for you (except the trailing commas) I'll look into it.