1#!/usr/bin/env python3
2#
3#   Copyright 2020 - 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
17from distutils import log
18from distutils.errors import DistutilsModuleError
19import os
20from setuptools import find_packages
21from setuptools import setup
22from setuptools.command.install import install
23import stat
24import subprocess
25import sys
26
27install_requires = [
28    'grpcio',
29    'psutil',
30]
31
32host_executables = [
33    'root-canal',
34    'bluetooth_stack_with_facade',  # c++
35    'bluetooth_with_facades',  # rust
36]
37
38
39# Need to verify acts is importable in a new Python context
40def is_acts_importable():
41    cmd = [sys.executable, '-c', 'import acts']
42    completed_process = subprocess.run(cmd, cwd=os.getcwd())
43    return completed_process.returncode == 0
44
45
46def setup_acts_for_cmd_or_die(cmd_str):
47    acts_framework_dir = os.path.abspath('acts_framework')
48    acts_setup_bin = os.path.join(acts_framework_dir, 'setup.py')
49    cmd = [sys.executable, acts_setup_bin, cmd_str]
50    subprocess.run(cmd, cwd=acts_framework_dir, check=True)
51
52
53def set_permissions_for_host_executables(outputs):
54    for file in outputs:
55        if os.path.basename(file) in host_executables:
56            current_mode = os.stat(file).st_mode
57            new_mode = current_mode | stat.S_IEXEC
58            os.chmod(file, new_mode)
59            log.log(log.INFO, "Changed file mode of %s from %s to %s" % (file, oct(current_mode), oct(new_mode)))
60
61
62class InstallLocalPackagesForInstallation(install):
63
64    user_options = install.user_options + [
65        ('reuse-acts', None, "Skip ACTS installation if already installed"),
66    ]
67    boolean_options = install.boolean_options + ['reuse-acts']
68
69    def initialize_options(self):
70        install.initialize_options(self)
71        self.reuse_acts = False
72
73    def run(self):
74        if self.reuse_acts and is_acts_importable():
75            self.announce('Reusing existing ACTS installation', log.WARN)
76        else:
77            self.announce('Installing ACTS library', log.WARN)
78            setup_acts_for_cmd_or_die("install")
79            self.announce('ACTS installed.', log.WARN)
80        if not is_acts_importable():
81            raise DistutilsModuleError("Cannot import acts after installation")
82        install.run(self)
83        set_permissions_for_host_executables(self.get_outputs())
84
85
86def main():
87    # Relative path from calling directory to this file
88    our_dir = os.path.dirname(__file__)
89    # Must cd into this dir for package resolution to work
90    # This won't affect the calling shell
91    os.chdir(our_dir)
92    setup(
93        name='bluetooth_cert_tests',
94        version='1.0',
95        author='Android Open Source Project',
96        license='Apache2.0',
97        description="""Bluetooth Cert Tests Package""",
98        # Include root package so that bluetooth_packets_python3.so can be
99        # included as well
100        packages=[''] +
101        find_packages(exclude=['acts_framework', 'acts_framework.*', 'llvm_binutils', 'llvm_binutils.*']),
102        install_requires=install_requires,
103        package_data={
104            '': host_executables + ['*.so', 'lib64/*.so', 'target/*', 'llvm_binutils/bin/*', 'llvm_binutils/lib64/*'],
105            'cert': ['all_test_cases'],
106        },
107        cmdclass={
108            'install': InstallLocalPackagesForInstallation,
109        })
110
111
112if __name__ == '__main__':
113    main()
114