diff --git a/.style.yapf b/.style.yapf new file mode 100644 index 0000000..728e3f0 --- /dev/null +++ b/.style.yapf @@ -0,0 +1,3 @@ +[style] +based_on_style = pep8 +column_limit = 100 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6f63de9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,13 @@ +Any contribution that you make to this repository will +be under the Apache 2 License, as dictated by that +[license](http://www.apache.org/licenses/LICENSE-2.0.html): + +~~~ +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. +~~~ diff --git a/LICENSE b/LICENSE index 8dada3e..8d89d4e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ + Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -175,24 +176,13 @@ END OF TERMS AND CONDITIONS - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} + Copyright 2016-2017 Esteve Fernandez Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..16d2754 --- /dev/null +++ b/NOTICE @@ -0,0 +1,5 @@ +ros2_java +Copyright 2016-2017 Esteve Fernandez (esteve@apache.org) + +This product includes software developed by +Esteve Fernandez (esteve@apache.org) diff --git a/ament_build_type_gradle/ament_build_type_gradle/__init__.py b/ament_build_type_gradle/ament_build_type_gradle/__init__.py index 6e38265..800ee81 100644 --- a/ament_build_type_gradle/ament_build_type_gradle/__init__.py +++ b/ament_build_type_gradle/ament_build_type_gradle/__init__.py @@ -1,5 +1,4 @@ -# Copyright 2014 Open Source Robotics Foundation, Inc. -# Copyright 2016 Esteve Fernandez +# Copyright 2016-2017 Esteve Fernandez # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,116 +12,246 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Based on +# https://github.com/ament/ament_tools/blob/master/ament_tools/build_types/ament_python.py +# Copyright 2014 Open Source Robotics Foundation, Inc. """Implements the BuildType support for gradle based ament packages.""" import os import shutil +from distutils import dir_util -from ament_tools.helper import extract_argument_group +from ament_package.templates import get_environment_hook_template_path +from ament_build_type_gradle.templates import get_environment_hook_classpath_template_path +from ament_package.templates import configure_string +from ament_package.templates import get_package_level_template_names + +from ament_tools.helper import extract_argument_group from ament_tools.build_type import BuildAction from ament_tools.build_type import BuildType +from ament_tools.build_types.common import expand_package_level_setup_files +from ament_tools.helper import deploy_file +from ament_tools.verbs.build_pkg import cli +from ament_tools.verbs import VerbExecutionError IS_WINDOWS = os.name == 'nt' -def get_gradle_executable(): - gradle_script = 'gradle.bat' if IS_WINDOWS else 'gradle' - if 'GRADLE_HOME' in os.environ: - gradle_home = os.environ['GRADLE_HOME'] - gradle_path = os.path.join(gradle_home, 'bin', gradle_script) - if os.path.isfile(gradle_path): - return gradle_path - return shutil.which(gradle_script) - - -GRADLE_EXECUTABLE = get_gradle_executable() - class AmentGradleBuildType(BuildType): build_type = 'ament_gradle' description = "ament package built with Gradle" + def _build_file_tree(self, start_path): + out_dirnames = set() + out_filenames = set() + for dirname, dirnames, filenames in os.walk(start_path): + for subdirname in dirnames: + out_dirnames.add( + os.path.relpath( + os.path.join(dirname, subdirname), start=start_path)) + + for filename in filenames: + out_filenames.add( + os.path.relpath( + os.path.join(dirname, filename), start=start_path)) + return (out_dirnames, out_filenames) + + def _ament_gradle_recursive_dependencies(self, context): + for export in context.package_manifest.exports: + if export.tagname == 'ament_gradle_recursive_dependencies': + return True + return False + + def _get_ament_args(self, context): + cmd_args = [ + '-Pament.source_space=' + context.source_space, + '-Pament.build_space=' + context.build_space, + '-Pament.install_space=' + context.install_space, + '-Pament.dependencies=' + ':'.join(context.build_dependencies), + '-Pament.build_tests=' + str(context.build_tests), + '-Pament.package_manifest.name=' + context.package_manifest.name, + '-Pament.exec_dependency_paths_in_workspace=' + + ':'.join(context.exec_dependency_paths_in_workspace), + '-Pament.gradle_recursive_dependencies=' + str( + self._ament_gradle_recursive_dependencies(context)), + '-Pament.gradle_isolated=' + str(context.ament_gradle_isolated), + ] + return cmd_args + + def _get_gradle_wrapper(self, context): + gradlew_script = 'gradlew.bat' if IS_WINDOWS else 'gradlew' + gradlew_path = os.path.join(context.source_space, gradlew_script) + if os.path.isfile(gradlew_path): + return gradlew_path + + def _get_gradle_executable(self, context): + gradlew_path = self._get_gradle_wrapper(context) + if gradlew_path: + return gradlew_path + + gradle_script = 'gradle.bat' if IS_WINDOWS else 'gradle' + if 'GRADLE_HOME' in os.environ: + gradle_home = os.environ['GRADLE_HOME'] + gradle_path = os.path.join(gradle_home, 'bin', gradle_script) + if os.path.isfile(gradle_path): + return gradle_path + gradle_path = shutil.which(gradle_script) + if gradle_path: + return gradle_path + raise VerbExecutionError("Could not find 'gradle' executable") + def prepare_arguments(self, parser): parser.add_argument( '--ament-gradle-args', nargs='*', default=[], help="Arbitrary arguments which are passed to 'ament_gradle' Gradle projects. " - "Argument collection can be terminated with '--'.") + "Argument collection can be terminated with '--'.") def argument_preprocessor(self, args): # The ament CMake pass-through flag collects dashed options. # This requires special handling or argparse will complain about # unrecognized options. args, gradle_args = extract_argument_group(args, '--ament-gradle-args') - extras = { - 'ament_gradle_args': gradle_args, - } + extras = {'ament_gradle_args': gradle_args, } return args, extras + def _prepare_cmd(self, context, gradle_task=None): + cmd_args = self._get_ament_args(context) + cmd_args += context.ament_gradle_args + + cmd = [self._get_gradle_executable(context)] + cmd += cmd_args + if gradle_task: + cmd += [gradle_task] + cmd += ['--stacktrace'] + + return cmd + def extend_context(self, options): ce = super(AmentGradleBuildType, self).extend_context(options) - ce.add('ament_gradle_args', options.ament_gradle_args) + ament_gradle_args = list(options.ament_gradle_args) + if not any([arg.startswith('-Pament.android_variant=') for arg in ament_gradle_args]): + ament_gradle_args.append('-Pament.android_variant=release') + ce.add('ament_gradle_args', ament_gradle_args) + ce.add('ament_gradle_isolated', options.isolated) return ce def on_build(self, context): - cmd_args = [ - '-Pament.build_space=' + context.build_space, - '-Pament.install_space=' + context.install_space, - '-Pament.dependencies=' + ':'.join(context.build_dependencies), - '-Pament.build_tests=' + str(context.build_tests), - ] - cmd_args += context.ament_gradle_args + environment_hooks_path = os.path.join('share', context.package_manifest.name, 'environment') - cmd = [GRADLE_EXECUTABLE] - cmd += cmd_args - cmd += ['assemble'] + ext = '.sh' if not IS_WINDOWS else '.bat' + # expand environment hook for AMENT_PREFIX_PATH + ament_prefix_path_environment_hook = os.path.join(environment_hooks_path, + 'ament_prefix_path' + ext) + # expand environment hook for PATH + path_environment_hook = os.path.join(environment_hooks_path, 'path' + ext) - yield BuildAction(cmd, cwd=context.source_space) + # expand environment hook for CLASSPATH + classpath_filename = 'classpath' + ext + template = get_environment_hook_classpath_template_path() - def on_test(self, context): - cmd_args = [ - '-Pament.build_space=' + context.build_space, - '-Pament.install_space=' + context.install_space, - '-Pament.dependencies=' + ':'.join(context.build_dependencies), - '-Pament.build_tests=' + str(context.build_tests), + # If using the Gradle Ament Plugin, JAR files are installed into + # $AMENT_CURRENT_PREFIX/share/$PROJECT_NAME/java/$PROJECT_NAME.jar + classpath = os.path.join('$AMENT_CURRENT_PREFIX', 'share', context.package_manifest.name, + 'java', context.package_manifest.name + ".jar") + + content = configure_string(template, {'_AMENT_EXPORT_JARS_CLASSPATH': classpath, }) + + classpath_environment_hook = os.path.join(environment_hooks_path, + os.path.basename(classpath_filename)) + + destination_path = os.path.join(context.build_space, classpath_environment_hook) + destination_dir = os.path.dirname(destination_path) + if not os.path.exists(destination_dir): + os.makedirs(destination_dir) + with open(destination_path, 'w') as h: + h.write(content) + + environment_hooks = [ + ament_prefix_path_environment_hook, + classpath_environment_hook, + path_environment_hook, ] - cmd_args += context.ament_gradle_args - cmd = [GRADLE_EXECUTABLE] - cmd += cmd_args - cmd += ['test'] + # expand package-level setup files + expand_package_level_setup_files(context, environment_hooks, + environment_hooks_path) + + # remove anything that's on the destination tree but not in the source tree + src_package_src_dir = os.path.join(context.source_space, 'src') + dst_package_src_dir = os.path.join(context.build_space, 'src') + + src_dirnames, src_filenames = self._build_file_tree(src_package_src_dir) + dst_dirnames, dst_filenames = self._build_file_tree(dst_package_src_dir) + + prune_dirnames = dst_dirnames - src_dirnames + prune_filenames = dst_filenames - src_filenames - yield BuildAction(cmd, cwd=context.source_space) + for prune_filename in prune_filenames: + os.remove(os.path.join(dst_package_src_dir, prune_filename)) + for prune_dirname in prune_dirnames: + if os.path.exists(prune_dirname): + shutil.rmtree(os.path.join(dst_package_src_dir, prune_dirname)) + + # copy files from source_space to build_space to avoid poluting the latter + # during the build process + dir_util.copy_tree(context.source_space, context.build_space, update=1) + + yield BuildAction( + self._prepare_cmd( + context, gradle_task='assemble'), cwd=context.build_space) + + def on_test(self, context): + yield BuildAction(self._prepare_cmd(context, gradle_task='test'), cwd=context.build_space) def on_install(self, context): - cmd_args = [ - '-Pament.build_space=' + context.build_space, - '-Pament.install_space=' + context.install_space, - '-Pament.dependencies=' + ':'.join(context.build_dependencies), - '-Pament.build_tests=' + str(context.build_tests), - ] + # deploy package manifest + deploy_file( + context, + context.source_space, + 'package.xml', + dst_subfolder=os.path.join('share', context.package_manifest.name)) - cmd_args += context.ament_gradle_args + # create marker file + marker_file = os.path.join(context.install_space, 'share', 'ament_index', 'resource_index', + 'packages', context.package_manifest.name) + if not os.path.exists(marker_file): + marker_dir = os.path.dirname(marker_file) + if not os.path.exists(marker_dir): + os.makedirs(marker_dir) + with open(marker_file, 'w'): # "touching" the file + pass - cmd = [GRADLE_EXECUTABLE] - cmd += cmd_args - cmd += ['assemble'] + ext = '.sh' if not IS_WINDOWS else '.bat' + # deploy AMENT_PREFIX_PATH environment hook + app_template_path = get_environment_hook_template_path('ament_prefix_path' + ext) + deploy_file( + context, os.path.dirname(app_template_path), os.path.basename(app_template_path), + dst_subfolder=os.path.join('share', context.package_manifest.name, 'environment')) - yield BuildAction(cmd, cwd=context.source_space) + # deploy PATH environment hook + path_template_path = get_environment_hook_template_path('path' + ext) + deploy_file( + context, os.path.dirname(path_template_path), os.path.basename(path_template_path), + dst_subfolder=os.path.join('share', context.package_manifest.name, 'environment')) - def on_uninstall(self, context): - cmd_args = [ - '-Pament.build_space=' + context.build_space, - '-Pament.install_space=' + context.install_space, - '-Pament.dependencies=' + ':'.join(context.build_dependencies), - '-Pament.build_tests=' + str(context.build_tests), - ] + # deploy CLASSPATH environment hook + destination_file = 'classpath' + ('.sh' if not IS_WINDOWS else '.bat') + deploy_file(context, context.build_space, + os.path.join('share', context.package_manifest.name, 'environment', + destination_file)) - cmd_args += context.ament_gradle_args + # deploy package-level setup files + for name in get_package_level_template_names(): + assert name.endswith('.in') + deploy_file(context, context.build_space, + os.path.join('share', context.package_manifest.name, name[:-3])) - cmd = [GRADLE_EXECUTABLE] - cmd += cmd_args - cmd += ['clean'] + yield BuildAction( + self._prepare_cmd( + context, gradle_task='assemble'), cwd=context.build_space) - yield BuildAction(cmd, cwd=context.source_space) + def on_uninstall(self, context): + yield BuildAction(self._prepare_cmd(context, gradle_task='clean'), cwd=context.build_space) diff --git a/ament_build_type_gradle/ament_build_type_gradle/templates.py b/ament_build_type_gradle/ament_build_type_gradle/templates.py new file mode 100644 index 0000000..07083ec --- /dev/null +++ b/ament_build_type_gradle/ament_build_type_gradle/templates.py @@ -0,0 +1,24 @@ +# Copyright 2016-2017 Esteve Fernandez +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from ament_index_python import get_resource + +IS_WINDOWS = os.name == 'nt' + + +def get_environment_hook_classpath_template_path(): + ext = 'sh' if not IS_WINDOWS else 'bat' + return get_resource('templates', 'ament_build_type_gradle_classpath_' + ext)[0] diff --git a/ament_build_type_gradle/package.xml b/ament_build_type_gradle/package.xml index 0926d42..044789f 100644 --- a/ament_build_type_gradle/package.xml +++ b/ament_build_type_gradle/package.xml @@ -10,10 +10,8 @@ ament_tools - ament_copyright - ament_pep257 - ament_pep8 - ament_pyflakes + ament_java_resources + ament_java_resources ament_python diff --git a/ament_build_type_gradle/resource/ament_build_type_gradle b/ament_build_type_gradle/resource/ament_build_type_gradle new file mode 100644 index 0000000..e69de29 diff --git a/ament_build_type_gradle/setup.py b/ament_build_type_gradle/setup.py index 400ec37..b20dec2 100644 --- a/ament_build_type_gradle/setup.py +++ b/ament_build_type_gradle/setup.py @@ -1,11 +1,21 @@ +import os + from setuptools import find_packages from setuptools import setup +package_name = 'ament_build_type_gradle' + setup( - name='ament_build_type_gradle', + name=package_name, version='0.0.0', packages=find_packages(exclude=['test']), + data_files=[ + ('share/' + package_name, ['package.xml']), + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ], install_requires=['ament-package', 'osrf_pycommon'], + zip_safe=True, author='Esteve Fernandez', author_email='esteve@apache.org', maintainer='Esteve Fernandez', @@ -21,8 +31,6 @@ license='Apache License, Version 2.0', test_suite='test', entry_points={ - 'ament.build_types': [ - 'ament_gradle = ament_build_type_gradle:AmentGradleBuildType', - ], - } -) + 'ament.build_types': [f'ament_gradle = {package_name}:AmentGradleBuildType', ], + }, + package_data={f'{package_name}': ['template/environment_hook/*.in']}, ) diff --git a/ament_java.repos b/ament_java.repos index 3c8ca96..9498230 100644 --- a/ament_java.repos +++ b/ament_java.repos @@ -2,39 +2,35 @@ repositories: ament/ament_cmake: type: git url: https://github.com/ament/ament_cmake.git - version: master + version: 0.5.1 ament/ament_index: type: git url: https://github.com/ament/ament_index.git - version: master + version: 0.5.1 ament/ament_lint: type: git url: https://github.com/ament/ament_lint.git - version: master + version: 0.5.2 ament/ament_package: type: git url: https://github.com/ament/ament_package.git - version: master + version: 0.5.2 ament/ament_tools: type: git - url: https://github.com/ament/ament_tools.git - version: master - ament/gmock_vendor: - type: git - url: https://github.com/ament/gmock_vendor.git - version: master - ament/gtest_vendor: + url: https://github.com/esteve/ament_tools.git + version: win32-platform + ament/googletest: type: git - url: https://github.com/ament/gtest_vendor.git - version: master + url: https://github.com/ament/googletest.git + version: 4b6e624e78ba3d43c1602ffc80478ee7253e0b04 ament/osrf_pycommon: type: git url: https://github.com/osrf/osrf_pycommon.git - version: master + version: 0.1.5 ament/uncrustify: type: git url: https://github.com/ament/uncrustify.git - version: master + version: 0.66.1 ament_java/ament_java: type: git url: https://github.com/esteve/ament_java.git diff --git a/ament_java_resources/CMakeLists.txt b/ament_java_resources/CMakeLists.txt new file mode 100644 index 0000000..fab14ab --- /dev/null +++ b/ament_java_resources/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.5) + +project(ament_java_resources NONE) + +find_package(ament_cmake REQUIRED) + +ament_index_register_resource( + "templates" + CONTENT_FILE "classpath.dsv.template" + PACKAGE_NAME "ament_build_type_gradle_classpath_dsv") + +ament_index_register_resource( + "templates" + CONTENT_FILE "jni_library_path.dsv.template" + PACKAGE_NAME "ament_build_type_gradle_jni_library_path_dsv") + +ament_package() diff --git a/ament_java_resources/classpath.dsv.template b/ament_java_resources/classpath.dsv.template new file mode 100644 index 0000000..428e14d --- /dev/null +++ b/ament_java_resources/classpath.dsv.template @@ -0,0 +1 @@ +prepend-non-duplicate;CLASSPATH;@_AMENT_EXPORT_JARS_CLASSPATH@ diff --git a/ament_java_resources/jni_library_path.dsv.template b/ament_java_resources/jni_library_path.dsv.template new file mode 100644 index 0000000..640bff5 --- /dev/null +++ b/ament_java_resources/jni_library_path.dsv.template @@ -0,0 +1 @@ +prepend-non-duplicate;@JNI_LIB_ENV_VAR@;lib/jni diff --git a/ament_java_resources/package.xml b/ament_java_resources/package.xml new file mode 100644 index 0000000..9c86291 --- /dev/null +++ b/ament_java_resources/package.xml @@ -0,0 +1,22 @@ + + + + ament_java_resources + 0.0.0 + + Register ament_java resources in the Ament index. + + Esteve Fernandez + Apache License 2.0 + + ament_cmake + + ament_cmake + + ament_lint_auto + ament_lint_common + + + ament_cmake + +