From 8d6591a19de88be4c2ed072b640c91cb4a9d640c Mon Sep 17 00:00:00 2001 From: v4n <105587619+v4n00@users.noreply.github.com> Date: Thu, 16 Jan 2025 09:24:19 +0200 Subject: [PATCH 1/4] feat: update functionality testing --- .gitignore | 3 ++- README.md | 4 ++-- h2mm | 38 +++++++++++++++++++++++++++++++++++++- version | 1 + 4 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 version diff --git a/.gitignore b/.gitignore index 34327d5..0418c82 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ * !h2mm !install.sh -!README.md \ No newline at end of file +!README.md +!version \ No newline at end of file diff --git a/README.md b/README.md index eb5bed1..58b52bf 100644 --- a/README.md +++ b/README.md @@ -89,8 +89,6 @@ You can use the short form of the commands to save some time. The shortcuts are: You can export all installed mods to a zip file and import mods from the same file. This can be useful for sharing mods with others or for backing up your mods. The zip file will be saved in the current directory. -This will serve as either a backup or a way to have multiple mod setups. - ```bash h2mm export modpack1.zip h2mm import modpack2.zip @@ -115,6 +113,8 @@ Feel free to contribute to this project by creating a pull request or opening an ## Planned features - [ ] ! Enable/disable mods +- [ ] ! Provide fixes for breaking updates +- [ ] ! Auto update mods - [ ] !! Easier way to change mod presets - [ ] !! Change to `.tar.xz` for exporting and importing - [ ] !!! Find a way to make use of `manifest.json` and simplify installing variants diff --git a/h2mm b/h2mm index 744a302..05c9f0d 100755 --- a/h2mm +++ b/h2mm @@ -1,5 +1,7 @@ #!/bin/bash +VERSION="0.1.6" + # --- Globals --- RED='\033[0;31m' @@ -11,6 +13,10 @@ H2PATH="${HOME}/.config/h2mm/h2path" MODS_DIR="" DB_FILE="" +LAST_UPDATE_FILE="${HOME}/.config/h2mm/last_update" +VERSION_URL="https://raw.githubusercontent.com/v4n00/h2mm-cli/refs/heads/dev/version" +REPO_URL="https://github.com/v4n00/h2mm-cli" + # --- Utility Functions --- function get_filename_without_path() { @@ -82,7 +88,7 @@ function initialize_directories() { # --- Help Functions --- function display_help() { - echo "Helldivers 2 Mod Manager v0.1.6" + echo "Helldivers 2 Mod Manager v${VERSION}" echo "Usage: h2mm [command] [options]" echo "Commands:" echo " install Install a mod with files (short form: h2mm i)." @@ -155,6 +161,35 @@ function display_import_help() { # --- Main Functions --- +# Check for updates + +function check_for_updates() { + if [[ -f "$LAST_UPDATE_FILE" ]]; then + last_update=$(cat "$LAST_UPDATE_FILE") + if [[ $(date +%Y-%m-%d) -gt $(date +%Y-%m-%d -d "$last_update + 7 days") ]]; then + return + fi + else + echo $(date +%Y-%m-%d) > "$LAST_UPDATE_FILE" + exit 0 + fi + + latest_version=$(curl -sS "$VERSION_URL") + if [[ $? -ne 0 ]]; then + echo "${RED}Error:${NC} Could not check for updates." >&2 + return + fi + + if [[ "$latest_version" != "$VERSION" ]]; then + echo -e "${RED}!${NC} A new version of h2mm is available: ${ORANGE}$VERSION${NC} -> ${GREEN}$latest_version${NC}" >&2 + echo -e "${RED}!${NC} You can download it from: $REPO_URL" >&2 + fi + + echo $(date +%Y-%m-%d) > "$LAST_UPDATE_FILE" +} + +# Mod management + function mod_reset() { if [[ "$1" == "--help" || "$1" == "-h" ]]; then display_reset_help @@ -507,6 +542,7 @@ function main() { command="$1" shift initialize_directories + check_for_updates case "$command" in install|i) diff --git a/version b/version new file mode 100644 index 0000000..341cf11 --- /dev/null +++ b/version @@ -0,0 +1 @@ +0.2.0 \ No newline at end of file From 6bcad99bec456088f86c7cf77595d137a76fffbd Mon Sep 17 00:00:00 2001 From: v4n <105587619+v4n00@users.noreply.github.com> Date: Thu, 16 Jan 2025 09:40:49 +0200 Subject: [PATCH 2/4] feat: changed from zip to tar.gz --- README.md | 4 ++-- h2mm | 32 ++++++++++---------------------- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 58b52bf..f76a025 100644 --- a/README.md +++ b/README.md @@ -112,9 +112,9 @@ Feel free to contribute to this project by creating a pull request or opening an ## Planned features +- [x] Check for mod updates +- [x] Change to `.tar.gz` for exporting and importing - [ ] ! Enable/disable mods - [ ] ! Provide fixes for breaking updates -- [ ] ! Auto update mods - [ ] !! Easier way to change mod presets -- [ ] !! Change to `.tar.xz` for exporting and importing - [ ] !!! Find a way to make use of `manifest.json` and simplify installing variants diff --git a/h2mm b/h2mm index 05c9f0d..01c7971 100755 --- a/h2mm +++ b/h2mm @@ -13,7 +13,7 @@ H2PATH="${HOME}/.config/h2mm/h2path" MODS_DIR="" DB_FILE="" -LAST_UPDATE_FILE="${HOME}/.config/h2mm/last_update" +LAST_CHECKED_UPDATE_FILE="${HOME}/.config/h2mm/last_update" VERSION_URL="https://raw.githubusercontent.com/v4n00/h2mm-cli/refs/heads/dev/version" REPO_URL="https://github.com/v4n00/h2mm-cli" @@ -164,13 +164,13 @@ function display_import_help() { # Check for updates function check_for_updates() { - if [[ -f "$LAST_UPDATE_FILE" ]]; then - last_update=$(cat "$LAST_UPDATE_FILE") + if [[ -f "$LAST_CHECKED_UPDATE_FILE" ]]; then + last_update=$(cat "$LAST_CHECKED_UPDATE_FILE") if [[ $(date +%Y-%m-%d) -gt $(date +%Y-%m-%d -d "$last_update + 7 days") ]]; then return fi else - echo $(date +%Y-%m-%d) > "$LAST_UPDATE_FILE" + echo $(date +%Y-%m-%d) > "$LAST_CHECKED_UPDATE_FILE" exit 0 fi @@ -185,7 +185,7 @@ function check_for_updates() { echo -e "${RED}!${NC} You can download it from: $REPO_URL" >&2 fi - echo $(date +%Y-%m-%d) > "$LAST_UPDATE_FILE" + echo $(date +%Y-%m-%d) > "$LAST_CHECKED_UPDATE_FILE" } # Mod management @@ -450,12 +450,7 @@ function mod_export() { exit 0 fi - if ! command -v zip &> /dev/null; then - echo -e "${RED}Error${NC}: zip is not installed, please install the package and try again." >&2 - exit 1 - fi - - echo -ne "Zip file will be saved in the current directory ($(pwd)). Continue? (Y/n): " + echo -ne "Archive file will be saved in the current directory ($(pwd)). Continue? (Y/n): " read -r confirm if [[ "$confirm" == "y" || "$confirm" == "Y" || "$confirm" = "" ]]; then OUT_DIR=$(mktemp -d) @@ -473,13 +468,11 @@ function mod_export() { fi current_path=$(pwd) - zip_name="Helldivers_2_Mods_$(date +%Y-%m-%d_%H-%M-%S).zip" - cd "$OUT_DIR" - zip -r "$zip_name" "Helldivers 2 Mods" - mv "$zip_name" "$current_path" + archive_name="Helldivers_2_Mods_$(date +%Y-%m-%d_%H-%M-%S).tar.gz" + tar -czf "$current_path/$archive_name" -C "$OUT_DIR" "Helldivers 2 Mods" if [[ $? -eq 0 ]]; then - echo -e "Mods exported to ${GREEN}$current_path/$zip_name${NC}." >&2 + echo -e "Mods exported to ${GREEN}$current_path/$archive_name${NC}." >&2 else echo -e "${RED}Error${NC}: Failed to export mods." >&2 fi @@ -497,11 +490,6 @@ function mod_import() { exit 1 fi - if ! command -v unzip &> /dev/null; then - echo -e "${RED}Error${NC}: unzip is not installed, please install the package and try again." >&2 - exit 1 - fi - echo -e "Importing mods will ${RED}reset${NC} your mods." >&2 mod_reset if [[ $? -eq 1 ]]; then @@ -509,7 +497,7 @@ function mod_import() { fi OUT_DIR=$(mktemp -d) - unzip -qq "$1" -d "$OUT_DIR" + tar -xzf "$1" -C "$OUT_DIR" if [[ $? -ne 0 ]]; then echo -e "${RED}Error${NC}: Could not import mods. Possibly because the zip file is invalid." >&2 From a46776838aa7cbe8306bafbda12cb222c36cbf16 Mon Sep 17 00:00:00 2001 From: v4n <105587619+v4n00@users.noreply.github.com> Date: Thu, 16 Jan 2025 11:22:19 +0200 Subject: [PATCH 3/4] feat: enable/disable functionality --- README.md | 29 ++++-- h2mm | 304 +++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 241 insertions(+), 92 deletions(-) diff --git a/README.md b/README.md index f76a025..a579672 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ - [Basic usage](#basic-usage) - [Install a mod](#install-a-mod) - [Uninstall a mod](#uninstall-a-mod) + - [Enable/disable mods](#enabledisable-mods) - [List installed mods](#list-installed-mods) - [Advanced usage](#advanced-usage) - [Shortcuts](#shortcuts) @@ -57,7 +58,7 @@ h2mm install -n "Example mod" mod.patch_0 mod.patch_0.stream # -n is mandatory w h2mm install -n "Example mod" mod* # using a wildcard to include all files ``` -Important: If the mod has more than 1 variant, you need to install the one you want by unarchiving it separately. +> Currently, if the mod has more than 1 variant, you need to install the one you want by unarchiving it separately. #### Uninstall a mod @@ -66,6 +67,16 @@ h2mm uninstall "Example mod" h2mm uninstall -i 1 # uninstall mod with index 1 ``` + +#### Enable/disable mods + +```bash +h2mm enable "Example mod" +h2mm enable -i 1 # enable mod with index 1 +h2mm disable "Example mod" +h2mm disable -i 1 # disable mod with index 1 +``` + #### List installed mods ```bash @@ -76,10 +87,12 @@ h2mm list ### Shortcuts -You can use the short form of the commands to save some time. The shortcuts are: +You can use the short form of commands to save some time. The shortcuts are: - `i` for `install` - `u` for `uninstall` +- `e` for `enable` +- `d` for `disable` - `l` for `list` - `ex` for `export` - `im` for `import` @@ -113,8 +126,10 @@ Feel free to contribute to this project by creating a pull request or opening an ## Planned features - [x] Check for mod updates -- [x] Change to `.tar.gz` for exporting and importing -- [ ] ! Enable/disable mods -- [ ] ! Provide fixes for breaking updates -- [ ] !! Easier way to change mod presets -- [ ] !!! Find a way to make use of `manifest.json` and simplify installing variants +- [x] Enable/disable mods +- [ ] Easier way to change mod presets +- [ ] Find a way to make use of `manifest.json` and simplify installing variants +- [x] [DEV] Change to `.tar.gz` for exporting and importing +- [ ] [DEV] Provide fixes for breaking updates +- [ ] [DEV] Optimize code - throw errors in 1 line +- [ ] [DEV] Rewrite some code to be more readable diff --git a/h2mm b/h2mm index 01c7971..6e0ffee 100755 --- a/h2mm +++ b/h2mm @@ -27,6 +27,31 @@ function get_basename() { echo $(get_filename_without_path "$1" | sed -E 's/\.+.*//') } +function get_extension() { + echo $(get_filename_without_path "$1" | sed -E 's/.*patch_[0-9]+//') +} + +function get_files_by_entry_from_db() { + echo $(echo "$1" | cut -d',' -f4- | tr ',' ' ' | head -1) +} + +function get_mod_name_and_index() { + if [[ -n "$mod_index" ]]; then # if mod index exists + entry=$(grep "^${mod_index}," "$DB_FILE") + mod_name=$(echo "$entry" | awk -F, '{print $3}') + elif [[ -n "$mod_name" ]]; then # if mod name exists + entry=$(grep -i ",$mod_name," "$DB_FILE") + mod_index=$(echo "$entry" | awk -F, '{print $1}' | head -1) + fi + + if [[ -z "$entry" || -z "$mod_index" || -z "$mod_name" ]]; then + echo -e "${RED}Error${NC}: Mod not found." >&2 + exit 1 + fi + + status=$(echo "$entry" | awk -F, '{print $2}') +} + function find_game_directory() { local search_dir="${HOME}" local target_dir="Steam/steamapps/common/Helldivers\ 2/data" @@ -35,7 +60,6 @@ function find_game_directory() { if [[ -f "$H2PATH" ]]; then saved_dir=$(cat "$H2PATH") if [[ -d "$saved_dir" ]]; then - echo "Using saved game directory \$MODS_DIR: $saved_dir" >&2 echo "$saved_dir" return else @@ -77,7 +101,7 @@ function initialize_directories() { if [[ ! -f "$DB_FILE" ]]; then touch "$DB_FILE" if [[ $? -eq 0 ]]; then - echo "Database file created at: $DB_FILE" + echo -e "Database file ${GREEN}created${NC}: $DB_FILE" else echo -e "${RED}Error${NC}: Could not create database file." >&2 exit 1 @@ -131,6 +155,26 @@ function display_uninstall_help() { echo " h2mm uninstall -i 1 # uninstall mod with index 1" } +function display_enable_help() { + echo "Usage: h2mm enable [options] \"\"" + echo "Short form: h2mm e" + echo "Options:" + echo " -i Index of the mod to enable." + echo "Usage:" + echo " h2mm enable \"Example mod\"" + echo " h2mm enable -i 1 # enable mod with index 1" +} + +function display_disable_help() { + echo "Usage: h2mm disable [options] \"\"" + echo "Short form: h2mm d" + echo "Options:" + echo " -i Index of the mod to disable." + echo "Usage:" + echo " h2mm disable \"Example mod\"" + echo " h2mm disable -i 1 # disable mod with index 1" +} + function display_list_help() { echo "Usage: h2mm list" echo "Short form: h2mm l" @@ -190,6 +234,119 @@ function check_for_updates() { # Mod management +function mod_disable() { + local mod_name="" + local mod_index="" + + [[ $# -eq 0 ]] && { display_disable_help; exit 0; } + + # parse arguments + while [[ $# -gt 0 ]]; do + case "$1" in + -i) + mod_index="$2"; shift 2 + ;; + --help|-h) + display_disable_help; exit 0 + ;; + *) + mod_name="$1"; shift 1 + ;; + esac + done + + if [[ -z "$mod_name" && -z "$mod_index" ]]; then + echo -e "${RED}Error${NC}: Mod name or index is required to disable." >&2 + exit 1 + fi + + # find mod files + get_mod_name_and_index "$mod_name" "$mod_index" + + if [[ "$status" == "DISABLED" ]]; then + echo -e "${RED}Error${NC}: Mod $mod_name is already disabled." >&2 + exit 1 + fi + + # disable each mod file by adding disabled_ to the start of the filename + files=$(get_files_by_entry_from_db "$entry") + for file in $files; do + if [[ ! -f "$MODS_DIR/$file" ]]; then + echo -e "${RED}Error${NC}: Mod file $file does not exist." >&2 + exit 1 + else + disabled_file="disabled_$file" + mv "$MODS_DIR/$file" "$MODS_DIR/$disabled_file" + echo -e "Disabled ${ORANGE}$file${NC} (changed to ${GREEN}\$MODS_DIR/$disabled_file${NC})." >&2 + fi + done + + # update the database + sed -i "/^$mod_index,/s/ENABLED/DISABLED/" "$DB_FILE" + + if [[ $? -eq 0 ]]; then + echo -e "Mod $mod_name ${ORANGE}disabled${NC} successfully." >&2 + else + echo -e "${RED}Error${NC}: Failed to disable mod." >&2 + exit 1 + fi +} + +function mod_enable() { + local mod_name="" + local mod_index="" + + [[ $# -eq 0 ]] && { display_enable_help; exit 0; } + + # parse arguments + while [[ $# -gt 0 ]]; do + case "$1" in + -i) + mod_index="$2"; shift 2 + ;; + --help|-h) + display_enable_help; exit 0 + ;; + *) + mod_name="$1"; shift 1 + ;; + esac + done + + [[ -z "$mod_name" && -z "$mod_index" ]] && { echo -e "${RED}Error${NC}: Mod name or index is required to enable." >&2; exit 1; } + + # find mod files + get_mod_name_and_index "$mod_name" "$mod_index" + + [[ "$status" == "ENABLED" ]] && { echo -e "${RED}Error${NC}: Mod $mod_name is already enabled." >&2; exit 1; } + + files=$(get_files_by_entry_from_db "$entry") + + # enable each mod file by removing disabled_ from the start of the filename + for file in $files; do + disabled_file="disabled_$file" + + # check if the files exists + [[ -f "$MODS_DIR/$disabled_file" ]] || { echo -e "${RED}Error${NC}: Mod file $file does not exist." >&2; exit 1; } + + mv "$MODS_DIR/$disabled_file" "$MODS_DIR/$file" + + # check if the file was moved successfully + [[ $? -ne 0 ]] && { echo -e "${RED}Error${NC}: Could not enable mod file $disabled_file." >&2; exit 1; } + echo -e "Enabled ${ORANGE}$disabled_file${NC} (changed to ${GREEN}\$MODS_DIR/$file${NC})." >&2 + done + + # update the database + sed -i "/^$mod_index,/s/DISABLED/ENABLED/" "$DB_FILE" + + if [[ $? -eq 0 ]]; then + echo -e "Mod $mod_name ${GREEN}enabled${NC} successfully." >&2 + else + echo -e "${RED}Error${NC}: Failed to enable mod." >&2 + exit 1 + fi +} + function mod_reset() { if [[ "$1" == "--help" || "$1" == "-h" ]]; then display_reset_help @@ -210,24 +367,19 @@ function mod_reset() { function mod_install() { local mod_name="" - local mod_files=() local mod_dir="" + local mod_files=() - if [[ $# -eq 0 ]]; then - display_install_help - exit 0 - fi + [[ $# -eq 0 ]] && { display_install_help; exit 0; } # parse arguments while [[ $# -gt 0 ]]; do case "$1" in -n) - mod_name="$2" - shift 2 + mod_name="$2"; shift 2 ;; --help|-h) - display_install_help - exit 0 + display_install_help; exit 0 ;; *) if [[ -f "$1" && "$1" == *.zip ]]; then @@ -239,20 +391,14 @@ function mod_install() { fi shift ;; - esac + esac done # zip file containing mod files if [[ -n "$mod_zip" ]]; then - if ! command -v unzip &> /dev/null; then - echo -e "${RED}Error${NC}: unzip is not installed, please install the package and try again." >&2 - exit 1 - fi + command -v unzip &> /dev/null || { echo -e "${RED}Error${NC}: unzip package is not installed." >&2; exit 1; } - if [[ ! -f "$mod_zip" ]]; then - echo -e "${RED}Error${NC}: Zip file $mod_zip does not exist." >&2 - exit 1 - fi + [[ ! -f "$mod_zip" ]] && { echo -e "${RED}Error${NC}: Zip file $mod_zip does not exist." >&2; exit 1; } # check if mod name was provided, otherwise use the zip file name, get rid of .zip and version numbers if [[ -z "$mod_name" ]]; then @@ -265,10 +411,8 @@ function mod_install() { # directory containing mod files if [[ -n "$mod_dir" ]]; then - if [[ ! -d "$mod_dir" ]]; then - echo -e "${RED}Error${NC}: Directory $mod_dir does not exist." >&2 - exit 1 - fi + # verify directory exists + [[ ! -d "$mod_dir" ]] && { echo -e "${RED}Error${NC}: Directory $mod_dir does not exist." >&2; exit 1; } readarray -d '' mod_files < <(find "$mod_dir" -type f -name "*.patch_*" -print0) if [[ -z "$mod_name" ]]; then @@ -277,20 +421,15 @@ function mod_install() { fi # verify minimum information required - if [[ -z "$mod_name" || ${#mod_files[@]} -eq 0 ]]; then - echo -e "${RED}Error${NC}: Mod name and files are required." >&2 - exit 1 - fi + [[ -z "$mod_name" || ${#mod_files[@]} -eq 0 ]] && { echo -e "${RED}Error${NC}: Mod name and files are required." >&2; exit 1; } # verify mod files exist and is not directory for file in "${mod_files[@]}"; do if [[ ! -f "$file" ]]; then - if [[ ! -d "$file" ]]; then - echo -e "${RED}Error${NC}: File $file does not exist." >&2 - exit 1 - else - mod_files=(${mod_files[@]/$file}) - fi + # if it isn't a file, check if it's a directory + [[ ! -d "$file" ]] && { echo -e "${RED}Error${NC}: File $file does not exist." >&2; exit 1; } + + mod_files=(${mod_files[@]/$file}) fi done @@ -313,7 +452,7 @@ function mod_install() { patch_count["$base_name"]=$count # if the file has an extension, look for the last patch number and use that - extension=$(echo "$file" | sed -E 's/.*patch_[0-9]+//') + extension=$(get_extension "$file") if [[ -n "$extension" ]]; then target_file="${base_name}.patch_$((patch_count[$base_name] - 1))${extension}" else @@ -321,60 +460,36 @@ function mod_install() { fi target_files+=($target_file) - cp "$file" "$MODS_DIR/$target_file" - if [[ $? -eq 0 ]]; then - echo -e "Mod file ${ORANGE}$file${NC} installed at ${GREEN}\$MODS_DIR/$target_file${NC}." >&2 - else - echo -e "${RED}Error${NC}: Could not install mod file $file." >&2 - exit 1 - fi + + # verify installation worked + [[ $? -ne 0 ]] && { echo -e "${RED}Error${NC}: Could not install mod file $file." >&2; exit 1; } + echo -e "Mod file ${ORANGE}$file${NC} installed at ${GREEN}\$MODS_DIR/$target_file${NC}." >&2 done # add entry to database next_id=$(awk -F, 'END {print $1 + 1}' "$DB_FILE") - echo "$next_id,$mod_name,${target_files[*]}" >> "$DB_FILE" - echo -e "Mod $mod_name ($base_name) ${GREEN}installed successfully${NC}." >&2 -} - -function mod_list() { - if [[ "$1" == "--help" || "$1" == "-h" ]]; then - display_list_help - exit 0 - fi - - if [[ ! -s "$DB_FILE" ]]; then - echo "No mods installed." - return - fi - - echo "Installed mods:" >&2 - awk -F, '{ if (length($3) > 150) $3 = substr($3, 1, 147) "..."; printf "%2s. %s (%s)\n", $1, $2, $3 }' "$DB_FILE" + echo "$next_id,ENABLED,$mod_name,${target_files[*]}" >> "$DB_FILE" + echo -e "Mod $mod_name ($base_name) ${GREEN}installed${NC} successfully." >&2 } function mod_uninstall() { local mod_name="" local mod_index="" - if [[ $# -eq 0 ]]; then - display_uninstall_help - exit 0 - fi + [[ $# -eq 0 ]] && { display_uninstall_help; exit 0; } # parse arguments while [[ $# -gt 0 ]]; do case "$1" in -i) - mod_index="$2" - shift 2 + mod_index="$2"; shift 2 ;; --help|-h) - display_uninstall_help - exit 0 + display_uninstall_help; exit 0 ;; *) - mod_name="$1" - shift 1 + mod_name="$1"; shift 1 ;; esac done @@ -385,21 +500,11 @@ function mod_uninstall() { fi # find mod files - if [[ -n "$mod_index" ]]; then - entry=$(grep "^${mod_index}," "$DB_FILE") - mod_name=$(echo "$entry" | awk -F, '{print $2}') - elif [[ -n "$mod_name" ]]; then - entry=$(grep -i ",$mod_name," "$DB_FILE") - mod_index=$(echo "$entry" | awk -F, '{print $1}' | head -1) - fi - - if [[ -z "$entry" ]]; then - echo -e "${RED}Error${NC}: Mod not found." >&2 - exit 1 - fi + get_mod_name_and_index "$mod_name" "$mod_index" # delete mod files - files=$(echo "$entry" | cut -d',' -f3- | tr ',' ' ' | head -1) + files=$(get_files_by_entry_from_db "$entry") + echo "$files" declare -A downgrades for file in $files; do if [[ ! -f "$MODS_DIR/$file" ]]; then @@ -407,7 +512,12 @@ function mod_uninstall() { exit 1 else echo -e "Removing ${ORANGE}\$MODS_DIR/$file${NC}." >&2 - rm -f "$MODS_DIR/$file" + rm "$MODS_DIR/$file" + + if [[ $? -ne 0 ]]; then + echo -e "${RED}Error${NC}: Could not remove mod file $file." >&2 + exit 1 + fi base_name=$(get_basename "$file") current_version=$(echo $file | grep -oP '(?<=patch_)\d+') @@ -426,7 +536,7 @@ function mod_uninstall() { patch_version=$(echo $patch | grep -oP '(?<=patch_)\d+') if [[ $patch_version -gt ${downgrades[$file]} ]]; then new_version=$((patch_version - downgrades[$base_name] - 1)) - extension=$(echo "$patch" | sed -E 's/.*patch_[0-9]+//') + extension=$(get_extension "$path") new_patch="${base_name}.patch_${new_version}${extension}" mv "$MODS_DIR/$patch" "$MODS_DIR/$new_patch" @@ -441,7 +551,25 @@ function mod_uninstall() { # remove entry from database sed -i "/^$mod_index/d" "$DB_FILE" - echo -e "Mod ${GREEN}uninstalled successfully${NC}." >&2 + echo -e "Mod $mod_name ${ORANGE}uninstalled${NC} successfully." >&2 +} + +function mod_list() { + if [[ "$1" == "--help" || "$1" == "-h" ]]; then + display_list_help + exit 0 + fi + + if [[ ! -s "$DB_FILE" ]]; then + echo "No mods installed." + return + fi + + echo "Installed mods:" >&2 + awk -v GREEN="$GREEN" -v RED="$RED" -v NC="$NC" -F, '{ + color = ($2 == "DISABLED") ? RED : GREEN; + if (length($3) > 150) $3 = substr($3, 1, 147) "..."; + printf "%2s. [%s%s%s] %s (%s)\n", $1, color, $2, NC, $3, $4}' "$DB_FILE" } function mod_export() { @@ -542,6 +670,12 @@ function main() { uninstall|u) mod_uninstall "$@" ;; + enable|e) + mod_enable "$@" + ;; + disable|d) + mod_disable "$@" + ;; export|ex) mod_export "$@" ;; From a6d0bcfb5f65a4c2ccd6b01cab131c43f752ae5a Mon Sep 17 00:00:00 2001 From: v4n <105587619+v4n00@users.noreply.github.com> Date: Thu, 16 Jan 2025 13:49:16 +0200 Subject: [PATCH 4/4] feat: installer treat breaking changes --- README.md | 2 +- h2mm | 7 +++-- install.sh | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a579672..2bd3204 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,6 @@ Feel free to contribute to this project by creating a pull request or opening an - [ ] Easier way to change mod presets - [ ] Find a way to make use of `manifest.json` and simplify installing variants - [x] [DEV] Change to `.tar.gz` for exporting and importing -- [ ] [DEV] Provide fixes for breaking updates +- [x] [DEV] Provide fixes for breaking updates - [ ] [DEV] Optimize code - throw errors in 1 line - [ ] [DEV] Rewrite some code to be more readable diff --git a/h2mm b/h2mm index 6e0ffee..c0e42d7 100755 --- a/h2mm +++ b/h2mm @@ -1,6 +1,6 @@ #!/bin/bash -VERSION="0.1.6" +VERSION="0.2.0" # --- Globals --- @@ -14,7 +14,7 @@ MODS_DIR="" DB_FILE="" LAST_CHECKED_UPDATE_FILE="${HOME}/.config/h2mm/last_update" -VERSION_URL="https://raw.githubusercontent.com/v4n00/h2mm-cli/refs/heads/dev/version" +VERSION_URL="https://raw.githubusercontent.com/v4n00/h2mm-cli/refs/heads/master/version" REPO_URL="https://github.com/v4n00/h2mm-cli" # --- Utility Functions --- @@ -685,6 +685,9 @@ function main() { reset|r) mod_reset "$@" ;; + version|v|-v|--version) + echo "${VERSION}" + ;; help|--help|-h|h) display_help ;; diff --git a/install.sh b/install.sh index b82f531..f098826 100755 --- a/install.sh +++ b/install.sh @@ -2,6 +2,8 @@ set -e RED='\033[0;31m' +GREEN='\033[0;32m' +ORANGE='\033[0;33m' NC='\033[0m' DESTINATION_PATH="/usr/local/bin" @@ -12,13 +14,87 @@ if [ "$(id -u)" -eq 0 ]; then exit 1 fi +# --- Main --- + +# Warning + echo -e "!!! ${RED}WARNING${NC} !!!" echo -e "This script will install Helldivers 2 Mod Manager CLI for Linux to $DESTINATION_PATH/$SCRIPT_NAME." echo -e "Running this script will require sudo permissions. ${RED}DO NOT TRUST${NC} random scripts from the internet." echo -e "If you want to review the script before running it, check out the mod repository for yourself:" echo -e "https://github.com/v4n00/h2mm-cli" +echo -e "!!! ${RED}WARNING${NC} !!!" echo +# Check if update + +# Breaking changes hash table + +breaking_changes_patches=( + ["2"]='sed -i "s/^\([0-9]\+\),/\1,ENABLED,/" "$1/mods.csv"' +) + +# Script + +if [[ -x "$(command -v $SCRIPT_NAME)" ]]; then + installed_version=$($SCRIPT_NAME --version) + # version 1 show the help message, if the first character is not a 0, store installed version as 0.1.6 + [[ ${installed_version:0:1} != "0" ]] && { installed_version="0.1.6"; } + + latest_version=$(curl -sS https://raw.githubusercontent.com/v4n00/h2mm-cli/refs/heads/master/version) + if [[ "$latest_version" == "$installed_version" ]]; then + echo -e "You are reinstalling version $installed_version." + else + echo -e "You are upgrading from ${ORANGE}$installed_version${NC} -> ${GREEN}$latest_version${NC}." + fi + + # split version numbers + installed_major="" + latest_major="" + IFS='.' read -r _1 installed_major _2 <<< "$installed_version" + IFS='.' read -r _1 latest_major _2 <<< "$latest_version" + + if [[ $latest_major -gt $installed_major ]]; then + echo -e "${ORANGE}Warning:${NC} Major version upgrade detected." + echo "The script will proceed to upgrade ${SCRIPT_NAME} to avoid breaking changes." + + # find hd2 path + search_dir="${HOME}" + target_dir="Steam/steamapps/common/Helldivers\ 2/data" + echo "Searching for the Helldivers 2 data directory..." >&2 + game_dir=$(find "$search_dir" -type d -path "*/$target_dir" 2>/dev/null | head -n 1) + if [[ -z "$game_dir" ]]; then + echo "Could not find the Helldivers 2 data directory automatically." >&2 + read -p "Please enter the path to the Helldivers 2 data directory: " game_dir + game_dir=$(eval echo "$game_dir") + + if [[ ! -d "$game_dir" ]]; then + echo -e "${RED}Error${NC}: Provided path is not a valid directory." >&2 + exit 1 + fi + fi + + [[ ! -f "$game_dir/mods.csv" ]] && { echo -e "${RED}Error:${NC} mods.csv not found in $game_dir."; exit 1; } + + # iterate from installed major number to latest major number + for ((i = installed_major + 1; i <= latest_major; i++)); do + echo -e "${RED}[ ]${NC} Applying breaking changes patch for version $i." + + [[ -n "${breaking_changes_patches[$i]}" ]] && eval $(echo "${breaking_changes_patches[$i]}" | sed "s:\$1:$game_dir:") + if [[ $? -ne 0 ]]; then + echo -ne "${RED}Error:${NC} Failed to apply breaking changes patch for version $i. Do you want to continue? (Y/n): " + read -r response + + [[ "$response" != "y" && "$response" != "Y" && -n "$response" ]] && { echo "Exiting. Uninstall the script first the retry the install script."; exit 1; } + else + echo -e "${GREEN}[X]${NC} Breaking changes patch for version $i applied successfully." + fi + done + fi +fi + +# Install + read -p "Install the script to $DESTINATION_PATH or specify another path (must be included in \$PATH)? (Y/path): " response if [[ "$response" != "y" && "$response" != "Y" && -n "$response" ]]; then