Archive: Strategy for Uninstallers?


Strategy for Uninstallers?
Coming from InstallerVISE, I'm having a wee bit of trouble with NSIS' uninstaller strategy. InstallerVISE keeps track of every single file it installs, and then removes them based on the entries in a log file.

With my NSIS installer & uninstaller, I do not want to delete entire directories / folders that I install my files to, even if I was the one who created those folders. Rather, I just want to delete the exact files that I installed, and no others.

Currently each group of files is in a unique section in a separate script file, that is then included into the main installer script.

I should mention that we're talking about lots of files (hundreds to thousands) in many different groups, and so there is no way that I can maintain separate lists of files to be installed and uninstalled. Rather, I want to create each file list once, and use that list to drive the installer and uninstaller.

So, is the best solution for me to simply include those same section scripts in the uninstaller?

Seems pretty obvious, but I want to make sure I'm not missing something.

Also, I'd like to remove each folder that I installed if after removing all of my files inside it, it's now empty. But not if some (user) files remain in that folder. How would I do that?

Thanks,


Uh oh ... I see that NSIS uses File and Delete where each one specifies the filename.

I would have preferred something like:

Install
File file1
File file2
File file3
InstallEnd

Uninstall
File file1
File file2
File file3
UnInstallEnd

because it would allow me to use a single file list to handle installs and uninstalls. So now I'm not clear on what I can do to create a single file list in one place, yet use it twice -- once to install, once to uninstall.

Ther reason why I need to explicitly remove only the files I create is that the user may create their own, useful files in the same directory, and it's imperative that I not delete them, too via a wholesale directory delete.

Any suggestions?

--Andrew


i guess you could use some function, that processes a list of all files. i only know of this, but it doesn't work recursively. maybe helps anyway.


Yathosho about what function you post? ("Locate" works recursively)


was speaking of MakeFileList


I already wrote something to do all this for you:
http://nsis.sourceforge.net/archive/...php?pageid=556

I posted this in this topic last night, but it some how failed to get posted!

Edit: Just updated script to remove folders too (only if those folders are empty of course).

Edit: Woops posted this before in another toppic by accident!

-Stu


Edit: Just updated script to remove folders too (only if those folders are empty of course).
1. Install order:
C:\ftp\a\b\c
C:\ftp\a
C:\ftp\a\b

Then you run uninstaller first empty directory will be deleted, but second will not, because it contain other empty directory.

2. Script will not write to log directories, if user used command "File /r ..."

Stu.

That looks pretty useful -- but while you're at it, could you add some more functionality? Please? :)

Specifically, the install log ought to record how many times a particular file is installed, and the uninstaller should remove it only when the file "install count" drops to zero.

E.g. Two installers (call them A and B). They both install to the same directory, and have the same license file, but A installs additional fileGroupA and B installs additional fileGroupB.

If you uninstall B, you want A's files in fileGroupA to remain (of course), and you also want the license file to remain (it was (also) installed by A, in the same place as B (re-)installed it).

That sort of functionality would be very, very cool.

Thanks,

--Andrew


Ahh well that's a lot more complicated, but it's possible and I know how it will be done. I will create a new archive page for it too (so the basic method is left intact for other people to use). However, now I need some relaxing multiplayer killage (because I've been adding more comments on some source code for the last hour).

I will get your script done tonight though.

-Stu


Ok I just realised how much code would be needed to get this to work properly and to be honest, it wouldn't be worth the trouble. It'd be much easier to just not extract a file from installer B if that file already exists.

Updated entire script.

Instructor:
1. Added note about order. Could add more code to check for this problem, but I want to keep this as simple as possible for people.
2. There would be no way to get this to work for File /r. That's why you use ${File} in the first place (because File on its own is not enough). It would be possible to allow for this by calling a seperate executable to write code for each file in a folder recursively (like ${SE-AddDir} in my NSIS SFX kit) but again, I want to keep this simple.

-Stu


Hi Stu.

Thanks for the feedback and your work here. I'll go ahead and use what's there for now.

--Andrew


Hi Stu.

I'm trying to use your script, and I ran into two problems.

Here's an example of where the macros get called:

Section "Pro Libraries" SEC_SALVOPROLIBRA430

SetOverwrite on

${SetOutPath} "$INSTDIR\Lib\RA430"

${File} "d:\Pumpkin\Salvo\Lib\RA430\libsalvolra430ia.hza"
${File} "d:\Pumpkin\Salvo\Lib\RA430\libsalvolra430id.hza"
${File} "d:\Pumpkin\Salvo\Lib\RA430\libsalvolra430ie.hza"
${File} "d:\Pumpkin\Salvo\Lib\RA430\libsalvolra430im.hza"
${File} "d:\Pumpkin\Salvo\Lib\RA430\libsalvolra430it.hza"

SectionEnd


where $INSTDIR is C:\Pumpkin_Test.

This file is included several levels deep in the installer (due to organizational and conditional compilation issues). Note that the files that NSIS installs come from a a large directory tree, and that tree must be preserved on the destination hard disk.

1) I had to add

!undef FileID

as the last line of the File macro, in order to avoid the error message that FileID was already defined (e.g. the second time ${File} is invoked).

2) The second problem is harder -- You can see that the various files have long path names associated with them.

Trouble is, those paths are concatenated with the output dir path name in the uninstall log, e.g.

C:\Pumpkin_Test\Salvo\Lib\RA430
C:\Pumpkin_Test\Salvo\Lib\RA430\d:\Pumpkin\Salvo\Lib\RA430\libsalvolra430ia.hza
C:\Pumpkin_Test\Salvo\Lib\RA430\d:\Pumpkin\Salvo\Lib\RA430\libsalvolra430id.hza
C:\Pumpkin_Test\Salvo\Lib\RA430\d:\Pumpkin\Salvo\Lib\RA430\libsalvolra430ie.hza
C:\Pumpkin_Test\Salvo\Lib\RA430\d:\Pumpkin\Salvo\Lib\RA430\libsalvolra430im.hza
C:\Pumpkin_Test\Salvo\Lib\RA430\d:\Pumpkin\Salvo\Lib\RA430\libsalvolra430it.hza

When what I really need is:

C:\Pumpkin_Test\Salvo\Lib\RA430
C:\Pumpkin_Test\Salvo\Lib\RA430\libsalvolra430ia.hza
C:\Pumpkin_Test\Salvo\Lib\RA430\libsalvolra430id.hza
C:\Pumpkin_Test\Salvo\Lib\RA430\libsalvolra430ie.hza
C:\Pumpkin_Test\Salvo\Lib\RA430\libsalvolra430im.hza
C:\Pumpkin_Test\Salvo\Lib\RA430\libsalvolra430it.hza

How can I get the latter while keeping the files in their current source directories?

Thanks. I'm sure this stuff is really simple for NSIS pro like you -- it's still a bit daunting to me. :)

--Andrew


I've updated the File macro.
http://nsis.sourceforge.net/archive/...php?pageid=556

It now takes two paramaters for the path and the file.

-Stu


Hi Stu.

Thanks -- I'm working with it now.

--Andrew


Hi Stu.

Here's a problem -- in Win98, $EXEDIR for the uninstaller is c:\windows\temp, even though I launch it from c:\Pumpkin_Test\Salvo. Therefore it cannot find the uninstaller's uninstall.log file ...

Is there a simple solution to this problem?

Thanks,

--Andrew


Hi Stu.

Similar issue with Win2k testing ... is there perhaps an NSIS global that I've failed to set that controls where the uninstaller runs from?

In Win 98 and Win2k, $EXEDIR is returned as temp directory when I try to run the uninstaller ...

--Andrew


Hi Stu.

Doh! I think you meant to type $INSTDIR throughout the uninstaller, instead of $EXEDIR.

Changed them to $INSTDIR and it works fine ...

I suspect $EXEDIR would be better, but $INSTDIR works for now (though it's more limited in applicability).

As you can see :), it's taking me a while to fully appreciate the "hang yourself" power of NSIS, esp. w/regards to variables and their run-timedness or lack thereof.

Thanks,

--Andrew


Where is the uninstaller located?

-Stu


Hi Stu.

I would also suggest adding a line to remove the uninstaller (.exe) itself, not just the .log file ...

Thanks,

--Andrew


Originally posted by Afrow UK
Where is the uninstaller located?

-Stu
In c:\Pumpkin\Salvo, e.g. c:\Pumpkin\Salvo\Remove Salvo Pro for TI's MSP430.exe.

I'm double-clicking / launching the uninstaller from there, in a Windows window.

I don't suppose the spaces or apostrophe in the filename are causing problems?

--Andrew

Bump.

As best I can tell, the existing script won't work because of $EXEDIR problems involving the uninstall log.

Using $INSTDIR as the pathname to the uninstall log won't work (I suspect) if the user changes the install path ...

--Andrew


$INSTDIR will be the $EXEDIR in the uninstaller unless changed.
NSIS uninstallers only work if they are placed in the install folder. If they are placed elsewhere then you need to tell it where the install location is (e.g. with a registry entry).

And you can't delete a program with itself (the uninstaller).

Thanks I updated the page.

-Stu


Hi Stu.

And you can't delete a program with itself (the uninstaller).
It works for me -- the uninstaller is running from a copy in Windows\Temp, so it's able to remove itself (in $INSTDIR).

Am I missing something?

Thanks for all your help,

--Andrew

Oh yes I see what you mean now. Forget what I said :)

-Stu