Search code examples
dynamiccomponentsnsissections

NSIS Create components based on folders


I'm working on creating an installer that has several applications that can be optionally installed. I'd like to write my installer script so that I don't need to update it every time I add a new application to my apps directory. Is this possible with NSIS? I've got code to search through a folder for sub folders and extract their names, but am having trouble using that to make components in the installer.


Folder Structure

-Install_Directory
    -Main_Application    
    -Applications
        -App_A
        -App_B
        -App_C
        -...

Current Code

!macro insert_application_section name
  Section "${name}"
    SetOutPath "{PRJ_BASE}\releases"
    File /nonfatal /r "..\releases\${name}"
  SectionEnd
!macroend

SectionGroup "Applications"
    !insertmacro insert_release_section "App_A"
SectionGroupEnd

The installer compiles but throws an "Error opening file for writing" error when trying to install files from a sub folder of Application created from the macro. Is there a way to achieve what I'm trying to do with NSIS?

My current working plan is to have a python file that generates a section for each sub folder of Applications and puts it in an "autogen_sections.nsh" file which the actual installer includes at the end of the file. That seems to work, but does seem a bit clunky. Any tips for how to do this with just NSIS would be greatly appreciated!


Solution

  • "{PRJ_BASE}\releases" is not a valid path. SetOutPath is usually set to $InstDir or a sub-folder inside $InstDir. If PRJ_BASE is a define starting with $InstDir then you must use "${PRJ_BASE}\releases" and not "{PRJ_BASE}\releases".

    NSIS has the !system command that lets you call external programs and batch files at compile-time:

    ; Generate batch file on the fly because this is a self-contained example
    !delfile "creatensh.bat"
    !appendfile "creatensh.bat" '@echo off$\r$\n'
    !appendfile "creatensh.bat" 'cd /D %1$\r$\n'
    !appendfile "creatensh.bat" 'FOR /D %%A in (*) DO ($\r$\n'
    !appendfile "creatensh.bat" '   >> %2 echo !insertmacro insert_application_section "%%~A"$\r$\n'
    !appendfile "creatensh.bat" ')$\r$\n'
    
    ; Running the batch file
    !define PRJ_BASE "$InstDir\Something"
    
    !macro insert_application_section name
      Section "${name}"
        SetOutPath "${PRJ_BASE}\releases"
        File /nonfatal /r "..\releases\${name}"
      SectionEnd
    !macroend
    
    !tempfile tmpnsh
    !system '"creatensh.bat" "c:\myfiles\Install_Directory\Applications" "${tmpnsh}"'
    !include "${tmpnsh}"
    !delfile "${tmpnsh}"
    

    NSIS cannot enumerate a directory tree at compile time, you must use some kind of external application or script.