diff --git a/README.md b/README.md index 1415d7e..a8c111e 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,9 @@ with eventual underscores (i.e. [a-zA-Z0-9\_]), otherwise you'll get errors. #### OTHERS `--clean` Clean the cache located in `~/.cache/love-release`. One can replace the Love files there. +`--config` Pass a configuration file as argument. + It describes which build you want to make, with what options. + See `config.ini`. #### MODULES The script is modular. diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..37b78c8 --- /dev/null +++ b/config.ini @@ -0,0 +1,63 @@ +; love-release config file + +; Default values will be used if the option is left blank. +; To prevent a build from being executed, comment its section name and options. + +[global] +; Directory where the zip archives will be stored +release_dir="releases" + +; Love version to use +love_version="0.9.1" + +; Project's name +project_name="" + +[windows] +; Path to an .ico file to use +icon="" + +[macosx] +; Set the maintainer's name. Provide it for CFBundleIdentifier. +; No spaces and no special characters except underscore. Better be lowercase. +maintainer_name="" + +; Path to an .icns file to use +icon="" + +[debian] +; Version of the package +package_version="" + +; Maintainer name (full name) +maintainer_name="" + +; Maintainer_email +maintainer_email="" + +; Homepage +homepage="" + +; Description +description="" + +; Package name +; No spaces and no special characters except underscore. Better be lowercase. +package_name="" + +[android] +; Android game activity +; No spaces and no special characters except underscore. Better be lowercase. +activity="" + +; Package version +package_version="" + +; Maintainer name +; No spaces and no special characters except underscore. Better be lowercase. +maintainer_name="" + +; Package name +; No spaces and no special characters except underscore. Better be lowercase. +package_name="" + diff --git a/include/getopt.sh b/include/getopt.sh old mode 100644 new mode 100755 diff --git a/include/read_ini.sh b/include/read_ini.sh new file mode 100755 index 0000000..08974fe --- /dev/null +++ b/include/read_ini.sh @@ -0,0 +1,280 @@ +# +# Copyright (c) 2009 Kevin Porter / Advanced Web Construction Ltd +# (http://coding.tinternet.info, http://webutils.co.uk) +# Copyright (c) 2010-2012 Ruediger Meier +# (https://github.com/rudimeier/) +# +# Simple INI file parser. +# +# See README for usage. +# +# + + + + +function read_ini() +{ + # Be strict with the prefix, since it's going to be run through eval + function check_prefix() + { + if ! [[ "${VARNAME_PREFIX}" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]] ;then + echo "read_ini: invalid prefix '${VARNAME_PREFIX}'" >&2 + return 1 + fi + } + + function check_ini_file() + { + if [ ! -r "$INI_FILE" ] ;then + echo "read_ini: '${INI_FILE}' doesn't exist or not" \ + "readable" >&2 + return 1 + fi + } + + # enable some optional shell behavior (shopt) + function pollute_bash() + { + if ! shopt -q extglob ;then + SWITCH_SHOPT="${SWITCH_SHOPT} extglob" + fi + if ! shopt -q nocasematch ;then + SWITCH_SHOPT="${SWITCH_SHOPT} nocasematch" + fi + shopt -q -s ${SWITCH_SHOPT} + } + + # unset all local functions and restore shopt settings before returning + # from read_ini() + function cleanup_bash() + { + shopt -q -u ${SWITCH_SHOPT} + unset -f check_prefix check_ini_file pollute_bash cleanup_bash + } + + local INI_FILE="" + local INI_SECTION="" + + # {{{ START Deal with command line args + + # Set defaults + local BOOLEANS=1 + local VARNAME_PREFIX=INI + local CLEAN_ENV=0 + + # {{{ START Options + + # Available options: + # --boolean Whether to recognise special boolean values: ie for 'yes', 'true' + # and 'on' return 1; for 'no', 'false' and 'off' return 0. Quoted + # values will be left as strings + # Default: on + # + # --prefix=STRING String to begin all returned variables with (followed by '__'). + # Default: INI + # + # First non-option arg is filename, second is section name + + while [ $# -gt 0 ] + do + + case $1 in + + --clean | -c ) + CLEAN_ENV=1 + ;; + + --booleans | -b ) + shift + BOOLEANS=$1 + ;; + + --prefix | -p ) + shift + VARNAME_PREFIX=$1 + ;; + + * ) + if [ -z "$INI_FILE" ] + then + INI_FILE=$1 + else + if [ -z "$INI_SECTION" ] + then + INI_SECTION=$1 + fi + fi + ;; + + esac + + shift + done + + if [ -z "$INI_FILE" ] && [ "${CLEAN_ENV}" = 0 ] ;then + echo -e "Usage: read_ini [-c] [-b 0| -b 1]] [-p PREFIX] FILE"\ + "[SECTION]\n or read_ini -c [-p PREFIX]" >&2 + cleanup_bash + return 1 + fi + + if ! check_prefix ;then + cleanup_bash + return 1 + fi + + local INI_ALL_VARNAME="${VARNAME_PREFIX}__ALL_VARS" + local INI_ALL_SECTION="${VARNAME_PREFIX}__ALL_SECTIONS" + local INI_NUMSECTIONS_VARNAME="${VARNAME_PREFIX}__NUMSECTIONS" + if [ "${CLEAN_ENV}" = 1 ] ;then + eval unset "\$${INI_ALL_VARNAME}" + fi + unset ${INI_ALL_VARNAME} + unset ${INI_ALL_SECTION} + unset ${INI_NUMSECTIONS_VARNAME} + + if [ -z "$INI_FILE" ] ;then + cleanup_bash + return 0 + fi + + if ! check_ini_file ;then + cleanup_bash + return 1 + fi + + # Sanitise BOOLEANS - interpret "0" as 0, anything else as 1 + if [ "$BOOLEANS" != "0" ] + then + BOOLEANS=1 + fi + + + # }}} END Options + + # }}} END Deal with command line args + + local LINE_NUM=0 + local SECTIONS_NUM=0 + local SECTION="" + + # IFS is used in "read" and we want to switch it within the loop + local IFS=$' \t\n' + local IFS_OLD="${IFS}" + + # we need some optional shell behavior (shopt) but want to restore + # current settings before returning + local SWITCH_SHOPT="" + pollute_bash + + while read -r line || [ -n "$line" ] + do +#echo line = "$line" + + ((LINE_NUM++)) + + # Skip blank lines and comments + if [ -z "$line" -o "${line:0:1}" = ";" -o "${line:0:1}" = "#" ] + then + continue + fi + + # Section marker? + if [[ "${line}" =~ ^\[[a-zA-Z0-9_]{1,}\]$ ]] + then + + # Set SECTION var to name of section (strip [ and ] from section marker) + SECTION="${line#[}" + SECTION="${SECTION%]}" + eval "${INI_ALL_SECTION}=\"\${${INI_ALL_SECTION}# } $SECTION\"" + ((SECTIONS_NUM++)) + + continue + fi + + # Are we getting only a specific section? And are we currently in it? + if [ ! -z "$INI_SECTION" ] + then + if [ "$SECTION" != "$INI_SECTION" ] + then + continue + fi + fi + + # Valid var/value line? (check for variable name and then '=') + if ! [[ "${line}" =~ ^[a-zA-Z0-9._]{1,}[[:space:]]*= ]] + then + echo "Error: Invalid line:" >&2 + echo " ${LINE_NUM}: $line" >&2 + cleanup_bash + return 1 + fi + + + # split line at "=" sign + IFS="=" + read -r VAR VAL <<< "${line}" + IFS="${IFS_OLD}" + + # delete spaces around the equal sign (using extglob) + VAR="${VAR%%+([[:space:]])}" + VAL="${VAL##+([[:space:]])}" + VAR=$(echo $VAR) + + + # Construct variable name: + # ${VARNAME_PREFIX}__$SECTION__$VAR + # Or if not in a section: + # ${VARNAME_PREFIX}__$VAR + # In both cases, full stops ('.') are replaced with underscores ('_') + if [ -z "$SECTION" ] + then + VARNAME=${VARNAME_PREFIX}__${VAR//./_} + else + VARNAME=${VARNAME_PREFIX}__${SECTION}__${VAR//./_} + fi + eval "${INI_ALL_VARNAME}=\"\${${INI_ALL_VARNAME}# } ${VARNAME}\"" + + if [[ "${VAL}" =~ ^\".*\"$ ]] + then + # remove existing double quotes + VAL="${VAL##\"}" + VAL="${VAL%%\"}" + elif [[ "${VAL}" =~ ^\'.*\'$ ]] + then + # remove existing single quotes + VAL="${VAL##\'}" + VAL="${VAL%%\'}" + elif [ "$BOOLEANS" = 1 ] + then + # Value is not enclosed in quotes + # Booleans processing is switched on, check for special boolean + # values and convert + + # here we compare case insensitive because + # "shopt nocasematch" + case "$VAL" in + yes | true | on ) + VAL=1 + ;; + no | false | off ) + VAL=0 + ;; + esac + fi + + + # enclose the value in single quotes and escape any + # single quotes and backslashes that may be in the value + VAL="${VAL//\\/\\\\}" + VAL="\$'${VAL//\'/\'}'" + + eval "$VARNAME=$VAL" + done <"${INI_FILE}" + + # return also the number of parsed sections + eval "$INI_NUMSECTIONS_VARNAME=$SECTIONS_NUM" + + cleanup_bash +} diff --git a/install.sh b/install.sh index 3349dad..5bed66f 100755 --- a/install.sh +++ b/install.sh @@ -11,20 +11,21 @@ BINARY_DIR=/usr/bin INSTALL_DIR=/usr/share/love-release MANPAGE_DIR=/usr/share/man/man1 +SED_ARG=$(echo "$INSTALL_DIR" | sed -e 's/[\/&]/\\&/g') mkdir -p "$BINARY_DIR" cp ./love-release.sh "$BINARY_DIR"/love-release -SED_ARG=s/INSTALL_DIR=/INSTALL_DIR=${INSTALL_DIR//\//\\\/}/g -sed -i -e "$SED_ARG" "$BINARY_DIR"/love-release +sed -i -e "s/INSTALL_DIR=/INSTALL_DIR=$SED_ARG/g" "$BINARY_DIR"/love-release mkdir -p "$INSTALL_DIR" cp ./README.md "$INSTALL_DIR" +cp ./config.ini "$INSTALL_DIR" cp -r ./scripts "$INSTALL_DIR" cp -r ./include "$INSTALL_DIR" mkdir -p "$MANPAGE_DIR" cp love-release.1 "$MANPAGE_DIR"/love-release.1 -sed -i -e "s/scripts/${INSTALL_DIR//\//\\\/}\/scripts/g" "$MANPAGE_DIR"/love-release.1 -gzip -9 "$MANPAGE_DIR"/love-release.1 +sed -i -e "s/scripts/$SED_ARG\/scripts/g" -e "s/config.ini/$SED_ARG\/config.ini/g" "$MANPAGE_DIR"/love-release.1 +gzip -9 -f "$MANPAGE_DIR"/love-release.1 echo "Done !" diff --git a/love-release.1 b/love-release.1 index 6eef0e3..8c424e8 100644 --- a/love-release.1 +++ b/love-release.1 @@ -131,6 +131,11 @@ Set the version of your package. .B \-\-clean Clean the cache located in \fI~/.cache/love-release\fR. One can replace the Love files there. +.TP +.B \-\-config \fIfile\fR +Pass a configuration file as argument. +It describes which build you want to make, with what options. +See \fIconfig.ini\fR. .SH MODULES The script is modular. Each different platform is handled by a subscript stored in \fIscripts\fR. diff --git a/love-release.sh b/love-release.sh index 0cfbfbc..f188d68 100755 --- a/love-release.sh +++ b/love-release.sh @@ -78,8 +78,10 @@ LOVE_GT_090=$(float_test "$LOVE_VERSION_MAJOR >= 0.9") # Global variables ARGS=( "$@" ) -SCRIPT_ARGS="$SCRIPT_ARGS h; n: r: v: clean help" +SCRIPT_ARGS="$SCRIPT_ARGS h; n: r: v: config: clean help" SCRIPT_ARGS=$(printf '%s\n' $SCRIPT_ARGS | sort -u) +CONFIG=false +CONFIG_FILE=config.ini PROJECT_FILES= EXCLUDE_FILES=$(/bin/ls -A | grep "^[.]" | tr '\n' ' ') @@ -106,10 +108,40 @@ Options: $SHORT_HELP" -# Parsing options +# Read config missing_operands=true source "$INCLUDE_DIR"/getopt.sh while getoptex "$SCRIPT_ARGS" "$@" +do + if [ "$OPTOPT" = "config" ]; then + source "$INCLUDE_DIR"/read_ini.sh + missing_operands=false + CONFIG_FILE=$OPTARG + read_ini "$CONFIG_FILE" || exit 1 + CONFIG=true + SED_ARG=$(echo "$PLATFORMS_DIR" | sed -e 's/[\/&]/\\&/g') + PLATFORM_SCRIPTS=$(echo "${INI__ALL_SECTIONS}" | sed -r -e 's/[ ]*global[ ]*//g' -e "s/\<[^ ]+\>/$SED_ARG\/&.sh/g") + IFS=" " read -a PLATFORM_SCRIPTS <<< "$PLATFORM_SCRIPTS" + if [ -n "${INI__global__release_dir}" ]; then + RELEASE_DIR=${INI__global__release_dir} + fi + if [ -n "${INI__global__love_version}" ]; then + LOVE_VERSION=${INI__global__love_version} + LOVE_VERSION_MAJOR=$(echo "$LOVE_VERSION" | grep -Eo '^[0-9]+\.?[0-9]*') + LOVE_GT_080=$(float_test "$LOVE_VERSION_MAJOR >= 0.8") + LOVE_GT_090=$(float_test "$LOVE_VERSION_MAJOR >= 0.9") + fi + if [ -n "${INI__global__project_name}" ]; then + PROJECT_NAME=${INI__global__project_name} + fi + fi +done +unset OPTIND +unset OPTOFS + + +# Parsing options +while getoptex "$SCRIPT_ARGS" "$@" do if [ "$OPTOPT" = "h" ]; then echo "$SHORT_HELP" @@ -146,10 +178,15 @@ unset OPTOFS ## $1: Module name init_module () { + GLOBAL_OPTIND=$OPTIND + GLOBAL_OPTOFS=$OPTOFS unset OPTIND unset OPTOFS - MAIN_RELEASE_DIR="${RELEASE_DIR##/*/}" - RELEASE_DIR="$RELEASE_DIR"/$LOVE_VERSION + if [ -z "$MAIN_RELEASE_DIR" ]; then + MAIN_RELEASE_DIR=$(cd "$(dirname "$RELEASE_DIR")" && pwd)/$(basename "$RELEASE_DIR") + RELEASE_DIR="$MAIN_RELEASE_DIR"/$LOVE_VERSION + fi + missing_operands=false CACHE_DIR="$MAIN_CACHE_DIR"/$LOVE_VERSION mkdir -p "$RELEASE_DIR" "$CACHE_DIR" rm -rf "$RELEASE_DIR"/"$PROJECT_NAME".love 2> /dev/null @@ -162,9 +199,9 @@ create_love_file () cd "$PROJECT_DIR" rm -rf "$RELEASE_DIR"/"$PROJECT_NAME".love 2> /dev/null if [ -z "$PROJECT_FILES" ]; then - zip --filesync -$1 -r "$RELEASE_DIR"/"$PROJECT_NAME".love -x "$0" "$MAIN_RELEASE_DIR"/\* $EXCLUDE_FILES @ * + zip --filesync -$1 -r "$RELEASE_DIR"/"$PROJECT_NAME".love -x "$0" "${MAIN_RELEASE_DIR#$PWD/}/*" "$CONFIG_FILE" $EXCLUDE_FILES @ * else - zip --filesync -$1 -r "$RELEASE_DIR"/"$PROJECT_NAME".love -x "$0" "$MAIN_RELEASE_DIR"/\* $EXCLUDE_FILES @ $PROJECT_FILES + zip --filesync -$1 -r "$RELEASE_DIR"/"$PROJECT_NAME".love -x "$0" "${MAIN_RELEASE_DIR#$PWD/}/*" "$CONFIG_FILE" $EXCLUDE_FILES @ $PROJECT_FILES fi cd "$RELEASE_DIR" LOVE_FILE="$PROJECT_NAME".love @@ -175,13 +212,23 @@ create_love_file () exit_module () { if [ -z "$1" ] || [ "$1" = "0" ]; then + OPTIND=$GLOBAL_OPTIND + OPTOFS=$GLOBAL_OPTOFS echo "Done !" else echo -e "$2" + exit $1 fi - exit $1 } +if [ "$CONFIG" = true ]; then + for script in "${PLATFORM_SCRIPTS[@]}" + do + source "$script" + done + exit +fi + # Platform-specific scripts registration diff --git a/scripts/android.sh b/scripts/android.sh index a5067c0..dc0b543 100644 --- a/scripts/android.sh +++ b/scripts/android.sh @@ -2,6 +2,23 @@ init_module "Android" +# Configuration +if [ "$CONFIG" = true ]; then + if [ -n "${INI__android__activity}" ]; then + ACTIVITY=${INI__android__activity} + fi + if [ -n "${INI__android__package_name}" ]; then + PACKAGE_NAME=${INI__android__package_name} + fi + if [ -n "${INI__android__package_version}" ]; then + PACKAGE_VERSION=${INI__android__package_version} + fi + if [ -n "${INI__android__maintainer_name}" ]; then + MAINTAINER_NAME=${INI__android__maintainer_name} + fi +fi + + # Options activity_defined_argument=false package_name_defined_argument=false @@ -104,5 +121,6 @@ else fi +unset ACTIVITY PACKAGE_NAME PACKAGE_VERSION MAINTAINER_NAME exit_module diff --git a/scripts/debian.sh b/scripts/debian.sh index 7018b1a..d29b8e4 100644 --- a/scripts/debian.sh +++ b/scripts/debian.sh @@ -1,6 +1,28 @@ # Debian package init_module "Debian" +# Configuration +if [ "$CONFIG" = true ]; then + if [ -n "${INI__debian__package_version}" ]; then + PACKAGE_VERSION=${INI__debian__package_version} + fi + if [ -n "${INI__debian__homepage}" ]; then + PROJECT_HOMEPAGE=${INI__debian__homepage} + fi + if [ -n "${INI__debian__description}" ]; then + PROJECT_DESCRIPTION=${INI__debian__description} + fi + if [ -n "${INI__debian__maintainer_name}" ]; then + MAINTAINER_NAME=${INI__debian__maintainer_name} + fi + if [ -n "${INI__debian__maintainer_email}" ]; then + MAINTAINER_EMAIL=${INI__debian__maintainer_email} + fi + if [ -n "${INI__android__package_name}" ]; then + PACKAGE_NAME=${INI__debian__package_name} + fi +fi + # Options package_name_defined_argument=false @@ -111,5 +133,6 @@ cd "$RELEASE_DIR" rm -rf $TEMP +unset PROJECT_DESCRIPTION PROJECT_HOMEPAGE MAINTAINER_NAME MAINTAINER_EMAIL PACKAGE_NAME PACKAGE_VERSION exit_module diff --git a/scripts/example.sh b/scripts/example.sh index c89e6dc..f2e88a5 100644 --- a/scripts/example.sh +++ b/scripts/example.sh @@ -12,6 +12,8 @@ # To create a new module, you have to create a file in this directory, # and to edit the main love-release script. # If you wish to submit a new module, please also edit README.md and love-release.1 +# You could add configuration options in config.ini too, +# but the name of the section must be the same as the name of the script. # Love-release script @@ -31,7 +33,7 @@ SHORT_HELP=" -q Create an Example application" while getoptex "$SCRIPT_ARGS" "$@" do if [ "$OPTOPT" = "q" ]; then - source "$PLATFORMS_DIR"/love.sh + source "$PLATFORMS_DIR"/example.sh fi done @@ -52,7 +54,21 @@ done ### $1: Module name init_module "Example" -## 2. Parse the options +## 2. Read the configuration +# Syntax is ${INI__section__variable} +if [ "$CONFIG" = true ]; then + if [ -n "${INI__q__wer}" ]; then + WER=${INI__q__wer} + fi + if [ -n "${INI__q__ty}" ]; then + TY=${INI_q_ty} + fi + if [ -n "${INI__q__uiop}" ]; then + UIOP=true + fi +fi + +## 3. Parse the options # $OPTOPT holds the option and $OPTARG holds the eventual argument passed to it. while getoptex "$SCRIPT_ARGS" "$@" do @@ -65,13 +81,18 @@ do fi done -## 3. Create the love file +## 4. Create the love file ### $1: Compression level 0-9 create_love_file 9 -## 4. Write your code -## 5. Exit the module +## 5. Write your code + + +## 6. Unset every variable passed by configuration or command-line +unset WER TY UIOP + +## 7. Exit the module ### $1: exit code. 0 - success, other - failure ### $2: error message exit_module diff --git a/scripts/macosx.sh b/scripts/macosx.sh index 98ebbcc..603bce8 100644 --- a/scripts/macosx.sh +++ b/scripts/macosx.sh @@ -2,6 +2,17 @@ init_module "Mac OS X" +# Configuration +if [ "$CONFIG" = true ]; then + if [ -n "${INI__macosx__maintainer_name}" ]; then + MAINTAINER_NAME=${INI__macosx__maintainer_name} + fi + if [ -n "${INI__macosx__icon}" ]; then + PROJECT_ICNS=${INI__macosx__icon} + fi +fi + + # Options while getoptex "$SCRIPT_ARGS" "$@" do @@ -137,5 +148,6 @@ else fi +unset PROJECT_ICNS exit_module diff --git a/scripts/windows.sh b/scripts/windows.sh index bbbbdfe..eba9822 100644 --- a/scripts/windows.sh +++ b/scripts/windows.sh @@ -2,6 +2,16 @@ init_module "Windows" +# Configuration +if [ "$CONFIG" = true ]; then + RELEASE_WIN_32=true + RELEASE_WIN_64=true + if [ -n "${INI__windows__icon}" ]; then + PROJECT_ICO=${INI__windows__icon} + fi +fi + + # Options while getoptex "$SCRIPT_ARGS" "$@" do @@ -80,10 +90,10 @@ if [ "$RELEASE_WIN_64" = true ] && [ "$LOVE_GT_080" = true ]; then cp "$CACHE_DIR"/love-$LOVE_VERSION-win-x64.zip ./love-$LOVE_VERSION-win64.zip fi fi - + unzip -qq love-$LOVE_VERSION-win64.zip rm -rf "$PROJECT_NAME"-win64.zip 2> /dev/null - + if [ "$FOUND_WINE" = true ] && [ -n "$PROJECT_ICO" ]; then WINEPREFIX="$WINEPREFIX" wine "$RESHACKER" -addoverwrite "love-$LOVE_VERSION-win32/love.exe,love-$LOVE_VERSION-win32/love.exe,"$PROJECT_ICO",ICONGROUP,MAINICON,0" 2> /dev/null fi @@ -95,5 +105,6 @@ if [ "$RELEASE_WIN_64" = true ] && [ "$LOVE_GT_080" = true ]; then fi +unset PROJECT_ICO exit_module