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