Nullsoft Scriptable Installer Service is a tool you can use to generate installers. It’s farily popular - you’ve probably used an installer generated by it - the one I can think of first would be WinAmp, but I don’t think anyone has installed WinAmp since 2003, so it’s not a good example.

I downloaded the NSIS installer from SourceForge. I downloaded the most recent version which is 3.03.

My goal here is to create a graphical installer which will encapsulate all of the files which are part of a Py2Exe-generated Python Executable and install them to a folder in the root of the C: drive on a PC.

Installation Steps

  1. Double click the installer to start it.
  2. On the first screen, click ‘Next’: Initial install screen
  3. Click ‘I agree’ on the next screen: License screen
  4. The ‘Full’ install is the default and is acceptable. Click ‘Next’: Install selection screen
  5. The default installation path is acceptable. Click ‘Install’: Install path screen
  6. The installation will proceed: Installation
  7. When finished you will be presented with a new screen. I de-selected viewing the release notes and left starting NSIS selected, then clicked ‘Finish’: Final install screen

Creating an Installer

This is the screen presented to you when you start NSIS.: Initial NSIS screen

Turns out that the basis of an NSIS installer is a script. Just a plan ol’ text file.

A good one is this:

This script assumes a Python script turned into an executable with the output files bing in ./dist.

#NSIS Example Install Script

#Basic definitions
!define APPNAME "Sample App"
!define COMPANYNAME "Steves Toolbox LLC"
!define DESCRIPTION "Basic Python Application"
!define APPSHORTNAME "pyApp"

#Ask for administrative rights
RequestExecutionLevel admin

#Other options include:
#none
#user
#highest

#Default installation location - let's clutter up our root directory!
InstallDir "C:\${APPSHORTNAME}"

#Text (or RTF) file with license information. The text file must be in DOS end line format (\r\n)
LicenseData "..\docs\license.md"

#'Name' goes in the installer's title bar
Name "${COMPANYNAME}-${APPSHORTNAME}"

#Icon for the installer - this is the default icon
#Icon "logo.ico"

#The following lines replace the default icons
!include "MUI2.nsh"

#The name of the installer executable
outFile "${APPSHORTNAME}-inst.exe"

#...Not certain about this one
!include LogicLib.nsh

#Defines installation pages - these are known to NSIS
#Shows the license
Page license
#Allows user to pick install path
Page directory
#Installs the files
Page instfiles

#A macro to verify that administrator rights have been acquired
!macro VerifyUserIsAdmin
UserInfo::GetAccountType
pop $0
${If} $0 != "admin" ;Require admin rights on NT4+
        messageBox mb_iconstop "Administrator rights required!"
        setErrorLevel 740 ;ERROR_ELEVATION_REQUIRED
        quit
${EndIf}
!macroend

#This ensures the administrator check is performed at startup?
function .onInit
	setShellVarContext all
	!insertmacro VerifyUserIsAdmin
functionEnd

# Files for the install directory - to build the installer, these should be in the same directory as the install script (this file)
section "install"
    setOutPath $INSTDIR
    
    # Files added here should be removed by the uninstaller (see section "uninstall")
    file /r ..\dist\*.*

    
	# Add any other files for the install directory (license files, app data, etc) here
 
    #This creates a shortcut to the executable on the desktop - the second set of options in quotes are for command-line arguments
	CreateShortcut "$desktop\Link to pyApp.lnk" "$instdir\pyApp.exe" "-c cfg\default.cfg"
 
sectionEnd

Creating a Directory

Most of my Python apps use a ‘logs’ directory to store logs, but I wouldn’t want the installer to package up my logs directory from a working directory structure - that would add all of my log files to the installer. No bueno.

Instead, I need the NSIS script to create the logs directory in the appropriate place.

NSIS can do that, here’s the documentation of CreateDirectory.

Here’s a modified ‘install’ section with the directive to create the log subdirectory:

# Files for the install directory - to build the installer, these should be in the same directory as the install script (this file)
section "install"
    setOutPath $INSTDIR
    
    # Files added here should be removed by the uninstaller (see section "uninstall")
    file /r ..\dist\*.*
	
	#Add a directory for logfiles
	CreateDirectory $INSTDIR\logs
	
	# Add any other files for the install directory (license files, app data, etc) here
 
    #This creates a shortcut to the executable on the desktop - the second set of options in quotes are for command-line arguments
	CreateShortcut "$desktop\pyApp.lnk" "$instdir\pyApp.exe" 
 
sectionEnd

Resources