diff --git a/h2mm b/h2mm index dec111b..3bda4d4 100755 --- a/h2mm +++ b/h2mm @@ -1,7 +1,7 @@ #!/usr/bin/env bash -VERSION="0.6.9" +VERSION="0.6.10" # --- Globals --- @@ -155,6 +155,81 @@ function remove_disabled_prefix() { echo "$disabled_file" } +function parse_indexes() { + _returned_indexes=() + + while [[ $# -gt 0 ]]; do + case "$1" in + "--range") + [[ -z "$2" ]] && { log ERROR "Function parse indexes: range is required"; exit 1; } + range="$2"; shift 2 + ;; + *) + input_indexes+=("$1") + shift + ;; + esac + done + + # parse input_indexes 1-by-1 + for index in "${input_indexes[@]}"; do + # normal index 5 + if [[ "$index" =~ ^[0-9]+$ ]]; then + [[ $index -lt 1 || $index -gt $range ]] && { log ERROR "Function parse indexes: index $index out of range (1 -> $range)"; exit 1; } + _returned_indexes+=("$index") + # range index 1..5 + elif [[ "$index" =~ ^[0-9]+\.\.[0-9]+$ ]]; then + # cut doesn't work with a delimiter of two characters + start=$(echo "$index" | cut -d. -f1) + end=$(echo "$index" | cut -d. -f3) + + [[ $start -lt 1 || $end -lt 1 || $start -gt $range || $end -gt $range ]] && { log ERROR "Function parse indexes: range $index out of range (1 -> $range)"; exit 1; } + + if [[ $start -le $end ]]; then + for ((i=start; i<=end; i++)); do + _returned_indexes+=("$i") + done + else + for ((i=start; i>=end; i--)); do + _returned_indexes+=("$i") + done + fi + # remove index -5 + elif [[ "$index" =~ ^-[0-9] ]]; then + index=${index#-} # remove the - sign + + # if _returned_indexes is empty, populate it with every number from 1 to range + [[ ${#_returned_indexes[@]} -eq 0 ]] && for ((i=1; i<=range; i++)); do _returned_indexes+=("$i"); done + + # if exclusion range + if [[ "$index" =~ ^[0-9]+\.\.[0-9]+$ ]]; then + start=$(echo "$index" | cut -d. -f1) + end=$(echo "$index" | cut -d. -f3) + + [[ $start -lt 1 || $end -lt 1 || $start -gt $range || $end -gt $range ]] && { log ERROR "Function parse indexes: exclusion range $index out of range (1 -> $range)"; exit 1; } + + if [[ $start -le $end ]]; then + for ((i=start; i<=end; i++)); do + _returned_indexes=("${_returned_indexes[@]/$i}") # remove index from array + done + else + for ((i=start; i>=end; i--)); do + _returned_indexes=("${_returned_indexes[@]/$i}") # remove index from array + done + fi + else + # single exclusion + [[ $index -lt 1 || $index -gt $range ]] && { log ERROR "Function parse indexes: index $index out of range (1 -> $range)"; exit 1; } + + _returned_indexes=("${_returned_indexes[@]/$index}") # remove index from array + fi + else + log ERROR "Function parse indexes: invalid index $index" + exit 1 + fi + done +} + function get_mod_name_and_index() { # if calling install multiple times in the same call of h2mm, the mod_index needs to be reset if it was -1 [[ $mod_index -eq -1 ]] && unset mod_index @@ -822,68 +897,95 @@ function mod_install() { # directory containing mod files if [[ -n "$mod_dir" ]]; then + # remove trailing slash if it exists + mod_dir="${mod_dir%/}" + # verify directory exists [[ ! -d "$mod_dir" ]] && { log ERROR "Directory $mod_dir does not exist."; exit 1; } # read every file from the directory readarray -d '' mod_files < <(find "$mod_dir" -type f -name "*.patch_*" -print0) + # if the name is not specified, use the name of the directory, last sed for making nexusmods names not have numbers if [[ -z "$mod_name" ]]; then mod_name=$(echo "$mod_dir" | sed 's:/*$::' | awk -F/ '{print $NF}' | sed -E 's/-[0-9]+-.*//') fi # check for mod variants and handle + # if it's a tmp directory in the format /tmp/tmp.*/, we need to go mindepth 1 to avoid listing the tmp dir itself + [[ "$mod_dir" == /tmp/tmp.* ]] && mindepth=1 || mindepth=0 + # if the mod directory contains more than 1 directory, it means there are multiple variants for the mod # prompt the user to choose which variant to install, or install multiple - readarray -d '' all_dirs < <(find "$mod_dir" -mindepth 1 -type d -print0) + readarray -d '' all_dirs < <(find "$mod_dir" -mindepth $mindepth -type d -print0) # filter so that we only have dirs that have *.patch_* files inside them filtered_dirs=() for dir in "${all_dirs[@]}"; do - if find "$dir" -maxdepth 1 -type f -name "*.patch_*" -print -quit | grep -q .; then + if find "$dir" -type f -name "*.patch_*" -print -quit | grep -q .; then filtered_dirs+=("$dir") fi done - if [[ ${#filtered_dirs[@]} -gt 1 ]]; then - log INFO "Multiple mod variants found for mod ${mod_name}." + if [[ ${#filtered_dirs[@]} -ne 0 ]]; then + log INFO "Multiple mod variants found for mod ${mod_name}:" # print the variant name by display all the directories (and how they're nested) # first, take the basename of the directory/zip we're installing from # then, make the variant name by removing the tmp dir name from the path (if it's a zip) # finally, take out this name, if it exists - if [[ -n "$mod_zip" ]]; then - mod_file_name="$(get_basename "$mod_zip")" - else - mod_file_name="*" - fi - for i in "${!filtered_dirs[@]}"; do - variant_name="${filtered_dirs[$i]#$mod_dir/}" # remote temp name in case its a zip - log INFO "$((i + 1)). ${variant_name#$mod_file_name/}" # remote the name of the zip/dir if it exists + variant_name="${filtered_dirs[$i]}" + + # if mod_dir contains /tmp/tmp.*/* then remove the /tmp/tmp.*/ part and leave the rest, else just remove the mod_dir part + if [[ "$mod_dir" == /tmp/tmp.* ]]; then + variant_name="${variant_name#$mod_dir/*/}" # remove /tmp/tmp.* part + + [[ $i == 0 && "$variant_name" == /tmp/tmp.* ]] && variant_name="$mod_name [base folder]" + else + variant_name="${variant_name#$mod_dir/}" # remove dir name before it + + [[ $i == 0 && "$variant_name" == "$mod_dir" ]] && variant_name="$mod_name [base folder]" + fi + + log INFO "$((i + 1)). $variant_name" done # prompt user to choose - log PROMPT "Enter the number of the variant(s) to install (separated by space) or press Enter to install all: " + log INFO "Use spaces to separate multiple variants (1 2 4) or use ranges (2..5) or use exclusions (-3) or any combination of them (1 3..5 7..12 -10)." + log INFO "When only exclusions are present (-3) it means all variants except the excluded ones. You can also use exclusion ranges (-3..5)." + log PROMPT "Enter the combination of variants to install (or press Enter to install all variants): " read -a variant_indices if [[ -n "${variant_indices[0]}" ]]; then # clear mod_files mod_files=() - # get the files from the chosen variant - for index in "${variant_indices[@]}"; do - [[ ! "$index" =~ ^[0-9]+$ ]] && { log ERROR "Invalid variant index."; exit 1; } - [[ $index -lt 1 || $index -gt ${#filtered_dirs[@]} ]] && { log ERROR "Variant index out of range."; exit 1; } + # use this variable for formatting the mod name + has_atleast_one_variant=false - readarray -d '' variant_files < <(find "${filtered_dirs[$((index - 1))]}" -type f -name "*.patch_*" -print0) + parse_indexes --range ${#filtered_dirs[@]} "${variant_indices[@]}" + + # get the files from the chosen variant + for index in "${_returned_indexes[@]}"; do + [[ -z "$index" ]] && continue + + # read the files from the directory + readarray -d '' variant_files < <(find "${filtered_dirs[$((index - 1))]}" -maxdepth 1 -type f -name "*.patch_*" -print0) # update mod_name to contain the variant name - mod_name="${mod_name} [$(basename "${filtered_dirs[$((index - 1))]}")]" + if [[ $has_atleast_one_variant == false ]]; then + mod_name="${mod_name} [$(basename "${filtered_dirs[$((index - 1))]}")" + has_atleast_one_variant=true + else + mod_name="${mod_name} - $(basename "${filtered_dirs[$((index - 1))]}")" + fi # add the files to the mod_files array mod_files+=("${variant_files[@]}") done + + [[ $has_atleast_one_variant == true ]] && mod_name="${mod_name}]" fi fi fi diff --git a/version b/version index 1a5ac0d..04e84f8 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.6.9 +0.6.10