Skip to content

Commit

Permalink
j2objcXcode now dependency of j2objcBuild
Browse files Browse the repository at this point in the history
- j2objcbuild depends on j2objcXcode, which depends on j2objcAssemble
- j2objcXcode skips task if xcodeProjectDir is not set
- j2objcXcode @input for project dependencies
- PodspecDetails is now serializable so it can be used for @input
- Cocoapods 0.39.0 is now installed in Travis build on OS X
  • Loading branch information
brunobowden committed Oct 22, 2015
1 parent 94223a8 commit 9cf24d2
Show file tree
Hide file tree
Showing 11 changed files with 142 additions and 106 deletions.
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ matrix:
- os: osx
osx_image: xcode7
language: objective-c
# # Cocoapods isn't installed on the default Ruby (2.0.0)
# # http://docs.travis-ci.com/user/common-build-problems/#Mac%3A-Errors-running-CocoaPods
## rvm: 1.9.3
env:
- TEST_SET=1
- USING_OS=osx
Expand Down Expand Up @@ -48,6 +51,7 @@ before_install:
# Don't spew graphic art.
- export TERM=dumb
- env
- if [ "$USING_OS" = "osx" ]; then gem install cocoapods -v '0.39.0'; fi
# Travis doesn't let us select the JDK version on OS X. Force it ourselves.
- if [ "$USING_OS" = "osx" ]; then ./install-osx-jdk7.sh; fi

Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ New functionality:
* Translate and run standalone test source Jar files (such as external library dependencies) #489
* Test-only dependencies on other libraries and projects #489
* Cocoa Pods supports multi-project applications #504
* iOS, watchOS, and OS X applications can be setup using Cocoa Pods #506
* iOS and OS X applications can be setup using Cocoa Pods #506
* Validate version of j2objc and provide install instructions #515

Breaking changes/functionality:
Expand Down
15 changes: 4 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@ plugins {
// Plugin settings:
j2objcConfig {
// Xcode project directory (suggested directory name)
xcodeProjectDir '../ios'
xcodeProjectDir '../ios' // suggested directory name
xcodeTargetsIos 'IOS-APP', 'IOS-APPTests' // replace with your iOS targets
finalConfigure() // Must be last call to configuration
}
```

Info on additional `j2objcConfig` settings are in
[J2objcConfig.groovy](https://github.com/j2objc-contrib/j2objc-gradle/blob/master/src/main/groovy/com/github/j2objccontrib/j2objcgradle/J2objcConfig.groovy#L30).
The default will link the transpiled code in to all of your Xcode build targets. To specify
a subset, add a line for `xcodeTargets 'IOS-APP', 'IOS-APP-TESTS', 'WATCHKIT-APP', ...`.
The Xcode targets may also be set for xcodeTargetsOsx and xcodeTargetsWatchos
([issue #525 to get watchOS working](https://github.com/j2objc-contrib/j2objc-gradle/issues/525)).
If your `shared` project depends on any other projects or third-party libraries, you may
need to [add them manually](FAQ.md#how-do-i-setup-dependencies-with-j2objc) if they aren't
[linked by default](FAQ.md#what-libraries-are-linked-by-default).
Expand Down Expand Up @@ -98,13 +98,6 @@ be run as follows:

./gradlew shared:build

During development, to build the libraries and update Xcode (skipping the tests):

./gradlew shared:j2objcXcode

For a complete build, run both:

./gradlew shared:build shared:j2objcXcode

### Problems

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,21 +272,20 @@ class J2objcPlugin implements Plugin<Project> {
group 'build'
description "Marker task for all release tasks that take part in regular j2objc builds"
}
// Xcode
tasks.create(name: 'j2objcXcode', type: XcodeTask,
dependsOn: 'j2objcAssemble') {
group 'build'
description 'Depends on j2objc translation, create a Pod file link it to Xcode project'
}
// If users need to depend on this project to build other j2objc projects, they can use this
// marker task.
tasks.create(name: 'j2objcBuild', type: DefaultTask,
dependsOn: ['j2objcBuildDebug', 'j2objcBuildRelease']) {
dependsOn: ['j2objcBuildDebug', 'j2objcBuildRelease', 'j2objcXcode']) {
group 'build'
description "Marker task for all tasks that take part in regular j2objc builds"
}
lateDependsOn(project, 'build', 'j2objcBuild')

// TODO: Where shall we fit this task in the plugin lifecycle?
tasks.create(name: 'j2objcXcode', type: XcodeTask,
dependsOn: 'j2objcAssemble') {
// This is not in the build group because you do not need to do it on every build.
description 'Depends on j2objc translation, create a Pod file link it to Xcode project'
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package com.github.j2objccontrib.j2objcgradle.tasks
import com.github.j2objccontrib.j2objcgradle.J2objcConfig
import com.google.common.annotations.VisibleForTesting
import groovy.transform.CompileStatic
import groovy.transform.EqualsAndHashCode
import org.gradle.api.DefaultTask
import org.gradle.api.InvalidUserDataException
import org.gradle.api.Project
Expand Down Expand Up @@ -53,6 +54,19 @@ class XcodeTask extends DefaultTask {
@Input @Optional
String getXcodeProjectDir() { return J2objcConfig.from(project).xcodeProjectDir }

boolean isTaskActive() { return getXcodeProjectDir() != null }

@Input
// List of all dependencies
List<PodspecDetails> getPodspecDependencies() {
println ("GET_DEPENDENCIES")
if (!isTaskActive()) {
// Optimization for only calculating dependencies where needed
return []
}
return getPodspecDependencies(getProject(), new HashSet<Project>())
}

@Input
List<String> getXcodeTargetsIos() { return J2objcConfig.from(project).xcodeTargetsIos }
@Input
Expand All @@ -69,11 +83,13 @@ class XcodeTask extends DefaultTask {

@OutputFile
File getPodfileFile() {
verifyXcodeArgs()
return project.file(new File(getXcodeProjectDir(), '/Podfile'))
}

static class PodspecDetails {
static class PodspecDetails implements Serializable {
// Increment this when the serialization output changes
private static final long serialVersionUID = 1L;

String projectName
File podspecDebug
File podspecRelease
Expand All @@ -87,6 +103,16 @@ class XcodeTask extends DefaultTask {
String getPodMethodName() {
return "j2objc_$projectName"
}

@SuppressWarnings('unused')
private static void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
}

@SuppressWarnings('unused')
private static void readObject(ObjectInputStream s) throws IOException {
s.defaultReadObject();
}
}

static class XcodeTargetDetails {
Expand Down Expand Up @@ -114,7 +140,25 @@ class XcodeTask extends DefaultTask {
void xcodeConfig() {
Utils.requireMacOSX('j2objcXcode task')

verifyXcodeArgs()
if (!isTaskActive()) {
logger.debug("j2objcXcode task disabled for ${project.name}")
return
}

// // TODO: figure out how to display error when not configured on root project
// String message =
// "xcodeProjectDir need to be configured in ${project.name}'s build.gradle.\n" +
// "The directory should point to the location containing your Xcode project,\n" +
// "including the IOS-APP.xccodeproj file.\n" +
// "\n" +
// "j2objcConfig {\n" +
// " xcodeProjectDir '../ios'\n" +
// "}\n" +
// "\n" +
// "Alternatively disable the j2objcXcode task if you wish to do your own Xcode build.\n"
// "Also see the guidelines for the folder structure:\n" +
// "https://github.com/j2objc-contrib/j2objc-gradle/blob/master/FAQ.md#what-is-the-recommended-folder-structure-for-my-app\n"
// throw new InvalidUserDataException(message)

// link the podspec in pod file
File podfile = getPodfileFile()
Expand All @@ -129,8 +173,8 @@ class XcodeTask extends DefaultTask {
"To fix this:\n" +
"\n" +
"1) Set xcodeProjectDir to the directory containing 'IOS-APP.xcodeproj':\n" +
" current value from j2objcConfig: ${getXcodeProjectDir()}\n" +
" current value for absolute path: $xcodeAbsPath\n" +
" curent value: ${getXcodeProjectDir()}\n" +
" resolves to: $xcodeAbsPath\n" +
"\n" +
"2) Within that directory, create the Podfile with:\n" +
" (cd $xcodeAbsPath && pod init)\n" +
Expand All @@ -142,8 +186,7 @@ class XcodeTask extends DefaultTask {
logger.debug("Pod exists at path: ${getXcodeProjectDir()}")

// Write Podfile based on all the podspecs from dependent projects
List<PodspecDetails> podspecDetailsList =
getPodspecsFromProject(getProject(), new HashSet<Project>())
List<PodspecDetails> podspecDetailsList = getPodspecDependencies()

XcodeTargetDetails xcodeTargetDetails = new XcodeTargetDetails(
getXcodeTargetsIos(), getXcodeTargetsOsx(), getXcodeTargetsWatchos(),
Expand Down Expand Up @@ -196,7 +239,8 @@ class XcodeTask extends DefaultTask {
* @return List of Files corresponding to debug / release pair of podspecs
* Even entries in the list are debug podspecs, odd for release podspecs
*/
private List<PodspecDetails> getPodspecsFromProject(Project proj, Set<Project> visitedProjects) {
@VisibleForTesting
List<PodspecDetails> getPodspecDependencies(Project proj, Set<Project> visitedProjects) {

// Find podspecs generated by this project
List<PodspecDetails> podspecs = new ArrayList<>()
Expand All @@ -211,30 +255,12 @@ class XcodeTask extends DefaultTask {

J2objcConfig j2objcConfig = proj.getExtensions().getByType(J2objcConfig)
j2objcConfig.getBeforeProjects().each { Project beforeProject ->
podspecs.addAll(getPodspecsFromProject(beforeProject, visitedProjects))
podspecs.addAll(getPodspecDependencies(beforeProject, visitedProjects))
}

return podspecs
}

@VisibleForTesting
void verifyXcodeArgs() {
if (getXcodeProjectDir() == null) {
String message =
"xcodeProjectDir need to be configured in ${project.name}'s build.gradle.\n" +
"The directory should point to the location containing your Xcode project,\n" +
"including the IOS-APP.xccodeproj file.\n" +
"\n" +
"j2objcConfig {\n" +
" xcodeProjectDir '../ios'\n" +
"}\n" +
"\n" +
"Also see the guidelines for the folder structure:\n" +
"https://github.com/j2objc-contrib/j2objc-gradle/blob/master/FAQ.md#what-is-the-recommended-folder-structure-for-my-app"
throw new InvalidUserDataException(message)
}
}

/**
* Extracts xcode targets in Podfile.
*/
Expand Down Expand Up @@ -355,7 +381,7 @@ class XcodeTask extends DefaultTask {
List<String> newPodfileLines = new ArrayList<String>(oldPodfileLines)

newPodfileLines = updatePodfile(
newPodfileLines, podspecDetailsList, xcodeTargetDetails, podfile, logger)
newPodfileLines, podspecDetailsList, xcodeTargetDetails, podfile)

// Write file only if it's changed
if (!oldPodfileLines.equals(newPodfileLines)) {
Expand All @@ -368,7 +394,7 @@ class XcodeTask extends DefaultTask {
List<String> podfileLines,
List<PodspecDetails> podspecDetailsList,
XcodeTargetDetails xcodeTargetDetails,
File podfile, Logger logger) {
File podfile) {

List<String> podfileTargets = extractXcodeTargets(podfileLines)
verifyTargets(xcodeTargetDetails.xcodeTargetsIos, podfileTargets, 'xcodeTargetsIos')
Expand All @@ -378,7 +404,7 @@ class XcodeTask extends DefaultTask {
if (xcodeTargetDetails.xcodeTargetsIos.isEmpty() &&
xcodeTargetDetails.xcodeTargetsOsx.isEmpty() &&
xcodeTargetDetails.xcodeTargetsWatchos.isEmpty()) {
// Need to warn about configuring
// Give example for configuring iOS as that's the common case
throw new InvalidUserDataException(
"You must configure the xcode targets for the J2ObjC Gradle Plugin.\n" +
"It must be a subset of the valid targets: '${podfileTargets.join("', '")}'\n" +
Expand All @@ -393,9 +419,8 @@ class XcodeTask extends DefaultTask {
// update pod methods
List<String> newPodfileLines = updatePodMethods(podfileLines, podspecDetailsList, podfile)

// Iterate over all podfileTargets as some may need to be cleared
newPodfileLines = updatePodfileTargets(
newPodfileLines, podspecDetailsList, xcodeTargetDetails)
// update pod targets
newPodfileLines = updatePodfileTargets(newPodfileLines, podspecDetailsList, xcodeTargetDetails)

return newPodfileLines
}
Expand Down
Loading

0 comments on commit 9cf24d2

Please sign in to comment.