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 logging 18import os 19import shutil 20import subprocess 21import sys 22from distutils import cmd 23from distutils import log 24 25import setuptools 26from setuptools.command.install import install 27 28FRAMEWORK_DIR = 'acts_framework' 29 30acts_tests_dir = os.path.abspath(os.path.dirname(__file__)) 31 32install_requires = [ 33 # Future needs to have a newer version that contains urllib. 34 'future>=0.16.0', 35 # Latest version of mock (4.0.0b) causes a number of compatibility issues 36 # with ACTS unit tests (b/148695846, b/148814743) 37 'mock==3.0.5', 38 'numpy', 39 'pyserial', 40 'pyyaml>=5.1', 41 'protobuf>=3.11.3', 42 'requests', 43 'scapy', 44 'xlsxwriter', 45 'mobly>=1.10.0', 46] 47 48if sys.version_info < (3, ): 49 install_requires.append('enum34') 50 install_requires.append('statistics') 51 # "futures" is needed for py2 compatibility and it only works in 2.7 52 install_requires.append('futures') 53 install_requires.append('subprocess32') 54 55 56class ActsContribInstall(install): 57 """Custom installation of the acts_contrib package. 58 59 First installs the required ACTS framework via its own setup.py script, 60 before proceeding with the rest of the installation. 61 62 The installation requires the ACTS framework to exist under the 63 "acts_framework" directory. 64 """ 65 def run(self): 66 acts_framework_dir = os.path.join(acts_tests_dir, FRAMEWORK_DIR) 67 if not os.path.isdir(acts_framework_dir): 68 logging.error('Cannot install ACTS framework. Framework dir ' 69 '"%s" not found' % acts_framework_dir) 70 exit(1) 71 acts_setup_bin = os.path.join(acts_framework_dir, 'setup.py') 72 if not os.path.isfile(acts_setup_bin): 73 logging.error('Cannot install ACTS framework. Setup script not ' 74 'found.') 75 exit(1) 76 command = [sys.executable, acts_setup_bin, 'install'] 77 subprocess.check_call(command, cwd=acts_framework_dir) 78 super().run() 79 80 81class ActsContribInstallDependencies(cmd.Command): 82 """Installs only required packages 83 84 Installs all required packages for acts_contrib to work. Rather than using 85 the normal install system which creates links with the python egg, pip is 86 used to install the packages. 87 """ 88 89 description = 'Install dependencies needed for acts_contrib packages.' 90 user_options = [] 91 92 def initialize_options(self): 93 pass 94 95 def finalize_options(self): 96 pass 97 98 def run(self): 99 install_args = [sys.executable, '-m', 'pip', 'install'] 100 subprocess.check_call(install_args + ['--upgrade', 'pip']) 101 required_packages = self.distribution.install_requires 102 103 for package in required_packages: 104 self.announce('Installing %s...' % package, log.INFO) 105 subprocess.check_call(install_args + 106 ['-v', '--no-cache-dir', package]) 107 108 self.announce('Dependencies installed.') 109 110 111class ActsContribUninstall(cmd.Command): 112 """acts_contrib uninstaller. 113 114 Uninstalls acts_contrib from the current version of python. This will 115 attempt to import acts_contrib from any of the python egg locations. If it 116 finds an import it will use the modules file location to delete it. This is 117 repeated until acts_contrib can no longer be imported and thus is 118 uninstalled. 119 """ 120 121 description = 'Uninstall acts_contrib from the local machine.' 122 user_options = [] 123 124 def initialize_options(self): 125 pass 126 127 def finalize_options(self): 128 pass 129 130 def uninstall_acts_contrib_module(self, acts_contrib_module): 131 """Uninstalls acts_contrib from a module. 132 133 Args: 134 acts_contrib_module: The acts_contrib module to uninstall. 135 """ 136 for acts_contrib_install_dir in acts_contrib_module.__path__: 137 self.announce('Deleting acts_contrib from: %s' 138 % acts_contrib_install_dir, log.INFO) 139 shutil.rmtree(acts_contrib_install_dir) 140 141 def run(self): 142 """Entry point for the uninstaller.""" 143 # Remove the working directory from the python path. This ensures that 144 # Source code is not accidentally targeted. 145 our_dir = os.path.abspath(os.path.dirname(__file__)) 146 if our_dir in sys.path: 147 sys.path.remove(our_dir) 148 149 if os.getcwd() in sys.path: 150 sys.path.remove(os.getcwd()) 151 152 try: 153 import acts_contrib as acts_contrib_module 154 except ImportError: 155 self.announce('acts_contrib is not installed, nothing to uninstall.', 156 level=log.ERROR) 157 return 158 159 while acts_contrib_module: 160 self.uninstall_acts_contrib_module(acts_contrib_module) 161 try: 162 del sys.modules['acts_contrib'] 163 import acts_contrib as acts_contrib_module 164 except ImportError: 165 acts_contrib_module = None 166 167 self.announce('Finished uninstalling acts_contrib.') 168 169 170def main(): 171 os.chdir(acts_tests_dir) 172 packages = setuptools.find_packages(include=('acts_contrib*',)) 173 setuptools.setup(name='acts_contrib', 174 version='0.9', 175 description='Android Comms Test Suite', 176 license='Apache2.0', 177 packages=packages, 178 include_package_data=True, 179 install_requires=install_requires, 180 cmdclass={ 181 'install': ActsContribInstall, 182 'install_deps': ActsContribInstallDependencies, 183 'uninstall': ActsContribUninstall 184 }, 185 url="http://www.android.com/") 186 187 188if __name__ == '__main__': 189 main() 190