我真的很想将我的脚本模块化为多个部分(测试,默认,文档,android)。但是当我尝试将子脚本应用于父脚本时遇到问题...
这是我的子脚本(IDE现在没有抱怨)
<select class="bootstrap-select show-tick" data-size="5" data-live-search="true" data-width="100%" name="TName1" required>
<option value="" disabled selected>Select Sub Account Name</option>
<?php foreach ($accName as $row ):
$selected = ($dbValueForDropDown == $row['id']) ? 'selected="selected"' : '';
?>
<option value="<?=$row['id']?>" <?php echo set_select('accName', $row['id']); ?> <?php echo $selected;?>><?=$row['accName']?></option>
<?php endforeach ?>
</select>
但是当我尝试将此脚本应用于主脚本时:
import io.gitlab.arturbosch.detekt.Detekt
task("hello").doLast {
println("Hello World from plugins! :D")
}
tasks {
val detekt by existing(Detekt::class) {
reports {
html {
val destination = "$buildDir/detekt"
}
}
}
}
出现以下错误:
apply(from = "tdd.gradle.kts")
如何解决此问题,以便可以在子脚本中应用例如detekt插件,并将其应用到父脚本中?
答案 0 :(得分:0)
From a Gradle core dev(情况与您的情况非常相似):
脚本插件无权访问主buildscript类路径。
您可以使用以下方式将对mycompany.plugin的依赖项添加到tests.gradle中 buildscript {}语法
因此,基本上,请使用旧的buildscript
语法,导入应该可以工作
答案 1 :(得分:0)
我尝试了很多方法。总之,在Kotlin DSL中是不可能的。
未测试:我会尝试的方法(因为这是我还没有尝试过的一件事)是在您所应用的脚本中同时进行插件(旧样式)的应用和配置 all 插件作为显式跨项目配置,而无需在应用的脚本中使用allProjects
或subProjects
块。
您应参考gradle的当前项目文档,但通常采用以下形式:
project(":foo") {
// Some configuration here
apply(plugin = "plugin.id.here.sample-plugin")
// Then use configuration techniques in the Kotlin DSL guide for configuring when you don't have access to type-safe accessors, small example below
configure<SamplePluginExtension> {
// Plugin extension configuration...
}
}
这是因为,在Kotlin DSL中,allProjects
和subProjects
块在应用脚本插件中定义时仍然不像人们希望/期望的那样运行。
尽管我的要求使我不值得测试上述完整的跨项目/应用插件技术,但我确实避开了allProjects
和subProjects
的行为(并且需要使用withPlugin<PluginClass>
正确地位于这些块中,因为这似乎也不适合上述插件问题),方法是在应用脚本中声明多余的lamb,然后从allProjects
内的目标脚本中调用它们,或者与它们相关的subProjects
个配置块。
例如:
applied.build.gradle.kts
val allProjectsConfiguration by extra { p: Project ->
// Some project configuration here...
}
build.gradle.kts
//Boilerplate build script dependencies, repositories, and buildscript block as necessary...
val allProjectsConfiguration: (Project) -> Unit by extra
allProjects {
allProjectsConfiguration(this)
// where `this` is not the host script's project, not the applied script's project (of course), but one of the given projects in *all* of the projects.
这些lambda的一些常规安全提示:
p
实例使用Project
将确保没有使用它的开发人员将需要考虑当前范围内的哪个项目实例(在应用脚本中或在何处调用)。这也意味着仍可以使用呼叫站点的封闭范围提供的project
。T.apply { }
,因为它将解析为Gradle的apply
,因此如果您要这样做(或返回到单元)可以轻松地跨多个配置lambda,最好创建一个小的辅助函数,该函数基本上可以完成Kotlin中所应用的工作,或者像我所做的那样,构建一个助手,该助手运行给出的块并始终返回Unit(或某些泛型)类型)。 @ToYonos-gradle建议对Kotlin DSL不起作用。我得到的结果很差(我特别使用了classpath
依赖项),因为gradle会报告该插件从未应用过,并且在同一错误消息中它表明已应用该扩展名。我的大概猜测是,这与字节码和/或具有适用于应用脚本的单独的类加载器有关。 (对不起,我会在您的回答中对此发表评论,但没有足够的代表)
答案 2 :(得分:0)
我的回答建立在模糊武器的回答之上,因为我在看到它之前无法弄清楚,恭喜!
我的回答基于 Gradle DSL 语法。我希望有足够的细节来收集适用于 Kotlin DSL 的解决方案。
您可以通过创建采用 Project 对象参数的闭包而不是将构建逻辑直接放入您应用的脚本中来解决大多数此类问题(尽管这显然适用于独立于项目的逻辑)。由于我不清楚的原因,在单独的脚本中创建新函数会导致 Project 对象参数参数始终为空。闭包的语法很接近,与Java lambda语法几乎相同,从调用者的角度来看,函数和闭包之间的语义基本相同(显然与外部脚本内部不同)。
我最近不得不解决一个类似的问题,我想将一些动态任务生成和清理逻辑提取到一个单独的脚本中。我是这样解决的:
$projectDir/gradle/env-config.gradle
的项目中将其命名为 env-config.gradle这是一个基于我为解决它所做的工作的简短示例,我在其中定义了任务创建和任务逻辑,然后将对闭包的引用外部化,以便可以从应用此脚本的脚本中调用它:
>在$projectDir/gradle/env-config.gradle
:
def genTasks = { p ->
def previousServicePropsTask = null
deploymentPlatforms.each {
def deploymentPlatform = it
deploymentEnvironments.each {
def deploymentEnv = it
def propsTaskName = "xslt_${deploymentPlatform}_service_props_$deploymentEnv"
p.logger.info("Creating XSL Transform task: $propsTaskName")
def newServicePropsXslTask = p.tasks.create(
[name: propsTaskName, type: SaxonXsltTask], {
input "${p.projectDir}/dist/config/$deploymentPlatform/config.properties.xml"
stylesheet "${p.projectDir}/transforms/build/apply-env-specific-service-properties.xsl"
output "${p.projectDir}/config/$deploymentPlatform/$deploymentEnv/config.properties"
parameters(envSpecificServicePropsXslTransformParameters[deploymentPlatform][deploymentEnv])
}
)
if (previousServicePropsTask != null) {
newServicePropsXslTask.dependsOn(previousServicePropsTask)
}
previousServicePropsTask = newServicePropsXslTask
}
}
return previousServicePropsTask
}
//... other stuff
ext {
//Add closure to script plugin extension object
generateTransformTasks = genTasks
}
然后在项目构建脚本的适当范围和阶段调用它,在我的例子中这是在配置阶段的自定义转换任务中:
在$projectDir/build.gradle
:
apply from: "$projectDir/gradle/env-config.gradle"
task transformConfigurations() {
def taskDepends = generateTransformTasks(project)
dependsOn(taskDepends)
}
我发现这种分解构建脚本的方法非常灵活,并且基本上可以处理大多数想将逻辑分解为单独脚本的情况。
这是最终产品单独构建脚本的精简版本(实际上它甚至在自定义脚本中应用了不同的自定义脚本):
buildscript {
repositories {
mavenLocal()
}
dependencies {
classpath 'gradle.plugin.com.github.eerohele:saxon-gradle:0.8.0'
}
}
import com.github.eerohele.SaxonXsltTask
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Paths
import java.util.Properties
def deploymentPlatforms = [
'platX'
]
def deploymentEnvironments = [
'dev',
'qa',
'prod'
]
def envSpecificLog4j2XslTransformParameters = [:]
def envSpecificServicePropsXslTransformParameters = [:]
//Have to use fully-qualified class name here, known issue in Gradle
apply plugin: com.github.eerohele.SaxonPlugin
deploymentPlatforms.each {
def plat = it
envSpecificLog4j2XslTransformParameters[plat] = [:]
envSpecificServicePropsXslTransformParameters[plat] = [:]
deploymentEnvironments.each {
Properties log4j2Props = new Properties()
Properties serviceProps = new Properties()
serviceProps.load(
Files.newBufferedReader(
Paths.get("$projectDir/dist/config/$plat/$it/config.properties"),
StandardCharsets.UTF_8
)
)
log4j2Props.load(
Files.newBufferedReader(
Paths.get("$projectDir/dist/config/$plat/$it/log4j2.xml.properties"),
StandardCharsets.UTF_8
)
)
envSpecificServicePropsXslTransformParameters[plat][it] = serviceProps
envSpecificLog4j2XslTransformParameters[plat][it] = log4j2Props
}
}
def genTasks = { p ->
def previousLog4j2Task = null
def previousServicePropsTask = null
deploymentPlatforms.each {
def deploymentPlatform = it
deploymentEnvironments.each {
def deploymentEnv = it
def propsTaskName = "xslt_${deploymentPlatform}_service_props_$deploymentEnv"
p.logger.info("Creating XSL Transform task: $propsTaskName")
def newServicePropsXslTask = p.tasks.create(
[name: propsTaskName, type: SaxonXsltTask], {
input "${p.projectDir}/dist/config/$deploymentPlatform/config.properties.xml"
stylesheet "${p.projectDir}/transforms/build/apply-env-specific-service-properties.xsl"
output "${p.projectDir}/config/$deploymentPlatform/$deploymentEnv/config.properties"
parameters(envSpecificServicePropsXslTransformParameters[deploymentPlatform][deploymentEnv])
}
)
def log4j2XmlTaskName = "xslt_${deploymentPlatform}_service_log4j2_$deploymentEnv"
p.logger.info("Creating XSL Transform task: $log4j2XmlTaskName")
def newLog4j2XslTask = p.tasks.create(
[name: log4j2XmlTaskName, type: SaxonXsltTask], {
input "${p.projectDir}/dist/config/$deploymentPlatform/log4j2.xml"
stylesheet "${p.projectDir}/transforms/build/apply-env-specific-service-logging.xsl"
output "${p.projectDir}/config/$deploymentPlatform/$deploymentEnv/log4j2.xml"
parameters(envSpecificLog4j2XslTransformParameters[deploymentPlatform][deploymentEnv])
}
)
if (previousServicePropsTask != null) {
newServicePropsXslTask.dependsOn(previousServicePropsTask)
}
if (previousLog4j2Task != null) {
newLog4j2XslTask.dependsOn(previousLog4j2Task)
}
previousServicePropsTask = newServicePropsXslTask
previousLog4j2Task = newLog4j2XslTask
}
}
return [
previousServicePropsTask: previousServicePropsTask,
previousLog4j2Task: previousLog4j2Task
]
}
def cleanupCustomTask = { p ->
def configsForRemoval = [:]
def dirsForRemoval = [:]
deploymentPlatforms.each {
def deploymentPlatform = it
def generatedPlatformDir = "${p.projectDir}/config/$deploymentPlatform"
deploymentEnvironments.each {
def deploymentEnv = it
def distributionName = "$deploymentPlatform${deploymentEnv.capitalize()}"
def generatedConfigDir = "$generatedPlatformDir/$deploymentEnv"
def generatedServicePropsConfig = "$generatedConfigDir/config.properties"
def generatedLog4j2Config = "$generatedConfigDir/lo4j2.xml"
def generatedDistNameDir = "${p.projectDir}/src/$distributionName"
def generatedConfigVersionDistDir = "$generatedDistNameDir/dist"
def generatedConfigVersionText = "$generatedConfigVersionDistDir/config-version.txt"
def generatedOldConfigVersionText = "$generatedConfigVersionDistDir/version.txt"
configsForRemoval[generatedServicePropsConfig] = Files.exists(Paths.get(generatedServicePropsConfig))
configsForRemoval[generatedLog4j2Config] = Files.exists(Paths.get(generatedLog4j2Config))
configsForRemoval[generatedConfigVersionText] = Files.exists(Paths.get(generatedConfigVersionText))
configsForRemoval[generatedOldConfigVersionText] = Files.exists(Paths.get(generatedOldConfigVersionText))
dirsForRemoval[generatedConfigDir] = Files.exists(Paths.get(generatedConfigDir))
dirsForRemoval[generatedConfigVersionDistDir] = Files.exists(Paths.get(generatedConfigVersionDistDir))
dirsForRemoval[generatedDistNameDir] = Files.exists(Paths.get(generatedDistNameDir))
}
dirsForRemoval[generatedPlatformDir] = Files.exists(Paths.get(generatedPlatformDir))
}
//Also handle mainConfig, which is not dynamic.
def mainConfigDistNameDir = "${p.projectDir}/src/mainConfig"
def mainConfigVersionDistDir = "$mainConfigDistNameDir/dist"
def mainConfigVersionText = "$mainConfigVersionDistDir/config-version.txt"
def mainConfigOldVersionText = "$mainConfigVersionDistDir/version.txt"
configsForRemoval[mainConfigVersionText] = Files.exists(Paths.get(mainConfigVersionText))
configsForRemoval[mainConfigOldVersionText] = Files.exists(Paths.get(mainConfigOldVersionText))
dirsForRemoval[mainConfigVersionDistDir] = Files.exists(Paths.get(mainConfigVersionDistDir))
dirsForRemoval[mainConfigDistNameDir] = Files.exists(Paths.get(mainConfigDistNameDir))
return [
configsForRemoval: configsForRemoval,
dirsForRemoval: dirsForRemoval
]
}
def genConfigDistTasks = { p, appName ->
deploymentPlatforms.each {
def deploymentPlatform = it
deploymentEnvironments.each {
def deploymentEnv = it
def distributionName = "$deploymentPlatform${deploymentEnv.capitalize()}"
p.distributions.create(distributionName, {
baseName = appName
contents {
into('config') {
from fileTree('src/main/resources').matching {
exclude 'spotbugs-exclusion-filters.xml',
'config/config.properties',
'config/log4j2.xml'
}.files
from fileTree("config/$deploymentPlatform/$deploymentEnv/log4j2.xml").
files
}
}
})
p.tasks.getByName("${distributionName}DistZip") {
preserveFileTimestamps = false
reproducibleFileOrder = true
archiveBaseName = appName
includeEmptyDirs = true
dependsOn p.tasks.transformConfigurations
def appVersion = null
doFirst {
appVersion = p.jar.ext.has('version') ? p.jar.ext.version : {
apply from: "${p.projectDir}/gradle/version-util.gradle"
return getVersionInfo().full
}()
def distDir = "${p.projectDir}/src/$distributionName/dist"
if (Files.notExists(Paths.get(distDir))) {
Files.createDirectories(Paths.get(distDir))
}
Files.write(Paths.get("${p.projectDir}/src/$distributionName/dist/config-version.txt"),
"$appName-config-$appVersion".toString().getBytes())
}
doLast {
def distAppName = "${p.properties['application.configTitle']}-${appVersion}" +
".${distributionName}.config.${archiveExtension.get()}"
p.logger.info(
"Fixing archive name, renaming from ${archiveFileName.get()} to $distAppName"
)
def zabd = "build/distributions"
file("$zabd/${archiveFileName.get()}").
renameTo(file("$zabd/$distAppName")
)
}
}
}
}
}
ext {
//Add closures to extension object
generateConfigurationDistributionTasks = genConfigDistTasks
cleanUpCustomTrash = cleanupCustomTask
generateTransformTasks = genTasks
}
我知道这有点晚了,但也许可以帮助面临大型构建文件或需要模块化构建的人。