Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic dependency resolution. #420

Merged
merged 1 commit into from
Aug 26, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
To see everything that has changed between version vA.B.C and vX.Y.Z, visit:
https://github.com/j2objc-contrib/j2objc-gradle/compare/vA.B.C...vX.Y.Z

# Prelease Alphas
# Prerelease 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:
Expand Down
1 change: 1 addition & 0 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Paste the results below, replacing existing contents.
- [Error: implicit declaration of function 'JreRelease' is invalid in C99 [-Werror,-Wimplicit-function-declaration] JreRelease(this$0_)](#error-implicit-declaration-of-function-jrerelease-is-invalid-in-c99--werror-wimplicit-function-declaration-jrereleasethis0_)
- [How do I disable a plugin task?](#how-do-i-disable-a-plugin-task)
- [How do I setup dependencies with J2ObjC?](#how-do-i-setup-dependencies-with-j2objc)
- [How do I setup a dependency to a third-party Java library?](#how-do-i-setup-a-dependency-to-a-third-party-java-library)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should dependencies be split out to their own doc? It feels like that's becoming a substantial section unto itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in my next PR, i hope to make dependencies a much shorter doc :)
it should be much simpler once this goes in.

- [How do I setup a dependency on a Java project?](#how-do-i-setup-a-dependency-on-a-java-project)
- [How do I setup a dependency on a prebuilt native library?](#how-do-i-setup-a-dependency-on-a-prebuilt-native-library)
- [How do I setup a dependency on a native library project?](#how-do-i-setup-a-dependency-on-a-native-library-project)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* 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 `[test]compile` dependencies to their
* `j2objcTranslation` and/or `j2objcLinkage` equivalents, depending on the type
* of dependency and whether or not they are already provided in native code.
* <p/>
* 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> J2OBJC_DEFAULT_LIBS = [
'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) {
// ex. `compile project(':peer1')`
visitProjectDependency(dep as ProjectDependency)
} else if (dep instanceof SelfResolvingDependency) {
// ex. `compile fileTree(dir: 'libs', include: ['*.jar'])`
visitSelfResolvingDependency(dep as SelfResolvingDependency)
} else if (dep instanceof ExternalModuleDependency) {
// ex. `compile "com.google.code.gson:gson:2.3.1"`
visitExternalModuleDependency(dep as ExternalModuleDependency)
} else {
// Everything else
visitGenericDependency(dep)
}
}

protected void visitSelfResolvingDependency(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add example, repeat for the other visitor methods below:

dependencies {
    compile project(':peer1')
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

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

protected void visitProjectDependency(ProjectDependency dep) {
project.logger.debug("j2objc dependency converter: Linking Project: $dep")
project.configurations.getByName('j2objcLinkage').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 (J2OBJC_DEFAULT_LIBS.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 J2OBJC_DEFAULT_LIB: $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('j2objcTranslation', "${group}:${dep.name}:${version}:sources")
}

protected void visitGenericDependency(Dependency dep) {
project.logger.warn("j2objc dependency converter: Unknown dependency type: $dep; copying naively")
project.configurations.getByName('j2objcTranslation').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 `j2objcTranslation` and 'j2objcLinkage' 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('j2objcTranslation').each { File it ->
// These are the resolved files, NOT the dependencies themselves.
visitTranslateFile(it)
}
project.configurations.getByName('j2objcLinkage').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