Xianyuan Jia | 1df188c | 2020-04-15 15:58:09 -0700 | [diff] [blame^] | 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 | |
| 17 | import logging |
| 18 | import os |
| 19 | import shutil |
| 20 | import subprocess |
| 21 | import sys |
| 22 | from distutils import cmd |
| 23 | from distutils import log |
| 24 | |
| 25 | import setuptools |
| 26 | from setuptools.command.install import install |
| 27 | |
| 28 | FRAMEWORK_DIR = 'acts_framework' |
| 29 | |
| 30 | acts_tests_dir = os.path.abspath(os.path.dirname(__file__)) |
| 31 | |
| 32 | install_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 | |
| 48 | if 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 | |
| 56 | class 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 | |
| 81 | class 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 | |
| 111 | class 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 | |
| 170 | def 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=False, |
| 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 | |
| 188 | if __name__ == '__main__': |
| 189 | main() |