1#!/usr/bin/env python3 2# 3# Copyright 2017 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import os 18import shutil 19import subprocess 20import sys 21from distutils import cmd 22from distutils import log 23 24import setuptools 25from setuptools.command.develop import develop 26from setuptools.command.install import install 27 28FRAMEWORK_DIR = 'acts_framework' 29LOCAL_FRAMEWORK_DIR = '../acts/framework' 30 31acts_tests_dir = os.path.abspath(os.path.dirname(__file__)) 32 33install_requires = ['soundfile'] 34 35if sys.version_info < (3, 6): 36 # Python <= 3.5 uses bokeh up to 1.4.x 37 install_requires.append('bokeh<1.5') 38elif sys.version_info < (3, 7): 39 # Python 3.6 uses bokeh up to 2.3.x 40 install_requires.append('bokeh<2.4') 41elif sys.version_info < (3, 8): 42 # Python 3.7+ uses bokeh up to 2.4.x 43 install_requires.append('bokeh<2.5') 44else: 45 # Python 3.8+ is support by latest bokeh 46 install_requires.append('bokeh') 47 48def _setup_acts_framework(option, *args): 49 """Locates and runs setup.py for the ACTS framework. 50 51 Args: 52 option: the option to use with setup.py, e.g. install, develop 53 args: additional args for the command 54 """ 55 acts_framework_dir = os.path.join(acts_tests_dir, FRAMEWORK_DIR) 56 if not os.path.isdir(acts_framework_dir): 57 log.info('Directory "%s" not found. Attempting to locate ACTS ' 58 'framework through local repository.' % acts_framework_dir) 59 acts_framework_dir = os.path.join(acts_tests_dir, LOCAL_FRAMEWORK_DIR) 60 if not os.path.isdir(acts_framework_dir): 61 log.error('Cannot install ACTS framework. Framework dir "%s" not ' 62 'found.' % acts_framework_dir) 63 exit(1) 64 acts_setup_bin = os.path.join(acts_framework_dir, 'setup.py') 65 if not os.path.isfile(acts_setup_bin): 66 log.error('Cannot install ACTS framework. Setup script not found.') 67 exit(1) 68 command = [sys.executable, acts_setup_bin, option, *args] 69 subprocess.check_call(command, cwd=acts_framework_dir) 70 71 72class ActsContribInstall(install): 73 """Custom installation of the acts_contrib package. 74 75 Also installs the required ACTS framework via its own setup.py script. 76 77 The installation requires the ACTS framework to exist under the 78 "acts_framework" directory, at the same level of this setup script. 79 Otherwise, it will attempt to locate the ACTS framework from the local 80 repository. 81 """ 82 83 def run(self): 84 _setup_acts_framework('install') 85 # Calling install.run() directly fails to install the dependencies as 86 # listed in install_requires. Use install.do_egg_install() instead. 87 # Ref: https://stackoverflow.com/questions/21915469 88 self.do_egg_install() 89 90 91class ActsContribDevelop(develop): 92 """Custom installation of the acts_contrib package (in develop mode). 93 94 See ActsContribInstall for more details. 95 """ 96 97 def run(self): 98 super().run() 99 if self.uninstall: 100 _setup_acts_framework('develop', '-u') 101 else: 102 _setup_acts_framework('develop') 103 104 105class ActsContribInstallDependencies(cmd.Command): 106 """Installs only required packages 107 108 Installs all required packages for acts_contrib to work. Rather than using 109 the normal install system which creates links with the python egg, pip is 110 used to install the packages. 111 """ 112 113 description = 'Install dependencies needed for acts_contrib packages.' 114 user_options = [] 115 116 def initialize_options(self): 117 pass 118 119 def finalize_options(self): 120 pass 121 122 def run(self): 123 install_args = [sys.executable, '-m', 'pip', 'install'] 124 subprocess.check_call(install_args + ['--upgrade', 'pip']) 125 required_packages = self.distribution.install_requires 126 127 for package in required_packages: 128 self.announce('Installing %s...' % package, log.INFO) 129 subprocess.check_call(install_args + 130 ['-v', '--no-cache-dir', package]) 131 132 self.announce('Dependencies installed.') 133 134 135class ActsContribUninstall(cmd.Command): 136 """acts_contrib uninstaller. 137 138 Uninstalls acts_contrib from the current version of python. This will 139 attempt to import acts_contrib from any of the python egg locations. If it 140 finds an import it will use the modules file location to delete it. This is 141 repeated until acts_contrib can no longer be imported and thus is 142 uninstalled. 143 """ 144 145 description = 'Uninstall acts_contrib from the local machine.' 146 user_options = [] 147 148 def initialize_options(self): 149 pass 150 151 def finalize_options(self): 152 pass 153 154 def uninstall_acts_contrib_module(self, acts_contrib_module): 155 """Uninstalls acts_contrib from a module. 156 157 Args: 158 acts_contrib_module: The acts_contrib module to uninstall. 159 """ 160 for acts_contrib_install_dir in acts_contrib_module.__path__: 161 self.announce( 162 'Deleting acts_contrib from: %s' % acts_contrib_install_dir, 163 log.INFO) 164 shutil.rmtree(acts_contrib_install_dir) 165 166 def run(self): 167 """Entry point for the uninstaller.""" 168 # Remove the working directory from the python path. This ensures that 169 # Source code is not accidentally targeted. 170 our_dir = os.path.abspath(os.path.dirname(__file__)) 171 if our_dir in sys.path: 172 sys.path.remove(our_dir) 173 174 if os.getcwd() in sys.path: 175 sys.path.remove(os.getcwd()) 176 177 try: 178 import acts_contrib as acts_contrib_module 179 except ImportError: 180 self.announce( 181 'acts_contrib is not installed, nothing to uninstall.', 182 level=log.ERROR) 183 return 184 185 while acts_contrib_module: 186 self.uninstall_acts_contrib_module(acts_contrib_module) 187 try: 188 del sys.modules['acts_contrib'] 189 import acts_contrib as acts_contrib_module 190 except ImportError: 191 acts_contrib_module = None 192 193 self.announce('Finished uninstalling acts_contrib.') 194 195 # Uninstall the ACTS framework 196 _setup_acts_framework('uninstall') 197 198 199def main(): 200 os.chdir(acts_tests_dir) 201 packages = setuptools.find_packages(include=('acts_contrib*', )) 202 setuptools.setup(name='acts_contrib', 203 version='0.9', 204 description='Android Comms Test Suite', 205 license='Apache2.0', 206 packages=packages, 207 include_package_data=True, 208 install_requires=install_requires, 209 cmdclass={ 210 'install': ActsContribInstall, 211 'develop': ActsContribDevelop, 212 'install_deps': ActsContribInstallDependencies, 213 'uninstall': ActsContribUninstall 214 }, 215 url="http://www.android.com/") 216 217 218if __name__ == '__main__': 219 main() 220