Archive: Rollback


Rollback
Hello everybody, it's my first post.
I'm doing evaluation on nsis and inno to choose the one that suits me more.
I've read and seen enough, just need one last question answered.
Does NSIS supports rollback functionality?
I mean, if I have a scenario of upgrade, which contains copying a lot of files over existing installation and after that calling some sophisticated sql scripts, which can fail, will it be possible to (depending on sql actions outcome) rollback the whole installation to the point before upgrade?
I am pretty sure Inno has it.
p.s.
I don't want no flamewar, just a simple answer, perhaps with some links.


oh come on!
Nobody?


no, there is no rollback, you could copy the original files to a backupdir and "restore" from that if needed


thx man.
I was already trying this route.
In my case it also means copying a db. But it should be do-able...


This might help you:
http://nsis.sourceforge.net/Backup_f...e_on_uninstall

Stu


rollback.nsh
I'm working on a nice rollback include. ( Aptly titled rollback.nsh ) Just a set of macros really, but it sets up a log that can be saved to a provided path.... builds the log...as you install or edit files and registry entries... and when you're done you close the "session". Then later you could come back and execute the rollback.

Works well for my application which can't really depend on having a clean folder for its files. So 'rollback' means recopying whatever files I detect that I've stepped on, back into the working folder on a rollback. ( Essentially parsing the log file... for FILE entries, and putting it back where the PATH attribute says to go. )

Maybe we should include a log for SQL calls to? Or better a log to execute SQL files against a database... that might abstract your issue better.

It'd be ready for a demo as a general include, except that I'd like to include the ability to tie in a CallBack on a failed copy.... i.e. If you tried to restore a file it was tied up or something. Currently I have a string that gets read from the log file and passed to ExecWait but that's just a bit limiting and somewhat impractical. I'd rather be able to read a string from the log file and call back a function in the NSIS script... like so:

Function handleErrorWithCustomCallback
MessageBox MB_OK "Handled Error."
FunctionEnd

## SNIP ##
## In some Section or function...
ReadFile $myFile $myCallBackString ; blah blah blah
## myCallBackString now has "handleErrorWithCustomCallback"

Call $myCallBackString ; but this isn't resolving....
; macros seem to do something like this with ${_label} but not quite....

The lack of runtime binding/resolution seems to not resolve this.... or maybe I'm not resolving the var's contents like I should be.... any comments Stu?


Try using GetFunctionAddress.

Stu


Not the answer.... still requries compile time binding.
Sadly, that doesn't seem to work.... for example....

Function testCallback
MessageBox MB_OK "Called it"
FunctionEnd


;--------------------------------
; There are no sections or pages in this installer. It just executes the .onInit and closes.
;
Function .onInit
var /GLOBAL testTheCallback
StrCmp "1" "0" 0 +2
call testCallback ; this so it doesn't zero the code.

MessageBox MB_OK "Testing callback:"
StrCpy $testTheCallback "testCallback"
GetFunctionAddress $R1 $testTheCallback ;Doesnt' work.

###
## WORKS: GetFunctionAddress $R1 "testCallback"
## BUT SINCE ITS READING IT FROM A FILE ITS NOT USEFUL.
#######################################################
Call $R1
FunctionEnd


GetFunctionAddress seems to want the literal function name entered, not some variable.....


The actual names of function and variables are not included in the compiled installer.


agreed......
Considering that we're sort of operating in an Assembly like stack mentality... I understand that the nice readable names get stored merely as a memory location.

Are you saying that there is no runtime-linking to functions based on an evaluated string? i.e...... something like this in a javascript mentality might look like.... ( during runtime... obviously )

myVar = eval("customFunctionName");

Thus, we could use a line like to this to interpret text files into operating instructions at runtime... such as a call back function for some condition.

What you are saying is that there is no way to reference that function abstractly in code during runtime?


Sorry to bump an old thread, but I did have something to contribute.

We are using quite an old version of NSIS, (2.14), with some custom modifications to the NSIS code to provide a primitive (but works for us) automated rollback system.

Deep down in the NSIS core, where the file is actually written to disk, before the write is actually done, we check to see if it already exists, if it does, we append the existing filename with the .previous extension and then write the new file. On uninstall, it's simply a process of recursively scanning the installation folder, if we find a .previous, delete the original file and restore the .previous version.

The whole .previous creation process can be enabled or disabled during the script execution by setting $R9 (this clearly could be improved to make it a keyword)

Anyone want the patch? (the reason we are still using NSIS 2.14 is because of the source changes we made, we don't see any issues with this old NSIS version, and don't want to constantly merge our NSIS, so there is a benefit for us if we can get this patch, or equivalent functionality into NSIS, so we can use standard NSIS)


There is no need to edit the NSIS sourcecode to get this behaviour. It's extremely simple to do this in script alone. I therefore very much doubt that your patch will be merged into the trunk.


It's extremely simple to do this in script alone.
Since when? :x

Not that I'm advocating this patch per se - but unless I missed something, you're going to need quite a bit of code to actually get this sort of behavior out of NSIS. There's probably examples in the wiki that make it easier because you don't have to come up with something from scratch*, but...

For single files, you'd have to define a macro that replaces the File command you'd normally use which...
1. Checks if the file exists
2. If it does, creates a backup*
3. Tries to overwrite the file
3a. If it succeeds - great, done
3b.1 If not, delete the backup
3b.2 Catch the error with custom handling if desired (see some other thread on this)
* and in the backup section check if you can actually back up to the location you want to back up to.

And that's single files. As soon as you use the File command to include multiple files or files recursively, you have to either... A. Drop that construction entirely and make a pre-installer build installer that generates a file inclusion list for the actual installer, or B. First extract the files to a temporary location and instead of using the File command to place the files directly, find the files that were created in the temporary location and use CopyFiles and CreateDirectory instead (further handling is similar to the above).

You'd need these as separate macros as well - or as a single macro but for 'single file' calls you'd have to explicitly indicate that it is such. e.g.
!macro macroname source dest recursive
For a single file would always have to specify the 'recursive' bit as being 'false', '0', or whatever one chooses.
This applies for every parameter in the File command that you'd want to support. Adding support for /x (exclude files) means adding another parameter... now a single file call might end up looking like:
${macroname} "somefile.ext" "$InstDir\somefile.ext" 0 0
Alternatively you'd have to define them before your call.. or callS in which case you have to make sure you don't forget to undefine them afterward.. etc.

It's not impossible, but 'extremely simple' is not how I would choose to describe it in general ;)

Originally posted by Animaether
It's not impossible, but 'extremely simple' is not how I would choose to describe it in general ;)
I was referring to the fact that it mostly requires just a bunch of ${If} statements, which are trivial to code if you're clearheaded enough. But sure, I stand corrected, it takes some effort to get it exactly right. :-)

(You could of course make two macros, one single and one recursive/wildcard...)

Originally posted by MSG
(You could of course make two macros, one single and one recursive/wildcard...)
Well that's something I addressed toward the end... now you want to support /x as well.
So now you need macros:
File
FileR
FileX
FileRX

Now add /a and /nonfatal ;) Granted, those are a little more obscure, but you can see how things quickly tend to explode into a number of macros. Hence why instead one might have something like a context switch...
${NonFatal} true
${FileSomething} a x ...
${FileSomething} b x ...
${FileSomething} c x ...
${NonFatal} False

But you phrased it well when you said
it takes some effort to get it exactly right. :-)
:)

And this was precisely the reason we decided on a change deep down at file writing level, as it works regardless of how the file is added to the installer :-)


Originally posted by mgillespie
And this was precisely the reason we decided on a change deep down at file writing level, as it works regardless of how the file is added to the installer :-)
Only to an extent, though, if I read your original post right:
Originally Posted by mgillespie We check to see if it already exists, if it does, we append the existing filename with the .previous extension and then write the new file.
So what if filename.previous already exists?

Originally Posted by mgillespie On uninstall, it's simply a process of recursively scanning the installation folder, if we find a .previous, delete the original file and restore the .previous version.
And what if 'the original' is not actually -your- original?

Doing it 'right' will never be easy - if even possible at all - but there's certainly room for improvement.

Originally posted by Andrew Wallo
I'm working on a nice rollback include. ( Aptly titled rollback.nsh ) Just a set of macros really, but it sets up a log that can be saved to a provided path.... builds the log...as you install or edit files and registry entries... and when you're done you close the "session". Then later you could come back and execute the rollback.
It'd be ready for a demo as a general include, except that I'd like to include the ability to tie in a CallBack on a failed copy.... i.e. If you tried to restore a file it was tied up or something. Currently I have a string that gets read from the log file and passed to ExecWait but that's just a bit limiting and somewhat impractical. I'd rather be able to read a string from the log file and call back a function in the NSIS script... like so:

Function handleErrorWithCustomCallback
MessageBox MB_OK "Handled Error."
FunctionEnd

## SNIP ##
## In some Section or function...
ReadFile $myFile $myCallBackString ; blah blah blah
## myCallBackString now has "handleErrorWithCustomCallback"

Call $myCallBackString ; but this isn't resolving....
; macros seem to do something like this with ${_label} but not quite....

The lack of runtime binding/resolution seems to not resolve this.... or maybe I'm not resolving the var's contents like I should be.... any comments Stu?
Any progress on that? I've coded a macro-based semi-solution which allows registering "callback groups", each containing up to 16 callbacks. See callback.nsh for code, and testcallback.nsi for an example of usage. In exchange I'd really like to see your rollback code :)