From ba8178489113fd7f99117b211ab6824c60678eed Mon Sep 17 00:00:00 2001 From: Timur Shakurov Date: Sun, 29 May 2016 21:21:58 +0300 Subject: [PATCH] #4 added overlay support to farms (#18) --- .../org/akhikhl/gretty/FarmConfigurer.groovy | 80 +++++++------ .../akhikhl/gretty/FarmConfigurerUtil.groovy | 48 ++++++++ .../org/akhikhl/gretty/FarmStartTask.groovy | 2 +- .../org/akhikhl/gretty/FarmWebappType.groovy | 8 ++ .../org/akhikhl/gretty/GrettyPlugin.groovy | 106 +++++++++++++++++- .../akhikhl/gretty/ProductConfigurer.groovy | 2 +- .../org/akhikhl/gretty/ProjectUtils.groovy | 42 +++++-- 7 files changed, 236 insertions(+), 52 deletions(-) create mode 100644 libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmConfigurerUtil.groovy create mode 100644 libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmWebappType.groovy diff --git a/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmConfigurer.groovy b/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmConfigurer.groovy index 4669d93c7..518d51734 100644 --- a/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmConfigurer.groovy +++ b/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmConfigurer.groovy @@ -64,9 +64,9 @@ class FarmConfigurer { sourceFarm } - WebAppConfig getWebAppConfigForMavenDependency(Map options, String dependency, List dependencies = null, String configurationName) { + WebAppConfig getWebAppConfigForMavenDependency(Map options, String dependency, String farmName) { WebAppConfig wconfig = new WebAppConfig() - ConfigUtils.complementProperties(wconfig, options, ProjectUtils.getDefaultWebAppConfigForMavenDependency(project, dependency, dependencies, configurationName)) + ConfigUtils.complementProperties(wconfig, options, ProjectUtils.getDefaultWebAppConfigForMavenDependency(project, farmName, dependency, options.dependencies)) wconfig.inplace = false // always war-file, ignore options.inplace ProjectUtils.resolveWebAppConfig(null, wconfig, sconfig) wconfig @@ -114,59 +114,67 @@ class FarmConfigurer { } // attention: this method may modify project configurations and dependencies. - void resolveWebAppRefs(Map wrefs, Collection destWebAppConfigs, Boolean inplace = null, String inplaceMode = null) { + void resolveWebAppRefs(String farmName, Map wrefs, Collection destWebAppConfigs, Boolean inplace = null, String inplaceMode = null) { wrefs.each { wref, options -> if(options.inplace != null) inplace = options.inplace - def proj = resolveWebAppRefToProject(wref) - def warFile - if(!proj) { - warFile = resolveWebAppRefToWarFile(wref) - if(!warFile) { - wref = wref.toString() - def gav = wref.split(':') - if(gav.length != 3) - throw new GradleException("'${wref}' is not an existing project or file or maven dependency.") + def proj, warFile + + // little hack for overlays: + if(options.finalArchivePath) { + wref = options.finalArchivePath + } + + def typeAndResult = FarmConfigurerUtil.resolveWebAppType(project, options.suppressMavenToProjectResolution, wref) + def type = typeAndResult[0] + def result = typeAndResult[1] + switch (type) { + case FarmWebappType.PROJECT: + proj = result + break + case FarmWebappType.WAR_FILE: + warFile = result + break + case FarmWebappType.DEPENDENCY_TO_PROJECT: + proj = result + log.info '{} comes from project {}, so using project instead of maven dependency', wref, proj.path + break + case FarmWebappType.WAR_DEPENDENCY: log.info '{} is not an existing project or war-file, treating it as a maven dependency', wref - if(!options.suppressMavenToProjectResolution) { - proj = project.rootProject.allprojects.find { it.group == gav[0] && it.name == gav[1] } - if(proj) - log.info '{} comes from project {}, so using project instead of maven dependency', wref, proj.path - } - } + break } + WebAppConfig webappConfig if(proj) webappConfig = getWebAppConfigForProject(options, proj, inplace, inplaceMode) else if (warFile) webappConfig = getWebAppConfigForWarFile(options, warFile) else { - def configurationName = 'farm' + wref - project.configurations.maybeCreate(configurationName) - project.dependencies.add configurationName, wref - List dependencies = options?.dependencies as List - dependencies?.each { - project.dependencies.add configurationName, it - } - webappConfig = getWebAppConfigForMavenDependency(options, wref, dependencies, configurationName) + webappConfig = getWebAppConfigForMavenDependency(options, wref, farmName) } destWebAppConfigs.add(webappConfig) } } + /** + * + * @param webAppRef + * @return + * @deprecated use {@link FarmConfigurerUtil} instead + */ + @Deprecated Project resolveWebAppRefToProject(webAppRef) { - def proj - if(webAppRef instanceof Project) - proj = webAppRef - else if(webAppRef instanceof String || webAppRef instanceof GString) - proj = project.findProject(webAppRef) - proj + FarmConfigurerUtil.resolveWebAppRefToProject(project, webAppRef) } + /** + * + * @param webAppRef + * @return + * @deprecated use {@link FarmConfigurerUtil} instead + */ + @Deprecated File resolveWebAppRefToWarFile(webAppRef) { - File warFile = webAppRef instanceof File ? webAppRef : new File(webAppRef.toString()) - if(!warFile.isFile() && !warFile.isAbsolute()) - warFile = new File(project.projectDir, warFile.path) - warFile.isFile() ? warFile.absoluteFile : null + FarmConfigurerUtil.resolveWebAppRefToWarFile(project, webAppRef) } } diff --git a/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmConfigurerUtil.groovy b/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmConfigurerUtil.groovy new file mode 100644 index 000000000..178fc7ccb --- /dev/null +++ b/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmConfigurerUtil.groovy @@ -0,0 +1,48 @@ +package org.akhikhl.gretty + +import org.gradle.api.GradleException +import org.gradle.api.Project + +/** + * @author sala + */ +class FarmConfigurerUtil { + + static Project resolveWebAppRefToProject(Project project, webAppRef) { + def proj + if(webAppRef instanceof Project) + proj = webAppRef + else if(webAppRef instanceof String || webAppRef instanceof GString) + proj = project.findProject(webAppRef) + proj + } + + static File resolveWebAppRefToWarFile(Project project, webAppRef, checkExistence = true) { + File warFile = webAppRef instanceof File ? webAppRef : new File(webAppRef.toString()) + if((!checkExistence || !warFile.isFile()) && !warFile.isAbsolute()) + warFile = new File(project.projectDir, warFile.path) + (!checkExistence || warFile.isFile()) ? warFile.absoluteFile : null + } + + static Tuple resolveWebAppType(Project project, suppressMavenToProjectResolution, wref, checkExistence = true) { + def proj = resolveWebAppRefToProject(project, wref) + if(proj) { + return new Tuple(FarmWebappType.PROJECT, proj) + } + def warFile = resolveWebAppRefToWarFile(project, wref, checkExistence) + if(warFile) { + return new Tuple(FarmWebappType.WAR_FILE, warFile) + } + wref = wref.toString() + def gav = wref.split(":") + if(gav.length != 3) { + throw new GradleException("'${wref}' is not an existing project or file or maven dependency.") + } + if(!suppressMavenToProjectResolution) { + proj = project.rootProject.allprojects.find { it.group == gav[0] && it.name == gav[1] } + if(proj) + return new Tuple(FarmWebappType.DEPENDENCY_TO_PROJECT, proj) + } + return new Tuple(FarmWebappType.WAR_DEPENDENCY, wref) + } +} diff --git a/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmStartTask.groovy b/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmStartTask.groovy index cc1aa748e..066c82a14 100644 --- a/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmStartTask.groovy +++ b/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmStartTask.groovy @@ -38,7 +38,7 @@ class FarmStartTask extends StartBaseTask { doPrepareServerConfig(tempFarm.serverConfig) List wconfigs = [] - configurer.resolveWebAppRefs(tempFarm.webAppRefs, wconfigs, inplace, inplaceMode) + configurer.resolveWebAppRefs(farmName, tempFarm.webAppRefs, wconfigs, inplace, inplaceMode) for(WebAppConfig wconfig in wconfigs) { doPrepareWebAppConfig(wconfig) diff --git a/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmWebappType.groovy b/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmWebappType.groovy new file mode 100644 index 000000000..a67d2990f --- /dev/null +++ b/libs/gretty/src/main/groovy/org/akhikhl/gretty/FarmWebappType.groovy @@ -0,0 +1,8 @@ +package org.akhikhl.gretty + +/** + * @author sala + */ +enum FarmWebappType { + PROJECT, WAR_FILE, WAR_DEPENDENCY, DEPENDENCY_TO_PROJECT +} \ No newline at end of file diff --git a/libs/gretty/src/main/groovy/org/akhikhl/gretty/GrettyPlugin.groovy b/libs/gretty/src/main/groovy/org/akhikhl/gretty/GrettyPlugin.groovy index a4e376238..d0e952b12 100644 --- a/libs/gretty/src/main/groovy/org/akhikhl/gretty/GrettyPlugin.groovy +++ b/libs/gretty/src/main/groovy/org/akhikhl/gretty/GrettyPlugin.groovy @@ -8,12 +8,16 @@ */ package org.akhikhl.gretty +import org.apache.commons.io.FilenameUtils import org.gradle.api.GradleException import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.tasks.Copy import org.slf4j.Logger import org.slf4j.LoggerFactory + +import java.nio.file.Paths + /** * * @author akhikhl @@ -127,6 +131,27 @@ class GrettyPlugin implements Plugin { } } } + + project.farms.farmsMap.each { fname, farm -> + farm.webAppRefs.each { wref, options -> + def typeAndResult = FarmConfigurerUtil.resolveWebAppType(project, options.suppressMavenToProjectResolution, wref, false) + def type = typeAndResult[0] as FarmWebappType + def result = typeAndResult[1] + + def configurationName = ProjectUtils.getFarmConfigurationName(fname) + if(FarmWebappType.WAR_DEPENDENCY == type) { + project.configurations.maybeCreate(configurationName) + project.dependencies.add configurationName, result + } + + if(type in [FarmWebappType.WAR_DEPENDENCY, FarmWebappType.WAR_FILE]) { + project.configurations.maybeCreate(configurationName) + options.dependencies?.each { + project.dependencies.add configurationName, it + } + } + } + } } private void addExtensions(Project project) { @@ -158,12 +183,12 @@ class GrettyPlugin implements Plugin { private void addTaskDependencies(Project project) { project.tasks.whenObjectAdded { task -> - if(GradleUtils.instanceOf(task, 'org.akhikhl.gretty.AppStartTask')) + if (GradleUtils.instanceOf(task, 'org.akhikhl.gretty.AppStartTask')) task.dependsOn { // We don't need any task for hard inplace mode. task.effectiveInplace ? project.tasks.prepareInplaceWebApp : project.tasks.prepareArchiveWebApp } - else if(GradleUtils.instanceOf(task, 'org.akhikhl.gretty.FarmStartTask')) + else if (GradleUtils.instanceOf(task, 'org.akhikhl.gretty.FarmStartTask')) { task.dependsOn { task.getWebAppConfigsForProjects().findResults { def proj = project.project(it.projectPath) @@ -178,6 +203,27 @@ class GrettyPlugin implements Plugin { projTask } } + + def farmName = task.farmName + project.farms.farmsMap[farmName].webAppRefs.each { wref, options -> + def typeAndResult = FarmConfigurerUtil.resolveWebAppType(project, options.suppressMavenToProjectResolution, wref, false) + def type = typeAndResult[0] + if(type in [FarmWebappType.WAR_FILE, FarmWebappType.WAR_DEPENDENCY]) { + if (options.overlays) { + def warFile + if (type == FarmWebappType.WAR_FILE) { + warFile = typeAndResult[1] + } else if (type == FarmWebappType.WAR_DEPENDENCY) { + warFile = ProjectUtils.getFileFromConfiguration(project, ProjectUtils.getFarmConfigurationName(farmName), typeAndResult[1]) + } + + def warFileName = warFile.name + def farmOverlayArchive = project.tasks.findByName("farmOverlayArchive${farmName}${warFileName}") + task.dependsOn farmOverlayArchive + } + } + } + } } } @@ -494,6 +540,60 @@ class GrettyPlugin implements Plugin { } // JVM project project.farms.farmsMap.each { fname, farm -> + def overlayTasks = [] + farm.webAppRefs.each { wref, options -> + def typeAndResult = FarmConfigurerUtil.resolveWebAppType(project, options.suppressMavenToProjectResolution, wref, false) + def type = typeAndResult[0] as FarmWebappType + switch (type) { + case FarmWebappType.WAR_FILE: + case FarmWebappType.WAR_DEPENDENCY: + def overlays = options.overlays + if (overlays) { + log.info("Farm {} contains webapp {} with overlays: {}", fname, wref, options.overlays) + + def warFile + if(type == FarmWebappType.WAR_FILE) { + warFile = typeAndResult[1] + } else if (type == FarmWebappType.WAR_DEPENDENCY) { + warFile = ProjectUtils.getFileFromConfiguration(project, ProjectUtils.getFarmConfigurationName(fname), typeAndResult[1]) + } + + def outputFolder = Paths.get(project.buildDir.absolutePath, 'farms', fname, 'explodedWebapps', FilenameUtils.removeExtension(warFile.name)).toFile() + def outputFolderPath = outputFolder.absolutePath + + def explodeWebappTask = project.task("farmExplodeWebapp$fname${warFile.name}", group: 'gretty') { + description = 'Explode webapp and all overlays into ${buildDir}/farms/${fname}/explodedWebapps/${wref}' + for(String overlay in overlays) { + dependsOn "$overlay:assemble" as String + } + for(String overlay in overlays) + inputs.file { ProjectUtils.getFinalArchivePath(project.project(overlay)) } + inputs.file warFile + outputs.dir outputFolder + doLast { + ProjectUtils.prepareExplodedFarmWebAppFolder(project, warFile, overlays, outputFolderPath) + } + } + + // TODO: gradle way of doing this? + def repackagedArchive = Paths.get(project.buildDir.absolutePath, 'farms', fname, 'explodedWebapps', warFile.name).toFile().absolutePath + def archiveWebappTask = project.task("farmOverlayArchive$fname${warFile.name}", group: 'gretty') { + description = 'Creates archive from exploded web-app in ${buildDir}/farms/${fname}/explodedWebapps/${wref}' + dependsOn explodeWebappTask + inputs.dir outputFolder + outputs.file repackagedArchive + doLast { + ant.zip destfile: repackagedArchive, basedir: outputFolderPath + } + } + + overlayTasks.addAll([explodeWebappTask, archiveWebappTask]) + + options.finalArchivePath = repackagedArchive + } + break + } + } String farmDescr = fname ? "farm '${fname}'" : 'default farm' @@ -677,7 +777,7 @@ class GrettyPlugin implements Plugin { tomcat8ServletApiVersion = Externalized.getString('tomcat8ServletApiVersion') } - if(!project.tasks.findByName('run')) + if(!project.tasks.findByName('run') && project.tasks.findByName('appRun')) project.task('run', group: 'gretty') { description = 'Starts web-app inplace, in interactive mode. Same as appRun task.' dependsOn 'appRun' diff --git a/libs/gretty/src/main/groovy/org/akhikhl/gretty/ProductConfigurer.groovy b/libs/gretty/src/main/groovy/org/akhikhl/gretty/ProductConfigurer.groovy index 2be000e9a..81f1c25e5 100644 --- a/libs/gretty/src/main/groovy/org/akhikhl/gretty/ProductConfigurer.groovy +++ b/libs/gretty/src/main/groovy/org/akhikhl/gretty/ProductConfigurer.groovy @@ -369,7 +369,7 @@ Version: ${project.version}""" sconfig = productFarm.serverConfig wconfigs = [] // we don't need to pass inplaceMode here cuz inplace=false anyway - configurer.resolveWebAppRefs(productFarm.webAppRefs, wconfigs, false) + configurer.resolveWebAppRefs(productName, productFarm.webAppRefs, wconfigs, false) for(WebAppConfig wconfig in wconfigs) ProjectUtils.prepareToRun(project, wconfig) CertificateGenerator.maybeGenerate(project, sconfig) diff --git a/libs/gretty/src/main/groovy/org/akhikhl/gretty/ProjectUtils.groovy b/libs/gretty/src/main/groovy/org/akhikhl/gretty/ProjectUtils.groovy index 82735b2f2..fbb2f1d16 100644 --- a/libs/gretty/src/main/groovy/org/akhikhl/gretty/ProjectUtils.groovy +++ b/libs/gretty/src/main/groovy/org/akhikhl/gretty/ProjectUtils.groovy @@ -154,23 +154,29 @@ final class ProjectUtils { return result } - static WebAppConfig getDefaultWebAppConfigForMavenDependency(Project project, String dependency, List dependencies = [], String configurationName) { + static String getFarmConfigurationName(farmName) { + return 'farm' + farmName + } + + static File getFileFromConfiguration(Project project, String configurationName, String dependency) { + def gav = dependency.split(':') + def artifact = project.configurations[configurationName].resolvedConfiguration.resolvedArtifacts.find { + it.moduleVersion.id.group == gav[0] && it.moduleVersion.id.name == gav[1] + } + artifact.file + } + + static WebAppConfig getDefaultWebAppConfigForMavenDependency(Project project, String farmName, String dependency, List dependencies = []) { WebAppConfig result = new WebAppConfig() result.contextPath = '/' + dependency.split(':')[1] + def configurationName = getFarmConfigurationName(farmName) + def resolvedDependency = getFileFromConfiguration(project, configurationName, dependency) result.resourceBase = { - def gav = dependency.split(':') - def artifact = project.configurations[configurationName].resolvedConfiguration.resolvedArtifacts.find { - it.moduleVersion.id.group == gav[0] && it.moduleVersion.id.name == gav[1] - } - artifact.file.absolutePath + resolvedDependency.absolutePath } if(dependencies) { result.classPath = dependencies.collect { - def gav = it.split(':') - def artifact = project.configurations[configurationName].resolvedConfiguration.resolvedArtifacts.find { - it.moduleVersion.id.group == gav[0] && it.moduleVersion.id.name == gav[1] - } - artifact.file.absolutePath + getFileFromConfiguration(project, configurationName, it).absolutePath } as Set } return result @@ -240,6 +246,20 @@ final class ProjectUtils { } } + static void prepareExplodedFarmWebAppFolder(Project project, File war, List overlays, String targetFolder) { + for(String overlay in overlays) { + def overlayProject = project.project(overlay) + project.copy { + from overlayProject.zipTree(getFinalArchivePath(overlayProject)) + into targetFolder + } + } + project.copy { + from project.zipTree(war) + into targetFolder + } + } + static void prepareInplaceWebAppFolder(Project project) { new File(project.buildDir, 'inplaceWebapp').mkdirs() // ATTENTION: overlay copy order is important!