wxPython on OSX can now be built in Unicode mode, can support multiple
version installs, and comes with an uninstaller script. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@30055 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
196
wxPython/distrib/mac/uninstall_wxPython.py
Executable file
196
wxPython/distrib/mac/uninstall_wxPython.py
Executable file
@@ -0,0 +1,196 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
This script will search for installed versions of wxPython on OSX and
|
||||
allow the user to choose one to uninstall. It then will use the
|
||||
metadata stored about the installed package to remove all the files
|
||||
associated with that install.
|
||||
|
||||
Only the files installed by the main Installer Package will be
|
||||
removed. This includes the Python modules and the wxWidgets shared
|
||||
libraries. If you also installed the demo or docs by dragging them out
|
||||
of the disk image, then you will need to drag them to the Trash
|
||||
yourself.
|
||||
"""
|
||||
|
||||
import sys, os, glob
|
||||
import cPickle, urllib
|
||||
|
||||
RCPTDIR = "/Library/Receipts"
|
||||
RSRCDIR = "Contents/Resources"
|
||||
|
||||
# only clean up dirs that have one of these as a prefix. We do this
|
||||
# because the file list returned from lsbom will include /, /usr,
|
||||
# /usr/local, etc.
|
||||
PREFIXES = [ '/Library/Python/2.3/',
|
||||
'/Library/Python/2.4/',
|
||||
'/usr/local/lib/',
|
||||
]
|
||||
|
||||
|
||||
class AccessError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class InstalledReceipt(object):
|
||||
def __init__(self, rcptPath):
|
||||
self.rcptPath = rcptPath
|
||||
self.rsrcPath = os.path.join(rcptPath, RSRCDIR)
|
||||
self.bomFile = glob.glob(os.path.join(self.rsrcPath, "*.bom"))[0]
|
||||
self.findMetaData()
|
||||
|
||||
|
||||
def findMetaData(self):
|
||||
# TODO: Make this be able to also look at Info.plist files
|
||||
infoFile = glob.glob(os.path.join(self.rsrcPath, "*.info"))[0]
|
||||
self.mdata = {}
|
||||
for line in open(infoFile, "r").readlines():
|
||||
line = line.strip()
|
||||
if line and line[0] != '#':
|
||||
ls = line.split()
|
||||
self.mdata[ls[0]] = line[len(ls[0])+1:]
|
||||
|
||||
|
||||
def getFileList(self):
|
||||
p = os.popen("lsbom -s %s" % self.bomFile, "r")
|
||||
data = p.read()
|
||||
data.strip()
|
||||
data = filter(lambda s: s!='' and s!='.', data.split('\n'))
|
||||
loc = self.mdata['DefaultLocation']
|
||||
return [loc+item for item in data]
|
||||
|
||||
|
||||
def walkFiles(self, handleFile, handleDir):
|
||||
dirs = []
|
||||
names = self.getFileList()
|
||||
|
||||
# the plain files
|
||||
for name in names:
|
||||
name = os.path.abspath(name)
|
||||
if os.path.isdir(name):
|
||||
dirs.append(name)
|
||||
else:
|
||||
handleFile(name)
|
||||
|
||||
# the directories
|
||||
dirs.reverse()
|
||||
for dir in dirs:
|
||||
for prefix in PREFIXES:
|
||||
if dir.startswith(prefix):
|
||||
handleDir(dir)
|
||||
break
|
||||
|
||||
# Finally, remove the Receipts package, bottom-up
|
||||
for dirpath, dirname, filenames in os.walk(self.rcptPath, False):
|
||||
for name in filenames:
|
||||
name = os.path.join(dirpath, name)
|
||||
handleFile(name)
|
||||
handleDir(dirpath)
|
||||
|
||||
|
||||
|
||||
def showFiles(self):
|
||||
def show(name):
|
||||
if os.path.exists(name):
|
||||
print "Will remove:", name
|
||||
self.walkFiles(show, show)
|
||||
|
||||
|
||||
def testUninstallAccess(self):
|
||||
def testFile(name):
|
||||
if os.path.exists(name):
|
||||
if not os.access(name, os.W_OK):
|
||||
raise AccessError(name)
|
||||
self.walkFiles(testFile, testFile)
|
||||
|
||||
|
||||
def doUninstall(self):
|
||||
def removeFile(name):
|
||||
if os.path.exists(name):
|
||||
print "Removing:", name
|
||||
os.unlink(name)
|
||||
def removeDir(name):
|
||||
print "Removing:", name
|
||||
if os.path.exists(name):
|
||||
hasFiles = os.listdir(name)
|
||||
if hasFiles: # perhaps some left over symlinks, or .pyc files
|
||||
for file in hasFiles:
|
||||
os.unlink(os.path.join(name, file))
|
||||
os.rmdir(name)
|
||||
|
||||
try:
|
||||
self.testUninstallAccess()
|
||||
except AccessError, e:
|
||||
print "UNABLE TO UNINSTALL!\nNo permission to remove: ", e.args[0]
|
||||
sys.exit()
|
||||
|
||||
self.walkFiles(removeFile, removeDir)
|
||||
|
||||
|
||||
|
||||
|
||||
def findInstalled():
|
||||
installed = []
|
||||
for name in glob.glob(os.path.join(RCPTDIR, "wxPython*")):
|
||||
ir = InstalledReceipt(name)
|
||||
installed.append(ir)
|
||||
|
||||
return installed
|
||||
|
||||
|
||||
# Just in case a Python < 2.3 is used to run this
|
||||
try:
|
||||
enumerate
|
||||
except NameError:
|
||||
def enumerate(sequence):
|
||||
return zip(range(len(sequence)), sequence)
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) > 1 and sys.argv[1] == "-doit":
|
||||
inst = cPickle.loads(urllib.unquote(sys.argv[2]))
|
||||
inst.doUninstall()
|
||||
sys.exit()
|
||||
|
||||
print __doc__
|
||||
installed = findInstalled()
|
||||
|
||||
if not installed:
|
||||
print "*** No wxPython installations found! ***"
|
||||
raw_input("Press RETURN...")
|
||||
sys.exit()
|
||||
|
||||
for i, inst in enumerate(installed):
|
||||
print " %d. %s \t%s" % (i+1, inst.mdata["Title"], inst.mdata["Version"])
|
||||
|
||||
print
|
||||
ans = raw_input("Enter the number of the install to examine or 'Q' to quit: ")
|
||||
if ans in ['Q', 'q']:
|
||||
sys.exit()
|
||||
inst = installed[int(ans) - 1]
|
||||
|
||||
while True:
|
||||
print
|
||||
print """
|
||||
Title: %(Title)s
|
||||
Version: %(Version)s
|
||||
Description: %(Description)s
|
||||
""" % inst.mdata
|
||||
|
||||
ans = raw_input("(U)ninstall, (S)how what will be removed, or (Q)uit? [u,s,q] ")
|
||||
if ans in ['Q', 'q']:
|
||||
sys.exit()
|
||||
|
||||
elif ans in ['S', 's']:
|
||||
inst.showFiles()
|
||||
|
||||
elif ans in ['U', 'u']:
|
||||
print
|
||||
print "Launching uninstaller with sudo, please enter your password if prompted:"
|
||||
os.system("sudo %s -doit %s" %
|
||||
(sys.argv[0],
|
||||
urllib.quote(cPickle.dumps(inst))))
|
||||
sys.exit()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Reference in New Issue
Block a user