#!/bin/bash # Creates a new blank OPSI package with install and remove scripts function usage { echo "Usage:" echo " $0 " echo "" echo "Optional parameters:" echo " -d Adds a description to the package" echo " -n Adds a product name instead of autogenerating one" echo " -g yes Adds the Gruelag prefix to package ID and name, do not manually add Gruelag when using this!" echo " -u Downloads an installer file from the specified URL" echo " -i Applies a logo to the package from the specified URL" echo " -t Sets the type of package to create, see below" echo " -v Sets the version of the program (not the package)" echo "" echo "Package types:" echo " winbatch Creates a blank WinBatch package" echo " winbatch-inno Creates a blank INNO Installer WinBatch package" echo " winbatch-nsis Creates a blank NSIS Installer WinBatch package" echo " dosicon Creates a blank DosInAnIcon package" echo " execps Creates a blank ExecWith Powershell package" echo " zip Creates a blank ZIP based package" echo " msi Creates a blank MSI installer package" echo " weblinks Creates a weblink creator package" echo "" echo "Parameters for 'zip' type package:" echo " -e Optional, specifies the launcher executable inside the ZIP file" echo "" echo "Parameters for 'weblinks' type package:" echo " -l ;;[] Can be used multiple times, specifies the URL and display name for one web link." echo " is optional and can hold one of the following values:" echo " 'desktop' to create only desktop links on the public user desktop" echo " 'startmenu' to create links only in the public user start menu" echo " 'both' to create links at both places, this is the default" } if [[ "$1" = "" ]]; then echo "Please specify the package name as first parameter." usage exit 1 else if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then usage exit 0 else productId="$1" shift fi fi # Defaults programVersion="1.0" pkgType="default" weblinks=() # Read command flags while getopts ":d:g:n:t:e:u:i:v:l:h:" flag do case "${flag}" in d) productDescription="${OPTARG}";; g) productIdPrefix="gruelag-" && productNamePrefix="Gruelag ";; n) productName=${OPTARG};; t) pkgType=${OPTARG};; e) zipExecutable="${OPTARG}";; u) downloadUrl="${OPTARG}";; i) imageUrl="${OPTARG}";; v) programVersion="${OPTARG}";; l) weblinks+=("${OPTARG}");; *) echo "Unrecognized option '${flag}'" h) usage exit 0 ;; esac done # Test if product ID was supplied empty if [ "${productId}" = "" ]; then echo "Product ID is empty, aborting!" exit 1 fi fullProductName="${productName}" # Generate product name from ID if it is not set already if [ "${productName}" = "" ]; then # Replace dashes with spaces and uppercase first letter of every word productName=$(echo "${productId//-/ }" | sed -r 's/\<./\U&/g') fi # Prepend optional prefixes to product name and ID if they aren't already if [ "${productIdPrefix}" != "" ] && \ [ "${productId:0:${#productIdPrefix}}" != "${productIdPrefix}" ]; then productId="${productIdPrefix}${productId}" fullProductName="${productNamePrefix}${productName}" fi # Dump some package info echo "-- Package info --" echo "ID: ${productId}" echo "Name: ${fullProductName}" echo "Description: ${productDescription}" echo "Type: ${pkgType}" echo "-- --" echo "" echo "Creating package directory..." if [ -d "${productId}" ]; then echo "A folder with the package name already exists" exit 1 elif ! mkdir "${productId}"; then echo "Could not create the package directory" exit 1 fi pushd "${productId}" >/dev/null echo "Creating control file..." cat >control </dev/null _filename=$(curl -Lfsw "%{filename_effective}" -O "${downloadUrl}") if [ $? -ne 0 ]; then echo "Curl failed to download the file from ${downloadUrl}" else bytes=$(wc -c "${_filename}" | awk '{ print $1 }') if [ ${bytes} -le 1 ]; then echo "Program file was downloaded, but is ${bytes} bytes in size!" else echo "Program file downloaded to data/${_filename}, ${bytes} bytes in size" filename="${_filename}" fi fi popd >/dev/null fi # Some reusable code snippets as variables: read -r -d '' Sub_HandleExitCode <install.ins <<-EOF [Initial] Message=Installiere ${productName}... DefVar \$ExitCode\$ [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" WinBatch_Install Sub_HandleExitCode [WinBatch_Install] "%ScriptPath%\\data\\${_instFile}" /S ${Sub_HandleExitCode} EOF cat >remove.ins <<-EOF [Initial] Message=Entferne ${productName}... DefVar \$ExitCode\$ DefVar \$InstallPath\$ DefVar \$UninsFile\$ [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" Sub_SetVars Files_CopyUninstallerToTemp WinBatch_Uninstall Sub_HandleExitCode Files_RemoveTempUninstaller [Sub_SetVars] Set \$InstallPath\$ = "%ProgramFilesDir%\\${productName}" Set \$UninsFile\$ = "unins000.exe" [Files_CopyUninstallerToTemp] Copy "\$InstallPath\$\\\$UninsFile\$" "%opsiTmpDir%" [WinBatch_Uninstall] "%opsiTmpDir%\\\$UninsFile\$" /S _?=\$InstallPath\$ [Files_RemoveTempUninstaller] Delete "%opsiTmpDir%\\\$UninsFile\$" ${Sub_HandleExitCode} EOF echo "Remember to change the path and uninstaller file name in remove.ins!" ;; winbatch-inno) if [ "${filename}" = "" ]; then _instFile="setup.exe" else _instFile="${filename}" fi cat >install.ins <<-EOF [Initial] Message=Installiere ${productName}... DefVar \$ExitCode\$ [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" WinBatch_Install Sub_HandleExitCode [WinBatch_Install] "%ScriptPath%\\data\\${_instFile}" /SILENT /NOCANCEL /NORESTART /FORCECLOSEAPPLICATIONS /NORESTARTAPPLICATIONS ${Sub_HandleExitCode} EOF cat >remove.ins <<-EOF [Initial] Message=Entferne ${productName}... DefVar \$ExitCode\$ DefVar \$UninstallPath\$ [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" WinBatch_Uninstall Sub_HandleExitCode [WinBatch_Uninstall] "%ProgramFilesDir%\\${productName}\\unins000.exe" /SILENT ${Sub_HandleExitCode} EOF echo "Remember to change the uninstaller path in remove.ins!" ;; winbatch) if [ "${filename}" = "" ]; then _instFile="setup.exe" else _instFile="${filename}" fi cat >install.ins <<-EOF [Initial] Message=Installiere ${productName}... DefVar \$ExitCode\$ [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" WinBatch_Install Sub_HandleExitCode [WinBatch_Install] "%ScriptPath%\\data\\${_instFile}" /S ${Sub_HandleExitCode} EOF cat >remove.ins <<-EOF [Initial] Message=Entferne ${productName}... DefVar \$ExitCode\$ [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" WinBatch_Remove Sub_HandleExitCode [WinBatch_Remove] "uninstall-exe-path-here" /S ${Sub_HandleExitCode} EOF echo "Remember to customize the executable paths in install.ins and remove.ins!" ;; dosicon) if [ "${filename}" = "" ]; then _instCommand="your-setup-command-here" else _instCommand="%ScriptPath%\\data\\${filename}" fi cat >install.ins <<-EOF [Initial] Message=Installiere ${productName}... DefVar \$ExitCode\$ [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" WinBatch_Install Sub_HandleExitCode [DosInAnIcon_Install] @echo off ${_instCommand} ${Sub_HandleExitCode} EOF cat >remove.ins <<-EOF [Initial] Message=Entferne ${productName}... DefVar \$ExitCode\$ [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" DosInAnIcon_Remove Sub_HandleExitCode [DosInAnIcon_Remove] @echo off your-uninstall-command-here ${Sub_HandleExitCode} EOF echo "Remember to customize the DosInAnIcon commands in install.ins and remove.ins!" ;; execps) if [ "${filename}" = "" ]; then _instCommand="your-setup-command-here" else _instCommand="%ScriptPath%\\data\\${filename}" fi cat >install.ins <<-EOF [Initial] Message=Installiere ${productName}... DefVar \$ExitCode\$ [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" ExecWith_Install "powershell.exe" -ExecutionPolicy Bypass Sub_HandleExitCode [ExecWith_Install] trap { "PS Error: \$_"; exit 1 } ${_instCommand} if(-not (\$?)) { exit 1 } ${Sub_HandleExitCode} EOF cat >remove.ins <<-EOF [Initial] Message=Entferne ${productName}... DefVar \$ExitCode\$ [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" ExecWith_Remove "powershell.exe" -ExecutionPolicy Bypass Sub_HandleExitCode [ExecWith_Remove] trap { "PS Error: $_"; exit 1 } your-uninstall-command-here if(-not (\$?)) { exit 1 } ${Sub_HandleExitCode} EOF echo "Remember to customize the PowerShell commands in install.ins and remove.ins!" ;; zip) if [ "${filename}" = "" ]; then _zipFile="${productId}.zip" else _zipFile="${filename}" fi if [ "${zipExecutable}" = "" ]; then _zipExe="start.exe" else _zipExec="${zipExecutable}" fi cat >install.ins <<-EOF [Initial] Message=Installiere ${productName}... [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" Sub "%ScriptPath%\\remove.inc.ins" Files_UnzipPackage LinkFolder_StartMenuEntry [Files_UnzipPackage] CheckTargetPath = "%ProgramFilesDir%\\${productId}" UnzipFile "%ScriptPath%\\data\\${_zipFile}" "%ProgramFilesDir%\\${productId}" [LinkFolder_StartMenuEntry] Set_BaseFolder Common_Programs Set_SubFolder "${productName}" Set_Link name: ${productName} target: "%ProgramFilesDir%\\${productId}\\${_zipExe}" parameters: working_dir: "%ProgramFilesDir%\\${productId}" icon_file: "%ProgramFilesDir%\\${productId}\\${_zipExe}" icon_index: 0 shortcut: End_Link EOF cat >remove.ins <<-EOF [Initial] Message=Entferne ${productName}... [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" Sub "%ScriptPath%\remove.inc.ins" EOF cat >remove.inc.ins <<-EOF Files_RemoveProgramFolder LinkFolder_RemoveStartMenuEntry [Files_RemoveProgramFolder] Del -sf "%ProgramFilesDir%\\${productId}" [LinkFolder_RemoveStartMenuEntry] Set_BaseFolder Common_Programs Delete_Subfolder "${productName}" EOF echo "Make sure the names and paths in install.ins and remove.inc.ins are correct!" ;; msi) if [ "${filename}" = "" ]; then _instFile="setup.msi" else _instFile="${filename}" fi cat >install.ins <<-EOF [Initial] Message=Installiere ${productName}... DefVar \$ExitCode\$ [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" WinBatch_Install Sub_HandleExitCode_MSI [WinBatch_Install] msiexec /passive /i "%ScriptPath%\\data\\${_instFile}" ${Sub_HandleExitCode_MSI} EOF cat >remove.ins <<-EOF [Initial] Message=Entferne ${productName}... DefVar \$ExitCode\$ [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" WinBatch_Remove Sub_HandleExitCode [WinBatch_Remove] "%ScriptDrive%\\tools\\autoit\\msiRemove_withLog.exe" "${productName}" ${Sub_HandleExitCode_MSI} EOF echo "Make sure the WinBatch_Remove section in remove.ins does the right things!" ;; weblinks) cat >install.ins <<-EOF [Initial] Message=Installiere ${productName}... DefVar \$PkgDir\$ [Actions] ShowBitmap "%ScriptPath%\logo.png" "${productName}" Sub_SetVars Files_CopyIcons Sub "%ScriptPath%\install-desktop.inc.ins" Sub "%ScriptPath%\install-startmenu.inc.ins" [Sub_SetVars] Set \$PkgDir\$ = "%ProgramFilesDir%\%installingProdName%" [Files_CopyIcons] CheckTargetPath = "\$PkgDir\$" Copy -s "%ScriptPath%\data\icons\" "\$PkgDir\$" EOF cat >remove.ins <<-EOF [Initial] Message=Entferne ${productName}... DefVar $PkgDir$ [Actions] ShowBitmap "%ScriptPath%\logo.png" "${productName}" Sub_SetVars Files_DeleteIcons Sub "%ScriptPath%\remove-desktop.inc.ins" Sub "%ScriptPath%\remove-startmenu.inc.ins" [Sub_SetVars] Set \$PkgDir\$ = "%ProgramFilesDir%\%installingProdName%" [Files_DeleteIcons] Del -s -f "\$PkgDir\$" EOF source ../fetch-favicon.sh mkdir -p data/icons desktopLinkFolderList=$(mktemp) startMenuLinkFolderList=$(mktemp) desktopRemoveFolderList=$(mktemp) startMenuRemoveFolderList=$(mktemp) for (( i = 0; i < ${#weblinks[@]}; i++ )); do link=${weblinks[${i}]} linkName=$(echo "${link}" | awk -F';' '{ print $1 }') linkInternalName=$(sed "s/[^a-zA-Z-]/_/g" <<< ${linkName}) linkTarget=$(echo "${link}" | awk -F';' '{ print $2 }') linkLocation=$(echo "${link}" | awk -F';' '{ print $3 }') # Desktop entries if [ "${linkLocation}" = "desktop" ] || [ "${linkLocation}" = "both" ]; then echo "LinkFolder_Desktop_${linkInternalName}" >> "install-desktop.inc.ins" echo "LinkFolder_Remove_Desktop_${linkInternalName}" >> "remove-desktop.inc.ins" cat >>"${desktopLinkFolderList}" <>"${desktopRemoveFolderList}" <<-EOP [LinkFolder_Remove_Desktop_${linkInternalName}] Set_BaseFolder Common_DesktopDirectory Set_SubFolder "" Delete_Element "${linkName}" EOP fi # Start menu entries if [ "${linkLocation}" = "startmenu" ] || [ "${linkLocation}" = "both" ]; then echo "LinkFolder_StartMenu_${linkInternalName}" >> "install-startmenu.inc.ins" echo "LinkFolder_Remove_StartMenu_${linkInternalName}" >> "remove-startmenu.inc.ins" cat >>"${startMenuLinkFolderList}" <>"${startMenuRemoveFolderList}" <<-EOP [LinkFolder_Remove_StartMenu_${linkInternalName}] Set_BaseFolder Common_StartMenu Set_SubFolder "" Delete_Element "${linkName}" EOP fi fetchFavicon "${linkTarget}" "data/icons/${linkInternalName}.ico" done echo >> "install-desktop.inc.ins" cat "${desktopLinkFolderList}" >> "install-desktop.inc.ins" echo >> "install-startmenu.inc.ins" cat "${startMenuLinkFolderList}" >> "install-startmenu.inc.ins" echo >> "remove-desktop.inc.ins" cat "${desktopRemoveFolderList}" >> "remove-desktop.inc.ins" echo >> "remove-startmenu.inc.ins" cat "${startMenuRemoveFolderList}" >> "remove-startmenu.inc.ins" rm "${desktopLinkFolderList}" rm "${startMenuLinkFolderList}" rm "${desktopRemoveFolderList}" rm "${startMenuRemoveFolderList}" ;; *) cat >install.ins <<-EOF [Initial] Message=Installiere ${productName}... [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" Sub_Install [Sub_Install] EOF cat >remove.ins <<-EOF [Initial] Message=Entferne ${productName}... [Actions] ShowBitmap "%ScriptPath%\\logo.png" "${productName}" Sub_Remove [Sub_Remove] EOF ;; esac # Create logo if specified if [ ! "${imageUrl}" = "" ]; then _imgfilename="$(curl -s -w "%{filename_effective}" -O "${imageUrl}")" if [ $? -ne 0 ]; then echo "Couldn't fetch the specified image URL to build the logo!" else if ! convert "${_imgfilename}" -resize 160x160 ../logo-overlay-small.png -gravity SouthEast -geometry +3+3 -composite logo.png; then echo "Couldn't convert the specified URL to logo.png, maybe it's not an image?" else echo "Logo successfully generated" fi rm "${_imgfilename}" fi else echo "Copying placeholder logo to package, consider replacing it" cp ../logo-placeholder.png logo.png fi