From 128a1a67936855798668a5de26d97c8c4269d595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Sat, 27 Sep 2014 17:32:07 +0200 Subject: [PATCH] Add Windows installer with Inno Setup ! --- README.md | 15 +++- completion.sh | 2 +- config.ini | 20 +++++ love-release.1 | 23 ++++++ love-release.sh | 2 +- scripts/assets/innosetup.iss | 41 ++++++++++ scripts/debian.sh | 1 - scripts/windows.sh | 142 +++++++++++++++++++++++++++++++---- 8 files changed, 226 insertions(+), 20 deletions(-) create mode 100644 scripts/assets/innosetup.iss diff --git a/README.md b/README.md index b556d49..49f56ef 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,20 @@ it will automatically detect which version your project uses. `--homepage` Set the homepage of your project. #### WINDOWS -`--win-icon` Path to an ico file to use. +You can create an installer. If you don’t, you will have zip of a folder +containing your game executable and its dlls. +Creating installers and using icons require [Wine](http://www.winehq.org/) to be installed. +`--win-icon` Path to an ico file to use. +`--win-installer` Create an installer with [Inno Setup](http://www.jrsoftware.org/isinfo.php). +`--win-appid` Your game ID. You can use a GUID/UUID and generate one with `uuidgen`. + It should remain the same between updates. + Mandatory if using an installer, not needed for a simple zip. +`--win-maintainer-name` Set the maintainer’s name. + Mandatory if using an installer, not needed for a simple zip. +`--win-package-name` + Mandatory if using an installer, not needed for a simple zip. +`--win-package-version` Set the version of your package. + Mandatory if using an installer, not needed for a simple zip. #### MAC OS X `--osx-icon` Path to an icns file to use. diff --git a/completion.sh b/completion.sh index e130a8a..297d3d9 100644 --- a/completion.sh +++ b/completion.sh @@ -7,7 +7,7 @@ _love-release() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" opts="-l" - opts="$opts -w --win-icon" + opts="$opts -w --win-icon --win-package-version --win-maintainer-name --win-package-name --win-appid --win-installer" opts="$opts -d --deb-icon --deb-package-version --deb-maintainer-name --maintainer-email --deb-package-name" opts="$opts -a --apk-icon --apk-activity --apk-package-version --apk-maintainer-name --apk-package-name --update-android" opts="$opts -m --osx-icon --osx-maintainer-name" diff --git a/config.ini b/config.ini index 005e681..b9a177c 100644 --- a/config.ini +++ b/config.ini @@ -19,10 +19,28 @@ homepage="" ; Description description="" + [windows] ; Path to an .ico file to use icon="" +; Create an installer rather than a zip +installer="false" + +; Package name +; No spaces and no special characters except underscore. Better be lowercase. +package_name="" + +; Version of the package +package_version="" + +; Maintainer name (full name) +maintainer_name="" + +; App id. Typically a GUID +appid="" + + [macosx] ; Set the maintainer's name. Provide it for CFBundleIdentifier. ; No spaces and no special characters except underscore. Better be lowercase. @@ -31,6 +49,7 @@ maintainer_name="" ; Path to an .icns file to use icon="" + [debian] ; Version of the package package_version="" @@ -51,6 +70,7 @@ package_name="" ; SVG files are recognized if suffixed with .svg icon="" + [android] ; Android game activity ; No spaces and no special characters except underscore. Better be lowercase. diff --git a/love-release.1 b/love-release.1 index f16e8cc..5b306cf 100644 --- a/love-release.1 +++ b/love-release.1 @@ -85,9 +85,32 @@ Set the description of your project. .B \-\-homepage \fIurl\fR Set the homepage of your project. .SH WINDOWS +You can create an installer. If you don’t, you will have zip of a folder +containing your game executable and its dlls. +Creating installers and using icons require Wine to be installed. .TP .B \-\-win\-icon \fIicon\fR Path to an ico file to use. +.TP +.B \-\-win\-installer +Create an installer with Inno Setup. +.TP +.B \-\-win\-appid \fIid\fR +Your game ID. You can use a GUID/UUID and generate one with \fIuuigen\fR. +It should remain the same between updates. +Mandatory if using an installer, not needed for a simple zip. +.TP +.B \-\-win\-maintainer\-name \fIname\fR +Set the maintainer’s name. +Mandatory if using an installer, not needed for a simple zip. +.TP +.B \-\-win\-package\-name \fIname\fR +Set the name of the package. +Mandatory if using an installer, not needed for a simple zip. +.TP +.B \-\-win\-package\-version \fIversion\fR +Set the version of your package. +Mandatory if using an installer, not needed for a simple zip. .SH MAC OS X .TP .B \-\-osx\-icon \fIicon\fR diff --git a/love-release.sh b/love-release.sh index 583fff4..8fb63c0 100755 --- a/love-release.sh +++ b/love-release.sh @@ -17,7 +17,7 @@ LOVE_VERSION=0.9.1 SCRIPT_ARGS="l;" ## Windows -SCRIPT_ARGS="w. win-icon: $SCRIPT_ARGS" +SCRIPT_ARGS="w. win-icon: win-package-version: win-maintainer-name: win-package-name: win-appid: win-installer; $SCRIPT_ARGS" ## Debian SCRIPT_ARGS="d; deb-icon: deb-package-version: deb-maintainer-name: maintainer-email: deb-package-name: $SCRIPT_ARGS" diff --git a/scripts/assets/innosetup.iss b/scripts/assets/innosetup.iss new file mode 100644 index 0000000..b29aa41 --- /dev/null +++ b/scripts/assets/innosetup.iss @@ -0,0 +1,41 @@ +#define MyAppName "" +#define MyAppVersion "" +#define MyAppPublisher "" +#define MyAppURL "" +#define MyAppExeName "" + +[Setup] +;ArchitecturesInstallIn64BitMode=x64 ia64 +AppId={{} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +;AppVerName={#MyAppName} {#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#MyAppURL} +AppUpdatesURL={#MyAppURL} +DefaultDirName={pf}\{#MyAppName} +DefaultGroupName={#MyAppName} +AllowNoIcons=yes +OutputBaseFilename= +SetupIconFile= +Compression=lzma +SolidCompression=yes + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" +Name: "french"; MessagesFile: "compiler:Languages\French.isl" +Name: "german"; MessagesFile: "compiler:Languages\German.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + +[Icons] +Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" +Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" +Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon + +[Run] +Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent + +[Files] diff --git a/scripts/debian.sh b/scripts/debian.sh index af67b41..46975c8 100644 --- a/scripts/debian.sh +++ b/scripts/debian.sh @@ -35,7 +35,6 @@ do MAINTAINER_EMAIL=$OPTARG elif [ "$OPTOPT" = "deb-package-name" ]; then PACKAGE_NAME=$OPTARG - package_name_defined_argument=true elif [ "$OPTOPT" = "deb-icon" ]; then ICON_DIR=$OPTARG fi diff --git a/scripts/windows.sh b/scripts/windows.sh index 1e175b9..c33dd3c 100644 --- a/scripts/windows.sh +++ b/scripts/windows.sh @@ -2,6 +2,8 @@ init_module "Windows" +PACKAGE_NAME=$(echo $PROJECT_NAME | sed -e 's/[^-a-zA-Z0-9_]/-/g' | tr '[:upper:]' '[:lower:]') + # Configuration if [ "$CONFIG" = true ]; then RELEASE_WIN_32=true @@ -9,6 +11,21 @@ if [ "$CONFIG" = true ]; then if [ -n "${INI__windows__icon}" ]; then PROJECT_ICO=${INI__windows__icon} fi + if [ "${INI__windows__installer}" = true ]; then + INSTALLER=true + fi + if [ -n "${INI__windows__package_version}" ]; then + PACKAGE_VERSION=${INI__debian__package_version} + fi + if [ -n "${INI__windows__maintainer_name}" ]; then + MAINTAINER_NAME=${INI__debian__maintainer_name} + fi + if [ -n "${INI__windows__package_name}" ]; then + PACKAGE_NAME=${INI__debian__package_name} + fi + if [ -n "${INI__windows__appid}" ]; then + APPID=${INI__windows__appid} + fi fi @@ -17,22 +34,101 @@ while getoptex "$SCRIPT_ARGS" "$@" do if [ "$OPTOPT" = "win-icon" ]; then PROJECT_ICO=$OPTARG + elif [ "$OPTOPT" = "win-installer" ]; then + INSTALLER=true + elif [ "$OPTOPT" = "win-package-version" ]; then + PACKAGE_VERSION=$OPTARG + elif [ "$OPTOPT" = "win-maintainer-name" ]; then + MAINTAINER_NAME=$OPTARG + elif [ "$OPTOPT" = "win-package-name" ]; then + PACKAGE_NAME=$OPTARG + elif [ "$OPTOPT" = "win-appid" ]; then + APPID=$OPTARG fi done + # Wine FOUND_WINE=true command -v wine >/dev/null 2>&1 || { FOUND_WINE=false; } -if [ "$FOUND_WINE" = true ] && [ -n "$PROJECT_ICO" ]; then +if [ "$FOUND_WINE" = true ]; then WINEPREFIX="$MAIN_CACHE_DIR"/wine mkdir -p "$WINEPREFIX"/drive_c - RESHACKER="$WINEPREFIX"/drive_c/"Program Files (x86)"/"Resource Hacker"/ResHacker.exe - if [ -f "$RESHACKER" ]; then - : - else - curl -L -C - -o "$WINEPREFIX"/drive_c/reshack_setup.exe http://www.angusj.com/resourcehacker/reshack_setup.exe - WINEPREFIX="$WINEPREFIX" wine "$WINEPREFIX/drive_c/reshack_setup.exe" + if [ -n "$PROJECT_ICO" ]; then + RESHACKER="$WINEPREFIX"/drive_c/"Program Files (x86)"/"Resource Hacker"/ResHacker.exe + if [ ! -f "$RESHACKER" ]; then + curl -L -C - -o "$WINEPREFIX"/drive_c/reshack_setup.exe http://www.angusj.com/resourcehacker/reshack_setup.exe + WINEPREFIX="$WINEPREFIX" wine "$WINEPREFIX/drive_c/reshack_setup.exe" + fi fi + if [ "$INSTALLER" = true ]; then + INNOSETUP="$WINEPREFIX"/drive_c/"Program Files (x86)"/"Inno Setup 5"/ISCC.exe + if [ ! -f "$INNOSETUP" ]; then + curl -L -C - -o "$WINEPREFIX"/drive_c/is-unicode.exe http://www.jrsoftware.org/download.php/is-unicode.exe + WINEPREFIX="$WINEPREFIX" wine "$WINEPREFIX/drive_c/is-unicode.exe" + fi + fi +else + unset PROJECT_ICO INSTALLER +fi + +# Inno Setup +# $1: Path to game exe directory +# $2: true if 64 bits release +create_installer () { + ln -s "$RELEASE_DIR"/"$1" "$WINEPREFIX"/drive_c/game + if [ -n "$PROJECT_ICO" ]; then + ln -s "$RELEASE_DIR"/"$PROJECT_ICO" "$WINEPREFIX"/drive_c/game.ico + else + ln -s "$RELEASE_DIR"/"$1"/game.ico "$WINEPREFIX"/drive_c/game.ico + fi + + sed -e "s/#define MyAppName \"\"/#define MyAppName \"$PROJECT_NAME\"/" \ + -e "s/#define MyAppVersion \"\"/#define MyAppVersion \"$PACKAGE_VERSION\"/" \ + -e "s/#define MyAppPublisher \"\"/#define MyAppPublisher \"$MAINTAINER_NAME\"/" \ + -e "s/#define MyAppURL \"\"/#define MyAppURL \"$HOMEPAGE\"/" \ + -e "s/#define MyAppExeName \"\"/#define MyAppExeName \"${PROJECT_NAME}.exe\"/" \ + -e "s/AppId={{}/AppId={{$APPID}/" \ + -e "s/OutputBaseFilename=/OutputBaseFilename=${PACKAGE_NAME}-setup/" \ + -e 's/SetupIconFile=/SetupIconFile=C:\\game.ico/' \ + "$PLATFORMS_DIR"/assets/innosetup.iss > "$WINEPREFIX"/drive_c/innosetup.iss + if [ "$2" = true ]; then + sed -i 's/;ArchitecturesInstallIn64BitMode/ArchitecturesInstallIn64BitMode/' \ + "$WINEPREFIX"/drive_c/innosetup.iss + fi + + for file in $(ls -AC1 "$1"); do + echo "Source: \"C:\\game\\$file\"; DestDir: \"{app}\"; Flags: ignoreversion" \ + >> "$WINEPREFIX"/drive_c/innosetup.iss + done + + WINEPREFIX="$WINEPREFIX" wine "$INNOSETUP" /Q 'c:\innosetup.iss' + mv "$WINEPREFIX"/drive_c/Output/"$PACKAGE_NAME"-setup.exe . + rm -rf "$WINEPREFIX"/drive_c/{game,game.ico,innosetup.iss,Output} +} + +# Missing commands +MISSING_INFO=0 +ERROR_MSG="Could not build Windows installer." +if [ -z "$PACKAGE_VERSION" ] && [ "$INSTALLER" = true ]; then + MISSING_INFO=1 + ERROR_MSG="$ERROR_MSG\nMissing project's version. Use --win-package-version." +fi +if [ -z "$PROJECT_HOMEPAGE" ] && [ "$INSTALLER" = true ]; then + MISSING_INFO=1 + ERROR_MSG="$ERROR_MSG\nMissing project's homepage. Use --homepage." +fi +if [ -z "$MAINTAINER_NAME" ] && [ "$INSTALLER" = true ]; then + MISSING_INFO=1 + ERROR_MSG="$ERROR_MSG\nMissing maintainer's name. Use --win-maintainer-name." +fi +if [ -z "$APPID" ] && [ "$INSTALLER" = true ]; then + MISSING_INFO=1 + ERROR_MSG="$ERROR_MSG\nMissing application GUID. Use --win-appid." +fi + +if [ "$MISSING_INFO" -eq 1 ]; then + exit_module "$MISSING_INFO" "$ERROR_MSG" fi @@ -59,16 +155,23 @@ if [ "$RELEASE_WIN_32" = true ]; then fi unzip -qq love-$LOVE_VERSION-win32.zip - rm -rf "$PROJECT_NAME"-win32.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 + if [ -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 cat love-$LOVE_VERSION-win32/love.exe "$LOVE_FILE" > love-$LOVE_VERSION-win32/"$PROJECT_NAME".exe rm love-$LOVE_VERSION-win32/love.exe mv love-$LOVE_VERSION-win32 "$PROJECT_NAME"-win32 - zip -9 -qr "$PROJECT_NAME"-win32.zip "$PROJECT_NAME"-win32 + if [ "$INSTALLER" = true ]; then + rm -rf "$PACKAGE_NAME"-setup-win32.exe 2> /dev/null + create_installer "$PROJECT_NAME-win32" + mv "$PACKAGE_NAME"-setup.exe "$PACKAGE_NAME"-setup-win32.exe + else + rm -rf "$PROJECT_NAME"-win32.zip 2> /dev/null + zip -9 -qr "$PROJECT_NAME"-win32.zip "$PROJECT_NAME"-win32 + fi rm -rf love-$LOVE_VERSION-win32.zip "$PROJECT_NAME"-win32 fi @@ -92,20 +195,27 @@ if [ "$RELEASE_WIN_64" = true ] && [ "$LOVE_GT_080" = true ]; then 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-win64/love.exe,love-$LOVE_VERSION-win64/love.exe,"$PROJECT_ICO",ICONGROUP,MAINICON,0" 2> /dev/null + if [ -n "$PROJECT_ICO" ]; then + WINEPREFIX="$WINEPREFIX" wine "$RESHACKER" \ + -addoverwrite "love-$LOVE_VERSION-win64/love.exe,love-$LOVE_VERSION-win64/love.exe,"$PROJECT_ICO",ICONGROUP,MAINICON,0" 2> /dev/null fi cat love-$LOVE_VERSION-win64/love.exe "$LOVE_FILE" > love-$LOVE_VERSION-win64/"$PROJECT_NAME".exe rm love-$LOVE_VERSION-win64/love.exe mv love-$LOVE_VERSION-win64 "$PROJECT_NAME"-win64 - zip -9 -qr "$PROJECT_NAME"-win64.zip "$PROJECT_NAME"-win64 + if [ "$INSTALLER" = true ]; then + rm -rf "$PACKAGE_NAME"-setup-win64.exe 2> /dev/null + create_installer "$PROJECT_NAME-win64" "true" + mv "$PACKAGE_NAME"-setup.exe "$PACKAGE_NAME"-setup-win64.exe + else + rm -rf "$PROJECT_NAME"-win64.zip 2> /dev/null + zip -9 -qr "$PROJECT_NAME"-win64.zip "$PROJECT_NAME"-win64 + fi rm -rf love-$LOVE_VERSION-win64.zip "$PROJECT_NAME"-win64 fi -unset PROJECT_ICO +unset PROJECT_ICO APPID INSTALLER PACKAGE_NAME PACKAGE_VERSION MAINTAINER_NAME exit_module