Feb 09 2009
NSIS installer for a Ruby application – Part 3 – A few script improvements
In this part of the series (see Part 1 and Part 2) we will:
- Make one of the components compulsory to install.
- We will look at a way to write our script in such a way that it can be reused for future releases of MyApplication.
- A few extra tips and tricks.
Making a component compulsory
At the end of Part 2 we added the components page to our installer. The component page gives the user the option to select which components he want to install. However, we want the installer not to give the user the option to not install MyApplication component but to make the installation of MyApplication when executing the script. We use the SectionSetFlags method to achieve this. SetSectionFlags allows you to set certain attributes of a section (component to be installed). We add the following code:
Function .onInit IntOp $0 ${SF_SELECTED} | ${SF_RO} SectionSetFlags ${SEC03} $0 FunctionEnd
- You will recall from Part 1 that the .onInit function is called on initiating the script.
- The SectionSetFlags method sets first 8 bits of the section’s flags. We are interested in the first bit (setting a sections and selected) and the fifth bit (setting a section as read only)
- To achieve this we use the SF_SELECTED and the SF_RO constants that are equal to 1 and 16 respectively.
- When we OR these to constants together we end up with a value of which the first and the fifth bit are set (line 2).
- In line 3 we use the SectionSetFlags method to apply the result of the OR to SEC03 which is our MyApplication component.
- The result is that the MyApplication component will be selected and read only on the components page of the installer.
Making our script usable for the future
I might happen that we want to release a new version of MyApplication that requires a new installer. The new version might have the same requirements but a few new files might be added that now needs to be added to the installer. If the install section of MyApplication gets very big (depending on the size of MyApplication) it can be a daunting task to review all the SetOutPath “$INSTDIR\my_folder” and File “application_files\myapplication.rb” type calls. It will be great if we can automate the creating of these calls.
I have created the following Ruby script that receives as commandline argument the folder in which MyApplication lives and the creates a text file that contains the instruction set that we need in the MyApplication section:
require 'fileutils' include FileUtils::Verbose def recursive_folder_dump(folder, install_file, uninstall_file, relative_path) cd(folder) { folders = [] Dir.foreach('.\\') { |inner_file| if File.directory?(inner_file) && inner_file != '.' && inner_file != '..' folders << inner_file elsif inner_file != '.' && inner_file != '..' install_file.puts "File \"" + relative_path + inner_file + "\"" uninstall_file.puts "Delete \"$INSTDIR\\" + relative_path + inner_file + "\"" end } folders.each { |folder| install_file.puts "SetOutPath \"$INSTDIR\\" + relative_path + folder + "\"" recursive_folder_dump(folder, install_file, uninstall_file, relative_path + folder + "\\") uninstall_file.puts "RMDir \"$INSTDIR\\" + relative_path + folder + "\"" } } end if ARGV[1] == nil puts 'usage: ruby nsis_folder_dump.rb ' puts 'where:' puts ' - is the folder/file structure to be dumped' puts ' - will be used to create the output file names: _install.nsi and _uninstall.nsi' exit end if !File.exists?(ARGV[0]) puts ARGV[0] + " is not an existing folder" exit end install_file = File.new(ARGV[1]+"_install.nsh",'w') uninstall_file = File.new(ARGV[1]+"_uninstall.nsh",'w') install_file.puts "SetOutPath \"$INSTDIR\\" + ARGV[0] + "\"" recursive_folder_dump(ARGV[0], install_file, uninstall_file, ARGV[0] + "\\") uninstall_file.puts "RMDir \"$INSTDIR\\" + ARGV[0] + "\"" install_file.close
The above script will create two files. Depending on the commandline parameters they might be myapplication_install.nsh and myapplication_uninstall.nsh.
NSIS allows us to include these files in our script with the !include. We change the MyApplication install section to look like this:
Section "MyApplication" SEC03 !include "myapplication_install.nsh" SectionEnd
And we add the following to the top of our Uninstall section:
!include "myapplication_uninstall.nsh"
We can now keep our NSIS install script the same for all future releases of MyApplication and just generate new myapplication_install.nsh and myapplication_uninstall.nsh files.
A few more tips and tricks
MyApplication has a database the can be initialised by a rake task. We can run this rake task at the end of a successful installation. We achieve that with the following code:
!define MUI_FINISHPAGE_RUN_TEXT "Initialise the database" !define MUI_FINISHPAGE_RUN "$0\bin\rake.bat" !define MUI_FINISHPAGE_RUN_PARAMETERS "-f $\"$INSTDIR\server\Rakefile$\" db:migrate"
On uninstall files and folders can be removed by the Delete and RMDir methods. If you want to delete a whole folder recursively its contents you can use the /r directive:
RMDir /r "$INSTDIR\my_application"
And that brings us to the end of Part 3.
Popularity: 11% [?]
