scripts/uninstall.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
child 7192
a22eee00b052
child 7210
8fe313d039e6
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3
4 # Copyright (c) 2002 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
5 #
6 # This is the uninstall script for eric6.
7 #
8
9 """
10 Uninstallation script for the eric6 IDE and all eric6 related tools.
11 """
12
13 from __future__ import unicode_literals, print_function
14
15 import sys
16 import os
17 import shutil
18 import glob
19 import distutils.sysconfig
20
21 if sys.version_info[0] == 2:
22 try:
23 from PyQt5 import sip
24 except ImportError:
25 import sip
26 sip.setapi('QString', 2)
27 else:
28 raw_input = input
29
30 # get a local eric6config.py out of the way
31 if os.path.exists("eric6config.py"):
32 os.rename("eric6config.py", "eric6config.py.orig")
33 from eric6config import getConfig
34
35 # Define the globals.
36 progName = None
37 currDir = os.getcwd()
38 pyModDir = None
39 progLanguages = ["Python", "Ruby", "QSS"]
40 includePythonVariant = False
41 defaultMacAppBundleName = "eric6.app"
42 defaultMacAppBundlePath = "/Applications"
43 settingsNameOrganization = "Eric6"
44 settingsNameGlobal = "eric6"
45
46 # Define file name markers for Python variants
47 PythonMarkers = {
48 2: "_py2",
49 3: "_py3",
50 }
51
52
53 def exit(rcode=0):
54 """
55 Exit the uninstall script.
56
57 @param rcode result code to report back (integer)
58 """
59 global currDir
60
61 # restore the local eric6config.py
62 if os.path.exists("eric6config.py.orig"):
63 if os.path.exists("eric6config.py"):
64 os.remove("eric6config.py")
65 os.rename("eric6config.py.orig", "eric6config.py")
66
67 if sys.platform.startswith(("win", "cygwin")):
68 # different meaning of input between Py2 and Py3
69 try:
70 input("Press enter to continue...")
71 except (EOFError, SyntaxError):
72 pass
73
74 os.chdir(currDir)
75
76 sys.exit(rcode)
77
78
79 def usage(rcode=2):
80 """
81 Display a usage message and exit.
82
83 @param rcode return code passed back to the calling process (integer)
84 """
85 global progName
86
87 print("Usage:")
88 print(" {0} [-h]".format(progName))
89 print("where:")
90 print(" -h display this help message")
91 print(" -y remove executables with Python variant in name")
92
93 exit(rcode)
94
95
96 def initGlobals():
97 """
98 Set the values of globals that need more than a simple assignment.
99 """
100 global pyModDir
101
102 pyModDir = distutils.sysconfig.get_python_lib(True)
103
104
105 def wrapperNames(dname, wfile):
106 """
107 Create the platform specific names for the wrapper script.
108
109 @param dname name of the directory to place the wrapper into
110 @param wfile basename (without extension) of the wrapper script
111 @return the names of the wrapper scripts
112 """
113 if sys.platform.startswith(("win", "cygwin")):
114 wnames = (dname + "\\" + wfile + ".cmd",
115 dname + "\\" + wfile + ".bat")
116 else:
117 wnames = (dname + "/" + wfile, )
118
119 return wnames
120
121
122 def uninstallEric():
123 """
124 Uninstall the eric files.
125 """
126 global pyModDir
127
128 # Remove the menu entry for Linux systems
129 if sys.platform.startswith("linux"):
130 uninstallLinuxSpecifics()
131 # Remove the Desktop and Start Menu entries for Windows systems
132 elif sys.platform.startswith(("win", "cygwin")):
133 uninstallWindowsLinks()
134
135 # Remove the wrapper scripts
136 rem_wnames = [
137 "eric6_api", "eric6_compare",
138 "eric6_configure", "eric6_diff",
139 "eric6_doc", "eric6_qregularexpression",
140 "eric6_qregexp", "eric6_re",
141 "eric6_trpreviewer", "eric6_uipreviewer",
142 "eric6_unittest", "eric6",
143 "eric6_tray", "eric6_editor",
144 "eric6_plugininstall", "eric6_pluginuninstall",
145 "eric6_pluginrepository", "eric6_sqlbrowser",
146 "eric6_webbrowser", "eric6_iconeditor",
147 "eric6_snap", "eric6_hexeditor", "eric6_browser",
148 "eric6_shell",
149 ]
150 if includePythonVariant:
151 marker = PythonMarkers[sys.version_info.major]
152 rem_wnames = [n + marker for n in rem_wnames]
153
154 try:
155 for rem_wname in rem_wnames:
156 for rwname in wrapperNames(getConfig('bindir'), rem_wname):
157 if os.path.exists(rwname):
158 os.remove(rwname)
159
160 # Cleanup our config file(s)
161 for name in ['eric6config.py', 'eric6config.pyc', 'eric6.pth']:
162 e5cfile = os.path.join(pyModDir, name)
163 if os.path.exists(e5cfile):
164 os.remove(e5cfile)
165 e5cfile = os.path.join(pyModDir, "__pycache__", name)
166 path, ext = os.path.splitext(e5cfile)
167 for f in glob.glob("{0}.*{1}".format(path, ext)):
168 os.remove(f)
169
170 # Cleanup the install directories
171 for name in ['ericExamplesDir', 'ericDocDir', 'ericDTDDir',
172 'ericCSSDir', 'ericIconDir', 'ericPixDir',
173 'ericTemplatesDir', 'ericCodeTemplatesDir',
174 'ericOthersDir', 'ericStylesDir', 'ericDir']:
175 dirpath = getConfig(name)
176 if os.path.exists(dirpath):
177 shutil.rmtree(dirpath, True)
178
179 # Cleanup translations
180 for name in glob.glob(
181 os.path.join(getConfig('ericTranslationsDir'), 'eric6_*.qm')):
182 if os.path.exists(name):
183 os.remove(name)
184
185 # Cleanup API files
186 apidir = getConfig('apidir')
187 if apidir:
188 for progLanguage in progLanguages:
189 for name in getConfig('apis'):
190 apiname = os.path.join(apidir, progLanguage.lower(), name)
191 if os.path.exists(apiname):
192 os.remove(apiname)
193 for apiname in glob.glob(
194 os.path.join(apidir, progLanguage.lower(), "*.bas")):
195 if os.path.basename(apiname) != "eric6.bas":
196 os.remove(apiname)
197
198 if sys.platform == "darwin":
199 # delete the Mac app bundle
200 uninstallMacAppBundle()
201
202 # remove plug-in directories
203 removePluginDirectories()
204
205 # remove the eric data directory
206 removeDataDirectory()
207
208 # remove the eric configuration directory
209 removeConfigurationData()
210
211 print("\nUninstallation completed")
212 except (IOError, OSError) as msg:
213 sys.stderr.write(
214 'Error: {0}\nTry uninstall with admin rights.\n'.format(msg))
215 exit(7)
216
217
218 def uninstallWindowsLinks():
219 """
220 Clean up the Desktop and Start Menu entries for Windows.
221 """
222 try:
223 from pywintypes import com_error # __IGNORE_WARNING__
224 except ImportError:
225 # links were not created by install.py
226 return
227
228 regPath = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer" + \
229 "\\User Shell Folders"
230
231 # 1. cleanup desktop links
232 regName = "Desktop"
233 desktopEntry = getWinregEntry(regName, regPath)
234 if desktopEntry:
235 desktopFolder = os.path.normpath(os.path.expandvars(desktopEntry))
236 for linkName in windowsDesktopNames():
237 linkPath = os.path.join(desktopFolder, linkName)
238 if os.path.exists(linkPath):
239 try:
240 os.remove(linkPath)
241 except EnvironmentError:
242 # maybe restrictions prohibited link removal
243 print("Could not remove '{0}'.".format(linkPath))
244
245 # 2. cleanup start menu entry
246 regName = "Programs"
247 programsEntry = getWinregEntry(regName, regPath)
248 if programsEntry:
249 programsFolder = os.path.normpath(os.path.expandvars(programsEntry))
250 eric6EntryPath = os.path.join(programsFolder, windowsProgramsEntry())
251 if os.path.exists(eric6EntryPath):
252 try:
253 shutil.rmtree(eric6EntryPath)
254 except EnvironmentError:
255 # maybe restrictions prohibited link removal
256 print("Could not remove '{0}'.".format(eric6EntryPath))
257
258
259 def uninstallLinuxSpecifics():
260 """
261 Uninstall Linux specific files.
262 """
263 if os.getuid() == 0:
264 for name in ["/usr/share/pixmaps/eric.png",
265 "/usr/share/pixmaps/ericWeb.png"]:
266 if os.path.exists(name):
267 os.remove(name)
268 if includePythonVariant:
269 marker = PythonMarkers[sys.version_info.major]
270 else:
271 marker = ""
272 for name in [
273 "/usr/share/applications/eric6" + marker + ".desktop",
274 "/usr/share/appdata/eric6" + marker + ".appdata.xml",
275 "/usr/share/metainfo/eric6" + marker + ".appdata.xml",
276 "/usr/share/applications/eric6_webbrowser" + marker +
277 ".desktop",
278 "/usr/share/applications/eric6_browser" + marker +
279 ".desktop",
280 "/usr/share/pixmaps/eric" + marker + ".png",
281 "/usr/share/pixmaps/ericWeb" + marker + ".png",
282 ]:
283 if os.path.exists(name):
284 os.remove(name)
285 elif os.getuid() >= 1000:
286 # it is assumed that user ids start at 1000
287 for name in ["~/.local/share/pixmaps/eric.png",
288 "~/.local/share/pixmaps/ericWeb.png"]:
289 path = os.path.expanduser(name)
290 if os.path.exists(path):
291 os.remove(path)
292 if includePythonVariant:
293 marker = PythonMarkers[sys.version_info.major]
294 else:
295 marker = ""
296 for name in [
297 "~/.local/share/applications/eric6" + marker + ".desktop",
298 "~/.local/share/appdata/eric6" + marker + ".appdata.xml",
299 "~/.local/share/metainfo/eric6" + marker + ".appdata.xml",
300 "~/.local/share/applications/eric6_webbrowser" + marker +
301 ".desktop",
302 "~/.local/share/applications/eric6_browser" + marker +
303 ".desktop",
304 "~/.local/share/pixmaps/eric" + marker + ".png",
305 "~/.local/share/pixmaps/ericWeb" + marker + ".png",
306 ]:
307 path = os.path.expanduser(name)
308 if os.path.exists(path):
309 os.remove(path)
310
311
312 def uninstallMacAppBundle():
313 """
314 Uninstall the macOS application bundle.
315 """
316 if os.path.exists("/Developer/Applications/Eric6"):
317 shutil.rmtree("/Developer/Applications/Eric6")
318 try:
319 macAppBundlePath = getConfig("macAppBundlePath")
320 macAppBundleName = getConfig("macAppBundleName")
321 except AttributeError:
322 macAppBundlePath = defaultMacAppBundlePath
323 macAppBundleName = defaultMacAppBundleName
324 for bundlePath in [os.path.join(defaultMacAppBundlePath,
325 macAppBundleName),
326 os.path.join(macAppBundlePath,
327 macAppBundleName),
328 ]:
329 if os.path.exists(bundlePath):
330 shutil.rmtree(bundlePath)
331
332
333 def removePluginDirectories():
334 """
335 Remove the plug-in directories.
336 """
337 pathsToRemove = []
338
339 globalPluginsDir = os.path.join(getConfig('mdir'), "eric6plugins")
340 if os.path.exists(globalPluginsDir):
341 pathsToRemove.append(globalPluginsDir)
342
343 localPluginsDir = os.path.join(getConfigDir(), "eric6plugins")
344 if os.path.exists(localPluginsDir):
345 pathsToRemove.append(localPluginsDir)
346
347 if pathsToRemove:
348 print("Found these plug-in directories")
349 for path in pathsToRemove:
350 print(" - {0}".format(path))
351 answer = "c"
352 while answer not in ["y", "Y", "n", "N", ""]:
353 answer = raw_input(
354 "Shall these directories be removed (y/N)? ")
355 if answer in ["y", "Y"]:
356 for path in pathsToRemove:
357 shutil.rmtree(path)
358
359
360 def removeDataDirectory():
361 """
362 Remove the eric data directory.
363 """
364 cfg = getConfigDir()
365 if os.path.exists(cfg):
366 print("Found the eric data directory")
367 print(" - {0}".format(cfg))
368 answer = "c"
369 while answer not in ["y", "Y", "n", "N", ""]:
370 answer = raw_input(
371 "Shall this directory be removed (y/N)? ")
372 if answer in ["y", "Y"]:
373 shutil.rmtree(cfg)
374
375
376 def removeConfigurationData():
377 """
378 Remove the eric configuration directory.
379 """
380 try:
381 from PyQt5.QtCore import QSettings
382 except ImportError:
383 try:
384 from PyQt4.QtCore import QSettings
385 except ImportError:
386 print("No PyQt variant installed. The configuration directory")
387 print("cannot be determined. You have to remove it manually.\n")
388 return
389
390 settings = QSettings(QSettings.IniFormat, QSettings.UserScope,
391 settingsNameOrganization, settingsNameGlobal)
392 settingsDir = os.path.dirname(settings.fileName())
393 if os.path.exists(settingsDir):
394 print("Found the eric configuration directory")
395 print(" - {0}".format(settingsDir))
396 answer = "c"
397 while answer not in ["y", "Y", "n", "N", ""]:
398 answer = raw_input(
399 "Shall this directory be removed (y/N)? ")
400 if answer in ["y", "Y"]:
401 shutil.rmtree(settingsDir)
402
403
404 def getConfigDir():
405 """
406 Module function to get the name of the directory storing the config data.
407
408 @return directory name of the config dir (string)
409 """
410 cdn = ".eric6"
411 return os.path.join(os.path.expanduser("~"), cdn)
412
413
414 def getWinregEntry(name, path):
415 """
416 Function to get an entry from the Windows Registry.
417
418 @param name variable name
419 @type str
420 @param path registry path of the variable
421 @type str
422 @return value of requested registry variable
423 @rtype any
424 """
425 # From http://stackoverflow.com/a/35286642
426 import winreg
427 try:
428 registryKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, path, 0,
429 winreg.KEY_READ)
430 value, _ = winreg.QueryValueEx(registryKey, name)
431 winreg.CloseKey(registryKey)
432 return value
433 except WindowsError:
434 return None
435
436
437 def windowsDesktopNames():
438 """
439 Function to generate the link names for the Windows Desktop.
440
441 @return list of desktop link names
442 @rtype list of str
443 """
444 majorVersion, minorVersion = sys.version_info[:2]
445 linkTemplates = [
446 "eric6 (Python {0}.{1}).lnk",
447 "eric6 Browser (Python {0}.{1}).lnk",
448 ]
449
450 return [l.format(majorVersion, minorVersion) for l in linkTemplates]
451
452
453 def windowsProgramsEntry():
454 """
455 Function to generate the name of the Start Menu top entry.
456
457 @return name of the Start Menu top entry
458 @rtype str
459 """
460 majorVersion, minorVersion = sys.version_info[:2]
461 return "eric6 (Python {0}.{1})".format(majorVersion, minorVersion)
462
463
464 def main(argv):
465 """
466 The main function of the script.
467
468 @param argv list of command line arguments
469 """
470 import getopt
471
472 global includePythonVariant
473
474 initGlobals()
475
476 # Parse the command line.
477 global progName
478 progName = os.path.basename(argv[0])
479
480 try:
481 optlist, args = getopt.getopt(argv[1:], "hy")
482 except getopt.GetoptError:
483 usage()
484
485 global platBinDir
486
487 for opt, _arg in optlist:
488 if opt == "-h":
489 usage(0)
490 if opt == "-y":
491 includePythonVariant = True
492
493 print("\nUninstalling eric6 ...")
494 uninstallEric()
495 print("\nUninstallation complete.")
496 print()
497
498 exit(0)
499
500
501 if __name__ == "__main__":
502 try:
503 main(sys.argv)
504 except SystemExit:
505 raise
506 except Exception:
507 print("""An internal error occured. Please report all the output of"""
508 """ the program,\n"""
509 """including the following traceback, to"""
510 """ eric-bugs@eric-ide.python-projects.org.\n""")
511 raise
512
513 #
514 # eflag: noqa = M801

eric ide

mercurial