Skip to content

Commit 87bcc45

Browse files
Merge pull request #15 from piotrminkina/feature/expose-task-properties
Tests optimisations, expose task properties and cleaning up temporary files
2 parents adb09a6 + 0a3827a commit 87bcc45

File tree

19 files changed

+247
-100
lines changed

19 files changed

+247
-100
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Ignore Gradle project-specific cache directory
2+
.gradle/
3+
4+
# Ignore Gradle build output directory
5+
build/

README.md

+17-4
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ Gradle automatically applies [init scripts](https://docs.gradle.org/current/user
7070
3. Specify target settings in the `gradleDist {}` block.
7171
**mandatory settings:**
7272
* `gradleVersion` - base Gradle wrapper version
73-
* `customDistributionVersion` - custom distribution version
74-
* `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*
73+
* `customDistributionVersion` - custom distribution version (`project.version` is used by default)
74+
* `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*
7575
* `gradleVersion` - base gradle distribution version as defined above
7676
* `customDistributionVersion` - custom distribution mixing version as defined above
7777
* `gradleDistributionType` - gradle distribution type as defined below
@@ -118,10 +118,13 @@ Gradle automatically applies [init scripts](https://docs.gradle.org/current/user
118118
}
119119
}
120120
```
121-
*Note: it's necessary to specify this property or 'customDistributionFileNameMapper' property. It's an error to define the both/none of them*
121+
*Note: it's necessary to specify this property or `customDistributionFileNameMapper` property. It's an error to define the both/none of them*
122+
123+
* `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`.
122124
123125
**optional settings:**
124-
* `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
126+
* `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
127+
* `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`.
125128
* `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.
126129
Example: consider the following project structure:
127130
```
@@ -270,6 +273,16 @@ Gradle automatically applies [init scripts](https://docs.gradle.org/current/user
270273
271274
The distribution(s) are located in the `build/gradle-dist`
272275
276+
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:
277+
```groovy
278+
import tech.harmonysoft.oss.gradle.dist.BuildCustomGradleDistributionTask
279+
280+
tasks.named('buildGradleDist', BuildCustomGradleDistributionTask) {
281+
gradleDownloadDir = project.layout.buildDirectory.dir('own-gradle-download')
282+
customDistributionOutputDir = project.layout.buildDirectory.dir('own-gradle-dist')
283+
}
284+
```
285+
273286
### Configure Client Project
274287
275288
Just define your custom Gradle wrapper's location in the *gradle/wrapper/gradle-wrapper.properties* file:

sample/multiple-custom-gradle-distributions/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ Note: a cool feature of init scripts is that we can apply Gradle plugins from th
1717
## In Action
1818

1919
1. Build custom distribution
20-
`pushd custom-distribution; ./gradlew build; popd`
20+
`pushd custom-distribution; ./gradlew buildGradleDist; popd`
2121
2. Run the client project
2222
`pushd client-project; ./gradlew bootRun; popd`
23-
3. Call a web server server started by the client project and ensure that it works
23+
3. Call a web server started by the client project and ensure that it works
2424
```
2525
curl 127.0.0.1:8080/ping
2626
Hi there!
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=../../../custom-distribution/build/gradle-dist/gradle-8.4-test-multi-distributions-1.0-service.zip
3+
distributionUrl=../../../custom-distribution/build/gradle-dist/gradle-8.4-test-multi-distributions-1.0-service-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

sample/multiple-custom-gradle-distributions/custom-distribution/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
plugins {
2-
id 'tech.harmonysoft.oss.custom-gradle-dist-plugin' version '1.9'
2+
id 'tech.harmonysoft.oss.custom-gradle-dist-plugin' version '1.17'
33
}
44

55
gradleDist {
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
1+
pluginManagement {
2+
includeBuild('../../../') {
3+
logger.warn(
4+
'Replaced indicated version of the Plugin with the current implementation from the root project directory.'
5+
)
6+
}
7+
}
8+
19
rootProject.name = 'multiple-custom-gradle-distributions'

sample/single-custom-gradle-distribution/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ This is an example of using custom Gradle distribution for projects with the sam
1515
## In Action
1616

1717
1. Build custom distribution
18-
`pushd custom-distribution; ./gradlew build; popd`
18+
`pushd custom-distribution; ./gradlew buildGradleDist; popd`
1919
2. Run the client project
2020
`pushd client-project; ./gradlew bootRun; popd`
21-
3. Call a web server server started by the client project and ensure that it works
21+
3. Call a web server started by the client project and ensure that it works
2222
```
2323
curl 127.0.0.1:8080/ping
2424
Hi there!
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=../../../custom-distribution/build/gradle-dist/gradle-8.4-test-single-distribution-1.0.zip
3+
distributionUrl=../../../custom-distribution/build/gradle-dist/gradle-8.4-test-single-distribution-1.0-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

sample/single-custom-gradle-distribution/custom-distribution/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
plugins {
2-
id 'tech.harmonysoft.oss.custom-gradle-dist-plugin' version '1.9'
2+
id 'tech.harmonysoft.oss.custom-gradle-dist-plugin' version '1.17'
33
}
44

55
gradleDist {
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
1+
pluginManagement {
2+
includeBuild('../../../') {
3+
logger.warn(
4+
'Replaced indicated version of the Plugin with the current implementation from the root project directory.'
5+
)
6+
}
7+
}
8+
19
rootProject.name = 'single-custom-gradle-distribution'

src/main/kotlin/tech/harmonysoft/oss/gradle/dist/BuildCustomGradleDistributionTask.kt

+57-42
Original file line numberDiff line numberDiff line change
@@ -5,54 +5,64 @@ import java.io.FileFilter
55
import java.io.FileInputStream
66
import java.io.FileOutputStream
77
import java.net.URI
8-
import java.net.URL
98
import java.nio.channels.Channels
109
import java.nio.file.FileSystem
1110
import java.nio.file.FileSystems
1211
import java.nio.file.Files
1312
import java.util.Properties
1413
import java.util.Stack
1514
import org.gradle.api.DefaultTask
16-
import org.gradle.api.provider.Property
15+
import org.gradle.api.file.DirectoryProperty
1716
import org.gradle.api.tasks.Internal
17+
import org.gradle.api.tasks.Nested
18+
import org.gradle.api.tasks.OutputDirectory
1819
import org.gradle.api.tasks.TaskAction
1920
import org.gradle.tooling.BuildException
2021
import tech.harmonysoft.oss.gradle.dist.config.CustomGradleDistConfig
22+
import javax.inject.Inject
2123

22-
abstract class BuildCustomGradleDistributionTask : DefaultTask() {
24+
@Suppress("LeakingThis")
25+
abstract class BuildCustomGradleDistributionTask @Inject constructor(
26+
@get:Nested val config: CustomGradleDistConfig
27+
) : DefaultTask() {
2328

2429
@get:Internal
25-
abstract val config: Property<CustomGradleDistConfig>
30+
abstract val gradleDownloadDir: DirectoryProperty
2631

27-
private val includeRootDir: File
28-
get() = project.file("src/main/resources/include")
32+
@get:OutputDirectory
33+
abstract val customDistributionOutputDir: DirectoryProperty
2934

30-
private val extensionsRootDir: File
31-
get() = project.file("src/main/resources/init.d")
35+
init {
36+
gradleDownloadDir.convention(
37+
project.layout.buildDirectory.dir("gradle-download")
38+
)
39+
customDistributionOutputDir.convention(
40+
project.layout.buildDirectory.dir("gradle-dist")
41+
)
42+
}
3243

3344
@TaskAction
3445
fun build() {
35-
val baseDistribution = getBaseGradleDistribution(config.get())
36-
val customDistributionsDir = getCustomDistributionsRootDir()
46+
val baseDistribution = getBaseGradleDistribution(config)
47+
val customDistributionsDir = customDistributionOutputDir.get().asFile
3748
remove(customDistributionsDir)
3849
Files.createDirectories(customDistributionsDir.toPath())
3950

40-
val currentConfig = config.get()
4151
val replacements = prepareReplacements()
4252
val distributions = getDistributions()
4353
if (distributions.isEmpty()) {
4454
prepareCustomDistribution(
4555
distribution = null,
4656
baseDistribution = baseDistribution,
47-
extension = currentConfig,
57+
extension = config,
4858
replacements = replacements
4959
)
5060
} else {
5161
for (distribution in distributions) {
5262
prepareCustomDistribution(
5363
distribution = distribution,
5464
baseDistribution = baseDistribution,
55-
extension = currentConfig,
65+
extension = config,
5666
replacements = replacements
5767
)
5868
}
@@ -73,7 +83,7 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
7383
private fun doGetBaseGradleDistribution(extension: CustomGradleDistConfig): File {
7484
val gradleBaseName = "gradle-${extension.gradleVersion.get()}"
7585
val gradleZip = "$gradleBaseName-${extension.gradleDistributionType.get()}.zip"
76-
val baseGradleArchive = project.layout.buildDirectory.file("download/$gradleZip").get().asFile
86+
val baseGradleArchive = gradleDownloadDir.map { it.file(gradleZip) }.get().asFile
7787
if (!baseGradleArchive.isFile) {
7888
val archiveDir = baseGradleArchive.parentFile
7989
if (!archiveDir.isDirectory) {
@@ -96,18 +106,14 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
96106
}
97107

98108
private fun download(fromUrl: String, toFile: File) {
99-
val from = Channels.newChannel(URL(fromUrl).openStream())
109+
val from = Channels.newChannel(URI(fromUrl).toURL().openStream())
100110
project.logger.lifecycle("about to download a gradle distribution from $fromUrl to ${toFile.canonicalPath}")
101111
FileOutputStream(toFile).channel.use {
102112
it.transferFrom(from, 0, Long.MAX_VALUE)
103113
}
104114
project.logger.lifecycle("downloaded a gradle distribution from $fromUrl to ${toFile.canonicalPath}")
105115
}
106116

107-
private fun getCustomDistributionsRootDir(): File {
108-
return project.layout.buildDirectory.file("gradle-dist").get().asFile
109-
}
110-
111117
private fun remove(toRemove: File) {
112118
if (toRemove.isDirectory) {
113119
toRemove.listFiles()?.forEach {
@@ -126,7 +132,7 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
126132
}
127133

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

166172
private fun loadReplacementsFromFiles(): Map<String, RichValue> {
167-
return includeRootDir
168-
.listFiles()
173+
return config.utilityScriptsSourceDir
174+
.orNull
175+
?.asFile
176+
?.listFiles()
169177
?.filter {
170178
it.name != REPLACEMENTS_FILE_NAME
171179
}?.associate { file ->
@@ -300,7 +308,7 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
300308
gradleDistributionType = extension.gradleDistributionType.get(),
301309
distributionName = distribution
302310
).toString()
303-
val customDistributionsDir = getCustomDistributionsRootDir()
311+
val customDistributionsDir = customDistributionOutputDir.get().asFile
304312
val result = File(customDistributionsDir, customDistributionFileName)
305313

306314
copyBaseDistribution(baseDistribution, result)
@@ -357,20 +365,23 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
357365
pathsToExcludeFromContentExpansion: Set<String>,
358366
replacements: Map<String, String>
359367
) {
360-
val zipFileSystem = FileSystems.newFileSystem(
368+
FileSystems.newFileSystem(
361369
URI.create("jar:${zip.toPath().toUri()}"),
362370
mapOf("create" to "true")
363371
)
364-
addToZip(
365-
zip = zipFileSystem,
366-
includeRootDir = distribution?.let {
367-
File(extensionsRootDir, it)
368-
} ?: extensionsRootDir,
369-
gradleVersion = gradleVersion,
370-
pathsToExcludeFromContentExpansion = pathsToExcludeFromContentExpansion,
371-
replacements = replacements
372-
)
373-
zipFileSystem.close()
372+
.use { zipFileSystem ->
373+
config.initScriptsSourceDir.get().asFile.let { initScriptsSourceDir ->
374+
addToZip(
375+
zip = zipFileSystem,
376+
includeRootDir = distribution?.let {
377+
File(initScriptsSourceDir, it)
378+
} ?: initScriptsSourceDir,
379+
gradleVersion = gradleVersion,
380+
pathsToExcludeFromContentExpansion = pathsToExcludeFromContentExpansion,
381+
replacements = replacements
382+
)
383+
}
384+
}
374385
}
375386

376387
private fun addToZip(
@@ -441,14 +452,18 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
441452
}
442453
if (exclusionRule == null) {
443454
val tempFile = Files.createTempFile("", "${fileToInclude.name}.tmp").toFile()
444-
val expandedContent = expand(RichValue(
445-
value = fileToInclude.readText(),
446-
description = "file ${fileToInclude.name}"
447-
)) {
448-
replacements[it]
455+
try {
456+
val expandedContent = expand(RichValue(
457+
value = fileToInclude.readText(),
458+
description = "file ${fileToInclude.name}"
459+
)) {
460+
replacements[it]
461+
}
462+
tempFile.writeText(expandedContent)
463+
Files.copy(tempFile.toPath(), to)
464+
} finally {
465+
tempFile.delete()
449466
}
450-
tempFile.writeText(expandedContent)
451-
Files.copy(tempFile.toPath(), to)
452467
} else {
453468
project.logger.lifecycle(
454469
"skipped content expansion for file $relativePath because of exclusion rule '$exclusionRule'"
@@ -471,6 +486,6 @@ abstract class BuildCustomGradleDistributionTask : DefaultTask() {
471486

472487
companion object {
473488
private val PATTERN = """\$(\S+)\$""".toRegex()
474-
private val REPLACEMENTS_FILE_NAME = "replacements.properties"
489+
private const val REPLACEMENTS_FILE_NAME = "replacements.properties"
475490
}
476491
}

0 commit comments

Comments
 (0)