Skip to content

Commit

Permalink
Merge pull request #15 from piotrminkina/feature/expose-task-properties
Browse files Browse the repository at this point in the history
Tests optimisations, expose task properties and cleaning up temporary files
  • Loading branch information
denis-zhdanov authored Apr 22, 2024
2 parents adb09a6 + 0a3827a commit 87bcc45
Show file tree
Hide file tree
Showing 19 changed files with 247 additions and 100 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Ignore Gradle project-specific cache directory
.gradle/

# Ignore Gradle build output directory
build/
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ Gradle automatically applies [init scripts](https://docs.gradle.org/current/user
3. Specify target settings in the `gradleDist {}` block.
**mandatory settings:**
* `gradleVersion` - base Gradle wrapper version
* `customDistributionVersion` - custom distribution version
* `customDistributionFileNameMapper` - a property of type [CustomDistributionNameMapper](./src/main/kotlin/tech/harmonysoft/oss/gradle/dist/config/CustomDistributionNameMapper.kt) which generates resulting custom distribution file name for the given parameters. *Note: it's necessary to specify this property or 'distributionNameMapper' property. It's an error to define the both/none of them*
* `customDistributionVersion` - custom distribution version (`project.version` is used by default)
* `customDistributionFileNameMapper` - a property of type [CustomDistributionNameMapper](./src/main/kotlin/tech/harmonysoft/oss/gradle/dist/config/CustomDistributionNameMapper.kt) which generates resulting custom distribution file name for the given parameters. *Note: it's necessary to specify this property or `distributionNameMapper` property. It's an error to define the both/none of them*
* `gradleVersion` - base gradle distribution version as defined above
* `customDistributionVersion` - custom distribution mixing version as defined above
* `gradleDistributionType` - gradle distribution type as defined below
Expand Down Expand Up @@ -118,10 +118,13 @@ Gradle automatically applies [init scripts](https://docs.gradle.org/current/user
}
}
```
*Note: it's necessary to specify this property or 'customDistributionFileNameMapper' property. It's an error to define the both/none of them*
*Note: it's necessary to specify this property or `customDistributionFileNameMapper` property. It's an error to define the both/none of them*
* `initScriptsSourceDir` - a path to the directory where your initialization scripts are located (see below docs for more details). The path to the directory must be set, and the pointed directory must exist. The default path is `src/main/resources/init.d`.
**optional settings:**
* `gradleDistributionType` - allows to specify base Gradle distribution type. `bin` and `all` [are available](https://docs.gradle.org/current/userguide/gradle_wrapper.html#sec:adding_wrapper) at the moment, `bin` is used by default
* `gradleDistributionType` - allows to specify base Gradle distribution type. `bin` and `all` [are available](https://docs.gradle.org/current/userguide/gradle_wrapper.html#sec:adding_wrapper) at the moment, `bin` is used by default
* `utilityScriptsSourceDir` - a path to the directory where your utility scripts and replacements are located (see below docs for more details). The path to the directory is optional, but the pointed directory must exist. The default path is `src/main/resources/include`.
* `skipContentExpansionFor` - the plugin by default expands content of the files included into custom Gradle distribution by default (see below). That might cause a problem if we want to add some binary file like `*.jar` or `*.so`. This property holds a list of root paths relative to `init.d` which content shouldn't be expanded.
Example: consider the following project structure:
```
Expand Down Expand Up @@ -270,6 +273,16 @@ Gradle automatically applies [init scripts](https://docs.gradle.org/current/user
The distribution(s) are located in the `build/gradle-dist`
6. In addition, if you need, you can configure the properties of the `buildGradleDist` task, such as the path to the directory where downloaded Gradle distributions and built custom Gradle distributions should be located. You can do this as follows:
```groovy
import tech.harmonysoft.oss.gradle.dist.BuildCustomGradleDistributionTask
tasks.named('buildGradleDist', BuildCustomGradleDistributionTask) {
gradleDownloadDir = project.layout.buildDirectory.dir('own-gradle-download')
customDistributionOutputDir = project.layout.buildDirectory.dir('own-gradle-dist')
}
```
### Configure Client Project
Just define your custom Gradle wrapper's location in the *gradle/wrapper/gradle-wrapper.properties* file:
Expand Down
4 changes: 2 additions & 2 deletions sample/multiple-custom-gradle-distributions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ Note: a cool feature of init scripts is that we can apply Gradle plugins from th
## In Action

1. Build custom distribution
`pushd custom-distribution; ./gradlew build; popd`
`pushd custom-distribution; ./gradlew buildGradleDist; popd`
2. Run the client project
`pushd client-project; ./gradlew bootRun; popd`
3. Call a web server server started by the client project and ensure that it works
3. Call a web server started by the client project and ensure that it works
```
curl 127.0.0.1:8080/ping
Hi there!
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=../../../custom-distribution/build/gradle-dist/gradle-8.4-test-multi-distributions-1.0-service.zip
distributionUrl=../../../custom-distribution/build/gradle-dist/gradle-8.4-test-multi-distributions-1.0-service-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id 'tech.harmonysoft.oss.custom-gradle-dist-plugin' version '1.9'
id 'tech.harmonysoft.oss.custom-gradle-dist-plugin' version '1.17'
}

gradleDist {
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
pluginManagement {
includeBuild('../../../') {
logger.warn(
'Replaced indicated version of the Plugin with the current implementation from the root project directory.'
)
}
}

rootProject.name = 'multiple-custom-gradle-distributions'
4 changes: 2 additions & 2 deletions sample/single-custom-gradle-distribution/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ This is an example of using custom Gradle distribution for projects with the sam
## In Action

1. Build custom distribution
`pushd custom-distribution; ./gradlew build; popd`
`pushd custom-distribution; ./gradlew buildGradleDist; popd`
2. Run the client project
`pushd client-project; ./gradlew bootRun; popd`
3. Call a web server server started by the client project and ensure that it works
3. Call a web server started by the client project and ensure that it works
```
curl 127.0.0.1:8080/ping
Hi there!
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=../../../custom-distribution/build/gradle-dist/gradle-8.4-test-single-distribution-1.0.zip
distributionUrl=../../../custom-distribution/build/gradle-dist/gradle-8.4-test-single-distribution-1.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id 'tech.harmonysoft.oss.custom-gradle-dist-plugin' version '1.9'
id 'tech.harmonysoft.oss.custom-gradle-dist-plugin' version '1.17'
}

gradleDist {
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
pluginManagement {
includeBuild('../../../') {
logger.warn(
'Replaced indicated version of the Plugin with the current implementation from the root project directory.'
)
}
}

rootProject.name = 'single-custom-gradle-distribution'
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,64 @@ import java.io.FileFilter
import java.io.FileInputStream
import java.io.FileOutputStream
import java.net.URI
import java.net.URL
import java.nio.channels.Channels
import java.nio.file.FileSystem
import java.nio.file.FileSystems
import java.nio.file.Files
import java.util.Properties
import java.util.Stack
import org.gradle.api.DefaultTask
import org.gradle.api.provider.Property
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.tooling.BuildException
import tech.harmonysoft.oss.gradle.dist.config.CustomGradleDistConfig
import javax.inject.Inject

abstract class BuildCustomGradleDistributionTask : DefaultTask() {
@Suppress("LeakingThis")
abstract class BuildCustomGradleDistributionTask @Inject constructor(
@get:Nested val config: CustomGradleDistConfig
) : DefaultTask() {

@get:Internal
abstract val config: Property<CustomGradleDistConfig>
abstract val gradleDownloadDir: DirectoryProperty

private val includeRootDir: File
get() = project.file("src/main/resources/include")
@get:OutputDirectory
abstract val customDistributionOutputDir: DirectoryProperty

private val extensionsRootDir: File
get() = project.file("src/main/resources/init.d")
init {
gradleDownloadDir.convention(
project.layout.buildDirectory.dir("gradle-download")
)
customDistributionOutputDir.convention(
project.layout.buildDirectory.dir("gradle-dist")
)
}

@TaskAction
fun build() {
val baseDistribution = getBaseGradleDistribution(config.get())
val customDistributionsDir = getCustomDistributionsRootDir()
val baseDistribution = getBaseGradleDistribution(config)
val customDistributionsDir = customDistributionOutputDir.get().asFile
remove(customDistributionsDir)
Files.createDirectories(customDistributionsDir.toPath())

val currentConfig = config.get()
val replacements = prepareReplacements()
val distributions = getDistributions()
if (distributions.isEmpty()) {
prepareCustomDistribution(
distribution = null,
baseDistribution = baseDistribution,
extension = currentConfig,
extension = config,
replacements = replacements
)
} else {
for (distribution in distributions) {
prepareCustomDistribution(
distribution = distribution,
baseDistribution = baseDistribution,
extension = currentConfig,
extension = config,
replacements = replacements
)
}
Expand All @@ -73,7 +83,7 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
private fun doGetBaseGradleDistribution(extension: CustomGradleDistConfig): File {
val gradleBaseName = "gradle-${extension.gradleVersion.get()}"
val gradleZip = "$gradleBaseName-${extension.gradleDistributionType.get()}.zip"
val baseGradleArchive = project.layout.buildDirectory.file("download/$gradleZip").get().asFile
val baseGradleArchive = gradleDownloadDir.map { it.file(gradleZip) }.get().asFile
if (!baseGradleArchive.isFile) {
val archiveDir = baseGradleArchive.parentFile
if (!archiveDir.isDirectory) {
Expand All @@ -96,18 +106,14 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
}

private fun download(fromUrl: String, toFile: File) {
val from = Channels.newChannel(URL(fromUrl).openStream())
val from = Channels.newChannel(URI(fromUrl).toURL().openStream())
project.logger.lifecycle("about to download a gradle distribution from $fromUrl to ${toFile.canonicalPath}")
FileOutputStream(toFile).channel.use {
it.transferFrom(from, 0, Long.MAX_VALUE)
}
project.logger.lifecycle("downloaded a gradle distribution from $fromUrl to ${toFile.canonicalPath}")
}

private fun getCustomDistributionsRootDir(): File {
return project.layout.buildDirectory.file("gradle-dist").get().asFile
}

private fun remove(toRemove: File) {
if (toRemove.isDirectory) {
toRemove.listFiles()?.forEach {
Expand All @@ -126,7 +132,7 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
}

private fun getDistributions(): Collection<String> {
val childDirectories = extensionsRootDir.listFiles(FileFilter { it.isDirectory })
val childDirectories = config.initScriptsSourceDir.get().asFile.listFiles(FileFilter { it.isDirectory })
return if (childDirectories == null || childDirectories.size < 2) {
project.logger.lifecycle("using a single custom gradle distribution")
emptyList()
Expand Down Expand Up @@ -164,8 +170,10 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
}

private fun loadReplacementsFromFiles(): Map<String, RichValue> {
return includeRootDir
.listFiles()
return config.utilityScriptsSourceDir
.orNull
?.asFile
?.listFiles()
?.filter {
it.name != REPLACEMENTS_FILE_NAME
}?.associate { file ->
Expand Down Expand Up @@ -300,7 +308,7 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
gradleDistributionType = extension.gradleDistributionType.get(),
distributionName = distribution
).toString()
val customDistributionsDir = getCustomDistributionsRootDir()
val customDistributionsDir = customDistributionOutputDir.get().asFile
val result = File(customDistributionsDir, customDistributionFileName)

copyBaseDistribution(baseDistribution, result)
Expand Down Expand Up @@ -357,20 +365,23 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
pathsToExcludeFromContentExpansion: Set<String>,
replacements: Map<String, String>
) {
val zipFileSystem = FileSystems.newFileSystem(
FileSystems.newFileSystem(
URI.create("jar:${zip.toPath().toUri()}"),
mapOf("create" to "true")
)
addToZip(
zip = zipFileSystem,
includeRootDir = distribution?.let {
File(extensionsRootDir, it)
} ?: extensionsRootDir,
gradleVersion = gradleVersion,
pathsToExcludeFromContentExpansion = pathsToExcludeFromContentExpansion,
replacements = replacements
)
zipFileSystem.close()
.use { zipFileSystem ->
config.initScriptsSourceDir.get().asFile.let { initScriptsSourceDir ->
addToZip(
zip = zipFileSystem,
includeRootDir = distribution?.let {
File(initScriptsSourceDir, it)
} ?: initScriptsSourceDir,
gradleVersion = gradleVersion,
pathsToExcludeFromContentExpansion = pathsToExcludeFromContentExpansion,
replacements = replacements
)
}
}
}

private fun addToZip(
Expand Down Expand Up @@ -441,14 +452,18 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
}
if (exclusionRule == null) {
val tempFile = Files.createTempFile("", "${fileToInclude.name}.tmp").toFile()
val expandedContent = expand(RichValue(
value = fileToInclude.readText(),
description = "file ${fileToInclude.name}"
)) {
replacements[it]
try {
val expandedContent = expand(RichValue(
value = fileToInclude.readText(),
description = "file ${fileToInclude.name}"
)) {
replacements[it]
}
tempFile.writeText(expandedContent)
Files.copy(tempFile.toPath(), to)
} finally {
tempFile.delete()
}
tempFile.writeText(expandedContent)
Files.copy(tempFile.toPath(), to)
} else {
project.logger.lifecycle(
"skipped content expansion for file $relativePath because of exclusion rule '$exclusionRule'"
Expand All @@ -471,6 +486,6 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {

companion object {
private val PATTERN = """\$(\S+)\$""".toRegex()
private val REPLACEMENTS_FILE_NAME = "replacements.properties"
private const val REPLACEMENTS_FILE_NAME = "replacements.properties"
}
}
Loading

0 comments on commit 87bcc45

Please sign in to comment.