Talk:Uninstall only installed files: Difference between revisions
No edit summary |
No edit summary |
||
Line 2: | Line 2: | ||
I searched a lot for a way to combine these 2 features using the NSIS script and I finally gave up. I wrote a small Python script that generates a pair of lists, to be included in a pair of sections (install and uninstall) in your .nsi script. I post hereafter the python scrip. Here is the small .bat that you would use to call in sequence that script and the NSIS build. | I searched a lot for a way to combine these 2 features using the NSIS script and I finally gave up. I wrote a small Python script that generates a pair of lists, to be included in a pair of sections (install and uninstall) in your .nsi script. I post hereafter the python scrip. Here is the small .bat that you would use to call in sequence that script and the NSIS build. | ||
Good luck and have fun, | |||
adrian DOT neagu AT scansoft DOT com | |||
---- | |||
python gen_list_files_for_nsis.py %LOCATION_SOURCES% install_list.nsh uninstall_list.nsh | python gen_list_files_for_nsis.py %LOCATION_SOURCES% install_list.nsh uninstall_list.nsh | ||
Line 123: | Line 129: | ||
</highlight-python> | </highlight-python> | ||
And your NSIS script would look something like this: | And your NSIS script (my_product.nsi) would look something like this: | ||
<highlight-nsis> | <highlight-nsis> | ||
;-------------------------------- | ;-------------------------------- |
Revision as of 18:34, 21 April 2006
The solution presented here to uninstall only the files we installed works fine. There is only one shortcoming: the list of files has to be known beforehand. This solution actually overloads File in a way that denies the recursive switch. Meaning that the created installation log is only useful if you don’t grab all the files from one source directory in your installer: File /r <my_dir>
I searched a lot for a way to combine these 2 features using the NSIS script and I finally gave up. I wrote a small Python script that generates a pair of lists, to be included in a pair of sections (install and uninstall) in your .nsi script. I post hereafter the python scrip. Here is the small .bat that you would use to call in sequence that script and the NSIS build.
Good luck and have fun,
adrian DOT neagu AT scansoft DOT com
python gen_list_files_for_nsis.py %LOCATION_SOURCES% install_list.nsh uninstall_list.nsh
"C:\Program Files\NSIS\makensis.exe" /DINST_LIST=install_list.nsh /DUNINST_LIST=uninstall_list.nsh my_product.nsi
The Script
""" This script generates 2 lists of NSIS commands (install&uninstall) for all files in a given directory Usage: gen_list_files_for_nsis.py <dir src> <inst list> <uninst list> Where <dir src> : dir with sources; must exist <inst list> : list of files to install (NSIS syntax) <uninst list> : list of files to uninstall (NSIS syntax) (both these will be overwriten each time) """ import sys, os, glob # global settings just_print_flag = 0 # turn to 1 for debugging # templates for the output inst_dir_tpl = ' SetOutPath $INSTDIR%s' inst_file_tpl = ' File ${FILES_SOURCE_PATH}%s' uninst_file_tpl = ' Delete $INSTDIR%s' uninst_dir_tpl = ' RMDir $INSTDIR%s' # check args if len(sys.argv) != 4: print __doc__ sys.exit(1) source_dir = sys.argv[1] if not os.path.isdir(source_dir): print __doc__ sys.exit(1) def open_file_for_writting(filename): "return a handle to the file to write to" try: h = file(filename, "w") except: print "Problem opening file %s for writting"%filename print __doc__ sys.exit(1) return h inst_list = sys.argv[2] uninst_list = sys.argv[3] if not just_print_flag: ih= open_file_for_writting(inst_list) uh= open_file_for_writting(uninst_list) stack_of_visited = [] counter_files = 0 counter_dirs = 0 print "Generating the install & uninstall list of files" print " for directory", source_dir print >> ih, " ; Files to install\n" print >> uh, " ; Files and dirs to remove\n" # man page of walk() in Python 2.2 (the new one in 2.4 is easier to use) # os.path.walk(path, visit, arg) #~ Calls the function visit with arguments (arg, dirname, names) for each directory #~ in the directory tree rooted at path (including path itself, if it is a directory). #~ The argument dirname specifies the visited directory, the argument names lists #~ the files in the directory (gotten from os.listdir(dirname)). The visit function #~ may modify names to influence the set of directories visited below dirname, #~ e.g., to avoid visiting certain parts of the tree. (The object referred to by names #~ must be modified in place, using del or slice assignment.) def my_visitor(my_stack, cur_dir, files_and_dirs): "add files to the install list and accumulate files for the uninstall list" global counter_dirs, counter_files, stack_of_visited counter_dirs += 1 if just_print_flag: print "here", my_dir return # first separate files my_files = [x for x in files_and_dirs if os.path.isfile(cur_dir+os.sep+x)] # and truncate dir name my_dir = cur_dir[len(source_dir):] if my_dir=="": my_dir = "\\." # save it for uninstall stack_of_visited.append( (my_files, my_dir) ) # build install list if len(my_files): print >> ih, inst_dir_tpl % my_dir for f in my_files: print >> ih, inst_file_tpl % my_dir+os.sep+f counter_files += 1 print >> ih, " " os.path.walk( source_dir, my_visitor, stack_of_visited) ih.close() print "Install list done" print " ", counter_files, "files in", counter_dirs, "dirs" stack_of_visited.reverse() # Now build the uninstall list for (my_files, my_dir) in stack_of_visited: for f in my_files: print >> uh, uninst_file_tpl % my_dir+os.sep+f print >> uh, uninst_dir_tpl % my_dir print >> uh, " " # now close everything uh.close() print "Uninstall list done. Got to end.\n"
And your NSIS script (my_product.nsi) would look something like this:
;-------------------------------- ; ; the stuff to install ; ;-------------------------------- Section "" ; No components page, name is not important !include ${INST_LIST} ; the payload of this installer is described in an externally generated list of files ;File /r "${FILES_SOURCE_PATH}\*.*" ; not OK because with /r we can not log what was installed ; and without logging we cannot uninstall only the files installed by us SectionEnd ;-------------------------------- ; ; uninstaller ; ;-------------------------------- Section "Uninstall" ; Remove the files (using externally generated file list) !include ${UNINST_LIST} ; Remove uninstaller Delete $INSTDIR\uninst*.exe RMDir $INSTDIR ; this is safe; it's not forced if you still have private files there. ; Important note: RMDir /r "$INSTDIR" ; is NOT OK! ; if the user installed in "C:\Program Files" by mistake, then we totally screw up his machine! SectionEnd ; Uninstall