|
1 #!/usr/bin/env python3 |
|
2 # -*- coding: utf-8 -*- |
|
3 |
|
4 # Copyright (c) 2016 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> |
|
5 # |
|
6 # This is the install script for the eric6 debug client. It may be used |
|
7 # to just install the debug clients for remote debugging. |
|
8 # |
|
9 |
|
10 """ |
|
11 Installation script for the eric6 debug clients. |
|
12 """ |
|
13 |
|
14 from __future__ import unicode_literals, print_function |
|
15 try: |
|
16 import cStringIO as io |
|
17 try: |
|
18 from PyQt5 import sip |
|
19 except ImportError: |
|
20 import sip |
|
21 sip.setapi('QString', 2) |
|
22 sip.setapi('QVariant', 2) |
|
23 sip.setapi('QTextStream', 2) |
|
24 except (ImportError): |
|
25 import io # __IGNORE_WARNING__ |
|
26 |
|
27 import sys |
|
28 import os |
|
29 import re |
|
30 import compileall |
|
31 import shutil |
|
32 import fnmatch |
|
33 |
|
34 # Define the globals. |
|
35 progName = None |
|
36 currDir = os.getcwd() |
|
37 modDir = None |
|
38 pyModDir = None |
|
39 distDir = None |
|
40 installPackage = "eric6DebugClients" |
|
41 doCleanup = True |
|
42 doCompile = True |
|
43 sourceDir = "eric" |
|
44 eric6SourceDir = os.path.join(sourceDir, "eric6") |
|
45 |
|
46 |
|
47 def exit(rcode=0): |
|
48 """ |
|
49 Exit the install script. |
|
50 |
|
51 @param rcode result code to report back (integer) |
|
52 """ |
|
53 global currDir |
|
54 |
|
55 if sys.platform.startswith("win"): |
|
56 # different meaning of input between Py2 and Py3 |
|
57 try: |
|
58 input("Press enter to continue...") |
|
59 except (EOFError, SyntaxError): |
|
60 pass |
|
61 |
|
62 os.chdir(currDir) |
|
63 |
|
64 sys.exit(rcode) |
|
65 |
|
66 |
|
67 def usage(rcode=2): |
|
68 """ |
|
69 Display a usage message and exit. |
|
70 |
|
71 @param rcode the return code passed back to the calling process. |
|
72 """ |
|
73 global progName, modDir, distDir |
|
74 |
|
75 print() |
|
76 print("Usage:") |
|
77 if sys.platform == "darwin": |
|
78 print(" {0} [-chz] [-d dir] [-i dir]".format(progName)) |
|
79 elif sys.platform.startswith("win"): |
|
80 print(" {0} [-chz] [-d dir]".format(progName)) |
|
81 else: |
|
82 print(" {0} [-chz][-d dir] [-i dir]".format(progName)) |
|
83 print("where:") |
|
84 print(" -h, --help display this help message") |
|
85 print(" -d dir where eric6 debug client files will be installed") |
|
86 print(" (default: {0})".format(modDir)) |
|
87 if not sys.platform.startswith("win"): |
|
88 print(" -i dir temporary install prefix") |
|
89 print(" (default: {0})".format(distDir)) |
|
90 print(" -c don't cleanup old installation first") |
|
91 print(" -z don't compile the installed python files") |
|
92 |
|
93 exit(rcode) |
|
94 |
|
95 |
|
96 def initGlobals(): |
|
97 """ |
|
98 Module function to set the values of globals that need more than a |
|
99 simple assignment. |
|
100 """ |
|
101 global modDir, pyModDir |
|
102 |
|
103 try: |
|
104 import distutils.sysconfig |
|
105 except ImportError: |
|
106 print("Please install the 'distutils' package first.") |
|
107 exit(5) |
|
108 |
|
109 modDir = distutils.sysconfig.get_python_lib(True) |
|
110 pyModDir = modDir |
|
111 |
|
112 |
|
113 def copyTree(src, dst, filters, excludeDirs=None, excludePatterns=None): |
|
114 """ |
|
115 Copy files of a directory tree. |
|
116 |
|
117 @param src name of the source directory |
|
118 @param dst name of the destination directory |
|
119 @param filters list of filter pattern determining the files to be copied |
|
120 @param excludeDirs list of (sub)directories to exclude from copying |
|
121 @keyparam excludePatterns list of filter pattern determining the files to |
|
122 be skipped |
|
123 """ |
|
124 if excludeDirs is None: |
|
125 excludeDirs = [] |
|
126 if excludePatterns is None: |
|
127 excludePatterns = [] |
|
128 try: |
|
129 names = os.listdir(src) |
|
130 except OSError: |
|
131 # ignore missing directories |
|
132 return |
|
133 |
|
134 for name in names: |
|
135 skipIt = False |
|
136 for excludePattern in excludePatterns: |
|
137 if fnmatch.fnmatch(name, excludePattern): |
|
138 skipIt = True |
|
139 break |
|
140 if not skipIt: |
|
141 srcname = os.path.join(src, name) |
|
142 dstname = os.path.join(dst, name) |
|
143 for fileFilter in filters: |
|
144 if fnmatch.fnmatch(srcname, fileFilter): |
|
145 if not os.path.isdir(dst): |
|
146 os.makedirs(dst) |
|
147 shutil.copy2(srcname, dstname) |
|
148 os.chmod(dstname, 0o644) |
|
149 break |
|
150 else: |
|
151 if os.path.isdir(srcname) and srcname not in excludeDirs: |
|
152 copyTree(srcname, dstname, filters, |
|
153 excludePatterns=excludePatterns) |
|
154 |
|
155 |
|
156 def cleanupSource(dirName): |
|
157 """ |
|
158 Cleanup the sources directory to get rid of leftover files |
|
159 and directories. |
|
160 |
|
161 @param dirName name of the directory to prune (string) |
|
162 """ |
|
163 # step 1: delete the __pycache__ directory and all *.pyc files |
|
164 if os.path.exists(os.path.join(dirName, "__pycache__")): |
|
165 shutil.rmtree(os.path.join(dirName, "__pycache__")) |
|
166 for name in [f for f in os.listdir(dirName) |
|
167 if fnmatch.fnmatch(f, "*.pyc")]: |
|
168 os.remove(os.path.join(dirName, name)) |
|
169 |
|
170 # step 2: descent into subdirectories and delete them if empty |
|
171 for name in os.listdir(dirName): |
|
172 name = os.path.join(dirName, name) |
|
173 if os.path.isdir(name): |
|
174 cleanupSource(name) |
|
175 if len(os.listdir(name)) == 0: |
|
176 os.rmdir(name) |
|
177 |
|
178 |
|
179 def cleanUp(): |
|
180 """ |
|
181 Uninstall the old eric debug client files. |
|
182 """ |
|
183 global pyModDir |
|
184 |
|
185 try: |
|
186 # Cleanup the install directories |
|
187 dirname = os.path.join(pyModDir, installPackage) |
|
188 if os.path.exists(dirname): |
|
189 shutil.rmtree(dirname, True) |
|
190 except (IOError, OSError) as msg: |
|
191 sys.stderr.write( |
|
192 'Error: {0}\nTry install with admin rights.\n'.format(msg)) |
|
193 exit(7) |
|
194 |
|
195 |
|
196 def shutilCopy(src, dst, perm=0o644): |
|
197 """ |
|
198 Wrapper function around shutil.copy() to ensure the permissions. |
|
199 |
|
200 @param src source file name (string) |
|
201 @param dst destination file name or directory name (string) |
|
202 @keyparam perm permissions to be set (integer) |
|
203 """ |
|
204 shutil.copy(src, dst) |
|
205 if os.path.isdir(dst): |
|
206 dst = os.path.join(dst, os.path.basename(src)) |
|
207 os.chmod(dst, perm) |
|
208 |
|
209 |
|
210 def installEricDebugClients(): |
|
211 """ |
|
212 Actually perform the installation steps. |
|
213 |
|
214 @return result code (integer) |
|
215 """ |
|
216 global distDir, doCleanup, sourceDir, modDir |
|
217 |
|
218 # set install prefix, if not None |
|
219 if distDir: |
|
220 targetDir = os.path.normpath(os.path.join(distDir, installPackage)) |
|
221 else: |
|
222 targetDir = os.path.join(modDir, installPackage) |
|
223 |
|
224 try: |
|
225 # Install the files |
|
226 # copy the various parts of eric6 debug clients |
|
227 copyTree( |
|
228 os.path.join(eric6SourceDir, "DebugClients"), targetDir, |
|
229 ['*.py', '*.pyc', '*.pyo', '*.pyw'], |
|
230 [os.path.join(sourceDir, ".ropeproject")], |
|
231 excludePatterns=["eric6config.py*"]) |
|
232 |
|
233 # copy the license file |
|
234 shutilCopy(os.path.join(sourceDir, "docs", "LICENSE.GPL3"), targetDir) |
|
235 |
|
236 except (IOError, OSError) as msg: |
|
237 sys.stderr.write( |
|
238 'Error: {0}\nTry install with admin rights.\n'.format(msg)) |
|
239 return(7) |
|
240 |
|
241 return 0 |
|
242 |
|
243 |
|
244 def main(argv): |
|
245 """ |
|
246 The main function of the script. |
|
247 |
|
248 @param argv the list of command line arguments. |
|
249 """ |
|
250 import getopt |
|
251 |
|
252 # Parse the command line. |
|
253 global progName, modDir, doCleanup, doCompile, distDir |
|
254 global sourceDir |
|
255 |
|
256 if sys.version_info < (2, 7, 0) or sys.version_info > (3, 9, 9): |
|
257 print('Sorry, eric6 requires at least Python 2.7 or ' |
|
258 'Python 3 for running.') |
|
259 exit(5) |
|
260 |
|
261 progName = os.path.basename(argv[0]) |
|
262 |
|
263 if os.path.dirname(argv[0]): |
|
264 os.chdir(os.path.dirname(argv[0])) |
|
265 |
|
266 initGlobals() |
|
267 |
|
268 try: |
|
269 if sys.platform.startswith("win"): |
|
270 optlist, args = getopt.getopt( |
|
271 argv[1:], "chzd:", ["help"]) |
|
272 elif sys.platform == "darwin": |
|
273 optlist, args = getopt.getopt( |
|
274 argv[1:], "chzd:i:", ["help"]) |
|
275 else: |
|
276 optlist, args = getopt.getopt( |
|
277 argv[1:], "chzd:i:", ["help"]) |
|
278 except getopt.GetoptError as err: |
|
279 print(err) |
|
280 usage() |
|
281 |
|
282 for opt, arg in optlist: |
|
283 if opt in ["-h", "--help"]: |
|
284 usage(0) |
|
285 elif opt == "-d": |
|
286 modDir = arg |
|
287 elif opt == "-i": |
|
288 distDir = os.path.normpath(arg) |
|
289 elif opt == "-c": |
|
290 doCleanup = False |
|
291 elif opt == "-z": |
|
292 doCompile = False |
|
293 |
|
294 installFromSource = not os.path.isdir(sourceDir) |
|
295 if installFromSource: |
|
296 sourceDir = os.path.dirname(__file__) or "." |
|
297 eric6SourceDir = os.path.join(sourceDir, "eric6") |
|
298 |
|
299 # cleanup source if installing from source |
|
300 if installFromSource: |
|
301 print("Cleaning up source ...") |
|
302 cleanupSource(os.path.join(eric6SourceDir, "DebugClients")) |
|
303 print() |
|
304 |
|
305 # cleanup old installation |
|
306 try: |
|
307 if doCleanup: |
|
308 print("Cleaning up old installation ...") |
|
309 if distDir: |
|
310 shutil.rmtree(distDir, True) |
|
311 else: |
|
312 cleanUp() |
|
313 except (IOError, OSError) as msg: |
|
314 sys.stderr.write('Error: {0}\nTry install as root.\n'.format(msg)) |
|
315 exit(7) |
|
316 |
|
317 if doCompile: |
|
318 print("\nCompiling source files ...") |
|
319 skipRe = re.compile(r"DebugClients[\\/]Python[\\/]") |
|
320 # Hide compile errors (mainly because of Py2/Py3 differences) |
|
321 sys.stdout = io.StringIO() |
|
322 if distDir: |
|
323 compileall.compile_dir( |
|
324 os.path.join(eric6SourceDir, "DebugClients"), |
|
325 ddir=os.path.join(distDir, modDir, installPackage), |
|
326 rx=skipRe, |
|
327 quiet=True) |
|
328 else: |
|
329 compileall.compile_dir( |
|
330 os.path.join(eric6SourceDir, "DebugClients"), |
|
331 ddir=os.path.join(modDir, installPackage), |
|
332 rx=skipRe, |
|
333 quiet=True) |
|
334 sys.stdout = sys.__stdout__ |
|
335 print("\nInstalling eric6 debug clients ...") |
|
336 res = installEricDebugClients() |
|
337 |
|
338 print("\nInstallation complete.") |
|
339 print() |
|
340 |
|
341 exit(res) |
|
342 |
|
343 |
|
344 if __name__ == "__main__": |
|
345 try: |
|
346 main(sys.argv) |
|
347 except SystemExit: |
|
348 raise |
|
349 except Exception: |
|
350 print("""An internal error occured. Please report all the output""" |
|
351 """ of the program,\nincluding the following traceback, to""" |
|
352 """ eric-bugs@eric-ide.python-projects.org.\n""") |
|
353 raise |
|
354 |
|
355 # |
|
356 # eflag: noqa = M801 |