• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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