cabec7a450ea17bd24126884d37d47a975f4fc22
[platform/upstream/connectedhomeip.git] / src / controller / python / build-chip-wheel.py
1 #
2 #    Copyright (c) 2020 Project CHIP Authors
3 #    Copyright (c) 2019 Google LLC.
4 #    All rights reserved.
5 #
6 #    Licensed under the Apache License, Version 2.0 (the "License");
7 #    you may not use this file except in compliance with the License.
8 #    You may obtain a copy of the License at
9 #
10 #        http://www.apache.org/licenses/LICENSE-2.0
11 #
12 #    Unless required by applicable law or agreed to in writing, software
13 #    distributed under the License is distributed on an "AS IS" BASIS,
14 #    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 #    See the License for the specific language governing permissions and
16 #    limitations under the License.
17 #
18
19 #
20 #    Description:
21 #      Builds a Python wheel package for CHIP.
22 #
23
24 from __future__ import absolute_import
25 from datetime import datetime
26 from setuptools import setup
27 from wheel.bdist_wheel import bdist_wheel
28
29 import argparse
30 import json
31 import os
32 import platform
33 import shutil
34
35
36 parser = argparse.ArgumentParser(description='build the pip package for chip using chip components generated during the build and python source code')
37 parser.add_argument('--package_name', default='chip', help='configure the python package name')
38 parser.add_argument('--build_number', default='0.0', help='configure the chip build number')
39 parser.add_argument('--build_dir', help='directory to build in')
40 parser.add_argument('--dist_dir', help='directory to place distribution in')
41 parser.add_argument('--manifest', help='list of files to package')
42 parser.add_argument('--plat-name', help='platform name to embed in generated filenames')
43
44 args = parser.parse_args()
45
46 class InstalledScriptInfo:
47     """Information holder about a script that is to be installed."""
48
49     def __init__(self, name):
50       self.name = name
51       self.installName = os.path.splitext(name)[0]
52
53
54 chipDLLName = '_ChipDeviceCtrl.so'
55 packageName = args.package_name
56 chipPackageVer = args.build_number
57
58 installScripts = [
59     InstalledScriptInfo('chip-device-ctrl.py'),
60     InstalledScriptInfo('chip-repl.py'),
61 ]
62
63 # Record the current directory at the start of execution.
64 curDir = os.curdir
65
66 manifestFile = os.path.abspath(args.manifest)
67 buildDir = os.path.abspath(args.build_dir)
68 distDir = os.path.abspath(args.dist_dir)
69
70 # Use a temporary directory within the build directory to assemble the components
71 # for the installable package.
72 tmpDir = os.path.join(buildDir, 'chip-wheel-components')
73
74 manifest = json.load(open(manifestFile, 'r'))
75
76 try:
77
78     #
79     # Perform a series of setup steps prior to creating the chip package...
80     #
81
82     # Create the temporary components directory.
83     if os.path.isdir(tmpDir):
84         shutil.rmtree(tmpDir)
85     os.makedirs(tmpDir, exist_ok=True)
86
87     # Switch to the temporary directory. (Foolishly, setuptools relies on the current directory
88     # for many of its features.)
89     os.chdir(tmpDir)
90
91     manifestBase = os.path.dirname(manifestFile)
92     for entry in manifest['files']:
93         srcDir = os.path.join(manifestBase, entry['src_dir'])
94         for path in entry['sources']:
95           srcFile = os.path.join(srcDir, path)
96           dstFile = os.path.join(tmpDir, path)
97           os.makedirs(os.path.dirname(dstFile), exist_ok=True)
98           shutil.copyfile(srcFile, dstFile)
99
100     for script in installScripts:
101       os.rename(os.path.join(tmpDir, script.name),
102                 os.path.join(tmpDir, script.installName))
103
104     # Define a custom version of the bdist_wheel command that configures the
105     # resultant wheel as platform-specific (i.e. not "pure").
106     class bdist_wheel_override(bdist_wheel):
107         def finalize_options(self):
108             bdist_wheel.finalize_options(self)
109             self.root_is_pure = False
110
111     requiredPackages = [
112         "coloredlogs",
113         'construct',
114         'ipython',
115     ]
116
117     if platform.system() == 'Darwin':
118         requiredPackages.append('pyobjc-framework-corebluetooth')
119
120     if platform.system() == 'Linux':
121         requiredPackages.append('dbus-python')
122         requiredPackages.append('pygobject')
123
124     #
125     # Build the chip package...
126     #
127     packages=[
128             'chip',
129             'chip.configuration',
130             'chip.exceptions',
131             'chip.internal',
132             'chip.logging',
133             'chip.native',
134             'chip.tlv',
135     ]
136
137     if os.path.isdir(os.path.join(tmpDir, 'chip', 'ble')):
138       packages += ['chip.ble']
139       packages += ['chip.ble.commissioning']
140
141     # Invoke the setuptools 'bdist_wheel' command to generate a wheel containing
142     # the CHIP python packages, shared libraries and scripts.
143     setup(
144         name=packageName,
145         version=chipPackageVer,
146         description='Python-base APIs and tools for CHIP.',
147         url='https://github.com/project-chip/connectedhomeip',
148         license='Apache',
149         classifiers=[
150             'Intended Audience :: Developers',
151             'License :: OSI Approved :: Apache Software License',
152             'Programming Language :: Python :: 2',
153             'Programming Language :: Python :: 2.7',
154             'Programming Language :: Python :: 3',
155         ],
156         python_requires='>=2.7',
157         packages=packages,
158         package_dir={
159             '':tmpDir,                      # By default, look in the tmp directory for packages/modules to be included.
160         },
161         package_data={
162             packageName:[
163                 chipDLLName                   # Include the wrapper DLL as package data in the "chip" package.
164             ]
165         },
166         scripts = [name for name in map(
167             lambda script: os.path.join(tmpDir, script.installName),
168             installScripts
169         )],
170         install_requires=requiredPackages,
171         options={
172             'bdist_wheel':{
173                 'universal':False,
174                 'dist_dir':distDir,         # Place the generated .whl in the dist directory.
175                 'py_limited_api':'cp37',
176                 'plat_name':args.plat_name,
177             },
178             'egg_info':{
179                 'egg_base':tmpDir           # Place the .egg-info subdirectory in the tmp directory.
180             }
181         },
182         cmdclass={
183             'bdist_wheel':bdist_wheel_override
184         },
185         script_args=[ 'clean', '--all', 'bdist_wheel' ]
186     )
187
188 finally:
189     
190     # Switch back to the initial current directory.
191     os.chdir(curDir)
192
193     # Remove the temporary directory.
194     if os.path.isdir(tmpDir):
195         shutil.rmtree(tmpDir)