Skip to content

Commit

Permalink
Automatic dependency resolution.
Browse files Browse the repository at this point in the history
Dependency configuration happens in 2 phases:
- Dependency conversion:
  This converts your compile and testCompile dependencies into
  equivalent j2objcTranslate and j2objcLink dependencies.  Namely
  local jars are copied to j2objcTranslate, external Maven jars are
  converted into their 'sources' form and copied to j2objcTranslate,
  and projects are copied to j2objcLink (they don't need translation).

  This phase is optional and controlled by j2objcConfig.autoConfigureDeps

- Dependency resolution:
  This phase converts j2objcTranslate and j2objcLink deps into
  actual j2objc commands.  Any source jar on j2objcTranslate is
  added to translateSourcepaths with --build-closure.  Any project
  on j2objcLink is added to translateClasspaths and has its final
  j2objc static library linked in to this project's objective c code.

  This phase always runs.  If your dependencies are too complicated
  for the plugin to figure out in the first phase, keep autoConfigureDeps=false,
  and just add the appropriate projets, jars, and libraries here.

Also adds system tests for both project and external Maven dependencies.

TESTED=yes
  • Loading branch information
advayDev1 committed Aug 26, 2015
1 parent 1223b5c commit 752931f
Show file tree
Hide file tree
Showing 10 changed files with 339 additions and 36 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ https://github.com/j2objc-contrib/j2objc-gradle/compare/vA.B.C...vX.Y.Z

# Prelease Alphas

## vNext (HEAD)
Functionality:
* Automatic dependency resolution for Maven jars and Gradle projects #420
* Proper limitation of functionality on non-Mac platforms #396
* Embedded docs and versioning info for easier debugging #395

Code quality:
* Continuous integration on Mac #406 and on Windows #401
* Added end to end tests on OSX (running j2objc) #409 #411 etc.
* Unit tests pass on Windows #404
* Prevent publishing of bad releases #395 #398
* Docs updates (various)

## v0.4.2-alpha
Functionality:
* Translation-only mode (skips building Objective-C libraries) #349
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2015 the authors of j2objc-gradle (see AUTHORS file)
*
* 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.
*/

package com.github.j2objccontrib.j2objcgradle

import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ExternalModuleDependency
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.artifacts.SelfResolvingDependency

/**
* Converts `compile` and `testCompile` dependencies to their
* `j2objcTranslate` and `j2objcLink` equivalents. They will be resolved
* to appropriate `j2objc` constructs using DependencyResolver.
*/
@PackageScope
@CompileStatic
class DependencyConverter {

final Project project
final J2objcConfig j2objcConfig

// List of `group:name`
// TODO: Handle versioning.
static final List<String> distLibDeps = [
'com.google.guava:guava',
'junit:junit',
'org.mockito:mockito-core',
'com.google.j2objc:j2objc-annotations']

DependencyConverter(Project project, J2objcConfig j2objcConfig) {
this.project = project
this.j2objcConfig = j2objcConfig
}

void configureAll() {
project.configurations.getByName('compile').dependencies.each {
visit(it)
}
project.configurations.getByName('testCompile').dependencies.each {
visit(it)
}
}

protected void visit(Dependency dep) {
if (dep instanceof ProjectDependency) {
visitProjectDependency(dep as ProjectDependency)
} else if (dep instanceof SelfResolvingDependency) {
// File collections (ex. libs/*.jar) are one kind of SelfResolvingDependency.
visitSelfResolvingDependency(dep as SelfResolvingDependency)
} else if (dep instanceof ExternalModuleDependency) {
visitExternalModuleDependency(dep as ExternalModuleDependency)
} else {
visitGenericDependency(dep)
}
}

protected void visitSelfResolvingDependency(
SelfResolvingDependency dep) {
project.logger.debug("j2objc dependency converter: Translating file dep: $dep")
project.configurations.getByName('j2objcTranslate').dependencies.add(
dep.copy())
}

protected void visitProjectDependency(ProjectDependency dep) {
project.logger.debug("j2objc dependency converter: Linking Project: $dep")
project.configurations.getByName('j2objcLink').dependencies.add(
dep.copy())
}

protected void visitExternalModuleDependency(ExternalModuleDependency dep) {
project.logger.debug("j2objc dependency converter: External module dep: $dep")
// If the dep is already in the j2objc dist, ignore it.
if (distLibDeps.contains("${dep.group}:${dep.name}".toString())) {
// TODO: A more correct method might be converting these into our own
// form of SelfResolvingDependency that specifies which j2objc dist lib
// to use.
project.logger.debug("-- Skipped: $dep")
return
}
project.logger.debug("-- Copied as source: $dep")
String group = dep.group == null ? '' : dep.group
String version = dep.version == null ? '' : dep.version
// TODO: Make this less fragile. What if sources don't exist for this artifact?
project.dependencies.add('j2objcTranslate', "${group}:${dep.name}:${version}:sources")
}

protected void visitGenericDependency(Dependency dep) {
project.logger.debug("j2objc dependency converter: Generic dep: $dep")
project.configurations.getByName('j2objcTranslate').dependencies.add(
dep.copy())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright (c) 2015 the authors of j2objc-gradle (see AUTHORS file)
*
* 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.
*/

package com.github.j2objccontrib.j2objcgradle

import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import org.gradle.api.InvalidUserDataException
import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.artifacts.SelfResolvingDependency
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.bundling.AbstractArchiveTask

/**
* Resolves `j2objcTranslate` and 'j2objcLink' dependencies into their `j2objc` constructs.
*/
@PackageScope
@CompileStatic
class DependencyResolver {

final Project project
final J2objcConfig j2objcConfig

DependencyResolver(Project project, J2objcConfig j2objcConfig) {
this.project = project
this.j2objcConfig = j2objcConfig
}

void configureAll() {
project.configurations.getByName('j2objcTranslate').each { File it ->
// These are the resolved files, NOT the dependencies themselves.
visitTranslateFile(it)
}
project.configurations.getByName('j2objcLink').dependencies.each {
visitLink(it)
}
}

protected void visitTranslateFile(File depFile) {
j2objcConfig.translateSourcepaths(depFile.absolutePath)
j2objcConfig.enableBuildClosure()
}

protected void visitLink(Dependency dep) {
if (dep instanceof ProjectDependency) {
visitLinkProjectDependency((ProjectDependency) dep)
} else if (dep instanceof SelfResolvingDependency) {
visitLinkSelfResolvingDependency((SelfResolvingDependency) dep)
} else {
visitLinkGenericDependency(dep)
}
}

protected void visitLinkSelfResolvingDependency(
SelfResolvingDependency dep) {
// TODO: handle native prebuilt libraries as files.
throw new UnsupportedOperationException("Cannot automatically link J2ObjC dependency: $dep")
}

protected void visitLinkProjectDependency(ProjectDependency dep) {
Project beforeProject = dep.dependencyProject
// We need to have j2objcConfig on the beforeProject configured first.
project.evaluationDependsOn beforeProject.path

if (!beforeProject.plugins.hasPlugin(JavaPlugin)) {
String message = "$beforeProject is not a Java project.\n" +
"dependsOnJ2ObjcLib can only automatically resolve a\n" +
"dependency on a Java project also converted using the\n" +
"J2ObjC Gradle Plugin."
throw new InvalidUserDataException(message)
}

if (!beforeProject.plugins.hasPlugin(J2objcPlugin)) {
String message = "$beforeProject does not use the J2ObjC Gradle Plugin.\n" +
"dependsOnJ2objcLib can be used only with another project that\n" +
"itself uses the J2ObjC Gradle Plugin."
throw new InvalidUserDataException(message)
}

// Build and test the java/objc libraries and the objc headers of
// the other project first.
// Since we assert the presence of the J2objcPlugin above,
// we are guaranteed that the java plugin, which creates the jar task,
// is also present.
project.tasks.getByName('j2objcPreBuild').dependsOn {
return [beforeProject.tasks.getByName('j2objcBuild'),
beforeProject.tasks.getByName('jar')]
}
AbstractArchiveTask jarTask = beforeProject.tasks.getByName('jar') as AbstractArchiveTask
project.logger.debug("$project:j2objcTranslate must use ${jarTask.archivePath}")
j2objcConfig.translateClasspaths += jarTask.archivePath.absolutePath
j2objcConfig.nativeCompilation.dependsOnJ2objcLib(beforeProject)
}

protected void visitLinkGenericDependency(Dependency dep) {
throw new UnsupportedOperationException("Cannot automatically link J2ObjC dependency: $dep")
}
}
Loading

0 comments on commit 752931f

Please sign in to comment.