NSIS Beyond a Traditional Installation II

From NSIS Wiki
Jump to navigationJump to search
Author: Red Wine (talk, contrib)


Links

Description

Continuing the project to demonstrate how NSIS coding could be useful beyond the traditional creation of an installation, we've created a nice, stand alone, multi language enabled downloader which checks the server for available new release of NSIS nightly builds and requests permission to download it when found.
If it has not found a new release, it asks users if they want to re download the current release.

In this project we're using some functions from the included headers StrFunc and TextFunc and of course the famous Inetc plug-in.

  • Applies to NSIS 2.24

NSIS Nightly Builds Downloader

; NSIS Nightly Builds Downloader.nsi
; Requires Inetc plug-in http://nsis.sourceforge.net/Inetc_plug-in
 
;--------------------------------
; Script Definitions
 
!define APP_NAME   "NSIS Nightly Builds Downloader"
!define OUT_DIR    "Output"
!define TEMP_INI   "$PLUGINSDIR\download.ini"
!define DOWN_INI   "$EXEDIR\download.ini"
!define DOWN_LNK   "http://nsis.sourceforge.net/nightly/nsis.zip"
!define HEAD_GET   "$PLUGINSDIR\head.txt"
!define FILE_GET   "$EXEDIR\nsis-$date2file.zip"
!define C_LENGTH   "Content-Length"
!define LAST_MOD   "Last-Modified"
!define LANG_STR  `"$(InetcStr1)" "$(InetcStr2)" \
                   "$(InetcStr3)" "$(InetcStr4)" \
                   "$(InetcStr5)" "$(InetcStr6)" \
                   "$(InetcStr7)" "$(InetcStr8)"`
 
 
;--------------------------------
; Create Output Directory
 
!system "md ${OUT_DIR}"
 
 
;--------------------------------
; Variables
 
var date2file
var header
var subheader
 
 
;--------------------------------
; Include Headers
 
!include MUI.nsh
!include TextFunc.nsh
!insertmacro LineFind
 
!include StrFunc.nsh
${StrStr}
${StrRep}
${StrLoc}
${StrTrimNewLines}
 
# LogicLib is already included in StrFunc header, no need to include it again.
 
 
;--------------------------------
; Script Macros
 
!macro HeaderDisplayText _Txt2Header _Txt2SubHeader
    StrCpy $header "${_Txt2Header}"
    StrCpy $subheader "${_Txt2SubHeader}"
!macroend
 
 
!macro InetcDownload _PluginFunc _DownLink _LocalFile
  Push $0
 
    ClearErrors
 
    inetc::${_PluginFunc} /NOPROXY /TRANSLATE ${LANG_STR} "${_DownLink}" "${_LocalFile}" /END
    Pop $0 # return value = exit code, "OK" if OK
 
   ${Unless} $0 == "OK"
    SetErrors
    MessageBox MB_ICONEXCLAMATION|MB_OK "$(ErrorMsg) $0"
   ${EndUnless}
 
  Pop $0
!macroend
 
 
!macro MakeDownloadIni _InputStr _Str2Find _Str2Replace
  Push $0
  Push $1
  Push $2
  Push $3
 
    ${StrTrimNewLines} $3 "${_InputStr}"
    ${StrStr} $0 "$3" "${_Str2Find}"
    ${StrRep} $0 "$0" "${_Str2Find}" "${_Str2Replace}"
    ${StrLoc} $1 "$0" "=" ">"
     StrCpy $1 "$0" "$1"
    ${StrLoc} $2 "$0" "=" "<"
     Intop $2 $2 - 1
     StrCpy $2 "$0" "" "-$2"
    ${If} $2 != ""
     WriteINIStr "${TEMP_INI}" "SETTINGS" "$1 " "$2"
    ${EndIf}
 
  Pop $3
  Pop $2
  Pop $1
  Pop $0
!macroend
 
 
!macro ReplaceIni
    Delete "${DOWN_INI}"
    Rename "${TEMP_INI}" "${DOWN_INI}"
!macroend
 
 
!macro CompareIniValues _Value
  Push $0
  Push $1
 
    ClearErrors
 
    ReadINIStr $0 "${DOWN_INI}" "SETTINGS" "${_Value}"
    ReadINIStr $1 "${TEMP_INI}" "SETTINGS" "${_Value}"
 
   ${Unless} "$0" == "$1"
    SetErrors
   ${EndUnless}
 
  Pop $1
  Pop $0
!macroend
 
 
!macro _Date2FileName_ _STRING _RETURN
  Push $0
  Push $1
  Push $2
  Push $3
 
   StrCpy ${_RETURN} "${_STRING}"
    ${StrLoc} $0 "${_RETURN}" " " ">"
    Intop $0 $0 + 1
 
   StrCpy ${_RETURN} "${_RETURN}" "" "$0"
    ${StrLoc} $0 "${_RETURN}" " " ">"
    StrCpy $1 "${_RETURN}" "$0" ""
    Intop $0 $0 + 1
 
   StrCpy ${_RETURN} "${_RETURN}" "" "$0"
    ${StrLoc} $0 "${_RETURN}" " " ">"
    StrCpy $2 "${_RETURN}" "$0" ""
    Intop $0 $0 + 1
 
   StrCpy ${_RETURN} "${_RETURN}" "" "$0"
    ${StrLoc} $0 "${_RETURN}" " " ">"
    StrCpy $3 "${_RETURN}" "$0" ""
    StrCpy ${_RETURN} "$1-$2-$3"
 
  Pop $3
  Pop $2
  Pop $1
  Pop $0
!macroend
 
 
!macro Date2FileName
  Push $0
 
   ReadINIStr $0 "${TEMP_INI}" "SETTINGS" "${LAST_MOD}"
   !insertmacro _Date2FileName_ "$0" "$date2file"
 
  Pop $0
!macroend
 
 
!define BuildString "!insertmacro _BUILD_STRINGS"
 
!macro _BUILD_STRINGS _MSG_ _ID_ _STR_
   LangString ${_MSG_}  "$${LANG_${_ID_}" "${_STR_}"
!macroend
 
 
!macro BUILD_LANGSTRINGS
 
   ${BuildString} "ReDowMsg" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_ReDowMsg}"
 
   ${BuildString} "FoundMsg" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_FoundMsg}"
 
   ${BuildString} "ErrorMsg" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_ErrorMsg}"
 
   ${BuildString} "VerHeader" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_VerHeader}"
 
   ${BuildString} "NewHeader" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_NewHeader}"
 
   ${BuildString} "DlHeader" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_DlHeader}"
 
   ${BuildString} "HeaderOk" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_HeaderOk}"
 
   ${BuildString} "HeaderEr" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_HeaderEr}"
 
   ${BuildString} "VerSubHead" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_VerSubHead}"
 
   ${BuildString} "NewSubHead" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_NewSubHead}"
 
   ${BuildString} "DlSubHead" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_DlSubHead}"
 
   ${BuildString} "SubHeadOk" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_SubHeadOk}"
 
   ${BuildString} "SubHeadEr" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_SubHeadEr}"
 
   ${BuildString} "DownPrint" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_DownPrint}"
 
   ${BuildString} "InetcStr1" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_InetcStr1}"
 
   ${BuildString} "InetcStr2" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_InetcStr2}"
 
   ${BuildString} "InetcStr3" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_InetcStr3}"
 
   ${BuildString} "InetcStr4" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_InetcStr4}"
 
   ${BuildString} "InetcStr5" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_InetcStr5}"
 
   ${BuildString} "InetcStr6" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_InetcStr6}"
 
   ${BuildString} "InetcStr7" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_InetcStr7}"
 
   ${BuildString} "InetcStr8" "${DL_LANGUAGE}" "${${DL_LANGUAGE}_InetcStr8}"
 
!macroend
 
 
!macro DOWN_LANGUAGE DL_LANGUAGE
 
   !insertmacro MUI_LANGUAGE "${DL_LANGUAGE}"
   !include "DL_${DL_LANGUAGE}.nsh"
   !insertmacro BUILD_LANGSTRINGS
 
!macroend
 
 
;--------------------------------
; General Attributes
 
Name "${APP_NAME}"
Caption "${APP_NAME}"
OutFile "${OUT_DIR}\${APP_NAME}.exe"
BrandingText "${APP_NAME}"
ShowInstDetails nevershow
 
 
;--------------------------------
; MUI Interface & Page Settings
 
  !define MUI_PAGE_HEADER_TEXT "$(DlHeader)"
  !define MUI_PAGE_HEADER_SUBTEXT "$(DlSubHead)"
  !define MUI_INSTFILESPAGE_FINISHHEADER_TEXT "$header"
  !define MUI_INSTFILESPAGE_FINISHHEADER_SUBTEXT "$subheader"
  !insertmacro MUI_PAGE_INSTFILES
 
 
;--------------------------------
; Languages
  ; Instead of MUI_LANGUAGE use DOWN_LAGUAGE for languages already translated
  ; see the header dl_english.nsh for details
 
  !insertmacro DOWN_LANGUAGE "English"
  ;!insertmacro DOWN_LANGUAGE "Greek"
 
 
;--------------------------------
; Installer Sections
 
Section "${APP_NAME}" Sec_01
 
    DetailPrint "$(DownPrint)"
 
    !insertmacro InetcDownload "head /silent" "${DOWN_LNK}" "${HEAD_GET}"
 
  ${Unless} ${Errors}
 
    SetDetailsPrint none
 
   ${LineFind} "$PLUGINSDIR\head.txt" "" "" LineFindCallBack
 
    !insertmacro Date2FileName
 
    SetDetailsPrint both
 
   ${If} ${FileExists} "${DOWN_INI}"
    !insertmacro CompareIniValues "${C_LENGTH}"
   ${AndUnless} ${Errors}
    !insertmacro CompareIniValues "${LAST_MOD}"
   ${AndUnless} ${Errors}
    MessageBox MB_ICONQUESTION|MB_YESNO "$(ReDowMsg)" IDYES _redown
    !insertmacro HeaderDisplayText "$(VerHeader)" "$(VerSubHead)"
    Goto _end
 
  _redown:
    Rename "${FILE_GET}" "${FILE_GET}.bak"
    !insertmacro InetcDownload "get" "${DOWN_LNK}" "${FILE_GET}"
   ${If} ${Errors}
    !insertmacro HeaderDisplayText "$(HeaderEr)" "$(SubHeadEr)"
   ${Else}
    !insertmacro HeaderDisplayText "$(HeaderOk)" "$(SubHeadOk)"
    !insertmacro ReplaceIni
   ${EndIf}
  _end:
   ${Else}
    !insertmacro HeaderDisplayText "$(NewHeader)" "$(NewSubHead)"
    MessageBox MB_ICONQUESTION|MB_YESNO "$(FoundMsg)" IDNO _exit
    !insertmacro InetcDownload "get" "${DOWN_LNK}" "${FILE_GET}"
   ${If} ${Errors}
    !insertmacro HeaderDisplayText "$(HeaderEr)" "$(SubHeadEr)"
   ${Else}
    !insertmacro HeaderDisplayText "$(HeaderOk)" "$(SubHeadOk)"
    !insertmacro ReplaceIni
   ${EndIf}
  _exit:
   ${EndIf}
 
   ${If} ${FileExists} "${FILE_GET}"
    Delete "${FILE_GET}.bak"
   ${Else}
    Rename "${FILE_GET}.bak" "${FILE_GET}"
   ${EndIf}
 
  ${Else}
    !insertmacro HeaderDisplayText "$(HeaderEr)" "$(SubHeadEr)"
  ${EndUnless}
 
SectionEnd
 
 
;--------------------------------
; Installer Functions
 
Function LineFindCallBack
 
   !insertmacro MakeDownloadIni "$R9" "${C_LENGTH}:" "${C_LENGTH} ="
 
   !insertmacro MakeDownloadIni "$R9" "${LAST_MOD}:" "${LAST_MOD} ="
 
  Push $0
 
FunctionEnd

English Translation Header

; dl_english.nsh
; English Language Strings
 ; Make a copy of this header and save it as dl_[NewLanguage].nsh
 ; where NewLanguage is the name of a language supported by NSIS e.g. dl_spanish.nsh
 ; Translate all strings below to the selected language
 
   !define ${DL_LANGUAGE}_ReDowMsg "There is not new version on server.$\r$\n\
   Do you want to re-download the current version?"
 
   !define ${DL_LANGUAGE}_FoundMsg "A new version of the program found on server.$\r$\n\
   Do you want to download the new version now?"
 
   !define ${DL_LANGUAGE}_ErrorMsg   "Download Error:"
 
   !define ${DL_LANGUAGE}_VerHeader  "New Version Check Out"
 
   !define ${DL_LANGUAGE}_NewHeader  "Found New Version"
 
   !define ${DL_LANGUAGE}_DlHeader   "Downloading..."
 
   !define ${DL_LANGUAGE}_HeaderOk   "Download Complete"
 
   !define ${DL_LANGUAGE}_HeaderEr   "Download Failed"
 
   !define ${DL_LANGUAGE}_VerSubHead "There is not new version on server."
 
   !define ${DL_LANGUAGE}_NewSubHead "A new version of the program found on server."
 
   !define ${DL_LANGUAGE}_DlSubHead  "Please wait while NSIS nightly build is being downloaded."
 
   !define ${DL_LANGUAGE}_SubHeadOk  "$(^NameDA) was completed successfully."
 
   !define ${DL_LANGUAGE}_SubHeadEr  "$(^NameDA) was failed."
 
   !define ${DL_LANGUAGE}_DownPrint  "New version check out (internet connection)"
 
   !define ${DL_LANGUAGE}_InetcStr1  "Downloading: %s"
 
   !define ${DL_LANGUAGE}_InetcStr2  "Connecting ..."
 
   !define ${DL_LANGUAGE}_InetcStr3  "second"
 
   !define ${DL_LANGUAGE}_InetcStr4  "minute"
 
   !define ${DL_LANGUAGE}_InetcStr5  "hour"
 
   !define ${DL_LANGUAGE}_InetcStr6  "s"
 
   !define ${DL_LANGUAGE}_InetcStr7  "%d kB (%d%%) of %d kB @ %d.%01d kB/s "
 
   !define ${DL_LANGUAGE}_InetcStr8  " (%d %s%s remaining)"

License

This example script is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this script.

Permission is granted to anyone to use this script for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:

  1. The origin of this script must not be misrepresented; you must not claim that you wrote the original code. If you use this script in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  2. Altered versions must be plainly marked as such, and must not be misrepresented as being the original script.
  3. This notice may not be removed or altered from any distribution.