Search code examples
nsis

NSIS section sizes doubled due to use of SetOverwrite


I've inherited an installer script, and I'm annoyed by it claiming to require twice as much space as it actually needs.

I found that this was due to how each section is using SetOverwrite (because they're re-used for a repair install?). I understand that it's necessary to keep the duplicated File commands in each of the If/Else blocks because of how SetOverwrite works (see below), but I have confirmed that it results in a doubling of the automatic section size calculations.

${MementoSection} $(APP_Section_SecHelp) SecHelp
  SetDetailsPrint textonly
  DetailPrint  $(APP_DetailPrint_SecHelp)
  SetDetailsPrint listonly

  SetOutPath $INSTDIR
  SectionIn 1 2
    ${If} $SetOverwriteOn == TRUE
      SetOverwrite ifnewer
      File /r "${APP_SOURCE_DIR}\Help"
    ${Else}
      SetOverwrite off
      File /r "${APP_SOURCE_DIR}\Help"
    ${EndIf}
  SectionGetFlags ${SecHelp} $SecHelp_GetFlag
${MementoSectionEnd}

Is this a bad design pattern that I should change? Do I need to add a hack to call SectionGetSize, divide by 2 and call SectionSetSize?


Solution

  • Personally I would just use SetOverwrite ifnewer for both but if you absolutely want to do it your way then using SectionSetSize is one option.

    Another thing you could do is to put the repair File /r instruction in a separate function that you call from the section. The downside of a function is that the progressbar does not move much during the extraction.

    A third alternative is to put some of the repair tasks in a separate section that is unchecked by default and you enable it when you are in repair mode.

    Edit: Here is a example that uses SectionSetSize:

    !include LogicLib.nsh
    InstallDir $Temp
    Page Components InitComponentsPage
    Page Directory
    Page InstFiles  
    
    !macro ModifySectionHack SID TEMPVAR
    SectionGetSize ${SID} ${TEMPVAR}
    IntOp ${TEMPVAR} ${TEMPVAR} / 2
    SectionSetSize ${SID} ${TEMPVAR}
    !macroend
    
    Function InitComponentsPage
    StrCpy $0 0
    loop:
        ClearErrors
        SectionGetFlags $0 $1 ; The error flag is set if we try to access a section that does not exist
        IfErrors done
        !insertmacro ModifySectionHack $0 $1
        IntOp $0 $0 + 1
        Goto loop
    done:
    FunctionEnd
    
    Section "Foo"
    InitPluginsDir ; Need a place to extract to for this example
    SetOutPath $PluginsDir
    
    ${If} 1 <> 2 ; Don't really care about the result
        SetOverwrite ifnewer
        File "${NSISDIR}\bin\makensis.exe" ; ~400kb
    ${Else}
        SetOverwrite off
        File "${NSISDIR}\bin\makensis.exe"
    ${EndIf}
    SectionEnd
    
    Section "Bar"
    InitPluginsDir ; Need a place to extract to for this example
    SetOutPath $PluginsDir
    
    ${If} 1 <> 2 ; Don't really care about the result
        SetOverwrite ifnewer
        File "${NSISDIR}\nsis.exe" ; ~700kb
    ${Else}
        SetOverwrite off
        File "${NSISDIR}\nsis.exe"
    ${EndIf}
    SectionEnd
    

    This loops through all the sections and adjusts all of them but I'm not sure if that is such a good idea. If this was my script then I would manually call ModifySectionHack on each section that has the SetOverwrite problem:

    !include LogicLib.nsh
    InstallDir $Temp
    Page Components
    Page Directory
    Page InstFiles
    
    !macro ModifySectionHack SID TEMPVAR
    SectionGetSize ${SID} ${TEMPVAR}
    IntOp ${TEMPVAR} ${TEMPVAR} / 2
    SectionSetSize ${SID} ${TEMPVAR}
    !macroend
    
    Section "Foo" SID_FOO
    InitPluginsDir ; Need a place to extract to for this example
    SetOutPath $PluginsDir
    
    ${If} 1 <> 2 ; Don't really care about the result
        SetOverwrite ifnewer
        File "${NSISDIR}\bin\makensis.exe" ; ~400kb
    ${Else}
        SetOverwrite off
        File "${NSISDIR}\bin\makensis.exe"
    ${EndIf}
    SectionEnd
    
    Section "Bar"
    ${If} 1 = 2
      File /r "${NSISDIR}\stubs"
    ${EndIf}
    SectionEnd
    
    Section "Baz" SID_BAZ
    InitPluginsDir ; Need a place to extract to for this example
    SetOutPath $PluginsDir
    
    ${If} 1 <> 2 ; Don't really care about the result
        SetOverwrite ifnewer
        File "${NSISDIR}\nsis.exe" ; ~700kb
    ${Else}
        SetOverwrite off
        File "${NSISDIR}\nsis.exe"
    ${EndIf}
    SectionEnd
    
    Function .onInit
    ; Adjust the section size for the sections that use SetOverwrite:
    !insertmacro ModifySectionHack ${SID_FOO} $1
    !insertmacro ModifySectionHack ${SID_BAZ} $1
    FunctionEnd