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