]> git.leonardobizzoni.com Git - pioneer-stm32/blob
4cc4923ab3f6ff09a0314ff16f4b1dc7d7ae2ef5
[pioneer-stm32] /
1 # Software License Agreement (BSD License)
2 #
3 # Copyright (c) 2012, Willow Garage, Inc.
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 #
10 #  * Redistributions of source code must retain the above copyright
11 #    notice, this list of conditions and the following disclaimer.
12 #  * Redistributions in binary form must reproduce the above
13 #    copyright notice, this list of conditions and the following
14 #    disclaimer in the documentation and/or other materials provided
15 #    with the distribution.
16 #  * Neither the name of Willow Garage, Inc. nor the names of its
17 #    contributors may be used to endorse or promote products derived
18 #    from this software without specific prior written permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 # POSSIBILITY OF SUCH DAMAGE.
32
33 from __future__ import print_function
34 import os
35 import runpy
36 import sys
37
38 import distutils.core
39 try:
40     import setuptools
41 except ImportError:
42     pass
43
44 from argparse import ArgumentParser
45
46
47 def _get_locations(pkgs, package_dir):
48     """
49     based on setuptools logic and the package_dir dict, builds a dict
50     of location roots for each pkg in pkgs.
51     See http://docs.python.org/distutils/setupscript.html
52
53     :returns: a dict {pkgname: root} for each pkgname in pkgs (and each of their parents)
54     """
55     # package_dir contains a dict {package_name: relativepath}
56     # Example {'': 'src', 'foo': 'lib', 'bar': 'lib2'}
57     #
58     # '' means where to look for any package unless a parent package
59     # is listed so package bar.pot is expected at lib2/bar/pot,
60     # whereas package sup.dee is expected at src/sup/dee
61     #
62     # if package_dir does not state anything about a package,
63     # setuptool expects the package folder to be in the root of the
64     # project
65     locations = {}
66     allprefix = package_dir.get('', '')
67     for pkg in pkgs:
68         parent_location = None
69         splits = pkg.split('.')
70         # we iterate over compound name from parent to child
71         # so once we found parent, children just append to their parent
72         for key_len in range(len(splits)):
73             key = '.'.join(splits[:key_len + 1])
74             if key not in locations:
75                 if key in package_dir:
76                     locations[key] = package_dir[key]
77                 elif parent_location is not None:
78                     locations[key] = os.path.join(parent_location, splits[key_len])
79                 else:
80                     locations[key] = os.path.join(allprefix, key)
81             parent_location = locations[key]
82     return locations
83
84
85 def generate_cmake_file(package_name, version, scripts, package_dir, pkgs, modules):
86     """
87     Generates lines to add to a cmake file which will set variables
88
89     :param version: str, format 'int.int.int'
90     :param scripts: [list of str]: relative paths to scripts
91     :param package_dir: {modulename: path}
92     :pkgs: [list of str] python_packages declared in catkin package
93     :modules: [list of str] python modules
94     """
95     prefix = '%s_SETUP_PY' % package_name
96     result = []
97     result.append(r'set(%s_VERSION "%s")' % (prefix, version))
98     result.append(r'set(%s_SCRIPTS "%s")' % (prefix, ';'.join(scripts)))
99
100     # Remove packages with '.' separators.
101     #
102     # setuptools allows specifying submodules in other folders than
103     # their parent
104     #
105     # The symlink approach of catkin does not work with such submodules.
106     # In the common case, this does not matter as the submodule is
107     # within the containing module.  We verify this assumption, and if
108     # it passes, we remove submodule packages.
109     locations = _get_locations(pkgs, package_dir)
110     for pkgname, location in locations.items():
111         if not '.' in pkgname:
112             continue
113         splits = pkgname.split('.')
114         # hack: ignore write-combining setup.py files for msg and srv files
115         if splits[1] in ['msg', 'srv']:
116             continue
117         # check every child has the same root folder as its parent
118         root_name = splits[0]
119         root_location = location
120         for _ in range(len(splits) - 1):
121             root_location = os.path.dirname(root_location)
122         if root_location != locations[root_name]:
123             raise RuntimeError(
124                 "catkin_export_python does not support setup.py files that combine across multiple directories: %s in %s, %s in %s" % (pkgname, location, root_name, locations[root_name]))
125
126     # If checks pass, remove all submodules
127     pkgs = [p for p in pkgs if '.' not in p]
128
129     resolved_pkgs = []
130     for pkg in pkgs:
131         resolved_pkgs += [locations[pkg]]
132
133     result.append(r'set(%s_PACKAGES "%s")' % (prefix, ';'.join(pkgs)))
134     result.append(r'set(%s_PACKAGE_DIRS "%s")' % (prefix, ';'.join(resolved_pkgs).replace("\\", "/")))
135
136     # skip modules which collide with package names
137     filtered_modules = []
138     for modname in modules:
139         splits = modname.split('.')
140         # check all parents too
141         equals_package = [('.'.join(splits[:-i]) in locations) for i in range(len(splits))]
142         if any(equals_package):
143             continue
144         filtered_modules.append(modname)
145     module_locations = _get_locations(filtered_modules, package_dir)
146
147     result.append(r'set(%s_MODULES "%s")' % (prefix, ';'.join(['%s.py' % m.replace('.', '/') for m in filtered_modules])))
148     result.append(r'set(%s_MODULE_DIRS "%s")' % (prefix, ';'.join([module_locations[m] for m in filtered_modules]).replace("\\", "/")))
149
150     return result
151
152
153 def _create_mock_setup_function(package_name, outfile):
154     """
155     Creates a function to call instead of distutils.core.setup or
156     setuptools.setup, which just captures some args and writes them
157     into a file that can be used from cmake
158
159     :param package_name: name of the package
160     :param outfile: filename that cmake will use afterwards
161     :returns: a function to replace disutils.core.setup and setuptools.setup
162     """
163
164     def setup(*args, **kwargs):
165         '''
166         Checks kwargs and writes a scriptfile
167         '''
168         if 'version' not in kwargs:
169             sys.stderr.write("\n*** Unable to find 'version' in setup.py of %s\n" % package_name)
170             raise RuntimeError("version not found in setup.py")
171         version = kwargs['version']
172         package_dir = kwargs.get('package_dir', {})
173
174         pkgs = kwargs.get('packages', [])
175         scripts = kwargs.get('scripts', [])
176         modules = kwargs.get('py_modules', [])
177
178         unsupported_args = [
179             'entry_points',
180             'exclude_package_data',
181             'ext_modules ',
182             'ext_package',
183             'include_package_data',
184             'namespace_packages',
185             'setup_requires',
186             'use_2to3',
187             'zip_safe']
188         used_unsupported_args = [arg for arg in unsupported_args if arg in kwargs]
189         if used_unsupported_args:
190             sys.stderr.write("*** Arguments %s to setup() not supported in catkin devel space in setup.py of %s\n" % (used_unsupported_args, package_name))
191
192         result = generate_cmake_file(package_name=package_name,
193                                      version=version,
194                                      scripts=scripts,
195                                      package_dir=package_dir,
196                                      pkgs=pkgs,
197                                      modules=modules)
198         with open(outfile, 'w') as out:
199             out.write('\n'.join(result))
200
201     return setup
202
203
204 def main():
205     """
206     Script main, parses arguments and invokes Dummy.setup indirectly.
207     """
208     parser = ArgumentParser(description='Utility to read setup.py values from cmake macros. Creates a file with CMake set commands setting variables.')
209     parser.add_argument('package_name', help='Name of catkin package')
210     parser.add_argument('setupfile_path', help='Full path to setup.py')
211     parser.add_argument('outfile', help='Where to write result to')
212
213     args = parser.parse_args()
214
215     # print("%s" % sys.argv)
216     # PACKAGE_NAME = sys.argv[1]
217     # OUTFILE = sys.argv[3]
218     # print("Interrogating setup.py for package %s into %s " % (PACKAGE_NAME, OUTFILE),
219     #      file=sys.stderr)
220
221     # print("executing %s" % args.setupfile_path)
222
223     # be sure you're in the directory containing
224     # setup.py so the sys.path manipulation works,
225     # so the import of __version__ works
226     os.chdir(os.path.dirname(os.path.abspath(args.setupfile_path)))
227
228     # patch setup() function of distutils and setuptools for the
229     # context of evaluating setup.py
230     try:
231         fake_setup = _create_mock_setup_function(package_name=args.package_name,
232                                                 outfile=args.outfile)
233
234         distutils_backup = distutils.core.setup
235         distutils.core.setup = fake_setup
236         try:
237             setuptools_backup = setuptools.setup
238             setuptools.setup = fake_setup
239         except NameError:
240             pass
241
242         runpy.run_path(args.setupfile_path)
243     finally:
244         distutils.core.setup = distutils_backup
245         try:
246             setuptools.setup = setuptools_backup
247         except NameError:
248             pass
249
250 if __name__ == '__main__':
251     main()