Skip to content

Commit 1636253

Browse files
authored
Merge pull request #22 from Cognifide/include-projects
Making assemblies with filters merging
2 parents e5f79bb + f16ea53 commit 1636253

13 files changed

Lines changed: 136 additions & 85 deletions

File tree

README.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
![Cognifide logo](doc/cognifide-logo.png)
1+
![Cognifide logo](docs/cognifide-logo.png)
22

33
[![Gradle Status](https://gradleupdate.appspot.com/Cognifide/gradle-aem-plugin/status.svg)](https://gradleupdate.appspot.com/Cognifide/gradle-aem-plugin/status)
44
[![Apache License, Version 2.0, January 2004](https://img.shields.io/github/license/Cognifide/gradle-aem-plugin.svg?label=License)](http://www.apache.org/licenses/)
@@ -7,7 +7,7 @@
77

88
<br>
99
<p align="center">
10-
<img src="doc/logo.png" alt="Gradle AEM Plugin Logo"/>
10+
<img src="docs/logo.png" alt="Gradle AEM Plugin Logo"/>
1111
</p>
1212
<br>
1313

@@ -50,7 +50,7 @@ buildscript {
5050
}
5151
5252
dependencies {
53-
classpath 'com.cognifide.gradle:aem-plugin:1.0.+'
53+
classpath 'com.cognifide.gradle:aem-plugin:1.2.+'
5454
}
5555
}
5656
@@ -120,6 +120,7 @@ Snippet above demonstrates customizations valid only for specific project.
120120
* `includeContent(projectPath: String)`, includes only JCR content, example: `includeContent ':example.design'`.
121121
* `includeBundles(projectPath: String)`, includes only bundles, example: `includeBundles ':example.auth'`.
122122
* `includeBundlesAtRunMode(projectPath: String, runMode: String)`, as above, useful when bundles need to be installed only on specific type of instance.
123+
* `includeSubprojects(withSamePathPrefix: Boolean = true)`, includes both bundles and JCR from all nested subprojects, example: project `:app` will include `:app:common`, `:app:core` etc. Vault filter file will be automatically generated with all filter roots merged. Useful for building assemblies (all-in-one packages).
123124
* all inherited from [ZIP task](https://docs.gradle.org/3.5/dsl/org.gradle.api.tasks.bundling.Zip.html).
124125
* `aemUpload` - Upload composed CRX package into AEM instance(s).
125126
* `aemInstall` - Install uploaded CRX package on AEM instance(s).
@@ -163,6 +164,26 @@ Snippet above demonstrates customizations valid only for specific project.
163164
-Paem.deploy.skipDownloadName=true
164165
```
165166

167+
### Expandable variables
168+
169+
By default, plugin is configured that in all XML files, variables can be injected:
170+
171+
```
172+
aem {
173+
vaultFilesExpanded = ["*.xml"]
174+
vaultExpandProperties = [:]
175+
}
176+
```
177+
178+
This feature is specially useful to generate valid *META-INF/properties.xml* file.
179+
What is more, there are predefined variables that also can be used:
180+
181+
* `rootProject` - project with directory in which *settings.gradle* is located.
182+
* `project` - current project.
183+
* `config` - [AEM configuration](src/main/kotlin/com/cognifide/gradle/aem/AemConfig.kt).
184+
* `created` - current date in ISO8601 format.
185+
* `buildCount` - number to be used as CRX package build count (current date in format `yDDmmssSSS`).
186+
* `filterRoots` - after using method `includeContent` of `aemCompose` task, Vault filter roots all being gathered. This variable contains all these XML tags concatenated especially useful for building assemblies. If no projects will be included, then this variable will contain a single filter root with bundle install path to be able to deploy auto-generated package with JAR file only.
166187

167188
## License
168189

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66
}
77

88
group 'com.cognifide.gradle'
9-
version '1.1.2-SNAPSHOT'
9+
version '1.2.0'
1010
description = 'Gradle AEM Plugin'
1111
defaultTasks = ['clean', 'publishToMavenLocal']
1212

@@ -28,6 +28,7 @@ dependencies {
2828
compile 'org.dm.gradle:gradle-bundle-plugin:0.10.0'
2929
compile 'org.apache.jackrabbit.vault:org.apache.jackrabbit.vault:3.1.26'
3030
compile 'org.apache.jackrabbit.vault:vault-cli:3.1.6'
31+
compile 'org.jsoup:jsoup:1.10.3'
3132
}
3233

3334
gradlePlugin {
File renamed without changes.

src/main/kotlin/com/cognifide/gradle/aem/AemConfig.kt

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ data class AemConfig(
4242
var acHandling: String = "merge_preserve",
4343

4444
/**
45-
* Relative to project, path to JCR content to be included in CRX package.
45+
* Absolute path to JCR content to be included in CRX package.
46+
* Default: "${project.projectDir.path}/src/main/content"
4647
*/
47-
var contentPath: String = "src/main/content",
48+
var contentPath: String = "",
4849

4950
/**
5051
* Content path to bundle jars being placed in CRX package.
@@ -173,24 +174,25 @@ data class AemConfig(
173174
return extended
174175
}
175176

177+
fun of(project: Project): AemConfig {
178+
return (project.tasks.getByName(ComposeTask.NAME) as AemTask).config
179+
}
180+
176181
private fun applyProjectDefaults(config: AemConfig, project: Project) {
177-
config.bundlePath = "/apps/" + project.rootProject.name + "/install"
182+
if (project.path == project.rootProject.path) {
183+
config.bundlePath = "/apps/${project.name}/install"
184+
} else {
185+
config.bundlePath = "/apps/${project.rootProject.name}/${project.name}/install"
186+
}
187+
188+
config.contentPath = "${project.projectDir.path}/src/main/content"
178189
}
179190
}
180191

181192
fun instance(url: String, user: String = "admin", password: String = "admin", type: String = "default") {
182193
instances.add(AemInstance(url, user, password, type))
183194
}
184195

185-
/**
186-
* While including another project content, use path configured in that project.
187-
*/
188-
fun determineContentPath(project: Project): String {
189-
val task = project.tasks.getByName(ComposeTask.NAME) as ComposeTask
190-
191-
return project.projectDir.path + "/" + task.config.contentPath
192-
}
193-
194196
/**
195197
* Following checks will be performed during configuration phase
196198
*/

src/main/kotlin/com/cognifide/gradle/aem/AemPlugin.kt

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import org.gradle.api.Project
1111
import org.gradle.api.artifacts.Configuration
1212
import org.gradle.api.plugins.BasePlugin
1313
import org.gradle.api.plugins.JavaPlugin
14-
import org.gradle.api.plugins.JavaPluginConvention
15-
import org.gradle.api.tasks.SourceSet
1614
import org.gradle.language.base.plugins.LifecycleBasePlugin
1715

1816
/**
@@ -24,14 +22,14 @@ import org.gradle.language.base.plugins.LifecycleBasePlugin
2422
class AemPlugin : Plugin<Project> {
2523

2624
companion object {
25+
val ID = "cognifide.aem"
26+
2727
val TASK_GROUP = "AEM"
2828

2929
val CONFIG_INSTALL = "aemInstall"
3030

3131
val CONFIG_EMBED = "aemEmbed"
3232

33-
val CONFIG_SOURCE_SETS = listOf(SourceSet.MAIN_SOURCE_SET_NAME, SourceSet.TEST_SOURCE_SET_NAME)
34-
3533
val VLT_PATH = "META-INF/vault"
3634

3735
val JCR_ROOT = "jcr_root"
@@ -102,41 +100,16 @@ class AemPlugin : Plugin<Project> {
102100
}
103101

104102
private fun setupConfigs(project: Project) {
105-
createConfig(project, CONFIG_INSTALL, JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME)
106-
createConfig(project, CONFIG_EMBED, JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME)
107-
}
108-
109-
private fun createConfig(project: Project, configName: String, configToBeExtended: String): Configuration {
110-
val result = project.configurations.create(configName, {
111-
it.isTransitive = false
112-
})
113-
forConfiguration(project, configToBeExtended, { config ->
114-
config.extendsFrom(result)
115-
appendConfigurationToCompileClasspath(project, result)
116-
})
117-
118-
return result
119-
}
120-
121-
private fun forConfiguration(project: Project, name: String, creator: (Configuration) -> Unit) {
122-
val config = project.configurations.findByName(name)
123-
if (config != null) {
124-
creator(config)
125-
} else {
126-
project.configurations.whenObjectAdded {
127-
if (it is Configuration) {
128-
if (name == it.name) {
129-
creator(config)
130-
}
131-
}
103+
project.plugins.withType(JavaPlugin::class.java, {
104+
val baseConfig = project.configurations.getByName(JavaPlugin.COMPILE_CONFIGURATION_NAME)
105+
val configurer: (Configuration) -> Unit = {
106+
it.isTransitive = false
107+
baseConfig.extendsFrom(it)
132108
}
133-
}
134-
}
135-
136-
private fun appendConfigurationToCompileClasspath(project: Project, config: Configuration) {
137-
val jar = project.convention.getPlugin(JavaPluginConvention::class.java)
138109

139-
jar.sourceSets.filter { CONFIG_SOURCE_SETS.contains(it.name) }.forEach { it.compileClasspath += config }
110+
project.configurations.create(CONFIG_EMBED, configurer)
111+
project.configurations.create(CONFIG_INSTALL, configurer)
112+
})
140113
}
141114

142115
private fun setupValidation(project: Project) {

src/main/kotlin/com/cognifide/gradle/aem/pkg/ComposeTask.kt

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import org.gradle.api.tasks.Internal
1717
import org.gradle.api.tasks.OutputDirectory
1818
import org.gradle.api.tasks.TaskAction
1919
import org.gradle.api.tasks.bundling.Zip
20+
import org.jsoup.Jsoup
21+
import org.jsoup.parser.Parser
2022
import org.reflections.Reflections
2123
import org.reflections.scanners.ResourcesScanner
2224
import java.io.File
@@ -31,11 +33,14 @@ open class ComposeTask : Zip(), AemTask {
3133
}
3234

3335
@Internal
34-
var bundleCollectors: MutableMap<String, MutableList<() -> Set<File>>> = mutableMapOf()
36+
var bundleCollectors: List<() -> Unit> = mutableListOf()
3537

3638
@Internal
3739
var contentCollectors: List<() -> Unit> = mutableListOf()
3840

41+
@Internal
42+
private val vaultFilters = mutableListOf<File>()
43+
3944
@OutputDirectory
4045
private val vaultDir = File(project.buildDir, "$NAME/${AemPlugin.VLT_PATH}")
4146

@@ -70,15 +75,7 @@ open class ComposeTask : Zip(), AemTask {
7075
}
7176

7277
private fun fromBundles() {
73-
for ((installPath, jarCollectors) in bundleCollectors) {
74-
val jars = jarCollectors.fold(TreeSet<File>(), { files, it -> files.addAll(it()); files })
75-
if (jars.isEmpty()) {
76-
logger.info("No bundles to copy into AEM package at install path '$installPath'")
77-
} else {
78-
logger.info("Copying bundles into AEM package at install path '$installPath': " + jars.toString())
79-
into("${AemPlugin.JCR_ROOT}/$installPath") { spec -> spec.from(jars) }
80-
}
81-
}
78+
bundleCollectors.onEach { it() }
8279
}
8380

8481
private fun includeVaultFiles() {
@@ -91,7 +88,7 @@ open class ComposeTask : Zip(), AemTask {
9188
val contentPath: String = if (!config.vaultFilesPath.isNullOrBlank()) {
9289
config.vaultFilesPath
9390
} else {
94-
"${config.determineContentPath(project)}/${AemPlugin.VLT_PATH}"
91+
"${config.contentPath}/${AemPlugin.VLT_PATH}"
9592
}
9693

9794
val contentDir = File(contentPath)
@@ -129,6 +126,19 @@ open class ComposeTask : Zip(), AemTask {
129126
}
130127
}
131128

129+
private fun parseVaultFilterRoots(): String {
130+
val tags = vaultFilters.filter { it.exists() }.fold(mutableListOf<String>(), { tags, filter ->
131+
val doc = Jsoup.parse(filter.bufferedReader().use { it.readText() }, "", Parser.xmlParser())
132+
tags.addAll(doc.select("filter[root]").map { it.toString() }.toList()); tags
133+
})
134+
135+
if (tags.isEmpty()) {
136+
tags.add("<filter root=\"${config.bundlePath}\"/>")
137+
}
138+
139+
return tags.joinToString(config.vaultLineSeparator)
140+
}
141+
132142
private fun expandVaultFiles() {
133143
val files = vaultDir.listFiles { _, name -> config.vaultFilesExpanded.any { FilenameUtils.wildcardMatch(name, it, IOCase.INSENSITIVE) } } ?: return
134144

@@ -156,55 +166,95 @@ open class ComposeTask : Zip(), AemTask {
156166
"project" to project,
157167
"config" to config,
158168
"created" to ISO8601Utils.format(now),
159-
"buildCount" to SimpleDateFormat("yDDmmssSSS").format(now)
169+
"buildCount" to SimpleDateFormat("yDDmmssSSS").format(now),
170+
"filterRoots" to parseVaultFilterRoots()
160171
))
161-
162172
return template.toString()
163173
}
164174

165175
private fun fromContents() {
166176
contentCollectors.onEach { it() }
167177
}
168178

179+
fun includeSubprojects() {
180+
includeSubprojects(true)
181+
}
182+
183+
fun includeSubprojects(withSamePathPrefix: Boolean) {
184+
project.gradle.afterProject { subproject ->
185+
if (subproject.path != project.path && subproject.plugins.hasPlugin(AemPlugin.ID)) {
186+
if (!withSamePathPrefix || subproject.path.startsWith("${project.path}:")) {
187+
includeProject(subproject)
188+
}
189+
}
190+
}
191+
}
192+
169193
fun includeProject(projectPath: String) {
170194
includeProject(project.findProject(projectPath))
171195
}
172196

173197
fun includeProject(project: Project) {
174198
includeContent(project)
175-
includeBundles(project, config.bundlePath)
199+
includeBundles(project)
176200
}
177201

178202
fun includeBundles(projectPath: String) {
179-
includeBundles(project.findProject(projectPath), config.bundlePath)
203+
val project = project.findProject(projectPath)
204+
205+
includeBundles(project, AemConfig.of(project).bundlePath)
206+
}
207+
208+
fun includeBundles(project: Project) {
209+
includeBundles(project, AemConfig.of(project).bundlePath)
180210
}
181211

182212
fun includeBundles(projectPath: String, installPath: String) {
183213
includeBundles(project.findProject(projectPath), installPath)
184214
}
185215

186-
fun includeBundlesAtRunMode(projectPath: String, runMode : String) {
216+
fun includeBundlesAtRunMode(projectPath: String, runMode: String) {
187217
val project = project.findProject(projectPath)
188-
includeBundles(project, "${config.bundlePath}.$runMode")
218+
val bundlePath = AemConfig.of(project).bundlePath
219+
220+
includeBundles(project, "$bundlePath.$runMode")
189221
}
190222

191223
fun includeBundles(project: Project, installPath: String) {
224+
val config = AemConfig.of(project)
225+
192226
dependProject(project, config.dependBundlesTaskNames(project))
193227

194-
bundleCollectors.getOrPut(installPath, { mutableListOf() }).add({
195-
JarCollector(project).all.toSet()
196-
})
228+
bundleCollectors += {
229+
val jars = JarCollector(project).all.toSet()
230+
231+
if (jars.isEmpty()) {
232+
logger.info("No bundles to copy into AEM package at install path '$installPath'")
233+
} else {
234+
logger.info("Copying bundles into AEM package at install path '$installPath': " + jars.toString())
235+
236+
into("${AemPlugin.JCR_ROOT}/$installPath") { spec ->
237+
spec.from(jars)
238+
}
239+
}
240+
}
197241
}
198242

199243
fun includeContent(projectPath: String) {
200244
includeContent(project.findProject(projectPath))
201245
}
202246

203247
fun includeContent(project: Project) {
248+
val config = AemConfig.of(project)
249+
204250
dependProject(project, config.dependContentTaskNames(project))
205251

252+
if (this.project.path != project.path) {
253+
vaultFilters.add(project.file(config.vaultFilterPath))
254+
}
255+
206256
contentCollectors += {
207-
val contentDir = File("${config.determineContentPath(project)}/${AemPlugin.JCR_ROOT}")
257+
val contentDir = File("${config.contentPath}/${AemPlugin.JCR_ROOT}")
208258
if (!contentDir.exists()) {
209259
logger.info("Package JCR content directory does not exist: ${contentDir.absolutePath}")
210260
} else {
@@ -218,11 +268,11 @@ open class ComposeTask : Zip(), AemTask {
218268
}
219269
}
220270

221-
fun dependProject(projectPath: String, taskNames : Set<String>) {
271+
fun dependProject(projectPath: String, taskNames: Set<String>) {
222272
dependProject(project.findProject(projectPath), taskNames)
223273
}
224274

225-
fun dependProject(project: Project, taskNames : Set<String>) {
275+
fun dependProject(project: Project, taskNames: Set<String>) {
226276
taskNames.forEach { taskName -> dependsOn("${project.path}:$taskName") }
227277
}
228278

0 commit comments

Comments
 (0)