0

I am trying to make a script that automates download of SpigotMC BuildTools, detect input version ( sh build.sh <version> ) , and set a variable which is used if the version is greater or equal with 1.14 (since this release, SpigotMC discontinued the automation of auto-compilation of craftbukkit by default. Now it compiles only the spigot jar and I need both of them compiled for my personal purposes.)

Here is what I have tried (I'm a Linux newbie, so this might be messed up):

#!/bin/bash

# Sources:
# Append variables in bash                : https://www.cyberciti.biz/faq/howto-linux-unix-bash-append-textto-variables/
# Check MANIFEST.MF content from jar file : https://www.manongdao.com/q-106728.html
# Check for specified property json file  : https://stackoverflow.com/questions/34543829/jq-cannot-index-array-with-string
#                                           https://www.ultralinux.org/post/json-bash/
# Bash Array                              : https://unix.stackexchange.com/questions/253892/syntax-error-unexpected-when-creating-an-array
# #######################################################################################################################################
# 
# #######################################################################################################################################
# BuildTools Jar Info Variables
# -----------------------------
# BuilsTools working directory
buildtools_root="$(pwd)" # We use $(command) to store "command" output in a variable. We use ${command} if we have to stick other strings near it without whitespace.
# BuildTools jar location
buildtools_jar="$buildtools_root/BuildTools.jar"
# Current BuildTools jar version
buildtools_ver="$(unzip -p "$buildtools_jar" META-INF/MANIFEST.MF | grep 'Implementation-Version:' | cut -d '-' -f 5)"
# Jenkins Api-related variables. 
# A. Retrieve BuildTools lastSuccessfulBuild link
targetJar="$(curl -s 'https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/api/json' | jq -r '.artifacts[].relativePath')"
lastSuccessfulBuild="$(curl -s 'https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/api/json' | jq -r '.url')"
# B. Make the download link
latestBuildToolsUrl="${lastSuccessfulBuild}artifacts/$targetJar"
# Latest BuildTools Build Version
latestBuildToolsVersion="$(curl -s 'https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/api/json' | jq -r '.number')"
displayFullName="$(curl -s 'https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/api/json' | jq -r '.fullDisplayName')"
# ---------------------------------------------------------------------------------------------------------------------------------------
# BuildTools Jar Run Variables
# -----------------------------
# 
# #######################################################################################################################################

# This is a function to set java home to current java version in use.
javahome_set () {
    JAVA_HOME=$(dirname "$(dirname "$( readlink -f /etc/alternatives/java )")")

    OIFS=$IFS
    IFS=':';
    for i in $VAR;
    do
            JAVA1=$i/bin/java
            JAVA2=$i/java
            if [ -d "$i" ];
            then
                    if [ ! -L "$JAVA1" ] && [ -x "$JAVA1" ] || [ ! -L "$JAVA2" ] && [ -x "$JAVA2" ]; then
                        echo "dropping path: $i";
                    else
                        NEW=$NEW:$i
                    fi
            fi
    done
    IFS=$OIFS
    JAVA_HOME=$NEW:$JAVA_HOME/bin
    JAVA_HOME=${JAVA_HOME#:*}

}
javahome_set

# This function requires arguments. Checks if $1 >= $2
vercomp () {
    if [[ $1 == $2 ]]
    then
        return 0
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
        if [[ -z ${ver2[i]} ]]
        then
            # fill empty fields in ver2 with zeros
            ver2[i]=0
        fi
        if ((10#${ver1[i]} > 10#${ver2[i]}))
        then
            return 1
        fi
        if ((10#${ver1[i]} < 10#${ver2[i]}))
        then
            return 2
        fi
    done
    return 0
}

# This is a function to download the latest BuildTools version and check if download is successful.
buildtools_download () {
    curl --silent "$latestBuildToolsUrl" --output BuildTools.jar #Request download to BuildTools.
    if [ "$?" -eq 0 ]; then #Check if file was downloaded. It returns error code non-zero if file was not properly downloaded. (in this  language)
        echo "$Green Successful downloaded BuildTools.$Color_Off"
    else
        echo "$Red Error while downloading BuildTools. $Color_Off"
    fi
}

# This is a function to check for updates for BuildTools jar
buildtools_check () {
    if [ ! -e "$buildtools_jar" ]; then #If BuildTools.jar does NOT exist in "BuildTools" folder
        echo "$Yellow Downloading BuildTools..."
        buildtools_download 
        exit
    elif [ -e "$buildtools_jar" ]; then
        if [ "$buildtools_ver" -lt "$latestBuildToolsVersion" ]; then
            echo "$Blue Updating BuildTools... $Color_Off"
            rm "$buildtools_jar"
            buildtools_download
        fi
    else
        echo "$Cyan BuildTools is up to date. $Color_Off"
    fi
}

info_menu () {
echo "==============================================[Local-Info]=============================================="
echo "BuildTools Root     : $buildtools_root"
echo "Executable Path     : $buildtools_jar"
echo "Installed Version   : $buildtools_ver"
echo "JAVA_HOME Directory : $JAVA_HOME"
echo "=============================================[JsonAPI-Info]============================================="
echo "Latest Download Url: $latestBuildToolsUrl"
echo "========================================================================================================"
echo
if [ "$buildtools_ver" -eq "$latestBuildToolsVersion" ]; then
    echo "$Green You have the latest SpigotMC BuildTools version. $Color_Off"
else
    echo "$Yellow A new build is available : $displayFullName"
fi
echo
}

if [ -z "$1" ]; then
    echo "$BCyan Usage: $0 $BBlue<version> $Color_Off" & exit #By default, $0 is the name of this file
else
    if [ -d "$1" ]; then #If argument is defined
        if [ "$1" = "latest" ]; then
            buildtools_check
        else
            vercomp "$1" "1.14"
            if [ $? -eq 0 -o $? -eq 1 ]; then
                BothJars=(--compile craftbukkit,spigot)  # means $1 >= 1.14 ; sets the $BothJars variable
                buildtools_check
            fi
        if [ "$1" -lt "1.14" ]; then
            echo "$Yellow You want to build an older server version. Good choice btw."
            buildtools_check
        fi
    fi
fi
    rm -rf "$1" && mkdir "$1"
    cd "$1" || exit
    java -jar ./BuildTools.jar --rev "$1" "${BothJars[@]}" --generate-source --generate-docs #../filename is for executing it from one dir far.


I have put comments for you to understand what's going on.

Can someone help me with the problem?

EDIT : If you ever played Minecraft, or if you saw different versions of Minecraft, you can encounter the following version formats:

1.7.10 ; 1.8 ; 1.13.2 ; 1.14 ; 1.15.3 (and no, there is not a '1.8.0' version. Just '1.8')

Here are examples of comparisons between versions which are mathematical false after tr command :

1.8 > 1.7.10 - 18 > 1710
1.14 > 1.13.2 - 114 > 1132

1.15.2 < 1.16 - 1152 < 116

So... There may be problems that could affect the comparison of those numbers, since they are versions, not fractions or integers.

EDIT 2 : I will not make more than 3 edits / post. Thank you Richard K. for helping me with version checking function! I have rewritten my script to make it more complete. I store important parts in functions to save space and to be more visible. Summary : I don't understand what have I done wrong here. U_U

EDIT 3 : As of Rachid K's answer, I got this part to test:

#!/bin/bash

vercomp () {
    if [[ $1 == $2 ]]
    then
        return 0
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
        if [[ -z ${ver2[i]} ]]
        then
            # fill empty fields in ver2 with zeros
            ver2[i]=0
        fi
        if ((10#${ver1[i]} > 10#${ver2[i]}))
        then
            return 1
        fi
        if ((10#${ver1[i]} < 10#${ver2[i]}))
        then
            return 2
        fi
    done
    return 0
}

if [ -z "$1" ]; then
    echo "$BCyan Usage: $0 $BBlue<version> $Color_Off" & exit #By default, $0 is the name of this file
else
    if [ -d "$1" ]; then #If argument is defined
        if [ "$1" = "latest" ]; then
            echo "Building latest version"
        else
            vercomp "$1" "1.14"
            rc=$?
            case $rc in
            0)
            echo " You want to build version 1.14"
            ;;
            1)
            echo " You want to build version above 1.14"
            ;;
            2)
            echo " You want to build version below 1.14"
            ;;
            latest)
            echo " You want to build latest version."
            ;;
            esac
        fi
    fi
fi

So the vercomp() should see if : $1 is equal with string latest ; $1 is greater or equal with 1.14 ; $1 is lower than 1.14.

The function looks good, but the echo command does not display. I noticed that in some cases the echo command doesn't display due to missing double quotes. So... putting that at it. But it doesn't work. Why?

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
WinScriptDev
  • 15
  • 1
  • 9
  • I updated my post with a function coming from another StackOverflow post to compare the versions. – Rachid K. Oct 24 '20 at 19:05
  • In your new version, you still have "if [ "$1" -lt "1.14" ]; then ..." ==> This does not work. Store $? in a variable named rc: vercomp "$1" "1.14"; rc=$? and use "rc" in all the following "if". – Rachid K. Oct 28 '20 at 13:11
  • In javahome_set(), $VAR is passed to the for loop but it is not initialized ? You wanted to put $JAVA_HOME instead. – Rachid K. Oct 28 '20 at 13:28
  • When echo does not display anything, it means that the above "if" are not true. To call vercomp(), you need $1 be a directory ([ -d "$1" ]) and not equal to "latest" (else branch of [ "$1" = "latest" ]). So, when nothing is displayed, this means that $1 does not pass those checks. – Rachid K. Oct 31 '20 at 13:45
  • I am realizing, reading your comment "#If argument is defined", that you may make a confusion about "[ -d "$1" ]" : this does not mean $1 is defined but $1 is a directory name. So, if you launch your test with 1.15.2 and the directory 1.15.2 does not exist, you don't enter into the branch. – Rachid K. Oct 31 '20 at 13:57
  • Oh... ;facepalm: I understand now... :sweat_smile: Thank you for telling me these ^_^ – WinScriptDev Nov 01 '20 at 10:35

2 Answers2

0

Apparently the version you get is either a number like 1.14 or the "latest" string. You need to split you check in two tests. First you check the "latest" value :

if [ "$1" = "latest" ]

and if it is false, check the versions by using the solution proposed in this post

vercomp () {
    if [[ $1 == $2 ]]
    then
        return 0
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
        if [[ -z ${ver2[i]} ]]
        then
            # fill empty fields in ver2 with zeros
            ver2[i]=0
        fi
        if ((10#${ver1[i]} > 10#${ver2[i]}))
        then
            return 1
        fi
        if ((10#${ver1[i]} < 10#${ver2[i]}))
        then
            return 2
        fi
    done
    return 0
}

So, to compare the version just do:

vercomp "$1" "1.14"
rc=$?
case $rc in
    0) echo '=';;
    1) echo '>';;
    2) echo '<';;
esac
Rachid K.
  • 4,490
  • 3
  • 11
  • 30
  • Hi Rachid K. ! Welcome to StackOverflow! Thank you for telling me what broke my code! ^_^ But my problem is more about the variable: If i tell ```BuildTools.jar``` to review a 1.14+ version (or latest), it does not in fact read that "--compile craftbukkit,spigot" if its stored in the variable. I tried both with and without quotes, but it didnt work. Putting it raw instead of in a variable works, but versions below 1.14 are capable of automatically compile both jars. What can I do for the variable $BothJars to work ? – WinScriptDev Oct 11 '20 at 16:10
  • With the bug in the "if" condition, you never enter into the branch assigning "BothJars". So, you need to fix the condition. Then, it is not advised to put double quotes around $BothJars as this would be interpreted as a single parameter with the value "--compile craftbukkit,spigot" instead of 2 (option "--compile" and value "craftbukkit,spigot"). After that I can see that you create a brand new "$1" directory, you "cd" into it and than you ask for a jar file in that directory (./BuildTools.jar). But when do you create this jar file in "$1" directory ? – Rachid K. Oct 11 '20 at 21:57
  • The folder is made before asking for the jar file. – WinScriptDev Oct 17 '20 at 12:37
  • But i still dont know how to fix the placeholder ```$BothJars``` . U_U – WinScriptDev Oct 17 '20 at 12:40
  • Hi Rachid K. ! The function is ok, but if i have $1 = 1.14.1 , it doesnt say that is > 1.14 – WinScriptDev Oct 28 '20 at 12:41
  • @WinScriptDev: On my side it works. Right after the call to vercomp(), make sure to store the return code into a variable named rc for example (i.e. vercomp xxx xxx; rc=$?) and use $rc otherwise you will loose it while executing any other command after the call to vercomp(). – Rachid K. Oct 28 '20 at 12:57
  • I do ```./test.sh 1.15.2``` for example and it prints nothing! – WinScriptDev Oct 31 '20 at 13:40
  • It should read the echo command from ```1) echo '>';;``` because ```1,15 > 1.14``` – WinScriptDev Oct 31 '20 at 13:41
  • @WinScriptDev: This works on my side. what do you have in your test.sh ? – Rachid K. Oct 31 '20 at 13:48
0
  1. I don't see $BCyan and $BMagenta variables defined anywhere so there will just be blank text instead of them.

  2. Problem with condition on line 7 is that you're comparing two string values but you in fact want to compare real numbers (or string "latest"). For real numbers it's best using bc utility. Here's the code equivalent to what you're trying to do (I think):

if [ `echo "$1>=1.14"|bc` -eq 1 ] || [ $1 == "latest" ]; then
welcomeboredom
  • 565
  • 3
  • 12
  • It is ok, but if the requested version is 1.14 , 1.14.3 , 1.15.2 , 1.16.4 etc, ```then``` it sets a variable. So... because this is required starting with ```1.14``` , i would still not recommand to make tha `1.` part static, because the version will eventually reach ```2.x``` format. There will also be ```1.2x.y``` format or etc. , where y is not 0 . – WinScriptDev Oct 24 '20 at 18:31
  • Also, i need the script to know that "$1" as number, not any name! Because it could for example delete "MyFolder" folder if i type that name in the input – WinScriptDev Oct 24 '20 at 18:34