diff --git a/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/CatkinPlugin.groovy b/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/CatkinPlugin.groovy index 49a4dfbec782813e353d321573c355768d1ab4ff..4bcd8d5c514054e1c39bfbe6305f113eee400656 100644 --- a/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/CatkinPlugin.groovy +++ b/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/CatkinPlugin.groovy @@ -4,6 +4,7 @@ import org.gradle.api.Project; import org.gradle.api.Plugin; import org.gradle.api.Task; import org.gradle.api.tasks.JavaExec +import org.gradle.api.tasks.StopActionException import org.gradle.api.*; @@ -14,22 +15,22 @@ import org.gradle.api.*; * - project.catkin.workspaces : list of Strings * - project.catkin.tree.generate() : create the pkgs dictionary * - project.catkin.tree.pkgs : dictionary of CatkinPackage objects - * + * * The latter can be iterated over for information: * * project.catkin.tree.pkgs.each { pair -> - * pkg = pair.value - * println pkg.name - * println pkg.version - * pkg.dependencies.each { d -> - * println d - * } - * // filtered list of *_msg dependencies. - * pkg.messageDependencies().each { d -> - * println d - * } + * pkg = pair.value + * println pkg.name + * println pkg.version + * pkg.dependencies.each { d -> + * println d + * } + * // filtered list of *_msg dependencies. + * pkg.getMessageDependencies().each { d -> + * println d + * } * } - * + * * Use this only once in the root of a multi-project gradle build - it will * only generate the properties once and share them this way. */ @@ -53,7 +54,7 @@ class CatkinPlugin implements Plugin<Project> { packageXml = project.file('package.xml') } if (packageXml != null) { - project.catkin.pkg = new CatkinPackage(packageXml) + project.catkin.pkg = new CatkinPackage(project, packageXml) } setTasks() } @@ -69,202 +70,126 @@ class CatkinPlugin implements Plugin<Project> { } } class CatkinPluginExtension { - CatkinPackage pkg - List<String> workspaces - CatkinPackages tree + CatkinPackage pkg + List<String> workspaces + CatkinPackages tree } + class CatkinPackages { - def Map<String, CatkinPackage> pkgs - def List<String> workspaces - def Project project - - def CatkinPackages(Project project, List<String> workspaces) { - this.project = project - this.workspaces = workspaces - this.pkgs = [:] - } - - def generate() { - if ( this.pkgs.size() == 0 ) { - this.workspaces.each { workspace -> - def manifestTree = project.fileTree(dir: workspace, include: '**/package.xml') - manifestTree.each { file -> - def pkg = new CatkinPackage(file) - if(this.pkgs.containsKey(pkg.name)) { - if(this.pkgs[pkg.name].version < pkg.version) { - println("Catkin generate tree: replacing older version of " + pkg.name + "[" + this.pkgs[pkg.name].version + "->" + pkg.version + "]") - this.pkgs[pkg.name] = pkg - } - } else { - this.pkgs.put(pkg.name, pkg) - } - } + + Map<String, CatkinPackage> pkgs + List<String> workspaces + Project project + + CatkinPackages(Project project, List<String> workspaces) { + this.project = project + this.workspaces = workspaces + pkgs = [:] + } + + void generate() { + if (pkgs.size() == 0) { + workspaces.each { workspace -> + def manifestTree = project.fileTree(dir: workspace, + include: "**/package.xml") + manifestTree.each { file -> + def pkg = new CatkinPackage(file) + if(this.pkgs.containsKey(pkg.name)) { + if(this.pkgs[pkg.name].version < pkg.version) { + println("Catkin generate tree: replacing older version of " + pkg.name + "[" + this.pkgs[pkg.name].version + "->" + pkg.version + "]") + pkgs[pkg.name] = pkg } + } else { + pkgs.put(pkg.name, pkg) + } } + } } + } - def isMessagePackage(String package_name) { - def pkg - def result = false - try { - pkg = this.pkgs[package_name] - /* println(" Name: " + pkg.name + "-" + pkg.version) */ - /* println(" Dep-dependencies: " + pkg.dependencies) */ - pkg.dependencies.each { d -> - if ( d.equalsIgnoreCase("message_generation") ) { - result = true - } - } - } catch (NullPointerException e) { - /* Not a catkin package dependency (e.g. boost), ignore */ - result = false + Boolean isMessagePackage(String package_name) { + def pkg + def result = false + try { + pkg = this.pkgs[package_name] + /* println(" Name: " + pkg.name + "-" + pkg.version) */ + /* println(" Dep-dependencies: " + pkg.dependencies) */ + pkg.dependencies.each { d -> + if ( d.equalsIgnoreCase("message_generation") ) { + result = true } - return result + } + } catch (NullPointerException e) { + /* Not a catkin package dependency (e.g. boost), ignore */ + result = false } + return result + } - def void generateMessageArtifact(Project p, String package_name) { - def pkg = this.pkgs[package_name] - p.version = pkg.version - /* println("Artifact: " + pkg.name + "-" + pkg.version) */ - p.dependencies.add("compile", 'org.ros.rosjava_bootstrap:message_generation:[0.1,0.2)') - List<String> messageDependencies = [] - pkg.dependencies.each { d -> - /* println(" Dependency: " + d) */ - if ( this.isMessagePackage(d) ) { - messageDependencies.add(d) - /* println(" Msg Pkg: yes") */ - } else { - /* println(" Msg Pkg: no") */ - } - } - messageDependencies.each { d -> - if ( p.getParent().getChildProjects().containsKey(d) ) { - /* println(" Internal: " + d) */ - p.dependencies.add("compile", p.dependencies.project(path: ':' + d)) - } else { - /* println(" External: " + d) */ - p.dependencies.add("compile", 'org.ros.rosjava_messages:' + d + ':[0.0,)') - } - } - def generatedSourcesDir = "${p.buildDir}/generated-src" - def generateSourcesTask = p.tasks.create("generateSources", JavaExec) - generateSourcesTask.description = "Generate sources for " + pkg.name - generateSourcesTask.outputs.dir(p.file(generatedSourcesDir)) - /* generateSourcesTask.args = new ArrayList<String>([generatedSourcesDir, pkg.name]) */ - generateSourcesTask.args = new ArrayList<String>([generatedSourcesDir, '--package-path=' + pkg.directory, pkg.name]) - generateSourcesTask.classpath = p.configurations.runtime - generateSourcesTask.main = 'org.ros.internal.message.GenerateInterfaces' - p.tasks.compileJava.source generateSourcesTask.outputs.files + void generateMessageArtifact(Project project, String package_name) { + def pkg = this.pkgs[package_name] + project.version = pkg.version + /* println("Artifact: " + pkg.name + "-" + pkg.version) */ + project.dependencies.add("compile", 'org.ros.rosjava_bootstrap:message_generation:[0.2,0.3)') + Set<String> messageDependencies = pkg.getMessageDependencies() + messageDependencies.each { d -> + if ( project.getParent().getChildProjects().containsKey(d) ) { + /* println(" Internal: " + d) */ + project.dependencies.add("compile", project.dependencies.project(path: ':' + d)) + } else { + /* println(" External: " + d) */ + project.dependencies.add("compile", 'org.ros.rosjava_messages:' + d + ':[0.0,)') + } } + def generatedSourcesDir = "${project.buildDir}/generated-src" + def generateSourcesTask = project.tasks.create("generateSources", JavaExec) + generateSourcesTask.description = "Generate sources for " + pkg.name + generateSourcesTask.outputs.dir(project.file(generatedSourcesDir)) + /* generateSourcesTask.args = new ArrayList<String>([generatedSourcesDir, pkg.name]) */ + generateSourcesTask.args = new ArrayList<String>([generatedSourcesDir, '--package-path=' + pkg.directory, pkg.name]) + generateSourcesTask.classpath = project.configurations.runtime + generateSourcesTask.main = "org.ros.internal.message.GenerateInterfaces" + project.tasks.compileJava.source generateSourcesTask.outputs.files + } } class CatkinPackage { - def name - def version - def dependencies - def directory - - def CatkinPackage(File packageXmlFilename) { - def packageXml = new XmlParser().parse(packageXmlFilename) - directory = packageXmlFilename.parent - name = packageXml.name.text() - version = packageXml.version.text() - dependencies = [] - packageXml.build_depend.each { d -> - dependencies.add(d.text()) - } - } - def String toString() { - def out = new String() - out += name + "\n" - out += " version: " + version + "\n" - out += " dependencies:" + "\n" - dependencies.each { d -> - out += " " + d + "\n" - } - return out - } - /* - * Find and annotate a list of package package dependencies. - * Useful for message artifact generation). - * - * Depracated, but kept around for legacy purposes, remove in igloo - * - * @return List<String> : dependencies (package name strings) - */ - def List<String> messageDependencies() { - List<String> msgDependencies = [] - dependencies.each { d -> - if ( d.contains("_msgs") ) { - msgDependencies.add(d) - } - } - return msgDependencies - } - - /* Depracated, but kept around for legacy purposes, remove in igloo */ - def void generateMessageArtifact(Project p) { - p.version = version - p.dependencies.add("compile", 'org.ros.rosjava_bootstrap:message_generation:[0.1,0.2)') - messageDependencies().each { d -> - p.dependencies.add("compile", p.dependencies.project(path: ':' + d)) - } - def generatedSourcesDir = "${p.buildDir}/generated-src" - def generateSourcesTask = p.tasks.create("generateSources", JavaExec) - generateSourcesTask.description = "Generate sources for " + name - generateSourcesTask.outputs.dir(p.file(generatedSourcesDir)) - generateSourcesTask.args = new ArrayList<String>([generatedSourcesDir, name]) - generateSourcesTask.classpath = p.configurations.runtime - generateSourcesTask.main = 'org.ros.internal.message.GenerateInterfaces' - p.tasks.compileJava.source generateSourcesTask.outputs.files - } + Project project + String name + String version + Set<String> dependencies + String directory - /* Depracated, but kept around for legacy purposes, remove in igloo */ - def void generateUnofficialMessageArtifact(Project p) { - /* Couple of constraints here: - 1) maven group forced to org.ros.rosjava_messages to that all message artifact - dependencies are easily found. - 2) Open ended dependency range (takes the latest in ROS_PACKAGE_PATH) since we - don't know the artifact versions the user really wants. - */ - p.version = version - p.group = 'org.ros.rosjava_messages' - p.dependencies.add("compile", 'org.ros.rosjava_bootstrap:message_generation:[0.1,0.2)') - messageDependencies().each { d -> - if ( p.getParent().getChildProjects().containsKey(d) ) { - p.dependencies.add("compile", p.dependencies.project(path: ':' + d)) - } else { - p.dependencies.add("compile", 'org.ros.rosjava_messages:' + d + ':[0.1,)') - } - } - def generatedSourcesDir = "${p.buildDir}/generated-src" - def generateSourcesTask = p.tasks.create("generateSources", JavaExec) - generateSourcesTask.description = "Generate sources for " + name - generateSourcesTask.outputs.dir(p.file(generatedSourcesDir)) - generateSourcesTask.args = new ArrayList<String>([generatedSourcesDir, '--package-path=' + directory, name]) - generateSourcesTask.classpath = p.configurations.runtime - generateSourcesTask.main = 'org.ros.internal.message.GenerateInterfaces' - p.tasks.compileJava.source generateSourcesTask.outputs.files - } + CatkinPackage(Project project, File packageXmlFilename) { + this.project = project + /* println "Loading " + packageXmlFilename */ + def packageXml = new XmlParser().parse(packageXmlFilename) + directory = packageXmlFilename.parent + name = packageXml.name.text() + version = packageXml.version.text() + dependencies = packageXml.build_depend.collect{ it.text() } + } - /* - * Hack to work around for rosjava_test_msgs - look in a subfolder for the - * msgs and name the artifact by the subfolder name/version. - */ - def void generateMessageArtifactInSubFolder(Project p, String subfolderName, List<String> dependencies) { - // p.version = version use the subfolder's project version - p.dependencies.add("compile", 'org.ros.rosjava_bootstrap:message_generation:[0.1,0.2)') - dependencies.each { d -> - p.dependencies.add("compile", p.dependencies.project(path: ':' + d)) - } - def generatedSourcesDir = "${p.buildDir}/generated-src" - def generateSourcesTask = p.tasks.create("generateSources", JavaExec) - generateSourcesTask.description = "Generate sources for " + name + "/" + subfolderName - generateSourcesTask.outputs.dir(p.file(generatedSourcesDir)) - generateSourcesTask.args = new ArrayList<String>([generatedSourcesDir, subfolderName]) - generateSourcesTask.classpath = p.configurations.runtime - generateSourcesTask.main = 'org.ros.internal.message.GenerateInterfaces' - p.tasks.compileJava.source generateSourcesTask.outputs.files + String toString() { "${name} ${version} ${dependencies}" } + + Set<String> getTransitiveDependencies(Collection<String> dependencies) { + Set<String> result = []; + dependencies.each { + if (project.catkin.tree.pkgs.containsKey(it)) { + result.add(it) + result.addAll(getTransitiveDependencies( + project.catkin.tree.pkgs[it].dependencies)) + } } + return result + } + + Set<String> getMessageDependencies() { + getTransitiveDependencies(dependencies).findAll { + project.catkin.tree.pkgs.containsKey(it) && + project.catkin.tree.pkgs[it].dependencies.contains("message_generation") + } as Set + } + } diff --git a/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/RosAndroid.groovy b/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/RosAndroid.groovy index 8d5e260809a98ac735a348558560bd6344c9e12f..0eb2297fba985991ea4d5fa919633a214171394d 100644 --- a/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/RosAndroid.groovy +++ b/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/RosAndroid.groovy @@ -4,63 +4,45 @@ import org.gradle.api.Project import org.gradle.api.Plugin import java.util.HashMap -/* - * Configures java for the ros-android build environment. Pretty elementary right now, - * just applies the java plugin and defines the jdk compatibility level. +/** + * Configures ROS on Android build environment. */ class RosAndroidPlugin implements Plugin<Project> { - Project project - - def void apply(Project project) { - this.project = project - if (!project.plugins.findPlugin('ros')) { - project.apply(plugin: 'ros') - } - project.extensions.create("rosandroid", RosAndroidPluginExtension) - project.rosandroid.buildToolsVersion = "19.1.0" - /********************************************************************* - * Find the android plugin - *********************************************************************/ - project.buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:0.11.+' - } - } - /********************************************************************** - * Publishing - not we're using old style here. Upgrade to maven-publish - * once they have support: - * https://github.com/rosjava/rosjava_bootstrap/issues/1 - **********************************************************************/ - project.uploadArchives { - repositories.mavenDeployer { - repository(url: 'file://' + project.ros.mavenDeploymentRepository) - } - } - /********************************************************************** - * Our maven repo 3rd parties are currently incompatible with android - * junit especially could use a look at - find a compatible version! - **********************************************************************/ - project.configurations.create('compile') - def excludes = new HashMap<String, String>() - excludes.put('group', 'junit') - excludes.put('group', 'xml-apis') - project.configurations['compile'].exclude(excludes) - /********************************************************************** - * Delay android plugin configuration because that will depend on - * the subproject's late loading of android or android-library plugin. - **********************************************************************/ - project.afterEvaluate { - project.android { - buildToolsVersion project.rosandroid.buildToolsVersion - } - } - + void apply(Project project) { + project.apply plugin: "ros" + project.extensions.create("rosandroid", RosAndroidPluginExtension) + project.rosandroid.buildToolsVersion = "19.1.0" + + /********************************************************************** + * Publishing - not we're using old style here. Upgrade to maven-publish + * once they have support: + * https://github.com/rosjava/rosjava_bootstrap/issues/1 + * This is specifically for releasing and working in a ros workspace. + **********************************************************************/ + project.uploadArchives { + repositories.mavenDeployer { + repository(url: 'file://' + project.ros.mavenDeploymentRepository) + } + } + /********************************************************************** + * Our maven repo 3rd parties are currently incompatible with android + * junit especially could use a look at - find a compatible version! + **********************************************************************/ + project.configurations.maybeCreate("compile") + project.configurations.compile.exclude "group": "junit" + project.configurations.compile.exclude "group": "xml-apis" + /********************************************************************** + * Delay android plugin configuration because that will depend on + * the subproject's late loading of android or android-library plugin. + **********************************************************************/ + project.afterEvaluate { + project.android { + buildToolsVersion project.rosandroid.buildToolsVersion + } } + } } class RosAndroidPluginExtension { - String buildToolsVersion + String buildToolsVersion } diff --git a/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/RosPlugin.groovy b/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/RosPlugin.groovy index 0c421b4c996d28a4108d45a8a15468db8c69315f..390cc610b693b2d9e863375c1b7d0de95234d79c 100644 --- a/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/RosPlugin.groovy +++ b/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/RosPlugin.groovy @@ -1,66 +1,67 @@ package org.ros.gradle_plugins; -import org.gradle.api.Project; -import org.gradle.api.Plugin; import org.gradle.api.*; +import org.gradle.api.publish.maven.MavenPublication; -/* - * Provides information about the ros workspace. +/** + * Configures a Java project for use with ROS. * * - project.ros.mavenPath : location of local ros maven repositories (in your chained workspaces) * - project.ros.mavenDeploymentRepository : location of the ros maven repository you will publish to * * It also performs the following actions - * + * * - checks and makes sure the maven plugin is running * - constructs the sequence of dependent maven repos (local ros maven repos, mavenLocal, external ros maven repo) * - configures the uploadArchives for artifact deployment to the local ros maven repo (devel/share/maven) */ class RosPlugin implements Plugin<Project> { - Project project - - def void apply(Project project) { - this.project = project - if (!project.plugins.findPlugin('maven')) { - project.apply(plugin: 'maven') - } - /* Create project.ros.* property extensions */ - project.extensions.create("ros", RosExtension) - project.ros.mavenPath = "$System.env.ROS_MAVEN_PATH".split(':') - project.ros.mavenDeploymentRepository = "$System.env.ROS_MAVEN_DEPLOYMENT_REPOSITORY" - def mavenRepository = "$System.env.ROS_MAVEN_REPOSITORY" - if ( mavenRepository != 'null' ) { - project.ros.mavenRepository = mavenRepository + + def void apply(Project project) { + project.apply plugin: "maven" + + project.extensions.create("ros", RosPluginExtension) + + project.ros.mavenRepository = System.getenv("ROS_MAVEN_REPOSITORY") + project.ros.mavenDeploymentRepository = System.getenv("ROS_MAVEN_DEPLOYMENT_REPOSITORY") + String mavenPath = System.getenv("ROS_MAVEN_PATH") + if (mavenPath != null) { + project.ros.mavenPath = mavenPath.tokenize(":") + } + project.repositories { + if (project.ros.mavenPath != null) { + project.ros.mavenPath.each { path -> + maven { + url project.uri(path) + } } - /* - * Could use some better handling for when this is not defined as it sets - * file://null, but it doesn't seem to hurt the process any - */ - def repoURLs = project.ros.mavenPath.collect { 'file://' + it } - project.repositories { - repoURLs.each { p -> - maven { - url p - } - } - mavenLocal() - maven { - url project.ros.mavenRepository - } - mavenCentral() + } + if (project.ros.mavenRepository != null) { + maven { + url project.ros.mavenRepository } + } + mavenLocal() + maven { + url "http://repository.springsource.com/maven/bundles/release" + } + maven { + url "http://repository.springsource.com/maven/bundles/external" + } + mavenCentral() } + } } /* http://www.gradle.org/docs/nightly/dsl/org.gradle.api.plugins.ExtensionAware.html */ -class RosExtension { - List<String> mavenPath - String mavenDeploymentRepository - String mavenRepository - - RosExtension() { - /* Initialising the strings here gets rid of the dynamic property deprecated warnings. */ - this.mavenDeploymentRepository = "" - this.mavenRepository = "https://github.com/rosjava/rosjava_mvn_repo/raw/master" - } +class RosPluginExtension { + String mavenRepository + String mavenDeploymentRepository + List<String> mavenPath + + RosPluginExtension() { + /* Initialising the strings here gets rid of the dynamic property deprecated warnings. */ + this.mavenDeploymentRepository = "" + this.mavenRepository = "https://github.com/rosjava/rosjava_mvn_repo/raw/master" + } } diff --git a/settings.gradle b/settings.gradle index b85c37b8ba5d45b695d794928da123e370701475..3be0d14b254a843c3a58dcbdfe1c24f0af628928 100644 --- a/settings.gradle +++ b/settings.gradle @@ -15,4 +15,4 @@ */ include 'gradle_plugins' -include 'message_generation' +include 'message_generation' \ No newline at end of file