]> git.saurik.com Git - wxWidgets.git/blob - wxPython/distrib/mac/uninstall_wxPython.py
Do not uninstall wxaddons module or files.
[wxWidgets.git] / wxPython / distrib / mac / uninstall_wxPython.py
1 #!/usr/bin/env python
2 """
3 This script will search for installed versions of wxPython on OSX and
4 allow the user to choose one to uninstall. It then will use the
5 metadata stored about the installed package to remove all the files
6 associated with that install.
7
8 Only the files installed by the main Installer Package will be
9 removed. This includes the Python modules and the wxWidgets shared
10 libraries. If you also installed the demo or docs by dragging them out
11 of the disk image, then you will need to drag them to the Trash
12 yourself.
13 """
14
15 import sys, os, glob
16 from fnmatch import fnmatchcase
17 import cPickle, urllib
18
19 RCPTDIR = "/Library/Receipts"
20 RSRCDIR = "Contents/Resources"
21
22 # Only completly clean out dirs that have one of these as a prefix.
23 # We do this because the file list returned from lsbom will include /,
24 # /usr, /usr/local, etc.
25 PREFIXES = [ '/Library/Python/2.3/',
26 '/Library/Python/2.4/',
27 '/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/site-packages/',
28 '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/',
29 '/usr/local/lib/',
30 ]
31
32 # The files that match one of the items in this list will only be
33 # removed if the last installation of wxPython on the system is being
34 # uninstalled.
35 COMMON_FILES = [ '/usr/local/bin/*',
36 'wx.pth',
37 'wxversion.py',
38 ]
39
40
41
42 class AccessError(Exception):
43 pass
44
45 class ReceiptError(Exception):
46 pass
47
48
49 class InstalledReceipt(object):
50 def __init__(self, rcptPath):
51 self.rcptPath = rcptPath
52 self.rsrcPath = os.path.join(rcptPath, RSRCDIR)
53 bf = glob.glob(os.path.join(self.rsrcPath, "*.bom"))
54 if bf:
55 self.bomFile = bf[0]
56 else:
57 print "WARNING: Unable to find %s/*.bom" % self.rsrcPath
58 raise ReceiptError
59 self.findMetaData()
60
61
62 def findMetaData(self):
63 # TODO: Make this be able to also look at Info.plist files
64 infoFiles = glob.glob(os.path.join(self.rsrcPath, "*.info"))
65 if infoFiles:
66 # there should be only one
67 infoFile = infoFiles[0]
68 self.mdata = {}
69 for line in open(infoFile, "r").readlines():
70 line = line.strip()
71 if line and line[0] != '#':
72 ls = line.split()
73 self.mdata[ls[0]] = line[len(ls[0])+1:]
74 else:
75 print "WARNING: Unable to find %s/*.info" % self.rsrcPath
76 raise ReceiptError
77
78
79 def getFileList(self):
80 p = os.popen("lsbom -s %s" % self.bomFile, "r")
81 data = p.read()
82 data.strip()
83 data = filter(lambda s: s!='' and s!='.', data.split('\n'))
84 loc = self.mdata['DefaultLocation']
85 return [loc+item for item in data]
86
87
88 def walkFiles(self, handleFile, handleDir):
89 dirs = []
90 names = self.getFileList()
91
92 # the plain files
93 for name in names:
94 name = os.path.abspath(name)
95 if os.path.isdir(name):
96 dirs.append(name)
97 else:
98 handleFile(name)
99
100 # the directories
101 dirs.reverse()
102 for dir in dirs:
103 for prefix in PREFIXES:
104 if dir.startswith(prefix):
105 handleDir(dir)
106 break
107
108 # Finally, remove the Receipts package, bottom-up
109 for dirpath, dirname, filenames in os.walk(self.rcptPath, False):
110 for name in filenames:
111 name = os.path.join(dirpath, name)
112 handleFile(name)
113 handleDir(dirpath)
114
115 # wxaddons should be always kept as the user may have installed
116 # third-party modules seperate from wxpython.
117 def testWxaddons(self, name):
118 for prefix in PREFIXES:
119 if name.startswith(prefix + "wxaddons"):
120 return True
121 return False
122
123 def testCommon(self, name):
124 for cmn in COMMON_FILES:
125 if fnmatchcase(name, cmn) or fnmatchcase(os.path.basename(name), cmn):
126 return True
127 return False
128
129
130 def showFiles(self):
131 def show(name):
132 if os.path.exists(name):
133 if not self.lastInstall and self.testCommon(name):
134 return
135 if self.testWxaddons(name):
136 return
137 print "Will remove:", name
138 self.walkFiles(show, show)
139
140
141 def testUninstallAccess(self):
142 def testFile(name):
143 if os.path.exists(name):
144 if not self.lastInstall and self.testCommon(name):
145 return
146 if not os.access(name, os.W_OK):
147 raise AccessError(name)
148 self.walkFiles(testFile, testFile)
149
150
151 def doUninstall(self):
152 def removeFile(name):
153 if os.path.exists(name):
154 if not self.lastInstall and self.testCommon(name):
155 return
156 if self.testWxaddons(name):
157 return
158 print "Removing:", name
159 os.unlink(name)
160 def removeDir(name):
161 print "Removing:", name
162 if os.path.exists(name) and not self.testWxaddons(name):
163 hasFiles = os.listdir(name)
164 if hasFiles: # perhaps some stale symlinks, or .pyc files
165 for file in hasFiles:
166 os.unlink(os.path.join(name, file))
167 os.rmdir(name)
168
169 try:
170 self.testUninstallAccess()
171 except AccessError, e:
172 print "UNABLE TO UNINSTALL!\nNo permission to remove: ", e.args[0]
173 sys.exit()
174
175 self.walkFiles(removeFile, removeDir)
176
177
178
179
180 def findInstalled():
181 installed = []
182 for name in glob.glob(os.path.join(RCPTDIR, "wxPython*")):
183 try:
184 ir = InstalledReceipt(name)
185 installed.append(ir)
186 except ReceiptError:
187 pass # just skip it...
188
189 return installed
190
191
192 # Just in case a Python < 2.3 is used to run this
193 try:
194 enumerate
195 except NameError:
196 def enumerate(sequence):
197 return zip(range(len(sequence)), sequence)
198
199
200 def main():
201 if len(sys.argv) > 1 and sys.argv[1] == "-doit":
202 inst = cPickle.loads(urllib.unquote(sys.argv[2]))
203 inst.doUninstall()
204 sys.exit()
205
206 print __doc__
207 installed = findInstalled()
208
209 if not installed:
210 print "*** No wxPython installations found! ***"
211 raw_input("Press RETURN...")
212 sys.exit()
213
214 for i, inst in enumerate(installed):
215 print " %2d. %-40s %s" % (i+1, inst.mdata["Title"], inst.mdata["Version"])
216
217 print
218 ans = raw_input("Enter the number of the install to examine or 'Q' to quit: ")
219 if ans in ['Q', 'q']:
220 sys.exit()
221 inst = installed[int(ans) - 1]
222 inst.lastInstall = len(installed) == 1
223
224 while True:
225 print
226 print """
227 Title: %(Title)s
228 Version: %(Version)s
229 Description: %(Description)s
230 """ % inst.mdata
231
232 ans = raw_input("(U)ninstall, (S)how what will be removed, or (Q)uit? [u,s,q] ")
233 if ans in ['Q', 'q']:
234 sys.exit()
235
236 elif ans in ['S', 's']:
237 inst.showFiles()
238
239 elif ans in ['U', 'u']:
240 print
241 print "Launching uninstaller with sudo, please enter your password if prompted:"
242 os.system("sudo %s -doit %s" %
243 (sys.argv[0],
244 urllib.quote(cPickle.dumps(inst))))
245 sys.exit()
246
247
248 if __name__ == '__main__':
249 main()