I want to call a function after installing a folder, but the InstallEnv function is seems to be called several times, maybe for each file is the folder (to be confirmed). Is there a way to call it only once after it installed all of those files? I can't use the Run section because I want to do error catching with the return code.
Source: "InputFiles\virtualenv-1.8.2\*"; DestDir: "{tmp}/virtualenv"; \
Flags: recursesubdirs; AfterInstall: InstallEnv;
There is no way to call it at the end of the installation of that group of files, from within a single entry. However it is possible to call the function at the appropriate time by making use of a dummy entry:
[Files]
Source: "InputFiles\virtualenv-1.8.2\*"; DestDir: "{tmp}\virtualenv"; Flags: recursesubdirs
Source: dummy.txt; DestDir: {tmp}; AfterInstall: InstallEnv
The Source file must exist but it can be a zero-byte file. As installation is into {tmp} it will be deleted after install anyway so its contents are irrelevant.
This works because [Files] entries are installed in the order specified.
Yes, it executes once per each file. The reference says about it (emphasized by me):
A BeforeInstall or AfterInstall function for a [Files] section entry
using a wildcard is called once per file matching the wildcard. Use
CurrentFileName to check for which file the function is called.
And no, there is no way to call it once after all the files are installed. If you were going to run it only once, it wouldn't be a problem, since you might declare a flag variable, indicating that the function was already called, but you want to detect if it's the last call, and for this there is no workaround.
Well, maybe if you would know, which file will be the latest installed from that folder, you might check that against the result of the CurrentFileName function call, but I doubt that you can determine which one will be installed as last at compilation time (since at runtime, there is currently no way to get list of files to be installed).
Related
I want to include language resource files from our build into our installers. The language resource files all have the same name, but reside in different sub-folders (one per locale), like this:
\Release
\bin
\es-MX
Localization.resources.dll
\fr-CA
Localization.resources.dll
etc.
In my [Files] section, I thought perhaps I might be able to do this (note the position of the asterisk):
Source: "..\\source\\Libraries\\Localization\\bin\\Release\\*\\Localization.resources.dll"; \
DestDir: "{app}\\MyApp"; Flags: ignoreversion recursesubdirs
Unfortunately, Inno Setup blows up, complaining that it can't find any files:
Compiler Error!
Line 129: No files found matching "C:\Development\HT\Installers\..\source\Libraries\Localization\bin\Release\*\Localization.resources.dll"
I would like Inno Setup to look for any sub-folder (hence the *) containing a file named Localization.resources.dll and upon installation, create a language directory with the same name (based on what is found via the wildcard) and copy the file to that folder, doing so for each folder that matches the criteria.
Essentially, I want to end up with this:
..
\MyApp
\es-MX
Localization.resources.dll
\fr-CA
Localization.resources.dll
In case it isn't obvious, I would prefer not to explicitly add the source and destination folder names, because we will be adding more languages/locales in the future, and I would like Inno Setup to automatically pick up any new language folders/files we create without having to change the installer source.
Is this possible?
Just use the recursesubdirs flag with a root path to a tree and the Localization.resources.dll filename. It will automatically do what you want: find all Localization.resources.dll files in the tree and install them to their respective subfolders:
Source: "..\source\Libraries\Localization\bin\Release\Localization.resources.dll"; \
DestDir: "{app}\MyApp"; Flags: ignoreversion recursesubdirs
As documented (emphasis mine):
recursesubdirs
Instructs the compiler or Setup to also search for the Source filename/wildcard in subdirectories under the Source directory.
Other possible approaches:
Generate the Files section using a preprocessor.
For a similar tasks, see:
Inno Setup - Recurse sub directories without creating those same sub directories
Generating Inno Setup file flags programmatically
Inno Setup: Dynamically add a component for all files in a folder and its subfolders
Generate the Files section using an external scripting language (with better functionality then Inno Setup preprocessor) and invoke it using the Exec preprocessor function. E.g. using PowerShell.
I am using a .iss script to build an exe file inside Inno Setup Compiler. I need to package some node_modules into this application so I have a line under [Files] which looks like this:
Source: "{#SourcePath}Encore.Warehouse.UI\bin\Warehouse_Release\warehouse\*"; \
DestDir: "{app}\warehouse"; Flags: ignoreversion recursesubdirs createallsubdirs
When I compile, I receive this error:
Here is the compiler output:
So, it appears to be running fine up until it aborted. My initial thought was that the browser.js doesn't exist but after double checking, this is not the case. Also, I'm using a wildcard in the source path so the compiler knows the file exists, but it seems to be having trouble compressing it.
One other thing that could be causing the issue is the file path length. Node modules usually end up having ridiculous file path lengths due to nested dependencies. In this case, the path length is 260. Assuming this is what's causing the problem, is there any way to get around it?
It's definitely due to a long path. Normally Windows applications cannot process paths longer than MAX_PATH (260 characters).
See Naming Files, Paths, and Namespaces in Microsoft documentation.
A common workaround is prefixing the path with \\?\ (again see the Microsoft article above). The prefix can be used for absolute paths only. But Inno Setup compiler chokes on that with the Source attribute. It looks for : and it accepts only path that either have a drive letter only before the : or that use compiler: or userdocs: prefixes.
You can hack that by using an UNC path with a volume ID (hence no colon).
Use the mountvol command to find the UNC path for your source drive.
And then you will have the same problem with a long path with the DestDir attribute, while installing (not when compiling). There, there's no problem with the colon, so you can simply use the \\?\ prefix.
Source: "\\?\Volume{bb919c3e-bdb1-42b8-9601-6715becd8683}\{#SourcePath}Encore.Warehouse.UI\bin\Warehouse_Release\warehouse\*"; \
DestDir: "\\?\{app}\warehouse"; Flags: ignoreversion recursesubdirs createallsubdirs
Of course, if the problem is caused by a root path being too long already, you can fix the problem simply be moving the source files to a folder with a shorter path. Or you can use subst to create a virtual drive or you can create a symlink/directory junction.
Falling into the same issue, here below is more details on workaround with subst as described in comments and accepted answer.
Here below is content of some precompile.bat file to associate some local path with the A: drive letter
#echo off
REM NB: Removing any previous association to be sure new one will work
subst A: /D 1> NUL 2>&1
subst A: "%~dp0.."
And content of some postcompile.bat to remove association in the end
#echo off
subst A: /D 1> NUL 2>&1
NB1: Careful, once associated, it is difficult to navigate upper paths directly within the .iss script because A:\.. is still A:\ ! (I fall into the issue, so worth to know). Association should then be made with closest top-most folder of all required files directly in precompile.bat.
NB2: I don't know if feasible to remind for any previous association and restore it in the end
These steps can be added to the .iss script as follow:
[PreCompile]
Name: "precompile.bat"; Flags: cmdprompt redirectoutput
[PostCompile]
Name: "postcompile.bat"; Flags: cmdprompt redirectoutput
Note finally that [PreCompile] and [PostCompile] sections will execute from the IDE only. They won't execute from the command line (at least with inno 5.5.9), I also fall into this... so complete compilation from command line should look like:
call "precompile.bat"
call "%ProgramFiles(x86)%\Inno Setup 5\ISCC.exe" "myscript.iss"
call "postcompile.bat"
NB: I think calling Compil32.exe /cc "myscript.iss" (IDE compiler) instead of ISCC.exe (command-line compiler) should run [PreCompile] and [PostCompile] sections but in my case I had to pass extra /D options to the compiler so it was not possible to call Compil32.exe directly.
I have few SQL script files which have to run before installation begin. The reason is if SQL scripts run successfully only, I want to do the installation.
If the SQL scripts need to run after the installation, I can copy the files to {app} path and run the files from there. But the requirement is run the files before installation begins. I am confused. What is the best way of doing it?
Say for example if it is a single file I can put it under Files section and can use ExtractTemporaryFile('FileName');
But as I mentioned, I have many files (in SQLSCRIPTS folder). What is the better way? (One solution is I can make it as a single file by zipping it and then unzip it)
[Files]
Source: "C:\\SQLSCRIPTS\\*"; DestDir: "{app}"; Flags: dontcopy
To extract multiple files from installer, use the ExtractTemporaryFiles, like:
ExtractTemporaryFiles('*.sql');
I've created a setup file for my application, which works fine for new installations, but I now need to adapt it to handle upgrades.
I understand I should add DisableDirPage=auto under [Setup], so the user won't be prompted for an installation folder during upgrades?
I also do a few things in [Run]. How do I skip these actions when it's an upgrade?
Under [Files] I currently use a single line to install everything to the application folder:-
Source: "{#BuildOutputFolder}\*"; DestDir: "{app}"; Flags: onlyifdoesntexist recursesubdirs createallsubdirs
Firstly, I'm guessing this won't work during an upgrade as "onlyifdoesntexist" would prevent the EXE and DLLs from ever being overwritten, even with newer versions?
Secondly, there are certain files (e.g. configs) that get installed, but should never be overwritten during an upgrade. I'm guessing the current line isn't sufficient and I would need to replace it with a number of separate lines to achieve this functionality, e.g. one to install the EXE, one for the DLLs, and one for the configs (with "onlyifdoesntexist")?
I have an embedded 7Zip archive in my setup script.
Is there a "native" way of extracting the contents to a target folder?
If not any hints on how this could be achieved?
Updated with my implementation. Thanks for the hint TLama
[Files]
Source: "Documentation.7zip"; DestDir: "{tmp}"
Source: "7za.exe"; DestDir: "{tmp}"
[Run]
Filename: "{tmp}\7za.exe"; Parameters: "x -o""{app}"" ""{tmp}\Documentation.7zip"""; Flags: runhidden; Description: "{cm:InstallingDocumentation}"; StatusMsg: "{cm:InstallingDocumentationStatus}"
[CustomMessages]
en.InstallingDocumentation=Documentation Files
en.InstallingDocumentationStatus=Installing Documentation Files. This may take several minutes...
No, there is no native way to extract 7zip files from InnoSetup installer. However, you can get a copy of 7zip library, which is redistributable and call it from InnoSetup script's code section.
Inno doesn't have any native method of extracting files from anything other than it's own archives (which normally compress better than 7Zip).
Inno Setup can however use wildcards for including files to install:
[Files]
Source: "Documentation\*.*"; DestDir: "{app}/Documentation/";
If you have many small files, using the solidcompression flag will improve compression performance and size.