Skip to content

Commit b5cf7cc

Browse files
authored
Merge pull request scalacenter#1768 from Arthurm1/gradle_scala_android
Support scala android plugin on Gradle
2 parents 117b7e0 + c3b3a29 commit b5cf7cc

File tree

3 files changed

+230
-77
lines changed

3 files changed

+230
-77
lines changed

integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/model/BloopConverter.scala

Lines changed: 88 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ import org.gradle.plugins.ide.internal.tooling.java.DefaultInstalledJdk
6565
* Define the conversion from Gradle's project model to Bloop's project model.
6666
* @param parameters Plugin input parameters
6767
*/
68-
class BloopConverter(parameters: BloopParameters, info: String => Unit) {
68+
class BloopConverter(parameters: BloopParameters) {
6969

7070
def toBloopConfig(
7171
projectName: String,
@@ -174,9 +174,10 @@ class BloopConverter(parameters: BloopParameters, info: String => Unit) {
174174
// some configs aren't allowed to be resolved - hence the catch
175175
// this can bring too many artifacts into the resolution section (e.g. junit on main projects) but there's no way to know which artifact is required by which sourceset
176176
// filter out internal scala plugin configurations
177-
val additionalModules = project.getConfigurations.asScala
177+
val allArtifacts = project.getConfigurations.asScala
178178
.filter(_.isCanBeResolved)
179179
.flatMap(getConfigurationArtifacts)
180+
val additionalModules = allArtifacts
180181
.filterNot(f => allOutputsToSourceSets.contains(f.getFile))
181182
.map(artifactToConfigModule(_, project))
182183
.toList
@@ -195,27 +196,34 @@ class BloopConverter(parameters: BloopParameters, info: String => Unit) {
195196
(List(Tag.Test), Some(Config.Test.defaultConfiguration))
196197
else (List(Tag.Library), None)
197198

198-
val bloopProject = Config.Project(
199-
name = projectName,
200-
directory = project.getProjectDir.toPath,
201-
workspaceDir = Option(project.getRootProject.getProjectDir.toPath),
202-
sources = sources,
203-
sourcesGlobs = None,
204-
sourceRoots = None,
205-
dependencies = projectDependencies,
206-
classpath = compileClasspathItems,
207-
out = outDir,
208-
classesDir = classesDir,
209-
resources = if (resources.isEmpty) None else Some(resources),
210-
`scala` = None,
211-
java = getAndroidJavaConfig(project, variant),
212-
sbt = None,
213-
test = testConfig,
214-
platform = None,
215-
resolution = if (modules.isEmpty) None else Some(Config.Resolution(modules)),
216-
tags = if (tags.isEmpty) None else Some(tags)
217-
)
218-
Success(Config.File(Config.File.LatestVersion, bloopProject))
199+
for {
200+
scalaConfig <- getScalaConfig(
201+
project,
202+
None,
203+
allArtifacts
204+
)
205+
206+
bloopProject = Config.Project(
207+
name = projectName,
208+
directory = project.getProjectDir.toPath,
209+
workspaceDir = Option(project.getRootProject.getProjectDir.toPath),
210+
sources = sources,
211+
sourcesGlobs = None,
212+
sourceRoots = None,
213+
dependencies = projectDependencies,
214+
classpath = compileClasspathItems,
215+
out = outDir,
216+
classesDir = classesDir,
217+
resources = if (resources.isEmpty) None else Some(resources),
218+
`scala` = scalaConfig,
219+
java = getAndroidJavaConfig(variant),
220+
sbt = None,
221+
test = testConfig,
222+
platform = None,
223+
resolution = if (modules.isEmpty) None else Some(Config.Resolution(modules)),
224+
tags = if (tags.isEmpty) None else Some(tags)
225+
)
226+
} yield Config.File(Config.File.LatestVersion, bloopProject)
219227
}
220228
}
221229

@@ -229,13 +237,11 @@ class BloopConverter(parameters: BloopParameters, info: String => Unit) {
229237
*
230238
* NOTE: Java classes will be also put into the above defined directory, not as with Gradle
231239
*
232-
* @param projectName unique project name
233240
* @param project The Gradle project model
234241
* @param sourceSet The source set to convert
235242
* @return Bloop configuration
236243
*/
237244
def toBloopConfig(
238-
projectName: String,
239245
project: Project,
240246
sourceSet: SourceSet,
241247
targetDir: File
@@ -355,7 +361,7 @@ class BloopConverter(parameters: BloopParameters, info: String => Unit) {
355361
for {
356362
scalaConfig <- getScalaConfig(
357363
project,
358-
sourceSet,
364+
Some(sourceSet),
359365
compileArtifacts
360366
)
361367

@@ -672,12 +678,12 @@ class BloopConverter(parameters: BloopParameters, info: String => Unit) {
672678
Option(variant.getJavaCompileProvider().getOrNull)
673679
}
674680

675-
private def getAndroidJavaConfig(project: Project, variant: BaseVariant): Option[Config.Java] = {
681+
private def getAndroidJavaConfig(variant: BaseVariant): Option[Config.Java] = {
676682
getAndroidJavaCompile(variant).flatMap(javaCompile => {
677683
val options = javaCompile.getOptions
678684
// bug in DefaultJavaCompileSpec handling Android bootstrapClasspath causes crash so set to null
679685
options.setBootstrapClasspath(null)
680-
getJavaConfig(project, javaCompile, options)
686+
getJavaConfig(javaCompile, options)
681687
})
682688
}
683689

@@ -812,9 +818,6 @@ class BloopConverter(parameters: BloopParameters, info: String => Unit) {
812818
private def getOutDir(targetDir: File, projectName: String): Path =
813819
(targetDir / projectName / "build").toPath
814820

815-
private def getOutDir(targetDir: File, project: Project, sourceSet: SourceSet): Path =
816-
getOutDir(targetDir, getProjectName(project, sourceSet))
817-
818821
private def getClassesDir(targetDir: File, projectName: String): Path =
819822
(targetDir / projectName / "build" / "classes").toPath
820823

@@ -903,12 +906,14 @@ class BloopConverter(parameters: BloopParameters, info: String => Unit) {
903906

904907
private def getScalaConfig(
905908
project: Project,
906-
sourceSet: SourceSet,
907-
artifacts: List[ResolvedArtifactResult]
909+
sourceSet: Option[SourceSet],
910+
artifacts: Iterable[ResolvedArtifactResult]
908911
): Try[Option[Config.Scala]] = {
909912
def isJavaOnly: Boolean = {
910-
val allSourceFiles = sourceSet.getAllSource.getFiles.asScala.toList
911-
!allSourceFiles.filter(f => f.exists && f.isFile).exists(_.getName.endsWith(".scala"))
913+
!sourceSet.exists(ss => {
914+
val allSourceFiles = ss.getAllSource.getFiles.asScala.toList
915+
allSourceFiles.filter(f => f.exists && f.isFile).exists(_.getName.endsWith(".scala"))
916+
})
912917
}
913918

914919
// Finding the compiler group and version from the standard Scala library added as dependency
@@ -922,41 +927,57 @@ class BloopConverter(parameters: BloopParameters, info: String => Unit) {
922927
artifactIds.filter(f => stdLibNames.contains(f.getComponentIdentifier.getModule))
923928
stdLibIds.headOption match {
924929
case Some(stdLibArtifact) =>
925-
val scalaCompileTaskName = sourceSet.getCompileTaskName("scala")
926-
val scalaCompileTask = project.getTask[ScalaCompile](scalaCompileTaskName)
927-
928-
if (scalaCompileTask != null) {
929-
val scalaVersion = stdLibArtifact.getComponentIdentifier.getVersion
930-
val scalaOrg = stdLibArtifact.getComponentIdentifier.getGroup
931-
val scalaJars = scalaCompileTask.getScalaClasspath.asScala.map(_.toPath).toList
932-
val opts = scalaCompileTask.getScalaCompileOptions
933-
val options = optionList(opts) ++ getPluginsAsOptions(scalaCompileTask)
934-
val compilerName = parameters.compilerName.getOrElse("scala-compiler")
935-
val compileOrder =
936-
if (!sourceSet.getJava.getSourceDirectories.isEmpty) JavaThenScala
937-
else Mixed
938-
val setup = CompileSetup.empty.copy(order = compileOrder)
939-
940-
// Use the compile setup and analysis out defaults, Gradle doesn't expose its customization
941-
Success(
942-
Some(
943-
Config
944-
.Scala(scalaOrg, compilerName, scalaVersion, options, scalaJars, None, Some(setup))
945-
)
946-
)
947-
} else {
948-
if (isJavaOnly) Success(None)
949-
else {
950-
// This is a heavy error on Gradle's side, but we will only report it in Scala projects
951-
Failure(
952-
new GradleException(s"$scalaCompileTaskName task is missing from ${project.getName}")
930+
val scalaCompileTask = sourceSet
931+
.map(sourceSet => {
932+
// task name is defined on the source set
933+
val scalaCompileTaskName = sourceSet.getCompileTaskName("scala")
934+
Option(project.getTask[ScalaCompile](scalaCompileTaskName))
935+
})
936+
.getOrElse({
937+
// no sourceset - probably Android plugin - look for any ScalaCompile task
938+
val scalaCompileTasks = project.getTasks.withType(classOf[ScalaCompile])
939+
scalaCompileTasks.asScala.headOption
940+
})
941+
942+
scalaCompileTask match {
943+
case Some(compileTask) =>
944+
val scalaVersion = stdLibArtifact.getComponentIdentifier.getVersion
945+
val scalaOrg = stdLibArtifact.getComponentIdentifier.getGroup
946+
val scalaJars = compileTask.getScalaClasspath.asScala.map(_.toPath).toList
947+
val opts = compileTask.getScalaCompileOptions
948+
val options = optionList(opts) ++ getPluginsAsOptions(compileTask)
949+
val compilerName = parameters.compilerName.getOrElse("scala-compiler")
950+
val noJavaFiles =
951+
sourceSet.exists(sourceSet => sourceSet.getJava.getSourceDirectories.isEmpty)
952+
val compileOrder = if (noJavaFiles) Mixed else JavaThenScala
953+
val setup = CompileSetup.empty.copy(order = compileOrder)
954+
955+
// Use the compile setup and analysis out defaults, Gradle doesn't expose its customization
956+
Success(
957+
Some(
958+
Config
959+
.Scala(
960+
scalaOrg,
961+
compilerName,
962+
scalaVersion,
963+
options,
964+
scalaJars,
965+
None,
966+
Some(setup)
967+
)
968+
)
953969
)
954-
}
970+
case None =>
971+
if (isJavaOnly) Success(None)
972+
else {
973+
// This is a heavy error on Gradle's side, but we will only report it in Scala projects
974+
Failure(new GradleException(s"No ScalaCompile task in ${project.getName}"))
975+
}
955976
}
956-
957977
case None if isJavaOnly => Success(None)
958978
case None =>
959-
val target = s"project ${project.getName}/${sourceSet.getName}"
979+
val target =
980+
s"project ${project.getName}/${sourceSet.map(sourceSet => sourceSet.getName).getOrElse("No sourceset")}"
960981
val artifactNames =
961982
if (artifacts.isEmpty) ""
962983
else
@@ -988,11 +1009,10 @@ class BloopConverter(parameters: BloopParameters, info: String => Unit) {
9881009
private def getJavaConfig(project: Project, sourceSet: SourceSet): Option[Config.Java] = {
9891010
val javaCompile = getJavaCompileTask(project, sourceSet)
9901011
val options = javaCompile.getOptions
991-
getJavaConfig(project, javaCompile, options)
1012+
getJavaConfig(javaCompile, options)
9921013
}
9931014

9941015
private def getJavaConfig(
995-
project: Project,
9961016
javaCompile: JavaCompile,
9971017
options: CompileOptions
9981018
): Option[Config.Java] = {

integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/tasks/BloopInstallTask.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class BloopInstallTask extends DefaultTask with PluginUtils with TaskLogging {
4444

4545
def runBloopPlugin(): Unit = {
4646
val parameters = extension.createParameters
47-
val converter = new BloopConverter(parameters, info)
47+
val converter = new BloopConverter(parameters)
4848
val targetDir: File = parameters.targetDir
4949
info(s"Generating Bloop configuration to ${targetDir.getAbsolutePath}")
5050

@@ -97,7 +97,7 @@ object ScalaJavaInstall {
9797
val targetFile = targetDir / s"$projectName.json"
9898
// Let's keep the error message as similar to the one in the sbt plugin as possible
9999
info(s"Generated ${targetFile.getAbsolutePath}")
100-
converter.toBloopConfig(projectName, project, sourceSet, targetDir) match {
100+
converter.toBloopConfig(project, sourceSet, targetDir) match {
101101
case Failure(reason) =>
102102
info(s"Skipping ${project.getName}/${sourceSet.getName} because: $reason")
103103
case Success(bloopConfig) =>

0 commit comments

Comments
 (0)