Skip to content

Commit

Permalink
Add support for gradle submodules (#219)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexstaeding authored Mar 14, 2023
1 parent 2d5b897 commit d1dbbcd
Show file tree
Hide file tree
Showing 12 changed files with 185 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,17 @@ internal fun SourceSet.getFiles(): Map<String, Set<String>> {
forEachFile { directorySet, fileName -> result.computeIfAbsent(directorySet) { mutableSetOf() }.add(fileName) }
return result
}

fun List<SourceSet>.mergeSourceSets(): Map<String, Map<String, Set<String>>> {
return asSequence()
.map { it.name to it.getFiles() }
.fold(mutableMapOf()) { acc, (sourceSetName, sourceSetDir) ->
acc.merge(sourceSetName, sourceSetDir) { a, b ->
(a.asSequence() + b.asSequence()).fold(mutableMapOf()) { map, (name, files) ->
map.merge(name, files) { x, y -> x + y }
map
}
}
acc
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,43 @@
package org.sourcegrade.jagr.gradle.extension

import org.gradle.api.Project
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.SetProperty
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.setProperty
import java.util.Locale

abstract class AbstractConfiguration(
val name: String,
private val project: Project,
private val sourceSetNamesConvention: Set<String>,
) {

private val dependencyConfiguration = DependencyConfiguration()
private val sourceSetContainer: SourceSetContainer = project.extensions.getByType()

private val _sourceSets: MutableList<SourceSet> = mutableListOf()
val sourceSets: List<SourceSet>
get() = _sourceSets

abstract val sourceSetNames: ListProperty<String>
val sourceSetNames: SetProperty<ProjectSourceSetTuple> = project.objects.setProperty<ProjectSourceSetTuple>()
.convention(ProjectSourceSetTuple.fromSourceSetNames("", sourceSetNamesConvention))

init {
project.afterEvaluate {
for (sourceSetName in sourceSetNames.get()) {
val sourceSet = sourceSetContainer.maybeCreate(sourceSetName)
sourceSet.initialize(it)
project.afterEvaluate { proj ->
sourceSetNames.get().forEach { (projectPath, name) ->
val sourceSet = proj.relative(projectPath).sourceSetContainer.maybeCreate(name)
_sourceSets.add(sourceSet)
}
initialize(proj)
}
}

private fun SourceSet.initialize(project: Project) {
private val Project.sourceSetContainer: SourceSetContainer
get() = extensions.getByType()

private fun initialize(project: Project) {
project.dependencies {
for ((suffix, dependencyNotations) in dependencyConfiguration.dependencies) {
val configurationName = if (name == "main") {
Expand Down Expand Up @@ -87,9 +93,23 @@ abstract class AbstractConfiguration(
}

fun from(vararg sourceSetNames: String) {
for (sourceSetName in sourceSetNames) {
this.sourceSetNames.add(sourceSetName)
}
this.sourceSetNames.addAll(ProjectSourceSetTuple.fromSourceSetNames("", sourceSetNames.asSequence()))
}

/**
* Adds the default source sets from the given project for the given configuration type.
*
* For example, using this method from a submission configuration will add the `main` and `test` source sets from the given project.
*/
fun from(otherProject: Project) {
this.sourceSetNames.addAll(ProjectSourceSetTuple.fromSourceSetNames(otherProject.path, sourceSetNamesConvention))
}

/**
* Adds the given source sets from the given project.
*/
fun from(otherProject: Project, vararg sourceSetNames: String) {
this.sourceSetNames.addAll(ProjectSourceSetTuple.fromSourceSetNames(otherProject.path, sourceSetNames.asSequence()))
}

fun configureDependencies(block: DependencyConfiguration.() -> Unit) = dependencyConfiguration.block()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@ import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.internal.provider.DefaultProvider
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.exclude
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.listProperty
import org.gradle.kotlin.dsl.property
import org.sourcegrade.jagr.launcher.env.Config
import org.sourcegrade.jagr.launcher.env.Jagr
Expand All @@ -37,10 +35,7 @@ import org.sourcegrade.jagr.launcher.env.Transformers
abstract class GraderConfiguration(
name: String,
project: Project,
) : AbstractConfiguration(name, project) {
override val sourceSetNames: ListProperty<String> = project.objects.listProperty<String>()
.convention(listOf(name))

) : AbstractConfiguration(name, project, setOf(name)) {
abstract val graderName: Property<String>
abstract val rubricProviderName: Property<String>
abstract val config: Property<Config>
Expand Down Expand Up @@ -85,15 +80,30 @@ abstract class GraderConfiguration(
}
}

internal fun getSourceSetNamesRecursive(): Set<String> {
val result = mutableSetOf<String>()
private fun <K, V> MutableMap<K, Set<V>>.mergeAll(other: Map<K, Set<V>>) {
other.forEach { (key, value) ->
merge(key, value) { a, b -> a + b }
}
}

internal fun getSourceSetNamesRecursive(): Set<ProjectSourceSetTuple> {
val result = mutableSetOf<ProjectSourceSetTuple>()
result.addAll(sourceSetNames.get())
if (parentConfiguration.isPresent) {
result.addAll(parentConfiguration.get().getSourceSetNamesRecursive())
}
return result
}

internal fun getSolutionSourceSetNamesRecursive(): Set<ProjectSourceSetTuple> {
val result = mutableSetOf<ProjectSourceSetTuple>()
result.addAll(solutionConfiguration.get().sourceSetNames.get())
if (parentConfiguration.isPresent) {
result.addAll(parentConfiguration.get().getSolutionSourceSetNamesRecursive())
}
return result
}

private fun addAsDependency(configuration: AbstractConfiguration) {
// add parent configuration as dependency
for (sourceSet in configuration.sourceSets) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.sourcegrade.jagr.gradle.extension

import org.gradle.api.Project
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.kotlin.dsl.getByType
import java.io.Serializable

data class ProjectSourceSetTuple(
val projectPath: String,
val sourceSetName: String,
) : Serializable {
companion object {
fun fromSourceSetNames(projectPath: String, sourceSetNames: Sequence<String>) =
sourceSetNames.map { ProjectSourceSetTuple(projectPath, it) }.toSet()

fun fromSourceSetNames(projectPath: String, sourceSetNames: Iterable<String>) =
fromSourceSetNames(projectPath, sourceSetNames.asSequence())
}
}

fun ProjectSourceSetTuple.getSourceSet(rootProject: Project): SourceSet =
rootProject.relative(projectPath).extensions.getByType<SourceSetContainer>().getByName(sourceSetName)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.sourcegrade.jagr.gradle.extension

import org.gradle.api.Project

fun Project.relative(path: String): Project {
if (path.isEmpty()) return this
return project.project(path)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,13 @@
package org.sourcegrade.jagr.gradle.extension

import org.gradle.api.Project
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.kotlin.dsl.listProperty
import org.gradle.kotlin.dsl.property

abstract class SubmissionConfiguration(
name: String,
project: Project,
) : AbstractConfiguration(name, project) {
override val sourceSetNames: ListProperty<String> = project.objects.listProperty<String>()
.convention(listOf("main", "test"))
) : AbstractConfiguration(name, project, setOf("main", "test")) {
abstract val studentId: Property<String>
abstract val firstName: Property<String>
abstract val lastName: Property<String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@
package org.sourcegrade.jagr.gradle.task

import org.gradle.api.Task
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.SetProperty
import org.gradle.api.tasks.Input
import org.sourcegrade.jagr.gradle.extension.ProjectSourceSetTuple

interface TargetSourceSetsTask : Task {

@get:Input
val configurationName: Property<String>

@get:Input
val sourceSetNames: ListProperty<String>
val sourceSetNames: SetProperty<ProjectSourceSetTuple>
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ abstract class GraderLibsTask : Jar(), GraderTask {

(sourceSets.asSequence() + solutionConfiguration.get().sourceSets).flatMap {
project.configurations[it.runtimeClasspathConfigurationName].resolvedConfiguration.resolvedArtifacts
}.filter { artifact ->
// TODO: This is not the best way to exclude modules from the project itself from the libs jar
project.name != artifact.moduleVersion.id.group
}.forEach { artifact ->
val matchingJagrArtifact: ResolvedArtifact? = jagrArtifacts.firstOrNull { jagrArtifact ->
artifact.moduleVersion.id.group == jagrArtifact.moduleVersion.id.group &&
Expand Down
Loading

0 comments on commit d1dbbcd

Please sign in to comment.