From 97ee953b19ba14e96f52ab245b783ff8ede9fe07 Mon Sep 17 00:00:00 2001 From: Lothar Buchholz Date: Wed, 28 Sep 2022 19:33:11 +0200 Subject: [PATCH] Version 1.1.4 - typos in descriptions - ambiguous variable definitions - bumped version for all versions of WoW (Classic Era, WotLK, Retail) - added TOCs for all versions of WoW, removed release script --- .release/release.sh | 2647 -------------------------------------- CHANGELOG.md | 8 +- Grichelde.toc | 39 +- GricheldeChat.lua | 82 +- GricheldeConstants.lua | 44 +- GricheldeDatabase.lua | 4 +- GricheldeMinimap.lua | 4 +- GricheldeTest.lua | 5 +- GricheldeUpgrade.lua | 4 +- Grichelde_TBC.toc | 48 + Grichelde_Vanilla.toc | 48 + Grichelde_Wrath.toc | 48 + Libs/LibStub/LibStub.toc | 9 + README.md | 2 +- 14 files changed, 253 insertions(+), 2739 deletions(-) delete mode 100644 .release/release.sh create mode 100644 Grichelde_TBC.toc create mode 100644 Grichelde_Vanilla.toc create mode 100644 Grichelde_Wrath.toc create mode 100644 Libs/LibStub/LibStub.toc diff --git a/.release/release.sh b/.release/release.sh deleted file mode 100644 index 0d15c1a..0000000 --- a/.release/release.sh +++ /dev/null @@ -1,2647 +0,0 @@ -#!/usr/bin/env bash - -# release.sh generates an addon zip file from a Git, SVN, or Mercurial checkout. -# -# This is free and unencumbered software released into the public domain. -# -# Anyone is free to copy, modify, publish, use, compile, sell, or -# distribute this software, either in source code form or as a compiled -# binary, for any purpose, commercial or non-commercial, and by any -# means. -# -# In jurisdictions that recognize copyright laws, the author or authors -# of this software dedicate any and all copyright interest in the -# software to the public domain. We make this dedication for the benefit -# of the public at large and to the detriment of our heirs and -# successors. We intend this dedication to be an overt act of -# relinquishment in perpetuity of all present and future rights to this -# software under copyright law. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -# For more information, please refer to - -## USER OPTIONS - -# Secrets for uploading -cf_token= -github_token= -wowi_token= -wago_token= - -# Variables set via command-line options -slug= -addonid= -wagoid= -topdir= -releasedir= -overwrite= -nolib= -line_ending="dos" -skip_copying= -skip_externals= -skip_localization= -skip_zipfile= -skip_upload= -skip_cf_upload= -pkgmeta_file= -game_version= -game_type= -file_type= -file_name="{package-name}-{project-version}{nolib}{classic}" - -wowi_markup="bbcode" - -## END USER OPTIONS - -if [[ ${BASH_VERSINFO[0]} -lt 4 ]] || [[ ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -lt 3 ]]; then - echo "ERROR! bash version 4.3 or above is required. Your version is ${BASH_VERSION}." >&2 - exit 1 -fi - -# Game versions for uploading -declare -A game_flavors=( ["retail"]="mainline" ["classic"]="classic" ["bcc"]="bcc" ) -declare -A game_versions -toc_version= - -# Script return code -exit_code=0 - -# Escape a string for use in sed substitutions. -escape_substr() { - local s="$1" - s=${s//\\/\\\\} - s=${s//\//\\/} - s=${s//&/\\&} - echo "$s" -} - -# File name templating -filename_filter() { - local classic alpha beta invalid - [ -n "$skip_invalid" ] && invalid="&" || invalid="_" - if [[ "$game_type" != "retail" ]] && [[ "$game_type" != "classic" || "${si_project_version,,}" != *"-classic"* ]] && [[ "$game_type" != "bcc" || "${si_project_version,,}" != *"-bcc"* ]]; then - # only append the game type if the tag doesn't include it - classic="-$game_type" - fi - [ "$file_type" == "alpha" ] && alpha="-alpha" - [ "$file_type" == "beta" ] && beta="-beta" - sed \ - -e "s/{package-name}/$( escape_substr "$package" )/g" \ - -e "s/{project-revision}/$si_project_revision/g" \ - -e "s/{project-hash}/$si_project_hash/g" \ - -e "s/{project-abbreviated-hash}/$si_project_abbreviated_hash/g" \ - -e "s/{project-author}/$( escape_substr "$si_project_author" )/g" \ - -e "s/{project-date-iso}/$si_project_date_iso/g" \ - -e "s/{project-date-integer}/$si_project_date_integer/g" \ - -e "s/{project-timestamp}/$si_project_timestamp/g" \ - -e "s/{project-version}/$( escape_substr "$si_project_version" )/g" \ - -e "s/{game-type}/${game_type}/g" \ - -e "s/{release-type}/${file_type}/g" \ - -e "s/{alpha}/${alpha}/g" \ - -e "s/{beta}/${beta}/g" \ - -e "s/{nolib}/${nolib:+-nolib}/g" \ - -e "s/{classic}/${classic}/g" \ - -e "s/\([^A-Za-z0-9._-]\)/${invalid}/g" \ - <<< "$1" -} - -toc_filter() { - local keyword="$1" - local remove="$2" - if [ -z "$remove" ]; then - # "active" build type: remove comments (keep content), remove non-blocks (remove all) - sed \ - -e "/#@\(end-\)\{0,1\}${keyword}@/d" \ - -e "/#@non-${keyword}@/,/#@end-non-${keyword}@/d" - else - # "non" build type: remove blocks (remove content), uncomment non-blocks (remove tags) - sed \ - -e "/#@${keyword}@/,/#@end-${keyword}@/d" \ - -e "/#@non-${keyword}@/,/#@end-non-${keyword}@/s/^#[[:blank:]]\{1,\}//" \ - -e "/#@\(end-\)\{0,1\}non-${keyword}@/d" - fi -} - - -# Process command-line options -usage() { - cat <<-'EOF' >&2 - Usage: release.sh [options] - -c Skip copying files into the package directory. - -d Skip uploading. - -e Skip checkout of external repositories. - -l Skip @localization@ keyword replacement. - -L Only do @localization@ keyword replacement (skip upload to CurseForge). - -o Keep existing package directory, overwriting its contents. - -s Create a stripped-down "nolib" package. - -u Use Unix line-endings. - -z Skip zip file creation. - -t topdir Set top-level directory of checkout. - -r releasedir Set directory containing the package directory. Defaults to "$topdir/.release". - -p curse-id Set the project id used on CurseForge for localization and uploading. (Use 0 to unset the TOC value) - -w wowi-id Set the addon id used on WoWInterface for uploading. (Use 0 to unset the TOC value) - -a wago-id Set the project id used on Wago Addons for uploading. (Use 0 to unset the TOC value) - -g game-version Set the game version to use for uploading. - -m pkgmeta.yaml Set the pkgmeta file to use. - -n package-name Set the package zip file name. Use "-n help" for more info. - EOF -} - -OPTIND=1 -while getopts ":celLzusop:dw:a:r:t:g:m:n:" opt; do - case $opt in - c) skip_copying="true" ;; # Skip copying files into the package directory - z) skip_zipfile="true" ;; # Skip creating a zip file - e) skip_externals="true" ;; # Skip checkout of external repositories - l) skip_localization="true" ;; # Skip @localization@ keyword replacement - L) skip_cf_upload="true" ;; # Skip uploading to CurseForge - d) skip_upload="true" ;; # Skip uploading - u) line_ending="unix" ;; # Use LF instead of CRLF as the line ending for all text files - o) overwrite="true" ;; # Don't delete existing directories in the release directory - p) slug="$OPTARG" ;; # Set CurseForge project id - w) addonid="$OPTARG" ;; # Set WoWInterface addon id - a) wagoid="$OPTARG" ;; # Set Wago Addons project id - r) releasedir="$OPTARG" ;; # Set the release directory - t) # Set the top-level directory of the checkout - if [ ! -d "$OPTARG" ]; then - echo "Invalid argument for option \"-t\" - Directory \"$OPTARG\" does not exist." >&2 - usage - exit 1 - fi - topdir="$OPTARG" - ;; - s) # Create a nolib package without externals - nolib="true" - skip_externals="true" - ;; - g) # Set the game type or version - OPTARG="${OPTARG,,}" - case "$OPTARG" in - retail|classic|bcc) game_type="$OPTARG" ;; # game_version from toc - mainline) game_type="retail" ;; - bc) - echo "Invalid argument for option \"-g\" ($OPTARG)" >&2 - echo "" >&2 - echo "The \"bc\" game type has been changed to \"bcc\" to match Blizzard." >&2 - echo "This affects TOC interface lines (Interface-BC -> Interface-BCC) and" >&2 - echo "build keywords (version-bc -> version-bcc)." >&2 - echo "" >&2 - exit 1 - ;; - *) - # Set game version (x.y.z) - # Build game type set from the last value if a list - IFS=',' read -ra V <<< "$OPTARG" - for i in "${V[@]}"; do - if [[ ! "$i" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)[a-z]?$ ]]; then - echo "Invalid argument for option \"-g\" ($i)" >&2 - usage - exit 1 - fi - if [[ ${BASH_REMATCH[1]} == "1" && ${BASH_REMATCH[2]} == "13" ]]; then - game_type="classic" - elif [[ ${BASH_REMATCH[1]} == "2" && ${BASH_REMATCH[2]} == "5" ]]; then - game_type="bcc" - else - game_type="retail" - fi - # Only one version per game type is allowed - if [ -n "${game_versions[$game_type]}" ]; then - echo "Invalid argument for option \"-g\" ($i) - Only one version per game type is supported." >&2 - usage - exit 1 - fi - game_versions[$game_type]="$i" - done - game_version="$OPTARG" - esac - ;; - m) # Set the pkgmeta file - if [ ! -f "$OPTARG" ]; then - echo "Invalid argument for option \"-m\" - File \"$OPTARG\" does not exist." >&2 - usage - exit 1 - fi - pkgmeta_file="$OPTARG" - ;; - n) # Set the package file name - if [ "$OPTARG" = "help" ]; then - cat <<-'EOF' >&2 - Set the package zip file name. There are several string substitutions you can - use to include version control and build type infomation in the file name. - - The default file name is "{package-name}-{project-version}{nolib}{classic}". - - Tokens: {package-name}{project-revision}{project-hash}{project-abbreviated-hash} - {project-author}{project-date-iso}{project-date-integer}{project-timestamp} - {project-version}{game-type}{release-type} - - Flags: {alpha}{beta}{nolib}{classic} - - Tokens are always replaced with their value. Flags are shown prefixed with a dash - depending on the build type. - EOF - exit 0 - fi - file_name="$OPTARG" - if skip_invalid=true filename_filter "$file_name" | grep -q '[{}]'; then - tokens=$( skip_invalid=true filename_filter "$file_name" | sed -e '/^[^{]*{\|}[^{]*{\|}[^{]*/s//}{/g' -e 's/^}\({.*}\){$/\1/' ) - echo "Invalid argument for option \"-n\" - Invalid substitutions: $tokens" >&2 - exit 1 - fi - ;; - :) - echo "Option \"-$OPTARG\" requires an argument." >&2 - usage - exit 1 - ;; - \?) - if [ "$OPTARG" = "?" ] || [ "$OPTARG" = "h" ]; then - usage - exit 0 - fi - echo "Unknown option \"-$OPTARG\"" >&2 - usage - exit 1 - ;; - esac -done -shift $((OPTIND - 1)) - -# Set $topdir to top-level directory of the checkout. -if [ -z "$topdir" ]; then - dir=$( pwd ) - if [ -d "$dir/.git" ] || [ -d "$dir/.svn" ] || [ -d "$dir/.hg" ]; then - topdir=. - else - dir=${dir%/*} - topdir=".." - while [ -n "$dir" ]; do - if [ -d "$topdir/.git" ] || [ -d "$topdir/.svn" ] || [ -d "$topdir/.hg" ]; then - break - fi - dir=${dir%/*} - topdir="$topdir/.." - done - if [ ! -d "$topdir/.git" ] && [ ! -d "$topdir/.svn" ] && [ ! -d "$topdir/.hg" ]; then - echo "No Git, SVN, or Hg checkout found." >&2 - exit 1 - fi - fi -fi - -# Handle folding sections in CI logs -start_group() { echo "$1"; } -end_group() { echo; } - -# Check for Travis CI -if [ -n "$TRAVIS" ]; then - # Don't run the packager for pull requests - if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then - echo "Not packaging pull request." - exit 0 - fi - if [ -z "$TRAVIS_TAG" ]; then - # Don't run the packager if there is a tag pending - check_tag=$( git -C "$topdir" tag --points-at HEAD ) - if [ -n "$check_tag" ]; then - echo "Found future tag \"${check_tag}\", not packaging." - exit 0 - fi - # Only package master, classic, or develop - if [ "$TRAVIS_BRANCH" != "master" ] && [ "$TRAVIS_BRANCH" != "classic" ] && [ "$TRAVIS_BRANCH" != "develop" ]; then - echo "Not packaging \"${TRAVIS_BRANCH}\"." - exit 0 - fi - fi - # https://github.com/travis-ci/travis-build/tree/master/lib/travis/build/bash - start_group() { - echo -en "travis_fold:start:$2\\r\033[0K" - # release_timer_id="$(printf %08x $((RANDOM * RANDOM)))" - # release_timer_start_time="$(date -u +%s%N)" - # echo -en "travis_time:start:${release_timer_id}\\r\033[0K" - echo "$1" - } - end_group() { - # local release_timer_end_time="$(date -u +%s%N)" - # local duration=$((release_timer_end_time - release_timer_start_time)) - # echo -en "\\ntravis_time:end:${release_timer_id}:start=${release_timer_start_time},finish=${release_timer_end_time},duration=${duration}\\r\033[0K" - echo -en "travis_fold:end:$1\\r\033[0K" - } -fi - -# Check for GitHub Actions -if [ -n "$GITHUB_ACTIONS" ]; then - # Prevent duplicate builds - if [[ "$GITHUB_REF" == "refs/heads"* ]]; then - check_tag=$( git -C "$topdir" tag --points-at HEAD ) - if [ -n "$check_tag" ]; then - echo "Found future tag \"${check_tag}\", not packaging." - exit 0 - fi - fi - start_group() { echo "##[group]$1"; } - end_group() { echo "##[endgroup]"; } -fi -unset check_tag - -# Load secrets -if [ -f "$topdir/.env" ]; then - # shellcheck disable=1090 - . "$topdir/.env" -elif [ -f ".env" ]; then - . ".env" -fi -[ -z "$cf_token" ] && cf_token=$CF_API_KEY -[ -z "$github_token" ] && github_token=$GITHUB_OAUTH -[ -z "$wowi_token" ] && wowi_token=$WOWI_API_TOKEN -[ -z "$wago_token" ] && wago_token=$WAGO_API_TOKEN - -# Set $releasedir to the directory which will contain the generated addon zipfile. -if [ -z "$releasedir" ]; then - releasedir="$topdir/.release" -fi - -# Set $basedir to the basename of the checkout directory. -basedir=$( cd "$topdir" && pwd ) -case $basedir in -/*/*) - basedir=${basedir##/*/} - ;; -/*) - basedir=${basedir##/} - ;; -esac - -# Set $repository_type to "git" or "svn" or "hg". -repository_type= -if [ -d "$topdir/.git" ]; then - repository_type=git -elif [ -d "$topdir/.svn" ]; then - repository_type=svn -elif [ -d "$topdir/.hg" ]; then - repository_type=hg -else - echo "No Git, SVN, or Hg checkout found in \"$topdir\"." >&2 - exit 1 -fi - -# $releasedir must be an absolute path or inside $topdir. -case $releasedir in -/*) ;; -$topdir/*) ;; -*) - echo "The release directory \"$releasedir\" must be an absolute path or inside \"$topdir\"." >&2 - exit 1 - ;; -esac - -# Create the staging directory. -mkdir -p "$releasedir" 2>/dev/null || { - echo "Unable to create the release directory \"$releasedir\"." >&2 - exit 1 -} - -# Expand $topdir and $releasedir to their absolute paths for string comparisons later. -topdir=$( cd "$topdir" && pwd ) -releasedir=$( cd "$releasedir" && pwd ) - -### -### set_info_ returns the following information: -### -si_repo_type= # "git" or "svn" or "hg" -si_repo_dir= # the checkout directory -si_repo_url= # the checkout url -si_tag= # tag for HEAD -si_previous_tag= # previous tag -si_previous_revision= # [SVN|Hg] revision number for previous tag - -si_project_revision= # Turns into the highest revision of the entire project in integer form, e.g. 1234, for SVN. Turns into the commit count for the project's hash for Git. -si_project_hash= # [Git|Hg] Turns into the hash of the entire project in hex form. e.g. 106c634df4b3dd4691bf24e148a23e9af35165ea -si_project_abbreviated_hash= # [Git|Hg] Turns into the abbreviated hash of the entire project in hex form. e.g. 106c63f -si_project_author= # Turns into the last author of the entire project. e.g. ckknight -si_project_date_iso= # Turns into the last changed date (by UTC) of the entire project in ISO 8601. e.g. 2008-05-01T12:34:56Z -si_project_date_integer= # Turns into the last changed date (by UTC) of the entire project in a readable integer fashion. e.g. 2008050123456 -si_project_timestamp= # Turns into the last changed date (by UTC) of the entire project in POSIX timestamp. e.g. 1209663296 -si_project_version= # Turns into an approximate version of the project. The tag name if on a tag, otherwise it's up to the repo. SVN returns something like "r1234", Git returns something like "v0.1-873fc1" - -si_file_revision= # Turns into the current revision of the file in integer form, e.g. 1234, for SVN. Turns into the commit count for the file's hash for Git. -si_file_hash= # Turns into the hash of the file in hex form. e.g. 106c634df4b3dd4691bf24e148a23e9af35165ea -si_file_abbreviated_hash= # Turns into the abbreviated hash of the file in hex form. e.g. 106c63 -si_file_author= # Turns into the last author of the file. e.g. ckknight -si_file_date_iso= # Turns into the last changed date (by UTC) of the file in ISO 8601. e.g. 2008-05-01T12:34:56Z -si_file_date_integer= # Turns into the last changed date (by UTC) of the file in a readable integer fashion. e.g. 20080501123456 -si_file_timestamp= # Turns into the last changed date (by UTC) of the file in POSIX timestamp. e.g. 1209663296 - -# SVN date helper function -strtotime() { - local value="$1" # datetime string - local format="$2" # strptime string - if [[ "${OSTYPE,,}" == *"darwin"* ]]; then # bsd - date -j -f "$format" "$value" "+%s" 2>/dev/null - else # gnu - date -d "$value" +%s 2>/dev/null - fi -} - -set_info_git() { - si_repo_dir="$1" - si_repo_type="git" - si_repo_url=$( git -C "$si_repo_dir" remote get-url origin 2>/dev/null | sed -e 's/^git@\(.*\):/https:\/\/\1\//' ) - if [ -z "$si_repo_url" ]; then # no origin so grab the first fetch url - si_repo_url=$( git -C "$si_repo_dir" remote -v | awk '/(fetch)/ { print $2; exit }' | sed -e 's/^git@\(.*\):/https:\/\/\1\//' ) - fi - - # Populate filter vars. - si_project_hash=$( git -C "$si_repo_dir" show --no-patch --format="%H" 2>/dev/null ) - si_project_abbreviated_hash=$( git -C "$si_repo_dir" show --no-patch --abbrev=7 --format="%h" 2>/dev/null ) - si_project_author=$( git -C "$si_repo_dir" show --no-patch --format="%an" 2>/dev/null ) - si_project_timestamp=$( git -C "$si_repo_dir" show --no-patch --format="%at" 2>/dev/null ) - si_project_date_iso=$( TZ='' printf "%(%Y-%m-%dT%H:%M:%SZ)T" "$si_project_timestamp" ) - si_project_date_integer=$( TZ='' printf "%(%Y%m%d%H%M%S)T" "$si_project_timestamp" ) - # XXX --depth limits rev-list :\ [ ! -s "$(git rev-parse --git-dir)/shallow" ] || git fetch --unshallow --no-tags - si_project_revision=$( git -C "$si_repo_dir" rev-list --count "$si_project_hash" 2>/dev/null ) - - # Get the tag for the HEAD. - si_previous_tag= - si_previous_revision= - _si_tag=$( git -C "$si_repo_dir" describe --tags --always --abbrev=7 2>/dev/null ) - si_tag=$( git -C "$si_repo_dir" describe --tags --always --abbrev=0 2>/dev/null ) - # Set $si_project_version to the version number of HEAD. May be empty if there are no commits. - si_project_version=$si_tag - # The HEAD is not tagged if the HEAD is several commits past the most recent tag. - if [ "$si_tag" = "$si_project_hash" ]; then - # --abbrev=0 expands out the full sha if there was no previous tag - si_project_version=$_si_tag - si_previous_tag= - si_tag= - elif [ "$_si_tag" != "$si_tag" ]; then - # not on a tag - si_project_version=$( git -C "$si_repo_dir" describe --tags --abbrev=7 --exclude="*[Aa][Ll][Pp][Hh][Aa]*" 2>/dev/null ) - si_previous_tag=$( git -C "$si_repo_dir" describe --tags --abbrev=0 --exclude="*[Aa][Ll][Pp][Hh][Aa]*" 2>/dev/null ) - si_tag= - else # we're on a tag, just jump back one commit - if [[ ${si_tag,,} != *"beta"* && ${si_tag,,} != *"alpha"* ]]; then - # full release, ignore beta tags - si_previous_tag=$( git -C "$si_repo_dir" describe --tags --abbrev=0 --exclude="*[Aa][Ll][Pp][Hh][Aa]*" --exclude="*[Bb][Ee][Tt][Aa]*" HEAD~ 2>/dev/null ) - else - si_previous_tag=$( git -C "$si_repo_dir" describe --tags --abbrev=0 --exclude="*[Aa][Ll][Pp][Hh][Aa]*" HEAD~ 2>/dev/null ) - fi - fi -} - -set_info_svn() { - si_repo_dir="$1" - si_repo_type="svn" - - # Temporary file to hold results of "svn info". - _si_svninfo="${si_repo_dir}/.svn/release_sh_svninfo" - svn info -r BASE "$si_repo_dir" 2>/dev/null > "$_si_svninfo" - - if [ -s "$_si_svninfo" ]; then - _si_root=$( awk '/^Repository Root:/ { print $3; exit }' < "$_si_svninfo" ) - _si_url=$( awk '/^URL:/ { print $2; exit }' < "$_si_svninfo" ) - _si_revision=$( awk '/^Last Changed Rev:/ { print $NF; exit }' < "$_si_svninfo" ) - si_repo_url=$_si_root - - case ${_si_url#${_si_root}/} in - tags/*) - # Extract the tag from the URL. - si_tag=${_si_url#${_si_root}/tags/} - si_tag=${si_tag%%/*} - si_project_revision="$_si_revision" - ;; - *) - # Check if the latest tag matches the working copy revision (/trunk checkout instead of /tags) - _si_tag_line=$( svn log --verbose --limit 1 "$_si_root/tags" 2>/dev/null | awk '/^ A/ { print $0; exit }' ) - _si_tag=$( echo "$_si_tag_line" | awk '/^ A/ { print $2 }' | awk -F/ '{ print $NF }' ) - _si_tag_from_revision=$( echo "$_si_tag_line" | sed -e 's/^.*:\([0-9]\{1,\}\)).*$/\1/' ) # (from /project/trunk:N) - - if [ "$_si_tag_from_revision" = "$_si_revision" ]; then - si_tag="$_si_tag" - si_project_revision=$( svn info "$_si_root/tags/$si_tag" 2>/dev/null | awk '/^Last Changed Rev:/ { print $NF; exit }' ) - else - # Set $si_project_revision to the highest revision of the project at the checkout path - si_project_revision=$( svn info --recursive "$si_repo_dir" 2>/dev/null | awk '/^Last Changed Rev:/ { print $NF }' | sort -nr | head -n1 ) - fi - ;; - esac - - if [ -n "$si_tag" ]; then - si_project_version="$si_tag" - else - si_project_version="r$si_project_revision" - fi - - # Get the previous tag and it's revision - _si_limit=$((si_project_revision - 1)) - _si_tag=$( svn log --verbose --limit 1 "$_si_root/tags" -r $_si_limit:1 2>/dev/null | awk '/^ A/ { print $0; exit }' | awk '/^ A/ { print $2 }' | awk -F/ '{ print $NF }' ) - if [ -n "$_si_tag" ]; then - si_previous_tag="$_si_tag" - si_previous_revision=$( svn info "$_si_root/tags/$_si_tag" 2>/dev/null | awk '/^Last Changed Rev:/ { print $NF; exit }' ) - fi - - # Populate filter vars. - si_project_author=$( awk '/^Last Changed Author:/ { print $0; exit }' < "$_si_svninfo" | cut -d" " -f4- ) - _si_timestamp=$( awk '/^Last Changed Date:/ { print $4,$5; exit }' < "$_si_svninfo" ) - si_project_timestamp=$( strtotime "$_si_timestamp" "%F %T" ) - si_project_date_iso=$( TZ='' printf "%(%Y-%m-%dT%H:%M:%SZ)T" "$si_project_timestamp" ) - si_project_date_integer=$( TZ='' printf "%(%Y%m%d%H%M%S)T" "$si_project_timestamp" ) - # SVN repositories have no project hash. - si_project_hash= - si_project_abbreviated_hash= - - rm -f "$_si_svninfo" 2>/dev/null - fi -} - -set_info_hg() { - si_repo_dir="$1" - si_repo_type="hg" - si_repo_url=$( hg --cwd "$si_repo_dir" paths -q default ) - if [ -z "$si_repo_url" ]; then # no default so grab the first path - si_repo_url=$( hg --cwd "$si_repo_dir" paths | awk '{ print $3; exit }' ) - fi - - # Populate filter vars. - si_project_hash=$( hg --cwd "$si_repo_dir" log -r . --template '{node}' 2>/dev/null ) - si_project_abbreviated_hash=$( hg --cwd "$si_repo_dir" log -r . --template '{node|short}' 2>/dev/null ) - si_project_author=$( hg --cwd "$si_repo_dir" log -r . --template '{author}' 2>/dev/null ) - si_project_timestamp=$( hg --cwd "$si_repo_dir" log -r . --template '{date}' 2>/dev/null | cut -d. -f1 ) - si_project_date_iso=$( TZ='' printf "%(%Y-%m-%dT%H:%M:%SZ)T" "$si_project_timestamp" ) - si_project_date_integer=$( TZ='' printf "%(%Y%m%d%H%M%S)T" "$si_project_timestamp" ) - si_project_revision=$( hg --cwd "$si_repo_dir" log -r . --template '{rev}' 2>/dev/null ) - - # Get tag info - si_tag= - # I'm just muddling through revsets, so there is probably a better way to do this - # Ignore tag commits, so v1.0-1 will package as v1.0 - if [ "$( hg --cwd "$si_repo_dir" log -r '.-filelog(.hgtags)' --template '{rev}' 2>/dev/null )" == "" ]; then - _si_tip=$( hg --cwd "$si_repo_dir" log -r 'last(parents(.))' --template '{rev}' 2>/dev/null ) - else - _si_tip=$( hg --cwd "$si_repo_dir" log -r . --template '{rev}' 2>/dev/null ) - fi - si_previous_tag=$( hg --cwd "$si_repo_dir" log -r "$_si_tip" --template '{latesttag}' 2>/dev/null ) - # si_project_version=$( hg --cwd "$si_repo_dir" log -r "$_si_tip" --template "{ ifeq(changessincelatesttag, 0, latesttag, '{latesttag}-{changessincelatesttag}-m{node|short}') }" 2>/dev/null ) # git style - si_project_version=$( hg --cwd "$si_repo_dir" log -r "$_si_tip" --template "{ ifeq(changessincelatesttag, 0, latesttag, 'r{rev}') }" 2>/dev/null ) # svn style - if [ "$si_previous_tag" = "$si_project_version" ]; then - # we're on a tag - si_tag=$si_previous_tag - si_previous_tag=$( hg --cwd "$si_repo_dir" log -r "last(parents($_si_tip))" --template '{latesttag}' 2>/dev/null ) - fi - si_previous_revision=$( hg --cwd "$si_repo_dir" log -r "$si_previous_tag" --template '{rev}' 2>/dev/null ) -} - -set_info_file() { - if [ "$si_repo_type" = "git" ]; then - _si_file=${1#si_repo_dir} # need the path relative to the checkout - # Populate filter vars from the last commit the file was included in. - si_file_hash=$( git -C "$si_repo_dir" log --max-count=1 --format="%H" "$_si_file" 2>/dev/null ) - si_file_abbreviated_hash=$( git -C "$si_repo_dir" log --max-count=1 --abbrev=7 --format="%h" "$_si_file" 2>/dev/null ) - si_file_author=$( git -C "$si_repo_dir" log --max-count=1 --format="%an" "$_si_file" 2>/dev/null ) - si_file_timestamp=$( git -C "$si_repo_dir" log --max-count=1 --format="%at" "$_si_file" 2>/dev/null ) - si_file_date_iso=$( TZ='' printf "%(%Y-%m-%dT%H:%M:%SZ)T" "$si_file_timestamp" ) - si_file_date_integer=$( TZ='' printf "%(%Y%m%d%H%M%S)T" "$si_file_timestamp" ) - si_file_revision=$( git -C "$si_repo_dir" rev-list --count "$si_file_hash" 2>/dev/null ) # XXX checkout depth affects rev-list, see set_info_git - elif [ "$si_repo_type" = "svn" ]; then - _si_file="$1" - # Temporary file to hold results of "svn info". - _sif_svninfo="${si_repo_dir}/.svn/release_sh_svnfinfo" - svn info "$_si_file" 2>/dev/null > "$_sif_svninfo" - if [ -s "$_sif_svninfo" ]; then - # Populate filter vars. - si_file_revision=$( awk '/^Last Changed Rev:/ { print $NF; exit }' < "$_sif_svninfo" ) - si_file_author=$( awk '/^Last Changed Author:/ { print $0; exit }' < "$_sif_svninfo" | cut -d" " -f4- ) - _si_timestamp=$( awk '/^Last Changed Date:/ { print $4,$5,$6; exit }' < "$_sif_svninfo" ) - si_file_timestamp=$( strtotime "$_si_timestamp" "%F %T %z" ) - si_file_date_iso=$( TZ='' printf "%(%Y-%m-%dT%H:%M:%SZ)T" "$si_file_timestamp" ) - si_file_date_integer=$( TZ='' printf "%(%Y%m%d%H%M%S)T" "$si_file_timestamp" ) - # SVN repositories have no project hash. - si_file_hash= - si_file_abbreviated_hash= - - rm -f "$_sif_svninfo" 2>/dev/null - fi - elif [ "$si_repo_type" = "hg" ]; then - _si_file=${1#si_repo_dir} # need the path relative to the checkout - # Populate filter vars. - si_file_hash=$( hg --cwd "$si_repo_dir" log --limit 1 --template '{node}' "$_si_file" 2>/dev/null ) - si_file_abbreviated_hash=$( hg --cwd "$si_repo_dir" log --limit 1 --template '{node|short}' "$_si_file" 2>/dev/null ) - si_file_author=$( hg --cwd "$si_repo_dir" log --limit 1 --template '{author}' "$_si_file" 2>/dev/null ) - si_file_timestamp=$( hg --cwd "$si_repo_dir" log --limit 1 --template '{date}' "$_si_file" 2>/dev/null | cut -d. -f1 ) - si_file_date_iso=$( TZ='' printf "%(%Y-%m-%dT%H:%M:%SZ)T" "$si_file_timestamp" ) - si_file_date_integer=$( TZ='' printf "%(%Y%m%d%H%M%S)T" "$si_file_timestamp" ) - si_file_revision=$( hg --cwd "$si_repo_dir" log --limit 1 --template '{rev}' "$_si_file" 2>/dev/null ) - fi -} - -# Set some version info about the project -case $repository_type in -git) set_info_git "$topdir" ;; -svn) set_info_svn "$topdir" ;; -hg) set_info_hg "$topdir" ;; -esac - -tag=$si_tag -project_version=$si_project_version -previous_version=$si_previous_tag -project_hash=$si_project_hash -project_revision=$si_project_revision -previous_revision=$si_previous_revision -project_timestamp=$si_project_timestamp -project_github_url= -project_github_slug= -if [[ "$si_repo_url" == "https://github.com"* ]]; then - project_github_url=${si_repo_url%.git} - project_github_slug=${project_github_url#https://github.com/} -fi -project_site= - -# Bare carriage-return character. -carriage_return=$( printf "\r" ) - -# Returns 0 if $1 matches one of the colon-separated patterns in $2. -match_pattern() { - _mp_file=$1 - _mp_list="$2:" - while [ -n "$_mp_list" ]; do - _mp_pattern=${_mp_list%%:*} - _mp_list=${_mp_list#*:} - # shellcheck disable=2254 - case $_mp_file in - $_mp_pattern) - return 0 - ;; - esac - done - return 1 -} - -# Simple .pkgmeta YAML processor. -yaml_keyvalue() { - yaml_key=${1%%:*} - yaml_value=${1#$yaml_key:} - yaml_value=${yaml_value#"${yaml_value%%[! ]*}"} # trim leading whitespace - yaml_value=${yaml_value#[\'\"]} # trim leading quotes - yaml_value=${yaml_value%[\'\"]} # trim trailing quotes -} - -yaml_listitem() { - yaml_item=${1#-} - yaml_item=${yaml_item#"${yaml_item%%[! ]*}"} # trim leading whitespace -} - -### -### Process .pkgmeta to set variables used later in the script. -### - -if [ -z "$pkgmeta_file" ]; then - pkgmeta_file="$topdir/.pkgmeta" - # CurseForge allows this so check for it - if [ ! -f "$pkgmeta_file" ] && [ -f "$topdir/pkgmeta.yaml" ]; then - pkgmeta_file="$topdir/pkgmeta.yaml" - fi -fi - -# Variables set via .pkgmeta. -package= -manual_changelog= -changelog= -changelog_markup="text" -enable_nolib_creation= -ignore= -contents= -nolib_exclude= -wowi_gen_changelog="true" -wowi_archive="true" -wowi_convert_changelog="true" -declare -A relations=() - -parse_ignore() { - pkgmeta="$1" - [ -f "$pkgmeta" ] || return 1 - - checkpath="$topdir" # paths are relative to the topdir - copypath="" - if [ "$2" != "" ]; then - checkpath=$( dirname "$pkgmeta" ) - copypath="$2/" - fi - - yaml_eof= - while [ -z "$yaml_eof" ]; do - IFS='' read -r yaml_line || yaml_eof="true" - # Skip commented out lines. - if [[ $yaml_line =~ ^[[:space:]]*\# ]]; then - continue - fi - # Strip any trailing CR character. - yaml_line=${yaml_line%$carriage_return} - - case $yaml_line in - [!\ ]*:*) - # Split $yaml_line into a $yaml_key, $yaml_value pair. - yaml_keyvalue "$yaml_line" - # Set the $pkgmeta_phase for stateful processing. - pkgmeta_phase=$yaml_key - ;; - [\ ]*"- "*) - yaml_line=${yaml_line#"${yaml_line%%[! ]*}"} # trim leading whitespace - # Get the YAML list item. - yaml_listitem "$yaml_line" - if [ "$pkgmeta_phase" = "ignore" ]; then - pattern=$yaml_item - if [ -d "$checkpath/$pattern" ]; then - pattern="$copypath$pattern/*" - elif [ ! -f "$checkpath/$pattern" ]; then - # doesn't exist so match both a file and a path - pattern="$copypath$pattern:$copypath$pattern/*" - else - pattern="$copypath$pattern" - fi - if [ -z "$ignore" ]; then - ignore="$pattern" - else - ignore="$ignore:$pattern" - fi - fi - ;; - esac - done < "$pkgmeta" -} - -if [ -f "$pkgmeta_file" ]; then - if grep -q $'^[ ]*\t\+[[:blank:]]*[[:graph:]]' "$pkgmeta_file"; then - # Try to cut down on some troubleshooting pain. - echo "ERROR! Your pkgmeta file contains a leading tab. Only spaces are allowed for indentation in YAML files." >&2 - grep -n $'^[ ]*\t\+[[:blank:]]*[[:graph:]]' "$pkgmeta_file" | sed $'s/\t/^I/g' - exit 1 - fi - - yaml_eof= - while [ -z "$yaml_eof" ]; do - IFS='' read -r yaml_line || yaml_eof="true" - # Skip commented out lines. - if [[ $yaml_line =~ ^[[:space:]]*\# ]]; then - continue - fi - # Strip any trailing CR character. - yaml_line=${yaml_line%$carriage_return} - - case $yaml_line in - [!\ ]*:*) - # Split $yaml_line into a $yaml_key, $yaml_value pair. - yaml_keyvalue "$yaml_line" - # Set the $pkgmeta_phase for stateful processing. - pkgmeta_phase=$yaml_key - - case $yaml_key in - enable-nolib-creation) - if [ "$yaml_value" = "yes" ]; then - enable_nolib_creation="true" - fi - ;; - manual-changelog) - changelog=$yaml_value - manual_changelog="true" - ;; - changelog-title) - project="$yaml_value" - ;; - package-as) - package=$yaml_value - ;; - wowi-create-changelog) - if [ "$yaml_value" = "no" ]; then - wowi_gen_changelog= - fi - ;; - wowi-convert-changelog) - if [ "$yaml_value" = "no" ]; then - wowi_convert_changelog= - fi - ;; - wowi-archive-previous) - if [ "$yaml_value" = "no" ]; then - wowi_archive= - fi - ;; - esac - ;; - " "*) - yaml_line=${yaml_line#"${yaml_line%%[! ]*}"} # trim leading whitespace - case $yaml_line in - "- "*) - # Get the YAML list item. - yaml_listitem "$yaml_line" - case $pkgmeta_phase in - ignore) - pattern=$yaml_item - if [ -d "$topdir/$pattern" ]; then - pattern="$pattern/*" - elif [ ! -f "$topdir/$pattern" ]; then - # doesn't exist so match both a file and a path - pattern="$pattern:$pattern/*" - fi - if [ -z "$ignore" ]; then - ignore="$pattern" - else - ignore="$ignore:$pattern" - fi - ;; - tools-used) - relations["$yaml_item"]="tool" - ;; - required-dependencies) - relations["$yaml_item"]="requiredDependency" - ;; - optional-dependencies) - relations["$yaml_item"]="optionalDependency" - ;; - embedded-libraries) - relations["$yaml_item"]="embeddedLibrary" - ;; - esac - ;; - *:*) - # Split $yaml_line into a $yaml_key, $yaml_value pair. - yaml_keyvalue "$yaml_line" - case $pkgmeta_phase in - manual-changelog) - case $yaml_key in - filename) - changelog=$yaml_value - manual_changelog="true" - ;; - markup-type) - if [ "$yaml_value" = "markdown" ] || [ "$yaml_value" = "html" ]; then - changelog_markup=$yaml_value - else - changelog_markup="text" - fi - ;; - esac - ;; - esac - ;; - esac - ;; - esac - done < "$pkgmeta_file" -fi - -# Add untracked/ignored files to the ignore list -if [ "$repository_type" = "git" ]; then - OLDIFS=$IFS - IFS=$'\n' - for _vcs_ignore in $( git -C "$topdir" ls-files --others --directory ); do - if [ -d "$topdir/$_vcs_ignore" ]; then - _vcs_ignore="$_vcs_ignore*" - fi - if [ -z "$ignore" ]; then - ignore="$_vcs_ignore" - else - ignore="$ignore:$_vcs_ignore" - fi - done - IFS=$OLDIFS -elif [ "$repository_type" = "svn" ]; then - # svn always being difficult. - OLDIFS=$IFS - IFS=$'\n' - for _vcs_ignore in $( cd "$topdir" && svn status --no-ignore --ignore-externals | awk '/^[?IX]/' | cut -c9- | tr '\\' '/' ); do - if [ -d "$topdir/$_vcs_ignore" ]; then - _vcs_ignore="$_vcs_ignore/*" - fi - if [ -z "$ignore" ]; then - ignore="$_vcs_ignore" - else - ignore="$ignore:$_vcs_ignore" - fi - done - IFS=$OLDIFS -elif [ "$repository_type" = "hg" ]; then - _vcs_ignore=$( hg --cwd "$topdir" status --ignored --unknown --no-status --print0 | tr '\0' ':' ) - if [ -n "$_vcs_ignore" ]; then - _vcs_ignore=${_vcs_ignore:0:-1} - if [ -z "$ignore" ]; then - ignore="$_vcs_ignore" - else - ignore="$ignore:$_vcs_ignore" - fi - fi -fi - -### -### Process TOC file -### - -# Set the package name from a TOC file name -if [[ -z "$package" ]]; then - package=$( cd "$topdir" && find *.toc -maxdepth 0 2>/dev/null | head -n1 ) - if [[ -z "$package" ]]; then - echo "Could not find an addon TOC file. In another directory? Set 'package-as' in .pkgmeta" >&2 - exit 1 - fi - package=${package%.toc} - if [[ $package =~ ^(.*)-(Mainline|Classic|BCC)$ ]]; then - package="${BASH_REMATCH[1]}" - fi -fi - -toc_path="$package.toc" - -# Handle having the main addon in a sub dir -if [[ ! -f "$topdir/$toc_path" && -f "$topdir/$package/$toc_path" ]]; then - toc_path="$package/$toc_path" -fi - -if [[ ! -f "$topdir/$toc_path" ]]; then - echo "Could not find an addon TOC file. In another directory? Make sure it matches the 'package-as' in .pkgmeta" >&2 - exit 1 -fi - -# Get the interface version for setting the upload version. -toc_file=$( - # remove bom and cr and apply some non-version toc filters - [ "$file_type" != "alpha" ] && _tf_alpha="true" - sed -e $'1s/^\xEF\xBB\xBF//' -e $'s/\r//g' "$topdir/$toc_path" | toc_filter alpha ${_tf_alpha} | toc_filter debug true -) -root_toc_version=$( awk '/^## Interface:/ { print $NF; exit }' <<< "$toc_file" ) -toc_version="$root_toc_version" -if [[ -n "$toc_version" && -z "$game_type" ]]; then - # toc -> game type - case $toc_version in - 113*) game_type="classic" ;; - 205*) game_type="bcc" ;; - *) game_type="retail" - esac -else - # game type -> toc - game_type_toc_version=$( awk 'tolower($0) ~ /^## interface-'${game_type:-retail}':/ { print $NF; exit }' <<< "$toc_file" ) - if [[ -z "$game_type" ]]; then - # default to retail - game_type="retail" - elif [[ -n "$game_type_toc_version" ]]; then - # use the game version value if set - toc_version="$game_type_toc_version" - fi - # Check for other interface lines - if [[ -z "$toc_version" ]] || \ - [[ "$game_type" == "classic" && "$toc_version" != "113"* ]] || \ - [[ "$game_type" == "bcc" && "$toc_version" != "205"* ]] || \ - [[ "$game_type" == "retail" && ("$toc_version" == "113"* || "$toc_version" == "205"*) ]] - then - toc_version="$game_type_toc_version" - if [[ -z "$toc_version" ]]; then - # Check @non-@ blocks - case $game_type in - classic) toc_version=$( sed -n '/@non-[-a-z]*@/,/@end-non-[-a-z]*@/{//b;p}' <<< "$toc_file" | awk '/#[[:blank:]]*## Interface:[[:blank:]]*(113)/ { print $NF; exit }' ) ;; - bcc) toc_version=$( sed -n '/@non-[-a-z]*@/,/@end-non-[-a-z]*@/{//b;p}' <<< "$toc_file" | awk '/#[[:blank:]]*## Interface:[[:blank:]]*(205)/ { print $NF; exit }' ) ;; - esac - # This becomes the actual interface version after string replacements - root_toc_version="$toc_version" - fi - fi - if [[ -z "$toc_version" ]]; then - echo "Addon TOC interface version is not compatible with the game version \"${game_type}\" or was not found." >&2 - exit 1 - fi - if [[ "${toc_version,,}" == "incompatible" ]]; then - echo "Addon TOC interface version is set as incompatible for game version \"${game_type}\"." >&2 - exit 1 - fi -fi -if [ -z "$game_version" ]; then - printf -v game_version "%d.%d.%d" ${toc_version:0:1} ${toc_version:1:2} ${toc_version:3:2} 2>/dev/null || { - echo "Addon TOC interface version \"${toc_version}\" is invalid." >&2 - exit 1 - } - game_versions[$game_type]="$game_version" -fi - -# Get the title of the project for using in the changelog. -if [ -z "$project" ]; then - project=$( awk '/^## Title:/ { print $0; exit }' <<< "$toc_file" | sed -e 's/|c[0-9A-Fa-f]\{8\}//g' -e 's/|r//g' -e 's/|T[^|]*|t//g' -e 's/## Title[[:space:]]*:[[:space:]]*\(.*\)/\1/' -e 's/[[:space:]]*$//' ) -fi -# Grab CurseForge ID and WoWI ID from the TOC file if not set by the script. -if [ -z "$slug" ]; then - slug=$( awk '/^## X-Curse-Project-ID:/ { print $NF; exit }' <<< "$toc_file" ) -fi -if [ -z "$addonid" ]; then - addonid=$( awk '/^## X-WoWI-ID:/ { print $NF; exit }' <<< "$toc_file" ) -fi -if [ -z "$wagoid" ]; then - wagoid=$( awk '/^## X-Wago-ID:/ { print $NF; exit }' <<< "$toc_file" ) -fi -unset toc_file - -# unset project ids if they are set to 0 -[ "$slug" = "0" ] && slug= -[ "$addonid" = "0" ] && addonid= -[ "$wagoid" = "0" ] && wagoid= - -# Automatic file type detection based on CurseForge rules -# 1) Untagged commits will be marked as an alpha. -# 2) Tagged commits will be marked as a release with the following exceptions: -# - If the tag contains the word "alpha", it will be marked as an alpha file. -# - If instead the tag contains the word "beta", it will be marked as a beta file. -if [ -n "$tag" ]; then - if [[ "${tag,,}" == *"alpha"* ]]; then - file_type="alpha" - elif [[ "${tag,,}" == *"beta"* ]]; then - file_type="beta" - else - file_type="release" - fi -else - file_type="alpha" -fi - -echo -echo "Packaging $package" -if [ -n "$project_version" ]; then - echo "Current version: $project_version" -fi -if [ -n "$previous_version" ]; then - echo "Previous version: $previous_version" -fi -( - [ "$game_type" = "retail" ] && retail="retail" || retail="non-retail version-${game_type}" - [ "$file_type" = "alpha" ] && alpha="alpha" || alpha="non-alpha" - echo "Build type: ${retail} ${alpha} non-debug${nolib:+ nolib}" - echo "Game version: ${game_version}" - echo -) -if [[ "$slug" =~ ^[0-9]+$ ]]; then - project_site="https://wow.curseforge.com" - echo "CurseForge ID: $slug${cf_token:+ [token set]}" -fi -if [ -n "$addonid" ]; then - echo "WoWInterface ID: $addonid${wowi_token:+ [token set]}" -fi -if [ -n "$wagoid" ]; then - echo "Wago ID: $wagoid${wago_token:+ [token set]}" -fi -if [ -n "$project_github_slug" ]; then - echo "GitHub: $project_github_slug${github_token:+ [token set]}" -fi -if [ -n "$project_site" ] || [ -n "$addonid" ] || [ -n "$wagoid" ] || [ -n "$project_github_slug" ]; then - echo -fi -echo "Checkout directory: $topdir" -echo "Release directory: $releasedir" -echo - -# Set $pkgdir to the path of the package directory inside $releasedir. -pkgdir="$releasedir/$package" -if [ -d "$pkgdir" ] && [ -z "$overwrite" ]; then - #echo "Removing previous package directory: $pkgdir" - rm -fr "$pkgdir" -fi -if [ ! -d "$pkgdir" ]; then - mkdir -p "$pkgdir" -fi - -# Set the contents of the addon zipfile. -contents="$package" - -### -### Create filters for pass-through processing of files to replace repository keywords. -### - -# Filter for simple repository keyword replacement. -vcs_filter() { - sed \ - -e "s/@project-revision@/$si_project_revision/g" \ - -e "s/@project-hash@/$si_project_hash/g" \ - -e "s/@project-abbreviated-hash@/$si_project_abbreviated_hash/g" \ - -e "s/@project-author@/$( escape_substr "$si_project_author" )/g" \ - -e "s/@project-date-iso@/$si_project_date_iso/g" \ - -e "s/@project-date-integer@/$si_project_date_integer/g" \ - -e "s/@project-timestamp@/$si_project_timestamp/g" \ - -e "s/@project-version@/$( escape_substr "$si_project_version" )/g" \ - -e "s/@file-revision@/$si_file_revision/g" \ - -e "s/@file-hash@/$si_file_hash/g" \ - -e "s/@file-abbreviated-hash@/$si_file_abbreviated_hash/g" \ - -e "s/@file-author@/$( escape_substr "$si_file_author" )/g" \ - -e "s/@file-date-iso@/$si_file_date_iso/g" \ - -e "s/@file-date-integer@/$si_file_date_integer/g" \ - -e "s/@file-timestamp@/$si_file_timestamp/g" -} - -# Find URL of localization api. -set_localization_url() { - localization_url= - if [ -n "$slug" ] && [ -n "$cf_token" ] && [ -n "$project_site" ]; then - localization_url="${project_site}/api/projects/$slug/localization/export" - fi - if [ -z "$localization_url" ] && find "$topdir" -path '*/.*' -prune -o -name "*.lua" -print0 | xargs -0 grep -q "@localization"; then - echo "Skipping localization! Missing CurseForge API token and/or project id is invalid." - echo - fi -} - -# Filter to handle @localization@ repository keyword replacement. -# https://authors.curseforge.com/knowledge-base/projects/531-localization-substitutions/ -declare -A unlocalized_values=( ["english"]="ShowPrimary" ["comment"]="ShowPrimaryAsComment" ["blank"]="ShowBlankAsComment" ["ignore"]="Ignore" ) -localization_filter() { - _ul_eof= - while [ -z "$_ul_eof" ]; do - IFS='' read -r _ul_line || _ul_eof="true" - # Strip any trailing CR character. - _ul_line=${_ul_line%$carriage_return} - case $_ul_line in - *@localization\(*\)@*) - _ul_lang= - _ul_namespace= - _ul_singlekey= - _ul_tablename="L" - # Get the prefix of the line before the comment. - _ul_prefix=${_ul_line%%@localization(*} - _ul_prefix=${_ul_prefix%%--*} - # Strip everything but the localization parameters. - _ul_params=${_ul_line#*@localization(} - _ul_params=${_ul_params%)@} - # Sanitize the params a bit. (namespaces are restricted to [a-zA-Z0-9_], separated by [./:]) - _ul_params=${_ul_params// /} - _ul_params=${_ul_params//,/, } - # Pull the locale language first (mainly for warnings). - _ul_lang="enUS" - if [[ $_ul_params == *"locale=\""* ]]; then - _ul_lang=${_ul_params##*locale=\"} - _ul_lang=${_ul_lang:0:4} - _ul_lang=${_ul_lang%%\"*} - else - echo " Warning! No locale set, using enUS." >&2 - fi - # Generate a URL parameter string from the localization parameters. - # https://authors.curseforge.com/knowledge-base/projects/529-api - _ul_url_params="" - set -- ${_ul_params} - for _ul_param; do - _ul_key=${_ul_param%%=*} - _ul_value=${_ul_param#*=} - _ul_value=${_ul_value%,*} - _ul_value=${_ul_value#*\"} - _ul_value=${_ul_value%\"*} - case ${_ul_key} in - escape-non-ascii) - if [ "$_ul_value" = "true" ]; then - _ul_url_params="${_ul_url_params}&escape-non-ascii-characters=true" - fi - ;; - format) - if [ "$_ul_value" = "lua_table" ]; then - _ul_url_params="${_ul_url_params}&export-type=Table" - fi - ;; - handle-unlocalized) - if [ "$_ul_value" != "english" ] && [ -n "${unlocalized_values[$_ul_value]}" ]; then - _ul_url_params="${_ul_url_params}&unlocalized=${unlocalized_values[$_ul_value]}" - fi - ;; - handle-subnamespaces) - if [ "$_ul_value" = "concat" ]; then # concat with / - _ul_url_params="${_ul_url_params}&concatenante-subnamespaces=true" - elif [ "$_ul_value" = "subtable" ]; then - echo " ($_ul_lang) Warning! ${_ul_key}=\"${_ul_value}\" is not supported. Include each full subnamespace, comma delimited." >&2 - fi - ;; - key) - # _ul_params was stripped of spaces, so reparse the line for the key - _ul_singlekey=${_ul_line#*@localization(} - _ul_singlekey=${_ul_singlekey#*key=\"} - _ul_singlekey=${_ul_singlekey%%\",*} - _ul_singlekey=${_ul_singlekey%%\")@*} - ;; - locale) - _ul_lang=$_ul_value - ;; - namespace) - # reparse to get all namespaces if multiple - _ul_namespace=${_ul_params##*namespace=\"} - _ul_namespace=${_ul_namespace%%\"*} - _ul_namespace=${_ul_namespace//, /,} - _ul_url_params="${_ul_url_params}&namespaces=${_ul_namespace}" - _ul_namespace="/${_ul_namespace}" - ;; - namespace-delimiter) - if [ "$_ul_value" != "/" ]; then - echo " ($_ul_lang) Warning! ${_ul_key}=\"${_ul_value}\" is not supported." >&2 - fi - ;; - prefix-values) - echo " ($_ul_lang) Warning! \"${_ul_key}\" is not supported." >&2 - ;; - same-key-is-true) - if [ "$_ul_value" = "true" ]; then - _ul_url_params="${_ul_url_params}&true-if-value-equals-key=true" - fi - ;; - table-name) - if [ "$_ul_value" != "L" ]; then - _ul_tablename="$_ul_value" - _ul_url_params="${_ul_url_params}&table-name=${_ul_value}" - fi - ;; - esac - done - - if [ -z "$_cdt_localization" ] || [ -z "$localization_url" ]; then - echo " Skipping localization (${_ul_lang}${_ul_namespace})" >&2 - - # If the line isn't a TOC entry, print anything before the keyword. - if [[ $_ul_line != "## "* ]]; then - if [ -n "$_ul_eof" ]; then - echo -n "$_ul_prefix" - else - echo "$_ul_prefix" - fi - fi - else - _ul_url="${localization_url}?lang=${_ul_lang}${_ul_url_params}" - echo " Adding ${_ul_lang}${_ul_namespace}" >&2 - - if [ -z "$_ul_singlekey" ]; then - # Write text that preceded the substitution. - echo -n "$_ul_prefix" - - # Fetch the localization data, but don't output anything if there is an error. - curl -s -H "x-api-token: $cf_token" "${_ul_url}" | awk -v url="$_ul_url" '/^{"error/ { o=" Error! "$0"\n "url; print o >"/dev/stderr"; exit 1 } /"/dev/stderr"; exit 1 } /^'"$_ul_tablename"' = '"$_ul_tablename"' or \{\}/ { next } { print }' - - # Insert a trailing blank line to match CF packager. - if [ -z "$_ul_eof" ]; then - echo "" - fi - else - # Parse out a single phrase. This is kind of expensive, but caching would be way too much effort to optimize for what is basically an edge case. - _ul_value=$( curl -s -H "x-api-token: $cf_token" "${_ul_url}" | awk -v url="$_ul_url" '/^{"error/ { o=" Error! "$0"\n "url; print o >"/dev/stderr"; exit 1 } /"/dev/stderr"; exit 1 } { print }' | sed -n '/L\["'"$_ul_singlekey"'"\]/p' | sed 's/^.* = "\(.*\)"/\1/' ) - if [ -n "$_ul_value" ] && [ "$_ul_value" != "$_ul_singlekey" ]; then - # The result is different from the base value so print out the line. - echo "${_ul_prefix}${_ul_value}${_ul_line##*)@}" - fi - fi - fi - ;; - *) - if [ -n "$_ul_eof" ]; then - echo -n "$_ul_line" - else - echo "$_ul_line" - fi - esac - done -} - -lua_filter() { - local level - case $1 in - alpha) level="=" ;; - debug) level="==" ;; - retail|version-*) level="====" ;; - *) level="===" - esac - sed \ - -e "s/--@$1@/--[${level}[@$1@/g" \ - -e "s/--@end-$1@/--@end-$1@]${level}]/g" \ - -e "s/--\[===\[@non-$1@/--@non-$1@/g" \ - -e "s/--@end-non-$1@\]===\]/--@end-non-$1@/g" -} - -toc_interface_filter() { - # Always remove BOM so ^ works - if [ "$root_toc_version" != "$toc_version" ]; then - # toc version isn't what is set in the toc file - if [ -n "$root_toc_version" ]; then # rewrite - sed -e $'1s/^\xEF\xBB\xBF//' -e 's/^## Interface:.*$/## Interface: '"$toc_version"'/' -e '/^## Interface-/d' - else # add - sed -e $'1s/^\xEF\xBB\xBF//' -e '1i\ -## Interface: '"$toc_version" -e '/^## Interface-/d' - fi - else # cleanup - sed -e $'1s/^\xEF\xBB\xBF//' -e '/^## Interface-/d' - fi -} - -xml_filter() { - sed \ - -e "s///@end-$1@-->/g" \ - -e "s//g" \ - -e "s/@end-non-$1@-->//g" -} - -do_not_package_filter() { - case $1 in - lua) sed '/--@do-not-package@/,/--@end-do-not-package@/d' ;; - toc) sed '/#@do-not-package@/,/#@end-do-not-package@/d' ;; - xml) sed '//,//d' ;; - esac -} - -line_ending_filter() { - local _lef_eof _lef_line - while [ -z "$_lef_eof" ]; do - IFS='' read -r _lef_line || _lef_eof="true" - # Strip any trailing CR character. - _lef_line=${_lef_line%$carriage_return} - if [ -n "$_lef_eof" ]; then - # Preserve EOF not preceded by newlines. - echo -n "$_lef_line" - else - case $line_ending in - dos) printf "%s\r\n" "$_lef_line" ;; # Terminate lines with CR LF. - unix) printf "%s\n" "$_lef_line" ;; # Terminate lines with LF. - esac - fi - done -} - -### -### Copy files from the working directory into the package directory. -### - -# Copy of the contents of the source directory into the destination directory. -# Dotfiles and any files matching the ignore pattern are skipped. Copied files -# are subject to repository keyword replacement. -# -copy_directory_tree() { - _cdt_alpha= - _cdt_debug= - _cdt_ignored_patterns= - _cdt_localization= - _cdt_nolib= - _cdt_do_not_package= - _cdt_unchanged_patterns= - _cdt_classic= - _cdt_external= - OPTIND=1 - while getopts :adi:lnpu:c:e _cdt_opt "$@"; do - # shellcheck disable=2220 - case $_cdt_opt in - a) _cdt_alpha="true" ;; - d) _cdt_debug="true" ;; - i) _cdt_ignored_patterns=$OPTARG ;; - l) _cdt_localization="true" - set_localization_url - ;; - n) _cdt_nolib="true" ;; - p) _cdt_do_not_package="true" ;; - u) _cdt_unchanged_patterns=$OPTARG ;; - c) _cdt_classic=$OPTARG ;; - e) _cdt_external="true" ;; - esac - done - shift $((OPTIND - 1)) - _cdt_srcdir=$1 - _cdt_destdir=$2 - - if [ -z "$_cdt_external" ]; then - start_group "Copying files into ${_cdt_destdir#$topdir/}:" "copy" - else # don't nest groups - echo "Copying files into ${_cdt_destdir#$topdir/}:" - fi - if [ ! -d "$_cdt_destdir" ]; then - mkdir -p "$_cdt_destdir" - fi - # Create a "find" command to list all of the files in the current directory, minus any ones we need to prune. - _cdt_find_cmd="find ." - # Prune everything that begins with a dot except for the current directory ".". - _cdt_find_cmd+=" \( -name \".*\" -a \! -name \".\" \) -prune" - # Prune the destination directory if it is a subdirectory of the source directory. - _cdt_dest_subdir=${_cdt_destdir#${_cdt_srcdir}/} - case $_cdt_dest_subdir in - /*) ;; - *) _cdt_find_cmd+=" -o -path \"./$_cdt_dest_subdir\" -prune" ;; - esac - # Print the filename, but suppress the current directory ".". - _cdt_find_cmd+=" -o \! -name \".\" -print" - ( cd "$_cdt_srcdir" && eval "$_cdt_find_cmd" ) | while read -r file; do - file=${file#./} - if [ -f "$_cdt_srcdir/$file" ]; then - # Check if the file should be ignored. - skip_copy= - # Prefix external files with the relative pkgdir path - _cdt_check_file=$file - if [ -n "${_cdt_destdir#$pkgdir}" ]; then - _cdt_check_file="${_cdt_destdir#$pkgdir/}/$file" - fi - # Skip files matching the colon-separated "ignored" shell wildcard patterns. - if [ -z "$skip_copy" ] && match_pattern "$_cdt_check_file" "$_cdt_ignored_patterns"; then - skip_copy="true" - fi - # Never skip files that match the colon-separated "unchanged" shell wildcard patterns. - unchanged= - if [ -n "$skip_copy" ] && match_pattern "$file" "$_cdt_unchanged_patterns"; then - skip_copy= - unchanged="true" - fi - # Copy unskipped files into $_cdt_destdir. - if [ -n "$skip_copy" ]; then - echo " Ignoring: $file" - else - dir=${file%/*} - if [ "$dir" != "$file" ]; then - mkdir -p "$_cdt_destdir/$dir" - fi - # Check if the file matches a pattern for keyword replacement. - if [ -n "$unchanged" ] || ! match_pattern "$file" "*.lua:*.md:*.toc:*.txt:*.xml"; then - echo " Copying: $file (unchanged)" - cp "$_cdt_srcdir/$file" "$_cdt_destdir/$dir" - else - # Set the filters for replacement based on file extension. - _cdt_filters="vcs_filter" - case $file in - *.lua) - [ -n "$_cdt_do_not_package" ] && _cdt_filters+="|do_not_package_filter lua" - [ -n "$_cdt_alpha" ] && _cdt_filters+="|lua_filter alpha" - [ -n "$_cdt_debug" ] && _cdt_filters+="|lua_filter debug" - if [ -n "$_cdt_classic" ]; then - _cdt_filters+="|lua_filter retail" - _cdt_filters+="|lua_filter version-retail" - [ "$_cdt_classic" = "classic" ] && _cdt_filters+="|lua_filter version-bcc" - [ "$_cdt_classic" = "bcc" ] && _cdt_filters+="|lua_filter version-classic" - else - _cdt_filters+="|lua_filter version-classic" - _cdt_filters+="|lua_filter version-bcc" - fi - [ -n "$_cdt_localization" ] && _cdt_filters+="|localization_filter" - ;; - *.xml) - [ -n "$_cdt_do_not_package" ] && _cdt_filters+="|do_not_package_filter xml" - [ -n "$_cdt_nolib" ] && _cdt_filters+="|xml_filter no-lib-strip" - [ -n "$_cdt_alpha" ] && _cdt_filters+="|xml_filter alpha" - [ -n "$_cdt_debug" ] && _cdt_filters+="|xml_filter debug" - if [ -n "$_cdt_classic" ]; then - _cdt_filters+="|xml_filter retail" - _cdt_filters+="|xml_filter version-retail" - [ "$_cdt_classic" = "classic" ] && _cdt_filters+="|xml_filter version-bcc" - [ "$_cdt_classic" = "bcc" ] && _cdt_filters+="|xml_filter version-classic" - else - _cdt_filters+="|xml_filter version-classic" - _cdt_filters+="|xml_filter version-bcc" - fi - ;; - *.toc) - _cdt_filters+="|do_not_package_filter toc" - [ -n "$_cdt_nolib" ] && _cdt_filters+="|toc_filter no-lib-strip true" # leave the tokens in the file normally - _cdt_filters+="|toc_filter alpha ${_cdt_alpha}" - _cdt_filters+="|toc_filter debug ${_cdt_debug}" - _cdt_filters+="|toc_filter retail ${_cdt_classic:+true}" - _cdt_filters+="|toc_filter version-retail ${_cdt_classic:+true}" - _cdt_filters+="|toc_filter version-classic $([[ -z "$_cdt_classic" || "$_cdt_classic" == "bcc" ]] && echo "true")" - _cdt_filters+="|toc_filter version-bcc $([[ -z "$_cdt_classic" || "$_cdt_classic" == "classic" ]] && echo "true")" - [[ -z "$_cdt_external" && ! $file =~ -(Mainline|Classic|BCC).toc$ ]] && _cdt_filters+="|toc_interface_filter" - [ -n "$_cdt_localization" ] && _cdt_filters+="|localization_filter" - ;; - esac - - # Set the filter for normalizing line endings. - _cdt_filters+="|line_ending_filter" - - # Set version control values for the file. - set_info_file "$_cdt_srcdir/$file" - - echo " Copying: $file" - eval < "$_cdt_srcdir/$file" "$_cdt_filters" > "$_cdt_destdir/$file" - fi - fi - fi - done - if [ -z "$_external_dir" ]; then - end_group "copy" - fi -} - -if [ -z "$skip_copying" ]; then - cdt_args="-dp" - [ "$file_type" != "alpha" ] && cdt_args+="a" - [ -z "$skip_localization" ] && cdt_args+="l" - [ -n "$nolib" ] && cdt_args+="n" - [ "$game_type" != "retail" ] && cdt_args+=" -c $game_type" - [ -n "$ignore" ] && cdt_args+=" -i \"$ignore\"" - [ -n "$changelog" ] && cdt_args+=" -u \"$changelog\"" - eval copy_directory_tree "$cdt_args" "\"$topdir\"" "\"$pkgdir\"" -fi - -# Reset ignore and parse pkgmeta ignores again to handle ignoring external paths -ignore= -parse_ignore "$pkgmeta_file" - -### -### Process .pkgmeta again to perform any pre-move-folders actions. -### - -retry() { - local result=0 - local count=1 - while [[ "$count" -le 3 ]]; do - [[ "$result" -ne 0 ]] && { - echo -e "\033[01;31mRetrying (${count}/3)\033[0m" >&2 - } - "$@" && { result=0 && break; } || result="$?" - count="$((count + 1))" - sleep 3 - done - return "$result" -} - -# Checkout the external into a ".checkout" subdirectory of the final directory. -checkout_external() { - _external_dir=$1 - _external_uri=$2 - _external_tag=$3 - _external_type=$4 - # shellcheck disable=2034 - _external_slug=$5 # unused until we can easily fetch the project id - _external_checkout_type=$6 - - _cqe_checkout_dir="$pkgdir/$_external_dir/.checkout" - mkdir -p "$_cqe_checkout_dir" - if [ "$_external_type" = "git" ]; then - if [ -z "$_external_tag" ]; then - echo "Fetching latest version of external $_external_uri" - retry git clone -q --depth 1 "$_external_uri" "$_cqe_checkout_dir" || return 1 - elif [ "$_external_tag" != "latest" ]; then - echo "Fetching $_external_checkout_type \"$_external_tag\" from external $_external_uri" - if [ "$_external_checkout_type" = "commit" ]; then - retry git clone -q "$_external_uri" "$_cqe_checkout_dir" || return 1 - git -C "$_cqe_checkout_dir" checkout -q "$_external_tag" || return 1 - else - git -c advice.detachedHead=false clone -q --depth 1 --branch "$_external_tag" "$_external_uri" "$_cqe_checkout_dir" || return 1 - fi - else # [ "$_external_tag" = "latest" ]; then - retry git clone -q --depth 50 "$_external_uri" "$_cqe_checkout_dir" || return 1 - _external_tag=$( git -C "$_cqe_checkout_dir" for-each-ref refs/tags --sort=-creatordate --format=%\(refname:short\) --count=1 ) - if [ -n "$_external_tag" ]; then - echo "Fetching tag \"$_external_tag\" from external $_external_uri" - git -C "$_cqe_checkout_dir" checkout -q "$_external_tag" || return 1 - else - echo "Fetching latest version of external $_external_uri" - fi - fi - - # pull submodules - git -C "$_cqe_checkout_dir" submodule -q update --init --recursive || return 1 - - set_info_git "$_cqe_checkout_dir" - echo "Checked out $( git -C "$_cqe_checkout_dir" describe --always --tags --abbrev=7 --long )" #$si_project_abbreviated_hash - elif [ "$_external_type" = "svn" ]; then - if [[ $external_uri == *"/trunk" ]]; then - _cqe_svn_trunk_url=$_external_uri - _cqe_svn_subdir= - else - _cqe_svn_trunk_url="${_external_uri%/trunk/*}/trunk" - _cqe_svn_subdir=${_external_uri#${_cqe_svn_trunk_url}/} - fi - - if [ -z "$_external_tag" ]; then - echo "Fetching latest version of external $_external_uri" - retry svn checkout -q "$_external_uri" "$_cqe_checkout_dir" || return 1 - else - _cqe_svn_tag_url="${_cqe_svn_trunk_url%/trunk}/tags" - if [ "$_external_tag" = "latest" ]; then - _external_tag=$( svn log --verbose --limit 1 "$_cqe_svn_tag_url" 2>/dev/null | awk '/^ A \/tags\// { print $2; exit }' | awk -F/ '{ print $3 }' ) - if [ -z "$_external_tag" ]; then - _external_tag="latest" - fi - fi - if [ "$_external_tag" = "latest" ]; then - echo "No tags found in $_cqe_svn_tag_url" - echo "Fetching latest version of external $_external_uri" - retry svn checkout -q "$_external_uri" "$_cqe_checkout_dir" || return 1 - else - _cqe_external_uri="${_cqe_svn_tag_url}/$_external_tag" - if [ -n "$_cqe_svn_subdir" ]; then - _cqe_external_uri="${_cqe_external_uri}/$_cqe_svn_subdir" - fi - echo "Fetching tag \"$_external_tag\" from external $_cqe_external_uri" - retry svn checkout -q "$_cqe_external_uri" "$_cqe_checkout_dir" || return 1 - fi - fi - set_info_svn "$_cqe_checkout_dir" - echo "Checked out r$si_project_revision" - elif [ "$_external_type" = "hg" ]; then - if [ -z "$_external_tag" ]; then - echo "Fetching latest version of external $_external_uri" - retry hg clone -q "$_external_uri" "$_cqe_checkout_dir" || return 1 - elif [ "$_external_tag" != "latest" ]; then - echo "Fetching $_external_checkout_type \"$_external_tag\" from external $_external_uri" - retry hg clone -q --updaterev "$_external_tag" "$_external_uri" "$_cqe_checkout_dir" || return 1 - else # [ "$_external_tag" = "latest" ]; then - retry hg clone -q "$_external_uri" "$_cqe_checkout_dir" || return 1 - _external_tag=$( hg --cwd "$_cqe_checkout_dir" log -r . --template '{latesttag}' ) - if [ -n "$_external_tag" ]; then - echo "Fetching tag \"$_external_tag\" from external $_external_uri" - hg --cwd "$_cqe_checkout_dir" update -q "$_external_tag" - else - echo "Fetching latest version of external $_external_uri" - fi - fi - set_info_hg "$_cqe_checkout_dir" - echo "Checked out r$si_project_revision" - else - echo "Unknown external: $_external_uri" >&2 - return 1 - fi - # Copy the checkout into the proper external directory. - ( - cd "$_cqe_checkout_dir" || return 1 - # Set the slug for external localization, if needed. - # Note: We don't actually do localization since we need the project id and - # the only way to convert slug->id would be to scrape the project page :\ - slug= #$_external_slug - project_site= - if [[ "$_external_uri" == *"wowace.com"* || "$_external_uri" == *"curseforge.com"* ]]; then - project_site="https://wow.curseforge.com" - fi - # If a .pkgmeta file is present, process it for an "ignore" list. - parse_ignore "$_cqe_checkout_dir/.pkgmeta" "$_external_dir" - copy_directory_tree -dnpe -i "$ignore" "$_cqe_checkout_dir" "$pkgdir/$_external_dir" - ) - # Remove the ".checkout" subdirectory containing the full checkout. - if [ -d "$_cqe_checkout_dir" ]; then - rm -fr "$_cqe_checkout_dir" - fi -} - -external_pids=() - -external_dir= -external_uri= -external_tag= -external_type= -external_slug= -external_checkout_type= -process_external() { - if [ -n "$external_dir" ] && [ -n "$external_uri" ] && [ -z "$skip_externals" ]; then - # convert old curse repo urls - case $external_uri in - *git.curseforge.com*|*git.wowace.com*) - external_type="git" - # git://git.curseforge.com/wow/$slug/mainline.git -> https://repos.curseforge.com/wow/$slug - external_uri=${external_uri%/mainline.git} - external_uri="https://repos${external_uri#*://git}" - ;; - *svn.curseforge.com*|*svn.wowace.com*) - external_type="svn" - # svn://svn.curseforge.com/wow/$slug/mainline/trunk -> https://repos.curseforge.com/wow/$slug/trunk - external_uri=${external_uri/\/mainline/} - external_uri="https://repos${external_uri#*://svn}" - ;; - *hg.curseforge.com*|*hg.wowace.com*) - external_type="hg" - # http://hg.curseforge.com/wow/$slug/mainline -> https://repos.curseforge.com/wow/$slug - external_uri=${external_uri%/mainline} - external_uri="https://repos${external_uri#*://hg}" - ;; - svn:*) - # just in case - external_type="svn" - ;; - *) - if [ -z "$external_type" ]; then - external_type="git" - fi - ;; - esac - - if [[ $external_uri == "https://repos.curseforge.com/wow/"* || $external_uri == "https://repos.wowace.com/wow/"* ]]; then - if [ -z "$external_slug" ]; then - external_slug=${external_uri#*/wow/} - external_slug=${external_slug%%/*} - fi - - # check if the repo is svn - _svn_path=${external_uri#*/wow/$external_slug/} - if [[ "$_svn_path" == "trunk"* ]]; then - external_type="svn" - elif [[ "$_svn_path" == "tags/"* ]]; then - external_type="svn" - # change the tag path into the trunk path and use the tag var so it gets logged as a tag - external_tag=${_svn_path#tags/} - external_tag=${external_tag%%/*} - external_uri="${external_uri%/tags*}/trunk${_svn_path#tags/$external_tag}" - fi - fi - - if [ -n "$external_slug" ]; then - relations["$external_slug"]="embeddedLibrary" - fi - - echo "Fetching external: $external_dir" - checkout_external "$external_dir" "$external_uri" "$external_tag" "$external_type" "$external_slug" "$external_checkout_type" &> "$releasedir/.$BASHPID.externalout" & - external_pids+=($!) - fi - external_dir= - external_uri= - external_tag= - external_type= - external_slug= - external_checkout_type= -} - -# Don't leave extra files around if exited early -kill_externals() { - rm -f "$releasedir"/.*.externalout - kill 0 -} -trap kill_externals INT - -if [ -z "$skip_externals" ] && [ -f "$pkgmeta_file" ]; then - yaml_eof= - while [ -z "$yaml_eof" ]; do - IFS='' read -r yaml_line || yaml_eof="true" - # Skip commented out lines. - if [[ $yaml_line =~ ^[[:space:]]*\# ]]; then - continue - fi - # Strip any trailing CR character. - yaml_line=${yaml_line%$carriage_return} - - case $yaml_line in - [!\ ]*:*) - # Started a new section, so checkout any queued externals. - process_external - # Split $yaml_line into a $yaml_key, $yaml_value pair. - yaml_keyvalue "$yaml_line" - # Set the $pkgmeta_phase for stateful processing. - pkgmeta_phase=$yaml_key - ;; - " "*) - yaml_line=${yaml_line#"${yaml_line%%[! ]*}"} # trim leading whitespace - case $yaml_line in - "- "*) - ;; - *:*) - # Split $yaml_line into a $yaml_key, $yaml_value pair. - yaml_keyvalue "$yaml_line" - case $pkgmeta_phase in - externals) - case $yaml_key in - url) external_uri=$yaml_value ;; - tag) - external_tag=$yaml_value - external_checkout_type=$yaml_key - ;; - branch) - external_tag=$yaml_value - external_checkout_type=$yaml_key - ;; - commit) - external_tag=$yaml_value - external_checkout_type=$yaml_key - ;; - type) external_type=$yaml_value ;; - curse-slug) external_slug=$yaml_value ;; - *) - # Started a new external, so checkout any queued externals. - process_external - - external_dir=$yaml_key - nolib_exclude="$nolib_exclude $pkgdir/$external_dir/*" - if [ -n "$yaml_value" ]; then - external_uri=$yaml_value - # Immediately checkout this fully-specified external. - process_external - fi - ;; - esac - ;; - esac - ;; - esac - ;; - esac - done < "$pkgmeta_file" - # Reached end of file, so checkout any remaining queued externals. - process_external - - if [ ${#external_pids[*]} -gt 0 ]; then - echo - echo "Waiting for externals to finish..." - echo - - while [ ${#external_pids[*]} -gt 0 ]; do - wait -n - for i in ${!external_pids[*]}; do - pid=${external_pids[i]} - if ! kill -0 $pid 2>/dev/null; then - _external_output="$releasedir/.$pid.externalout" - if ! wait $pid; then - _external_error=1 - # wrap each line with a bright red color code - awk '{ printf "\033[01;31m%s\033[0m\n", $0 }' "$_external_output" - echo - else - start_group "$( head -n1 "$_external_output" )" "external.$pid" - tail -n+2 "$_external_output" - end_group "external.$pid" - fi - rm -f "$_external_output" 2>/dev/null - unset 'external_pids[i]' - fi - done - done - - if [ -n "$_external_error" ]; then - echo - echo "There was an error fetching externals :(" >&2 - exit 1 - fi - fi -fi - -# Restore the signal handlers -trap - INT - -### -### Create the changelog of commits since the previous release tag. -### - -if [ -z "$project" ]; then - project="$package" -fi - -# Create a changelog in the package directory if the source directory does -# not contain a manual changelog. -if [ -n "$manual_changelog" ] && [ -f "$topdir/$changelog" ]; then - start_group "Using manual changelog at $changelog" "changelog" - head -n7 "$topdir/$changelog" - [ "$( wc -l < "$topdir/$changelog" )" -gt 7 ] && echo "..." - end_group "changelog" - - # Convert Markdown to BBCode (with HTML as an intermediary) for sending to WoWInterface - # Requires pandoc (http://pandoc.org/) - if [ "$changelog_markup" = "markdown" ] && [ -n "$wowi_convert_changelog" ] && hash pandoc &>/dev/null; then - wowi_changelog="$releasedir/WOWI-$project_version-CHANGELOG.txt" - pandoc -f commonmark -t html "$topdir/$changelog" | sed \ - -e 's/<\(\/\)\?\(b\|i\|u\)>/[\1\2]/g' \ - -e 's/<\(\/\)\?em>/[\1i]/g' \ - -e 's/<\(\/\)\?strong>/[\1b]/g' \ - -e 's/]*>/[list]/g' -e 's/]*>/[list="1"]/g' \ - -e 's/<\/[ou]l>/[\/list]\n/g' \ - -e 's/
  • /[*]/g' -e 's/

  • /[*]/g' -e 's/<\/p><\/li>//g' -e 's/<\/li>//g' \ - -e 's/\[\*\]\[ \] /[*]☐ /g' -e 's/\[\*\]\[[xX]\] /[*]☒ /g' \ - -e 's/]*>/[size="6"]/g' -e 's/]*>/[size="5"]/g' -e 's/]*>/[size="4"]/g' \ - -e 's/]*>/[size="3"]/g' -e 's/]*>/[size="3"]/g' -e 's/]*>/[size="3"]/g' \ - -e 's/<\/h[1-6]>/[\/size]\n/g' \ - -e 's/
    /[quote]/g' -e 's/<\/blockquote>/[\/quote]\n/g' \ - -e 's/
    ]*>
    /[highlight="lua"]/g' -e 's/<\/code><\/pre><\/div>/[\/highlight]\n/g' \
    -			-e 's/
    /[code]/g' -e 's/<\/code><\/pre>/[\/code]\n/g' \
    -			-e 's//[font="monospace"]/g' -e 's/<\/code>/[\/font]/g' \
    -			-e 's/]*>/[url="\1"]/g' -e 's/<\/a>/\[\/url]/g' \
    -			-e 's/]*>/[img]\1[\/img]/g' \
    -			-e 's/
    /_____________________________________________________________________________\n/g' \ - -e 's/<\/p>/\n/g' \ - -e '/^<[^>]\+>$/d' -e 's/<[^>]\+>//g' \ - -e 's/"/"/g' \ - -e 's/&/&/g' \ - -e 's/<//g' \ - -e "s/'/'/g" \ - | line_ending_filter > "$wowi_changelog" - fi -else - if [ -n "$manual_changelog" ]; then - echo "Warning! Could not find a manual changelog at $topdir/$changelog" - manual_changelog= - fi - changelog="CHANGELOG.md" - changelog_markup="markdown" - - if [ -n "$wowi_gen_changelog" ] && [ -z "$wowi_convert_changelog" ]; then - wowi_markup="markdown" - fi - - start_group "Generating changelog of commits into $changelog" "changelog" - - _changelog_range= - if [ "$repository_type" = "git" ]; then - changelog_url= - changelog_version= - changelog_previous="[Previous Releases](${project_github_url}/releases)" - changelog_url_wowi= - changelog_version_wowi= - changelog_previous_wowi="[url=${project_github_url}/releases]Previous Releases[/url]" - if [ -z "$previous_version" ] && [ -z "$tag" ]; then - # no range, show all commits up to ours - changelog_url="[Full Changelog](${project_github_url}/commits/${project_hash})" - changelog_version="[${project_version}](${project_github_url}/tree/${project_hash})" - changelog_url_wowi="[url=${project_github_url}/commits/${project_hash}]Full Changelog[/url]" - changelog_version_wowi="[url=${project_github_url}/tree/${project_hash}]${project_version}[/url]" - _changelog_range="$project_hash" - elif [ -z "$previous_version" ] && [ -n "$tag" ]; then - # first tag, show all commits upto it - changelog_url="[Full Changelog](${project_github_url}/commits/${tag})" - changelog_version="[${project_version}](${project_github_url}/tree/${tag})" - changelog_url_wowi="[url=${project_github_url}/commits/${tag}]Full Changelog[/url]" - changelog_version_wowi="[url=${project_github_url}/tree/${tag}]${project_version}[/url]" - _changelog_range="$tag" - elif [ -n "$previous_version" ] && [ -z "$tag" ]; then - # compare between last tag and our commit - changelog_url="[Full Changelog](${project_github_url}/compare/${previous_version}...${project_hash})" - changelog_version="[$project_version](${project_github_url}/tree/${project_hash})" - changelog_url_wowi="[url=${project_github_url}/compare/${previous_version}...${project_hash}]Full Changelog[/url]" - changelog_version_wowi="[url=${project_github_url}/tree/${project_hash}]${project_version}[/url]" - _changelog_range="$previous_version..$project_hash" - elif [ -n "$previous_version" ] && [ -n "$tag" ]; then - # compare between last tag and our tag - changelog_url="[Full Changelog](${project_github_url}/compare/${previous_version}...${tag})" - changelog_version="[$project_version](${project_github_url}/tree/${tag})" - changelog_url_wowi="[url=${project_github_url}/compare/${previous_version}...${tag}]Full Changelog[/url]" - changelog_version_wowi="[url=${project_github_url}/tree/${tag}]${project_version}[/url]" - _changelog_range="$previous_version..$tag" - fi - # lazy way out - if [ -z "$project_github_url" ]; then - changelog_url= - changelog_version=$project_version - changelog_previous= - changelog_url_wowi= - changelog_version_wowi="[color=orange]${project_version}[/color]" - changelog_previous_wowi= - elif [ -z "$github_token" ]; then - # not creating releases :( - changelog_previous= - changelog_previous_wowi= - fi - changelog_date=$( TZ='' printf "%(%Y-%m-%d)T" "$project_timestamp" ) - - cat <<- EOF | line_ending_filter > "$pkgdir/$changelog" - # $project - - ## $changelog_version ($changelog_date) - $changelog_url $changelog_previous - - EOF - git -C "$topdir" log "$_changelog_range" --pretty=format:"###%B" \ - | sed -e 's/^/ /g' -e 's/^ *$//g' -e 's/^ ###/- /g' -e 's/$/ /' \ - -e 's/\([a-zA-Z0-9]\)_\([a-zA-Z0-9]\)/\1\\_\2/g' \ - -e 's/\[ci skip\]//g' -e 's/\[skip ci\]//g' \ - -e '/git-svn-id:/d' -e '/^[[:space:]]*This reverts commit [0-9a-f]\{40\}\.[[:space:]]*$/d' \ - -e '/^[[:space:]]*$/d' \ - | line_ending_filter >> "$pkgdir/$changelog" - - # WoWI uses BBCode, generate something usable to post to the site - # the file is deleted on successful upload - if [ -n "$addonid" ] && [ -n "$tag" ] && [ -n "$wowi_gen_changelog" ] && [ "$wowi_markup" = "bbcode" ]; then - wowi_changelog="$releasedir/WOWI-$project_version-CHANGELOG.txt" - cat <<- EOF | line_ending_filter > "$wowi_changelog" - [size=5]${project}[/size] - [size=4]${changelog_version_wowi} (${changelog_date})[/size] - ${changelog_url_wowi} ${changelog_previous_wowi} - [list] - EOF - git -C "$topdir" log "$_changelog_range" --pretty=format:"###%B" \ - | sed -e 's/^/ /g' -e 's/^ *$//g' -e 's/^ ###/[*]/g' \ - -e 's/\[ci skip\]//g' -e 's/\[skip ci\]//g' \ - -e '/git-svn-id:/d' -e '/^[[:space:]]*This reverts commit [0-9a-f]\{40\}\.[[:space:]]*$/d' \ - -e '/^[[:space:]]*$/d' \ - | line_ending_filter >> "$wowi_changelog" - echo "[/list]" | line_ending_filter >> "$wowi_changelog" - fi - - elif [ "$repository_type" = "svn" ]; then - if [ -n "$previous_revision" ]; then - _changelog_range="-r$project_revision:$previous_revision" - else - _changelog_range="-rHEAD:1" - fi - changelog_date=$( TZ='' printf "%(%Y-%m-%d)T" "$project_timestamp" ) - - cat <<- EOF | line_ending_filter > "$pkgdir/$changelog" - # $project - - ## $project_version ($changelog_date) - - EOF - svn log "$topdir" "$_changelog_range" --xml \ - | awk '//,/<\/msg>/' \ - | sed -e 's//###/g' -e 's/<\/msg>//g' \ - -e 's/^/ /g' -e 's/^ *$//g' -e 's/^ ###/- /g' -e 's/$/ /' \ - -e 's/\([a-zA-Z0-9]\)_\([a-zA-Z0-9]\)/\1\\_\2/g' \ - -e 's/\[ci skip\]//g' -e 's/\[skip ci\]//g' \ - -e '/^[[:space:]]*$/d' \ - | line_ending_filter >> "$pkgdir/$changelog" - - # WoWI uses BBCode, generate something usable to post to the site - # the file is deleted on successful upload - if [ -n "$addonid" ] && [ -n "$tag" ] && [ -n "$wowi_gen_changelog" ] && [ "$wowi_markup" = "bbcode" ]; then - wowi_changelog="$releasedir/WOWI-$project_version-CHANGELOG.txt" - cat <<- EOF | line_ending_filter > "$wowi_changelog" - [size=5]${project}[/size] - [size=4][color=orange]${project_version}[/color] (${changelog_date})[/size] - - [list] - EOF - svn log "$topdir" "$_changelog_range" --xml \ - | awk '//,/<\/msg>/' \ - | sed -e 's//###/g' -e 's/<\/msg>//g' \ - -e 's/^/ /g' -e 's/^ *$//g' -e 's/^ ###/[*]/g' \ - -e 's/\[ci skip\]//g' -e 's/\[skip ci\]//g' \ - -e '/^[[:space:]]*$/d' \ - | line_ending_filter >> "$wowi_changelog" - echo "[/list]" | line_ending_filter >> "$wowi_changelog" - fi - - elif [ "$repository_type" = "hg" ]; then - if [ -n "$previous_revision" ]; then - _changelog_range="::$project_revision - ::$previous_revision - filelog(.hgtags)" - else - _changelog_range="." - fi - changelog_date=$( TZ='' printf "%(%Y-%m-%d)T" "$project_timestamp" ) - - cat <<- EOF | line_ending_filter > "$pkgdir/$changelog" - # $project - - ## $project_version ($changelog_date) - - EOF - hg --cwd "$topdir" log -r "$_changelog_range" --template '- {fill(desc|strip, 76, "", " ")}\n' | line_ending_filter >> "$pkgdir/$changelog" - - # WoWI uses BBCode, generate something usable to post to the site - # the file is deleted on successful upload - if [ -n "$addonid" ] && [ -n "$tag" ] && [ -n "$wowi_gen_changelog" ] && [ "$wowi_markup" = "bbcode" ]; then - wowi_changelog="$releasedir/WOWI-$project_version-CHANGELOG.txt" - cat <<- EOF | line_ending_filter > "$wowi_changelog" - [size=5]${project}[/size] - [size=4][color=orange]${project_version}[/color] (${changelog_date})[/size] - - [list] - EOF - hg --cwd "$topdir" log "$_changelog_range" --template '[*]{desc|strip|escape}\n' | line_ending_filter >> "$wowi_changelog" - echo "[/list]" | line_ending_filter >> "$wowi_changelog" - fi - fi - - echo "$(<"$pkgdir/$changelog")" - end_group "changelog" -fi - -### -### Process .pkgmeta to perform move-folders actions. -### - -if [ -f "$pkgmeta_file" ]; then - yaml_eof= - while [ -z "$yaml_eof" ]; do - IFS='' read -r yaml_line || yaml_eof="true" - # Skip commented out lines. - if [[ $yaml_line =~ ^[[:space:]]*\# ]]; then - continue - fi - # Strip any trailing CR character. - yaml_line=${yaml_line%$carriage_return} - - case $yaml_line in - [!\ ]*:*) - # Split $yaml_line into a $yaml_key, $yaml_value pair. - yaml_keyvalue "$yaml_line" - # Set the $pkgmeta_phase for stateful processing. - pkgmeta_phase=$yaml_key - ;; - " "*) - yaml_line=${yaml_line#"${yaml_line%%[! ]*}"} # trim leading whitespace - case $yaml_line in - "- "*) - ;; - *:*) - # Split $yaml_line into a $yaml_key, $yaml_value pair. - yaml_keyvalue "$yaml_line" - case $pkgmeta_phase in - move-folders) - srcdir="$releasedir/$yaml_key" - destdir="$releasedir/$yaml_value" - if [[ -d "$destdir" && -z "$overwrite" && "$srcdir" != "$destdir/"* ]]; then - rm -fr "$destdir" - fi - if [ -d "$srcdir" ]; then - if [ ! -d "$destdir" ]; then - mkdir -p "$destdir" - fi - echo "Moving $yaml_key to $yaml_value" - mv -f "$srcdir"/* "$destdir" && rm -fr "$srcdir" - contents="$contents $yaml_value" - # Check to see if the base source directory is empty - _mf_basedir=${srcdir%$(basename "$yaml_key")} - if [ ! "$( ls -A "$_mf_basedir" )" ]; then - echo "Removing empty directory ${_mf_basedir#$releasedir/}" - rm -fr "$_mf_basedir" - fi - fi - # update external dir - nolib_exclude=${nolib_exclude//$srcdir/$destdir} - ;; - esac - ;; - esac - ;; - esac - done < "$pkgmeta_file" - if [ -n "$srcdir" ]; then - echo - fi -fi - -### -### Create the final zipfile for the addon. -### - -if [ -z "$skip_zipfile" ]; then - archive_version="$project_version" - archive_name="$( filename_filter "$file_name" ).zip" - archive_label="$archive_version" - if [[ "${file_name}" == *"{game-type}"* ]] || [[ "$game_type" != "retail" && "${file_name}" == *"{classic}"* ]]; then - # append the game-type for clarity - archive_label="$archive_version-$game_type" - if [[ "$game_type" == "classic" && "${project_version,,}" == *"-classic"* ]] || [[ "$game_type" == "bcc" && "${project_version,,}" == *"-bcc"* ]]; then - # this is mostly for BigWigs projects that tag classic separately (eg, v10-classic) - # to prevent the extra -classic without changing all our workflows - archive_label="$archive_version" - fi - fi - archive="$releasedir/$archive_name" - - if [ -n "$GITHUB_ACTIONS" ]; then - echo "::set-output name=archive_path::${archive}" - fi - - nolib_archive_version="${project_version}-nolib" - nolib_archive_name="$( nolib=true filename_filter "$file_name" ).zip" - if [ "$archive_name" = "$nolib_archive_name" ]; then - # someone didn't include {nolib} and they're forcing nolib creation - nolib_archive_name="${nolib_archive_name#.zip}-nolib.zip" - fi - nolib_archive_label="${archive_label}-nolib" - nolib_archive="$releasedir/$nolib_archive_name" - - if [ -n "$nolib" ]; then - archive_version="$nolib_archive_version" - archive_name="$nolib_archive_name" - archive_label="$nolib_archive_label" - archive="$nolib_archive" - nolib_archive= - fi - - start_group "Creating archive: $archive_name" "archive" - if [ -f "$archive" ]; then - rm -f "$archive" - fi - #( cd "$releasedir" && zip -X -r "$archive" $contents ) - ( cd "$releasedir" && 7z a -bso0 -sns- -r "$archive" $contents ) - - if [ ! -f "$archive" ]; then - exit 1 - fi - end_group "archive" - - # Create nolib version of the zipfile - if [ -n "$enable_nolib_creation" ] && [ -z "$nolib" ] && [ -n "$nolib_exclude" ]; then - # run the nolib_filter - find "$pkgdir" -type f \( -name "*.xml" -o -name "*.toc" \) -print | while read -r file; do - case $file in - *.toc) _filter="toc_filter no-lib-strip true" ;; - *.xml) _filter="xml_filter no-lib-strip" ;; - esac - $_filter < "$file" > "$file.tmp" && mv "$file.tmp" "$file" - done - - # make the exclude paths relative to the release directory - nolib_exclude=${nolib_exclude//$releasedir\//} - - start_group "Creating no-lib archive: $nolib_archive_name" "archive.nolib" - if [ -f "$nolib_archive" ]; then - rm -f "$nolib_archive" - fi - # set noglob so each nolib_exclude path gets quoted instead of expanded - ( set -f; cd "$releasedir" && zip -X -r -q "$nolib_archive" $contents -x $nolib_exclude ) - - if [ ! -f "$nolib_archive" ]; then - exit_code=1 - fi - end_group "archive.nolib" - fi - - ### - ### Deploy the zipfile. - ### - - upload_curseforge=$( [[ -z "$skip_upload" && -z "$skip_cf_upload" && -n "$slug" && -n "$cf_token" && -n "$project_site" ]] && echo true ) - upload_wowinterface=$( [[ -z "$skip_upload" && -n "$tag" && -n "$addonid" && -n "$wowi_token" ]] && echo true ) - upload_wago=$( [[ -z "$skip_upload" && -n "$wagoid" && -n "$wago_token" ]] && echo true ) - upload_github=$( [[ -z "$skip_upload" && -n "$tag" && -n "$project_github_slug" && -n "$github_token" ]] && echo true ) - - if [[ -n "$upload_curseforge" || -n "$upload_wowinterface" || -n "$upload_github" || -n "$upload_wago" ]] && ! hash jq &>/dev/null; then - echo "Skipping upload because \"jq\" was not found." - echo - upload_curseforge= - upload_wowinterface= - upload_wago= - upload_github= - exit_code=1 - fi - - if [ -n "$upload_curseforge" ]; then - _cf_versions=$( curl -s -H "x-api-token: $cf_token" $project_site/api/game/versions ) - if [ -n "$_cf_versions" ]; then - _cf_game_version="$game_version" - if [ -n "$_cf_game_version" ]; then - _cf_game_version_id=$( echo "$_cf_versions" | jq -c --argjson v "[\"${game_version//,/\",\"}\"]" 'map(select(.name as $x | $v | index($x)) | .id) | select(length > 0)' 2>/dev/null ) - if [ -n "$_cf_game_version_id" ]; then - # and now the reverse, since an invalid version will just be dropped - _cf_game_version=$( echo "$_cf_versions" | jq -r --argjson v "$_cf_game_version_id" 'map(select(.id as $x | $v | index($x)) | .name) | join(",")' 2>/dev/null ) - fi - fi - if [ -z "$_cf_game_version_id" ]; then - case $game_type in - retail) _cf_game_type_id=517 ;; - classic) _cf_game_type_id=67408 ;; - bcc) _cf_game_type_id=73246 ;; - esac - _cf_game_version_id=$( echo "$_cf_versions" | jq -c --argjson v "$_cf_game_type_id" 'map(select(.gameVersionTypeID == $v)) | max_by(.id) | [.id]' 2>/dev/null ) - _cf_game_version=$( echo "$_cf_versions" | jq -r --argjson v "$_cf_game_type_id" 'map(select(.gameVersionTypeID == $v)) | max_by(.id) | .name' 2>/dev/null ) - fi - fi - if [ -z "$_cf_game_version_id" ]; then - echo "Error fetching game version info from $project_site/api/game/versions" - echo - echo "Skipping upload to CurseForge." - echo - upload_curseforge= - exit_code=1 - fi - fi - - # Upload to CurseForge. - if [ -n "$upload_curseforge" ]; then - _cf_payload=$( cat <<-EOF - { - "displayName": "$archive_label", - "gameVersions": $_cf_game_version_id, - "releaseType": "$file_type", - "changelog": $( jq --slurp --raw-input '.' < "$pkgdir/$changelog" ), - "changelogType": "$changelog_markup" - } - EOF - ) - _cf_payload_relations= - for i in "${!relations[@]}"; do - _cf_payload_relations="$_cf_payload_relations{\"slug\":\"$i\",\"type\":\"${relations[$i]}\"}," - done - if [[ -n $_cf_payload_relations ]]; then - _cf_payload_relations="{\"relations\":{\"projects\":[${_cf_payload_relations%,}]}}" - _cf_payload=$( echo "$_cf_payload $_cf_payload_relations" | jq -s -c '.[0] * .[1]' ) - fi - - echo "Uploading $archive_name ($_cf_game_version $file_type) to $project_site/projects/$slug" - resultfile="$releasedir/cf_result.json" - result=$( echo "$_cf_payload" | curl -sS --retry 3 --retry-delay 10 \ - -w "%{http_code}" -o "$resultfile" \ - -H "x-api-token: $cf_token" \ - -F "metadata=<-" \ - -F "file=@$archive" \ - "$project_site/api/projects/$slug/upload-file" - ) && { - case $result in - 200) echo "Success!" ;; - 302) - echo "Error! ($result)" - # don't need to ouput the redirect page - exit_code=1 - ;; - 404) - echo "Error! No project for \"$slug\" found." - exit_code=1 - ;; - *) - echo "Error! ($result)" - if [ -s "$resultfile" ]; then - echo "$(<"$resultfile")" - fi - exit_code=1 - ;; - esac - } || { - exit_code=1 - } - echo - - rm -f "$resultfile" 2>/dev/null - fi - - if [ -n "$upload_wowinterface" ]; then - _wowi_game_version= - _wowi_versions=$( curl -s -H "x-api-token: $wowi_token" https://api.wowinterface.com/addons/compatible.json ) - if [ -n "$_wowi_versions" ]; then - # Multiple versions, match on game version - if [[ "$game_version" == *","* ]]; then - _wowi_game_version=$( echo "$_wowi_versions" | jq -r --argjson v "[\"${game_version//,/\",\"}\"]" 'map(select(.id as $x | $v | index($x)) | .id) | join(",")' 2>/dev/null ) - fi - # TOC matching - if [ -z "$_wowi_game_version" ]; then - _wowi_game_version=$( echo "$_wowi_versions" | jq -r --arg toc "$toc_version" '.[] | select(.interface == $toc and .default == true) | .id' 2>/dev/null ) - fi - if [ -z "$_wowi_game_version" ]; then - _wowi_game_version=$( echo "$_wowi_versions" | jq -r --arg toc "$toc_version" 'map(select(.interface == $toc))[0] | .id // empty' 2>/dev/null ) - fi - # Handle delayed support (probably don't really need this anymore) - if [ -z "$_wowi_game_version" ] && [ "$game_type" != "retail" ]; then - _wowi_game_version=$( echo "$_wowi_versions" | jq -r --arg toc $((toc_version - 1)) '.[] | select(.interface == $toc) | .id' 2>/dev/null ) - fi - if [ -z "$_wowi_game_version" ]; then - _wowi_game_version=$( echo "$_wowi_versions" | jq -r '.[] | select(.default == true) | .id' 2>/dev/null ) - fi - fi - if [ -z "$_wowi_game_version" ]; then - echo "Error fetching game version info from https://api.wowinterface.com/addons/compatible.json" - echo - echo "Skipping upload to WoWInterface." - echo - upload_wowinterface= - exit_code=1 - fi - fi - - # Upload tags to WoWInterface. - if [ -n "$upload_wowinterface" ]; then - _wowi_args=() - if [ -f "$wowi_changelog" ]; then - _wowi_args+=("-F changelog=<$wowi_changelog") - elif [ -n "$manual_changelog" ] || [ "$wowi_markup" = "markdown" ]; then - _wowi_args+=("-F changelog=<$pkgdir/$changelog") - fi - if [ -z "$wowi_archive" ]; then - _wowi_args+=("-F archive=No") - fi - - echo "Uploading $archive_name ($_wowi_game_version) to https://www.wowinterface.com/downloads/info$addonid" - resultfile="$releasedir/wi_result.json" - result=$( curl -sS --retry 3 --retry-delay 10 \ - -w "%{http_code}" -o "$resultfile" \ - -H "x-api-token: $wowi_token" \ - -F "id=$addonid" \ - -F "version=$archive_version" \ - -F "compatible=$_wowi_game_version" \ - "${_wowi_args[@]}" \ - -F "updatefile=@$archive" \ - "https://api.wowinterface.com/addons/update" - ) && { - case $result in - 202) - echo "Success!" - if [ -f "$wowi_changelog" ]; then - rm -f "$wowi_changelog" 2>/dev/null - fi - ;; - 401) - echo "Error! No addon for id \"$addonid\" found or you do not have permission to upload files." - exit_code=1 - ;; - 403) - echo "Error! Incorrect api key or you do not have permission to upload files." - exit_code=1 - ;; - *) - echo "Error! ($result)" - if [ -s "$resultfile" ]; then - echo "$(<"$resultfile")" - fi - exit_code=1 - ;; - esac - } || { - exit_code=1 - } - echo - - rm -f "$resultfile" 2>/dev/null - fi - - # Upload to Wago - if [ -n "$upload_wago" ] ; then - _wago_support_property="" - for type in "${!game_versions[@]}"; do - if [[ "$type" == "bcc" ]]; then - _wago_support_property+="\"supported_bc_patch\": \"${game_versions[$type]}\", " - else - _wago_support_property+="\"supported_${type}_patch\": \"${game_versions[$type]}\", " - fi - done - - _wago_stability="$file_type" - if [ "$file_type" = "release" ]; then - _wago_stability="stable" - fi - - _wago_payload=$( cat <<-EOF - { - "label": "$archive_label", - $_wago_support_property - "stability": "$_wago_stability", - "changelog": $( jq --slurp --raw-input '.' < "$pkgdir/$changelog" ) - } - EOF - ) - - echo "Uploading $archive_name ($game_version $file_type) to Wago" - resultfile="$releasedir/wago_result.json" - result=$( echo "$_wago_payload" | curl -sS --retry 3 --retry-delay 10 \ - -w "%{http_code}" -o "$resultfile" \ - -H "authorization: Bearer $wago_token" \ - -H "accept: application/json" \ - -F "metadata=<-" \ - -F "file=@$archive" \ - "https://addons.wago.io/api/projects/$wagoid/version" - ) && { - case $result in - 200|201) echo "Success!" ;; - 302) - echo "Error! ($result)" - # don't need to ouput the redirect page - exit_code=1 - ;; - 404) - echo "Error! No Wago project for id \"$wagoid\" found." - exit_code=1 - ;; - *) - echo "Error! ($result)" - if [ -s "$resultfile" ]; then - echo "$(<"$resultfile")" - fi - exit_code=1 - ;; - esac - } || { - exit_code=1 - } - echo - - rm -f "$resultfile" 2>/dev/null - fi - - # Create a GitHub Release for tags and upload the zipfile as an asset. - if [ -n "$upload_github" ]; then - upload_github_asset() { - _ghf_release_id=$1 - _ghf_file_name=$2 - _ghf_file_path=$3 - _ghf_resultfile="$releasedir/gh_asset_result.json" - _ghf_content_type="application/${_ghf_file_name##*.}" # zip or json - - # check if an asset exists and delete it (editing a release) - asset_id=$( curl -sS \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token $github_token" \ - "https://api.github.com/repos/$project_github_slug/releases/$_ghf_release_id/assets" \ - | jq --arg file "$_ghf_file_name" '.[] | select(.name? == $file) | .id' - ) - if [ -n "$asset_id" ]; then - curl -s \ - -X DELETE \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token $github_token" \ - "https://api.github.com/repos/$project_github_slug/releases/assets/$asset_id" &>/dev/null - fi - - echo -n "Uploading $_ghf_file_name... " - result=$( curl -sS --retry 3 --retry-delay 10 \ - -w "%{http_code}" -o "$_ghf_resultfile" \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token $github_token" \ - -H "Content-Type: $_ghf_content_type" \ - --data-binary "@$_ghf_file_path" \ - "https://uploads.github.com/repos/$project_github_slug/releases/$_ghf_release_id/assets?name=$_ghf_file_name" - ) && { - if [ "$result" = "201" ]; then - echo "Success!" - else - echo "Error ($result)" - if [ -s "$_ghf_resultfile" ]; then - echo "$(<"$_ghf_resultfile")" - fi - exit_code=1 - fi - } || { - exit_code=1 - } - - rm -f "$_ghf_resultfile" 2>/dev/null - return 0 - } - - _gh_metadata='{ "filename": "'"$archive_name"'", "nolib": false, "metadata": [' - for type in "${!game_versions[@]}"; do - _gh_metadata+='{ "flavor": "'"${game_flavors[$type]}"'", "interface": '"$toc_version"' },' - done - _gh_metadata=${_gh_metadata%,} - _gh_metadata+='] }' - if [ -f "$nolib_archive" ]; then - _gh_metadata+=',{ "filename": "'"$nolib_archive_name"'", "nolib": true, "metadata": [' - for type in "${!game_versions[@]}"; do - _gh_metadata+='{ "flavor": "'"${game_flavors[$type]}"'", "interface": '"$toc_version"' },' - done - _gh_metadata=${_gh_metadata%,} - _gh_metadata+='] }' - fi - _gh_metadata='{ "releases": ['"$_gh_metadata"'] }' - - versionfile="$releasedir/release.json" - jq -c '.' <<< "$_gh_metadata" > "$versionfile" || echo "There was an error creating release.json" >&2 - - _gh_payload=$( cat <<-EOF - { - "tag_name": "$tag", - "name": "$tag", - "body": $( jq --slurp --raw-input '.' < "$pkgdir/$changelog" ), - "draft": false, - "prerelease": $( [[ "$file_type" != "release" ]] && echo true || echo false ) - } - EOF - ) - resultfile="$releasedir/gh_result.json" - - release_id=$( curl -sS \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token $github_token" \ - "https://api.github.com/repos/$project_github_slug/releases/tags/$tag" \ - | jq '.id // empty' - ) - if [ -n "$release_id" ]; then - echo "Updating GitHub release: https://github.com/$project_github_slug/releases/tag/$tag" - _gh_release_url="-X PATCH https://api.github.com/repos/$project_github_slug/releases/$release_id" - - # combine version info - _gh_metadata_url=$( curl -sS \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token $github_token" \ - "https://api.github.com/repos/$project_github_slug/releases/$release_id/assets" \ - | jq -r '.[] | select(.name? == "release.json") | .url // empty' - ) - if [ -n "$_gh_metadata_url" ]; then - _gh_previous_metadata=$( curl -sSL --fail \ - -H "Accept: application/octet-stream" \ - -H "Authorization: token $github_token" \ - "$_gh_metadata_url" - ) && { - jq -sc '.[0].releases + .[1].releases | unique_by(.filename) | { releases: [.[]] }' <<< "${_gh_previous_metadata} ${_gh_metadata}" > "$versionfile" - } || { - echo "Warning: Unable to update release.json ($?)" - } - fi - else - echo "Creating GitHub release: https://github.com/$project_github_slug/releases/tag/$tag" - _gh_release_url="https://api.github.com/repos/$project_github_slug/releases" - fi - result=$( echo "$_gh_payload" | curl -sS --retry 3 --retry-delay 10 \ - -w "%{http_code}" -o "$resultfile" \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token $github_token" \ - -d @- \ - $_gh_release_url - ) && { - if [ "$result" = "200" ] || [ "$result" = "201" ]; then # edited || created - if [ -z "$release_id" ]; then - release_id=$( jq '.id' < "$resultfile" ) - fi - upload_github_asset "$release_id" "$archive_name" "$archive" - if [ -f "$nolib_archive" ]; then - upload_github_asset "$release_id" "$nolib_archive_name" "$nolib_archive" - fi - if [ -s "$versionfile" ]; then - upload_github_asset "$release_id" "release.json" "$versionfile" - fi - else - echo "Error! ($result)" - if [ -s "$resultfile" ]; then - echo "$(<"$resultfile")" - fi - exit_code=1 - fi - } || { - exit_code=1 - } - - rm -f "$resultfile" 2>/dev/null - [ -z "$CI" ] && rm -f "$versionfile" 2>/dev/null - echo - fi -fi - -# All done. - -echo -echo "Packaging complete." -echo - -exit $exit_code diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c0ff52..943f3c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Version 1.1.4 - 2022-09-28 +### Changed +- typos in descriptions +- ambiguous variable definitions +- bumped version for all versions of WoW (Classic Era, WotLK, Retail) + ## Version 1.1.3 - 2021-10-06 ### Changed - bumped version for all versions of WoW (Classic Era, Season of Mastery, BCC, Retail) @@ -131,7 +137,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Version 0.3.0 - 2020-05-27 ### Fixed -- fixed DB storange and debug printing +- fixed DB storage and debug printing ## Version 0.2.2 (unreleased) - 2020-05-26 ### Added diff --git a/Grichelde.toc b/Grichelde.toc index 481631e..144a02b 100644 --- a/Grichelde.toc +++ b/Grichelde.toc @@ -1,37 +1,16 @@ -## Interface: 11401 -## Interface-Classic: 11401 -## Interface-BCC: 20502 -## Interface-Retail: 90100 +## Interface: 90207 ## Title: Grichelde ## Notes: Replaces characters of your chat input line before sending. ## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile vor dem Versenden. -#@debug@ -## Version: 1.1.3 -#@end-debug@ -#@non-debug@ -# ## Version: @project-version@ -#@end-non-debug@ +## Version: 1.1.4 ## Author: Teilzeit-Jedi ## eMail: tj@teilzeit-jedi.de -#@version-classic@ -## X-Build: Classic -## X-Compatible: 20502 -## X-Compatible: 90100 -#@end-version-classic@ -#@non-version-classic@ -#@version-bcc@ -# ## X-Build: BCC -# ## X-Compatible: 11401 -# ## X-Compatible: 90100 -#@end-version-bcc@ -#@version-retail@ -# ## X-Build: Retail -# ## X-Compatible: 11401 -# ## X-Compatible: 20502 -#@end-version-retail@ -#@end-non-version-classic@ +## X-Build: Retail +## X-Compatible: 11403 +## X-Compatible: 20504 +## X-Compatible: 30400 ## X-Curse-Project-ID: 385480 ## X-License: GPLv3 @@ -42,7 +21,6 @@ ## OptionalDeps: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon ## SavedVariables: GricheldeDB -#@no-lib-strip@ Libs\LibStub\LibStub.lua Libs\CallbackHandler-1.0\CallbackHandler-1.0.xml Libs\AceAddon-3.0\AceAddon-3.0.xml @@ -56,7 +34,6 @@ Libs\AceGUI-3.0\AceGUI-3.0.xml Libs\AceConfig-3.0\AceConfig-3.0.xml Libs\LibDataBroker-1.1\LibDataBroker-1.1.lua Libs\LibDBIcon-1.0\LibDBIcon-1.0.lua -#@end-no-lib-strip@ Grichelde.lua GricheldeConstants.lua @@ -69,7 +46,3 @@ GricheldeUpgrade.lua GricheldeOptions.lua GricheldeMinimap.lua GricheldeChat.lua - -#@do-not-package@ -GricheldeTest.lua -#@end-do-not-package@ \ No newline at end of file diff --git a/GricheldeChat.lua b/GricheldeChat.lua index ef2c482..2ce9ccb 100644 --- a/GricheldeChat.lua +++ b/GricheldeChat.lua @@ -2,9 +2,9 @@ local _G = _G local Grichelde = _G.Grichelde or {} -local IsAddOnLoaded, assert, nilOrEmpty, pairs, ipairs, spairs, tContains, tFilter, tInsert, tConcat, tSize, tIsEmpty, find, sub, gsub, gmatch, getNextCharUtf8, isLetter, isUpper, isLower, toUpper, toLower, capitalize, bytes2Char, trim, length, lengthUtf8 - = Grichelde.F.IsAddOnLoaded, Grichelde.F.assert, Grichelde.F.nilOrEmpty, Grichelde.F.pairs, Grichelde.F.ipairs, Grichelde.F.spairs, Grichelde.F.tContains, Grichelde.F.tFilter, Grichelde.F.tInsert, Grichelde.F.tConcat, Grichelde.F.tSize, Grichelde.F.tIsEmpty, - Grichelde.F.find, Grichelde.F.sub, Grichelde.F.gsub, Grichelde.F.gmatch, Grichelde.F.getNextCharUtf8, Grichelde.F.isLetter, Grichelde.F.isUpper, Grichelde.F.isLower, Grichelde.F.toUpper, Grichelde.F.toLower, Grichelde.F.capitalize, Grichelde.F.bytes2Char, Grichelde.F.trim, Grichelde.F.length, Grichelde.F.lengthUtf8 +local IsAddOnLoaded, assert, nilOrEmpty, pairs, ipairs, spairs, tContains, tFilter, tInsert, tIsEmpty, find, sub, gsub, getNextCharUtf8, isUtf8MultiByte, getUtf8Sequence, isUpper, isLower, toUpper, toLower, bytes2Char, trim, length, lengthUtf8 + = Grichelde.F.IsAddOnLoaded, Grichelde.F.assert, Grichelde.F.nilOrEmpty, Grichelde.F.pairs, Grichelde.F.ipairs, Grichelde.F.spairs, Grichelde.F.tContains, Grichelde.F.tFilter, Grichelde.F.tInsert, Grichelde.F.tIsEmpty, + Grichelde.F.find, Grichelde.F.sub, Grichelde.F.gsub, Grichelde.F.getNextCharUtf8, Grichelde.F.isUtf8MultiByte, Grichelde.F.getUtf8Sequence, Grichelde.F.isUpper, Grichelde.F.isLower, Grichelde.F.toUpper, Grichelde.F.toLower, Grichelde.F.bytes2Char, Grichelde.F.trim, Grichelde.F.length, Grichelde.F.lengthUtf8 --- Splits a long text in longest possible chunks of <= 255 length, split at last available space -- @param text string @@ -58,7 +58,6 @@ function Grichelde:SplitText(text) -- must not enforce UTF-8 support here, as the positions are used while ((length(newText) > 0) and (escape < Grichelde.ENDLESS_LOOP_LIMIT)) do escape = escape + 1 - local previousChar = currentChar local first, textAhead = getNextCharUtf8(newText) currentChar = first self:DebugPrint("SplitText : currentChar, escape: %s, %s", currentChar, escape) @@ -154,6 +153,24 @@ function Grichelde:SendChunkifiedChatMessage(message, ...) end function Grichelde:ReplaceCharacters(text, replName, replTable, consolidate, replacedTexts) + local function convertToCaseInsensitivePatternGroup(p) + local upperP, lowerP = toUpper(p), toLower(p) +--[[ + if (isUtf8MultiByte(p)) then + local sequence = nil + for _, byteSequence in spairs(getUtf8Table(upperP)) do + sequence = sequence .. byteSequence + end + else +]] + if (upperP ~= lowerP) then + return upperP .. lowerP + else + return p + end + --end + end + local function convertToCaseInsensitivePattern(pattern) local ciPattern = "" local ignored = {'^', '$', '(', ')', '.'} @@ -184,18 +201,13 @@ function Grichelde:ReplaceCharacters(text, replName, replTable, consolidate, rep ciPattern = ciPattern .. "%" .. p end else - local upperP, lowerP = toUpper(p), toLower(p) - if (upperP ~= lowerP) then - ciPattern = ciPattern .. upperP .. lowerP - else - ciPattern = ciPattern .. p - end + ciPattern = ciPattern .. convertToCaseInsensitivePatternGroup(p) end p, patRest = getNextCharUtf8(patRest) end ciPattern = ciPattern .. "]" else - ciPattern = ciPattern .. "[" .. Grichelde.F.toUpper(p) .. Grichelde.F.toLower(p) .. "]" + ciPattern = ciPattern .. "[" .. convertToCaseInsensitivePatternGroup(p) .. "]" end p, patRest = getNextCharUtf8(patRest) @@ -204,9 +216,9 @@ function Grichelde:ReplaceCharacters(text, replName, replTable, consolidate, rep return ciPattern end - local function replaceCaptures(text, replaceText, captures) + local function replaceCaptures(txt, replaceText, captures) local replText = replaceText - self:TracePrint("replaceCaptures : text: %s, #captures: %d", text, #captures) + self:TracePrint("replaceCaptures : txt: %s, #captures: %d", txt, #captures) if (#captures > 0) then for i, cap in ipairs(captures) do @@ -285,9 +297,6 @@ function Grichelde:ReplaceCharacters(text, replName, replTable, consolidate, rep self:TracePrint("ReplaceCharacters : pos1: %d, pos2: %d", pos1, pos2) self:TracePrint("ReplaceCharacters : cap1: %s, cap2: %s, cap3: %s, cap4: %s, cap5: %s, cap6: %s, cap7: %s, cap8: %s, cap9: %s", cap1, cap2, cap3, cap4, cap5, cap6, cap7, cap8, cap9) while (pos1 ~= nil) and (pos2 ~= nil) and (pos1 <= pos2) do - -- continue from that position later - pos = pos2 + 1 - if doStopOnMatch then stopOnMatch = true end @@ -297,6 +306,24 @@ function Grichelde:ReplaceCharacters(text, replName, replTable, consolidate, rep local post = sub(result, pos2 + 1) local wordStart = sub(pre, -1, -1) local wordEnd = sub(post, 1, 1) + self:TracePrint("ReplaceCharacters : result: %s", result) + self:TracePrint("ReplaceCharacters : pre: %s, match: %s, post: %s, wordStart: %s, wordEnd: %s", pre, match, post, wordStart, wordEnd) + +--[[ + self:TracePrint("ReplaceCharacters : pos2: %d, isChar: %s", pos2, isChar(match)) + while (not isChar(match) and pos2 < length(result)) do + pos2 = pos2 + 1 + pre = sub(result, 1, pos1 - 1) + match = sub(result, pos1, pos2) + post = sub(result, pos2 + 1) + wordStart = sub(pre, -1, -1) + wordEnd = sub(post, 1, 1) + self:TracePrint("ReplaceCharacters : pos2: %d, isChar: %s", pos2, isChar(match)) + end +]] + + -- continue from that position later + pos = pos2 + 1 -- additional checks for word boundaries local doesMatchWhen = false @@ -441,8 +468,8 @@ end -- @param text string -- @param replacements table of mappings -- @return string -function Grichelde:ReplaceAndConsolidate(text, replacements) - local replacements = replacements or self.db.profile.replacements or {} +function Grichelde:ReplaceAndConsolidate(text, _replacements) + local replacements = _replacements or self.db.profile.replacements or {} self:TracePrint("ReplaceAndConsolidate : replacements") self:TracePrint(replacements) @@ -531,7 +558,6 @@ function Grichelde:CheckForLink(text, currentChar) for _, pattern in ipairs(Grichelde.IGNORE_PATTERNS.LINKS) do local pos1, pos2 = find(text, "^" .. pattern) if (pos1 == 1) and (pos2 ~= nil) then - local match = sub(text, pos1, pos2) self:DebugPrint("CheckForLink : Found link or texture pattern \"%s\" at (%d, %d)", pattern, pos1, pos2) return pos2 end @@ -590,10 +616,10 @@ function Grichelde:CheckForRaidTargetMarkers(text, currentChar) local translation = toLower(self.L["IgnorePattern_" .. localizedRT]) local localizedPattern = "^{" .. translation .. "}" self:TracePrint("CheckForPreversableText : localizedPattern:", localizedPattern) - local pos1, pos2 = find(lowerText, localizedPattern) - if (pos1 == 1) and (pos2 ~= nil) then - self:DebugPrint("CheckForPreversableText : Found localized raid target marker \"%s\" at (%d, %d)", localizedPattern, pos1, pos2) - return pos2 + local p1, p2 = find(lowerText, localizedPattern) + if (p1 == 1) and (p2 ~= nil) then + self:DebugPrint("CheckForPreversableText : Found localized raid target marker \"%s\" at (%d, %d)", localizedPattern, p1, p2) + return p2 end end end @@ -636,9 +662,9 @@ end -- @param previousChar string(1) previous character of the text, otherwise unreachable -- @param preserveEmotes boolean ignore replacements for emotes, for testing purposes -- @return number -function Grichelde:CheckForPreversableText(text, currentChar, previousChar, replaceEmotes) +function Grichelde:CheckForPreversableText(text, currentChar, previousChar, _replaceEmotes) self:DebugPrint("CheckForPreversableText : text:", text) - local replaceEmotes = replaceEmotes or self.db.profile.channels.emote or false + local replaceEmotes = _replaceEmotes or self.db.profile.channels.emote or false local linkPos = self:CheckForLink(text, currentChar) if (linkPos ~= nil) then @@ -679,11 +705,11 @@ end -- @param text string the text to apply the mappings on -- @param preserveEmotes boolean ignore replacements for emotes, for testing purposes -- @return string -function Grichelde:ReplaceText(text, replacements, replaceEmotes) +function Grichelde:ReplaceText(text, _replacements, _replaceEmotes) local lookAheads = { '|', '*', '<', '%', '{', '(', 'o' } local newText = text - local preserveEmotes = replaceEmotes or self.db.profile.channels.emote or false - local replacements = replacements or self.db.profile.replacements or {} + local preserveEmotes = _replaceEmotes or self.db.profile.channels.emote or false + local replacements = _replacements or self.db.profile.replacements or {} local finalText, replaceText = "", "" local currentChar local escape = 0 diff --git a/GricheldeConstants.lua b/GricheldeConstants.lua index c4682fe..e1074d5 100644 --- a/GricheldeConstants.lua +++ b/GricheldeConstants.lua @@ -5,7 +5,9 @@ local Grichelde = _G.Grichelde or {} -- constants and upvalues Grichelde.LOG_LEVEL = { DEBUG = 1, TRACE = 2 } +-- chat input in client is limited to 255 bytes (unicode length is less) Grichelde.INPUT_LIMIT = 255 +-- safety measure in case malformed user input causes infinite loops on string parsing Grichelde.ENDLESS_LOOP_LIMIT = 10000 Grichelde.MAPPING_OFFSET = 10 Grichelde.MINIMAP_ENABLED = 1.0 @@ -169,11 +171,11 @@ local function nilOrEmpty(s) return s == nil or s:trim() == "" end -local function spairs(t, orderFunc) +local function spairs(tbl, orderFunc) -- collect the keys local sortedKeys = {} -- for every non-nil value - for key, _ in Grichelde.F.pairs(t) do + for key, _ in Grichelde.F.pairs(tbl) do Grichelde.F.tInsert(sortedKeys, key) end @@ -189,22 +191,22 @@ local function spairs(t, orderFunc) return function() it = it + 1 if (sortedKeys[it] ~= nil) then - return sortedKeys[it], t[sortedKeys[it]] + return sortedKeys[it], tbl[sortedKeys[it]] else return nil end end end -local function tFilter(t, condition, extract) +local function tFilter(type, condition, extract) local filtered = {} - for key, value in Grichelde.F.pairs(t) do + for key, value in Grichelde.F.pairs(type) do local cond = false if (condition) then - local t = Grichelde.F.type(condition) - if (t == "function") then - cond = condition(t, key, value) - elseif (t == "string") or (t == "number") then + local typ = Grichelde.F.type(condition) + if (typ == "function") then + cond = condition(typ, key, value) + elseif (typ == "string") or (typ == "number") then cond = (value == condition) end end @@ -212,7 +214,7 @@ local function tFilter(t, condition, extract) if (cond) then local val = value if (extract and (Grichelde.F.type(extract) == "function")) then - val = extract(t, key, value) + val = extract(type, key, value) end Grichelde.F.tInsert(filtered, val) end @@ -220,20 +222,20 @@ local function tFilter(t, condition, extract) return filtered end -local function tSize(t) +local function tSize(tbl) local size = 0 - if (t ~= nil) then + if (tbl ~= nil) then -- for every non-nil value - for _, _ in Grichelde.F.pairs(t) do + for _, _ in Grichelde.F.pairs(tbl) do size = size + 1 end end return size end -local function tIsEmpty(t) - if (not t) then return true end - return Grichelde.F.tNext(t) == nil +local function tIsEmpty(tbl) + if (not tbl) then return true end + return Grichelde.F.tNext(tbl) == nil end local function tClone(orig) @@ -323,11 +325,11 @@ local function isCapital(word) return false else local first, rest = Grichelde.F.getNextCharUtf8(word) - local isCapital = Grichelde.F.isUpper(first) + local isCap = Grichelde.F.isUpper(first) if (rest ~= nil) then - return isCapital and Grichelde.F.isLower(rest) + return isCap and Grichelde.F.isLower(rest) else - return isCapital + return isCap end end end @@ -346,8 +348,8 @@ local function capitalize(word) end end -local function color(color, text) - return color .. text .. Grichelde.COLOR_CODES.CLOSE +local function color(colour, text) + return colour .. text .. Grichelde.COLOR_CODES.CLOSE end local function cPrefix(text) diff --git a/GricheldeDatabase.lua b/GricheldeDatabase.lua index 846b54b..d0e8fb8 100644 --- a/GricheldeDatabase.lua +++ b/GricheldeDatabase.lua @@ -2,8 +2,8 @@ local _G = _G local Grichelde = _G.Grichelde or {} -local pairs, tInsert, tClone, tWipe, unpack, join, toString - = Grichelde.F.pairs, Grichelde.F.tInsert, Grichelde.F.tClone, Grichelde.F.tWipe, Grichelde.F.unpack, Grichelde.F.join, Grichelde.F.toString +local pairs, tInsert, tClone, unpack, join, toString + = Grichelde.F.pairs, Grichelde.F.tInsert, Grichelde.F.tClone, Grichelde.F.unpack, Grichelde.F.join, Grichelde.F.toString function Grichelde.getDefaultConfig() return { diff --git a/GricheldeMinimap.lua b/GricheldeMinimap.lua index 51de63f..a588d96 100644 --- a/GricheldeMinimap.lua +++ b/GricheldeMinimap.lua @@ -2,8 +2,8 @@ local _G = _G local Grichelde = _G.Grichelde or {} -local cPrefix, cGreen, cRed - = Grichelde.F.cPrefix, Grichelde.F.cGreen, Grichelde.F.cRed +local cGreen, cRed + = Grichelde.F.cGreen, Grichelde.F.cRed --- add Minimap button diff --git a/GricheldeTest.lua b/GricheldeTest.lua index 67c05c9..46f8f18 100644 --- a/GricheldeTest.lua +++ b/GricheldeTest.lua @@ -2,7 +2,7 @@ local _G = _G local Grichelde = _G.Grichelde or {} -local find, pairs, tSize, cRed, cGreen, format = Grichelde.F.find, Grichelde.F.pairs, Grichelde.F.tSize, Grichelde.F.cRed, Grichelde.F.cGreen, Grichelde.F.format +local find, pairs, tSize, cRed, cGreen = Grichelde.F.find, Grichelde.F.pairs, Grichelde.F.tSize, Grichelde.F.cRed, Grichelde.F.cGreen function Grichelde:TestMatch(text, pattern) -- disable debug print out for testing @@ -17,6 +17,7 @@ function Grichelde:TestMatch(text, pattern) Grichelde.logLevel = oldLogLevel end +--- Invoke ingame with /run Grichelde:RunTests() function Grichelde:RunTests() local function test(name, replacements, testData, replaceEmotes) local i, ok, size = 0, 0, tSize(testData) @@ -778,7 +779,7 @@ function Grichelde:RunTests() if (ok == all) then self:PrefixedPrint("All %d tests %s", all, cGreen("passed")) else - self:PrefixedPrint("%d test %s, %d tests %s", all - ok, cRed("failed"), ok, cGreen("passed")) + self:PrefixedPrint("%d test%s %s, %d tests %s", all - ok, all - ok > 1 and "s" or "", cRed("failed"), ok, cGreen("passed")) end -- restore old loglevel diff --git a/GricheldeUpgrade.lua b/GricheldeUpgrade.lua index 43676ef..a10a3b5 100644 --- a/GricheldeUpgrade.lua +++ b/GricheldeUpgrade.lua @@ -2,8 +2,8 @@ local _G = _G local Grichelde = _G.Grichelde or {} -local pairs, tSize, tClone, find, sub, cGreen, cOrange, cRed, toNumber - = Grichelde.F.pairs, Grichelde.F.tSize,Grichelde.F.tClone, Grichelde.F.find, Grichelde.F.sub, Grichelde.F.cGreen, Grichelde.F.cOrange, Grichelde.F.cRed, Grichelde.F.toNumber +local pairs, tClone, find, sub, cGreen, cOrange, cRed, toNumber + = Grichelde.F.pairs, Grichelde.F.tClone, Grichelde.F.find, Grichelde.F.sub, Grichelde.F.cGreen, Grichelde.F.cOrange, Grichelde.F.cRed, Grichelde.F.toNumber function Grichelde:Upgrade_To_v060() self:PrefixedPrint(self.L.Upgrade_ToVersion, cOrange("0.6.0")) diff --git a/Grichelde_TBC.toc b/Grichelde_TBC.toc new file mode 100644 index 0000000..9f949a9 --- /dev/null +++ b/Grichelde_TBC.toc @@ -0,0 +1,48 @@ +## Interface: 20504 + +## Title: Grichelde +## Notes: Replaces characters of your chat input line before sending. +## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile vor dem Versenden. +## Version: 1.1.4 +## Author: Teilzeit-Jedi +## eMail: tj@teilzeit-jedi.de + +## X-Build: BCC +## X-Compatible: 11403 +## X-Compatible: 30400 +## X-Compatible: 90207 + +## X-Curse-Project-ID: 385480 +## X-License: GPLv3 +## X-Category: Chat/Communication +## X-Credits: Teilzeit-Jedi +## X-Embeds: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon + +## OptionalDeps: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon +## SavedVariables: GricheldeDB + +Libs\LibStub\LibStub.lua +Libs\CallbackHandler-1.0\CallbackHandler-1.0.xml +Libs\AceAddon-3.0\AceAddon-3.0.xml +Libs\AceLocale-3.0\AceLocale-3.0.xml +Libs\AceEvent-3.0\AceEvent-3.0.xml +Libs\AceHook-3.0\AceHook-3.0.xml +Libs\AceConsole-3.0\AceConsole-3.0.xml +Libs\AceDB-3.0\AceDB-3.0.xml +Libs\AceDBOptions-3.0\AceDBOptions-3.0.xml +Libs\AceGUI-3.0\AceGUI-3.0.xml +Libs\AceConfig-3.0\AceConfig-3.0.xml +Libs\LibDataBroker-1.1\LibDataBroker-1.1.lua +Libs\LibDBIcon-1.0\LibDBIcon-1.0.lua + +Grichelde.lua +GricheldeConstants.lua + +localisation.xml + +GricheldeUtils.lua +GricheldeDatabase.lua +GricheldeUpgrade.lua +GricheldeOptions.lua +GricheldeMinimap.lua +GricheldeChat.lua diff --git a/Grichelde_Vanilla.toc b/Grichelde_Vanilla.toc new file mode 100644 index 0000000..4a2165d --- /dev/null +++ b/Grichelde_Vanilla.toc @@ -0,0 +1,48 @@ +## Interface: 11403 + +## Title: Grichelde +## Notes: Replaces characters of your chat input line before sending. +## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile vor dem Versenden. +## Version: 1.1.4 +## Author: Teilzeit-Jedi +## eMail: tj@teilzeit-jedi.de + +## X-Build: Classic +## X-Compatible: 20504 +## X-Compatible: 30400 +## X-Compatible: 90207 + +## X-Curse-Project-ID: 385480 +## X-License: GPLv3 +## X-Category: Chat/Communication +## X-Credits: Teilzeit-Jedi +## X-Embeds: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon + +## OptionalDeps: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon +## SavedVariables: GricheldeDB + +Libs\LibStub\LibStub.lua +Libs\CallbackHandler-1.0\CallbackHandler-1.0.xml +Libs\AceAddon-3.0\AceAddon-3.0.xml +Libs\AceLocale-3.0\AceLocale-3.0.xml +Libs\AceEvent-3.0\AceEvent-3.0.xml +Libs\AceHook-3.0\AceHook-3.0.xml +Libs\AceConsole-3.0\AceConsole-3.0.xml +Libs\AceDB-3.0\AceDB-3.0.xml +Libs\AceDBOptions-3.0\AceDBOptions-3.0.xml +Libs\AceGUI-3.0\AceGUI-3.0.xml +Libs\AceConfig-3.0\AceConfig-3.0.xml +Libs\LibDataBroker-1.1\LibDataBroker-1.1.lua +Libs\LibDBIcon-1.0\LibDBIcon-1.0.lua + +Grichelde.lua +GricheldeConstants.lua + +localisation.xml + +GricheldeUtils.lua +GricheldeDatabase.lua +GricheldeUpgrade.lua +GricheldeOptions.lua +GricheldeMinimap.lua +GricheldeChat.lua diff --git a/Grichelde_Wrath.toc b/Grichelde_Wrath.toc new file mode 100644 index 0000000..1d521dd --- /dev/null +++ b/Grichelde_Wrath.toc @@ -0,0 +1,48 @@ +## Interface: 30400 + +## Title: Grichelde +## Notes: Replaces characters of your chat input line before sending. +## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile vor dem Versenden. +## Version: 1.1.4 +## Author: Teilzeit-Jedi +## eMail: tj@teilzeit-jedi.de + +## X-Build: WotLK +## X-Compatible: 11403 +## X-Compatible: 20504 +## X-Compatible: 90207 + +## X-Curse-Project-ID: 385480 +## X-License: GPLv3 +## X-Category: Chat/Communication +## X-Credits: Teilzeit-Jedi +## X-Embeds: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon + +## OptionalDeps: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon +## SavedVariables: GricheldeDB + +Libs\LibStub\LibStub.lua +Libs\CallbackHandler-1.0\CallbackHandler-1.0.xml +Libs\AceAddon-3.0\AceAddon-3.0.xml +Libs\AceLocale-3.0\AceLocale-3.0.xml +Libs\AceEvent-3.0\AceEvent-3.0.xml +Libs\AceHook-3.0\AceHook-3.0.xml +Libs\AceConsole-3.0\AceConsole-3.0.xml +Libs\AceDB-3.0\AceDB-3.0.xml +Libs\AceDBOptions-3.0\AceDBOptions-3.0.xml +Libs\AceGUI-3.0\AceGUI-3.0.xml +Libs\AceConfig-3.0\AceConfig-3.0.xml +Libs\LibDataBroker-1.1\LibDataBroker-1.1.lua +Libs\LibDBIcon-1.0\LibDBIcon-1.0.lua + +Grichelde.lua +GricheldeConstants.lua + +localisation.xml + +GricheldeUtils.lua +GricheldeDatabase.lua +GricheldeUpgrade.lua +GricheldeOptions.lua +GricheldeMinimap.lua +GricheldeChat.lua diff --git a/Libs/LibStub/LibStub.toc b/Libs/LibStub/LibStub.toc new file mode 100644 index 0000000..4d9130c --- /dev/null +++ b/Libs/LibStub/LibStub.toc @@ -0,0 +1,9 @@ +## Interface: 20400 +## Title: Lib: LibStub +## Notes: Universal Library Stub +## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel +## X-Website: http://jira.wowace.com/browse/LS +## X-Category: Library +## X-License: Public Domain + +LibStub.lua diff --git a/README.md b/README.md index 42779dc..18cf606 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Grichelde - Text replacer -Grichelde is a WoW Addon for Classic, Burning Crusade Classic and Retail (Shadowlands) that replaces any characters or words you typed in a chat input line according to your replacement rules. +Grichelde is a WoW Addon for Classic, Wrath of the Lich King Classic and Retail (Shadowlands) that replaces any characters or words you typed in a chat input line according to your replacement rules. The replacement is done **before** the text is send to other players/in the target channel. It does **not** change text other players have written in the chat, but the text they will see **from you**. Its purpose is to simulate a speaking disability of your toon and hereby strengthen immersion in roleplay.