识别Gradle约定
通過約定進(jìn)行配置具有許多優(yōu)點(diǎn),尤其是在簡潔方面,因?yàn)殚_發(fā)人員不需要顯式配置通過約定隱式配置的內(nèi)容。 但是,在利用約定進(jìn)行配置時,需要了解約定。 這些約定可能已經(jīng)記錄在案,但是當(dāng)我可以編程方式確定約定時,我總是喜歡它,因?yàn)槲臋n可能會過時(代碼背后的相同原理總是正確的,而注釋有時是正確的)。 我通過查看如何識別與Gradle Java Plugin關(guān)聯(lián)的特定約定開始本文。 然后,我對該方法進(jìn)行一般化,以識別與與Gradle構(gòu)建的根項(xiàng)目相關(guān)聯(lián)的所有任務(wù)相關(guān)聯(lián)的所有屬性。
Gradle插件上的Gradle文檔說明了以下有關(guān)Gradle插件的重要性以及它們對Gradle構(gòu)建的補(bǔ)充:
Gradle的核心故意為現(xiàn)實(shí)世界的自動化提供了很少的有用功能。 插件添加了所有有用的功能,例如編譯Java代碼的功能。 插件添加新任務(wù)(例如JavaCompile),域?qū)ο?#xff08;例如SourceSet),約定(例如主Java源位于src / main / java),以及擴(kuò)展核心對象和其他插件的對象。
這篇文章介紹了Java插件為Gradle構(gòu)建帶來的一些任務(wù),域?qū)ο蠛图s定。 首先,我需要一個非常簡單的Gradle構(gòu)建文件。 它僅由應(yīng)用Java插件的一行組成。 接下來顯示在Gradle構(gòu)建文件build-java-plugin.gradle 。
build-java-plugin.gradle
apply plugin: 'java'有了該單行的Gradle構(gòu)建文件,可以通過運(yùn)行g(shù)radle -b build-java-plugin.gradle tasks命令輕松查看插件提供的Gradle gradle -b build-java-plugin.gradle tasks 。 接下來的兩個屏幕快照顯示了運(yùn)行空的Gradle構(gòu)建文件的輸出,以及僅使用Java插件的應(yīng)用程序運(yùn)行Gradle構(gòu)建文件的輸出。
通過將運(yùn)行Gradle“任務(wù)”的輸出與空構(gòu)建文件的輸出與運(yùn)行Gradle“任務(wù)”的構(gòu)建文件與應(yīng)用Java插件的輸出進(jìn)行比較,我們可以看到Gradle具有相同的“ Build Setup Tasks”集。和“幫助任務(wù)”,無論是否應(yīng)用了插件。 更重要的是,我們看到Java插件添加了許多新任務(wù),這些任務(wù)分類為“構(gòu)建任務(wù)”(匯編,構(gòu)建,buildDependents,buildNeeded,類,clean,jar,testClasses),“文檔任務(wù)”(javadoc),“驗(yàn)證任務(wù)”(檢查,測試)和“規(guī)則”。
我在Gradle 1.10中享受的一項(xiàng)功能是Gradle 1.8 (我使用的較早版本)沒有的功能是,可以在命令行中查詢特定Gradle任務(wù)的詳細(xì)信息 。 下一個屏幕快照展示了Java插件任務(wù)compileJava , jar和javadoc 。 通過在命令行上使用help --task <task_name>命令,所有這三個任務(wù)都有寫入標(biāo)準(zhǔn)輸出的詳細(xì)信息。 有關(guān)Java插件任務(wù)的這些詳細(xì)信息,也可以在Gradle用戶指南中找到 。
由于Gradle基于Groovy構(gòu)建,因此使用“蠻力”確定Java插件的特性相當(dāng)容易。 下一個代碼清單( build-java-plugin-properties.gradle )演示了如何使用Groovy確定Gradle屬性(可以用-P指定的那些,而不是用-D指定的系統(tǒng)屬性 ),該屬性可在構(gòu)建腳本之前和之后使用。在應(yīng)用Java插件之后,然后使用Groovy的高度方便的重寫減法運(yùn)算符來查找差異。 Java插件添加到Gradle腳本的所有屬性的名稱和值(屬性“ properties”除外)按字母順序顯示。
// build-java-plugin-properties.gradle // // Displays properties that Gradle Java Plugin adds beyond properties already // specified for any Gradle build.def propertiesBefore = this.propertiesapply plugin: 'java'def propertiesAfter = this.propertiesdef extraProperties = propertiesAfter - propertiesBeforedef extraPropertiesKeys = new TreeSet<String>() extraProperties.each { property ->if (property.key != "properties"){extraPropertiesKeys.add(property.key)} }extraPropertiesKeys.each { key ->println "${key} : ${extraProperties.get(key)}" }下圖顯示了屏幕快照,其中包含運(yùn)行此腳本的輸出。 屏幕快照未顯示完整的輸出,但是在圖像后的文本中顯示了較大的一部分輸出(所有屬性)。
從Gradle腳本上方運(yùn)行以查看Java插件屬性的輸出
apiDocTitle : gradleExample API archivesBaseName : gradleExample assemble : task ':assemble' binaries : [classes 'main', classes 'test'] build : task ':build' buildDependents : task ':buildDependents' buildNeeded : task ':buildNeeded' buildTasks : [build] check : task ':check' classes : task ':classes' clean : task ':clean' compileJava : task ':compileJava' compileTestJava : task ':compileTestJava' defaultArtifacts : org.gradle.api.internal.plugins.DefaultArtifactPublicationSet_Decorated@bc80d8 dependencyCacheDir : C:\java\examples\groovyExamples\gradleExample\build\dependency-cache dependencyCacheDirName : dependency-cache distsDir : C:\java\examples\groovyExamples\gradleExample\build\distributions distsDirName : distributions docsDir : C:\java\examples\groovyExamples\gradleExample\build\docs docsDirName : docs inheritedScope : org.gradle.api.internal.ExtensibleDynamicObject$InheritedDynamicObject@c10304 jar : task ':jar' javadoc : task ':javadoc' libsDir : C:\java\examples\groovyExamples\gradleExample\build\libs libsDirName : libs manifest : org.gradle.api.java.archives.internal.DefaultManifest@1ad3677 metaInf : [] module : org.gradle.api.internal.artifacts.ProjectBackedModule@d2eead processResources : task ':processResources' processTestResources : task ':processTestResources' rebuildTasks : [clean, build] reporting : org.gradle.api.reporting.ReportingExtension_Decorated@33ab8f reportsDir : C:\java\examples\groovyExamples\gradleExample\build\reports reportsDirName : reports runtimeClasspath : file collection sourceCompatibility : 1.7 sourceSets : sources : [, ] status : integration targetCompatibility : 1.7 test : task ':test' testClasses : task ':testClasses' testReportDir : C:\java\examples\groovyExamples\gradleExample\build\reports\tests testReportDirName : tests testResultsDir : C:\java\examples\groovyExamples\gradleExample\build\test-results testResultsDirName : test-resultsGradle使用命令gradle properties可以輕松查看所有Gradle屬性,但是此命令行操作將顯示所有屬性,無論其來源(Gradle本身還是插件)。
Java插件添加到構(gòu)建中的每個Gradle任務(wù)都有其自己的屬性集。 這些屬性可以在Gradle Build Language Reference中找到 。 該文檔的“ 任務(wù)類型”部分具有指向每種任務(wù)類型的鏈接。 每個任務(wù)類型的鏈接到頁面均包含該任務(wù)類型支持的屬性的詳細(xì)信息。 例如,任務(wù)類型JavaCompile在其頁面上列出為具有諸如classpath , destinationDir和source之 類的屬性。
以下相當(dāng)廣泛的腳本顯示了compileJava,jar和javadoc Gradle Java Plugin任務(wù)的屬性設(shè)置。 該腳本演示了將Groovy應(yīng)用于識別Gradle構(gòu)建設(shè)置的強(qiáng)大功能。 如果使用更多的反射,該腳本可能會更短,但是明確地調(diào)用任務(wù)的屬性確實(shí)在讀取方面和作為每個任務(wù)可用屬性的參考方面具有優(yōu)勢。
build-java-plugin-metadata.gradle
// build-java-plugin-metadata.gradle // // Displays the properties associated with the Gradle Java Plugin tasks // of "compileJava", "jar", and "javadoc".import groovy.transform.Fieldapply plugin: 'java'@Field int MAX_COLUMNS = 80 @Field String headerSeparator = "=".multiply(MAX_COLUMNS)printCompileJavaProperties() printJarProperties() printJavadocProperties()def printCompileJavaProperties() {printHeader("compileJava Task")println "compileJava.classpath:\n${extractStringRepresentation(compileJava.classpath)}"println "compileJava.destinationDir:\n${extractStringRepresentation(compileJava.destinationDir)}"println "compileJava.source:\n${extractStringRepresentation(compileJava.source)}"println "compileJava.options:\n${extractStringRepresentation(compileJava.options)}"println "compileJava.includes:\n${extractStringRepresentation(compileJava.includes)}"println "compileJava.excludes:\n${extractStringRepresentation(compileJava.excludes)}"println "compileJava.sourceCompatibility:\n${extractStringRepresentation(compileJava.sourceCompatibility)}"println "compileJava.targetCompatibility:\n${extractStringRepresentation(compileJava.targetCompatibility)}" }def printJarProperties() {printHeader("jar Task")println "jar.appendix:\n${extractStringRepresentation(jar.appendix)}"println "jar.archiveName:\n${extractStringRepresentation(jar.archiveName)}"println "jar.archivePath:\n${extractStringRepresentation(jar.archivePath)}"println "jar.baseName:\n${extractStringRepresentation(jar.baseName)}"println "jar.caseSensitive:\n${extractStringRepresentation(jar.caseSensitive)}"println "jar.classifier:\n${extractStringRepresentation(jar.classifier)}"println "jar.destinationDir:\n${extractStringRepresentation(jar.destinationDir)}"println "jar.dirMode:\n${extractStringRepresentation(jar.dirMode)}"println "jar.duplicatesStrategy:\n${extractStringRepresentation(jar.duplicatesStrategy)}"println "jar.entryCompression:\n${extractStringRepresentation(jar.entryCompression)}"println "jar.excludes:\n${extractStringRepresentation(jar.excludes)}"println "jar.extension:\n${extractStringRepresentation(jar.extension)}"println "jar.fileMode:\n${extractStringRepresentation(jar.fileMode)}"println "jar.includeEmptyDirs:\n${extractStringRepresentation(jar.includeEmptyDirs)}"println "jar.includes:\n${extractStringRepresentation(jar.includes)}"println "jar.manifest:\n${extractStringRepresentation(jar.manifest)}"println "jar.source:\n${extractStringRepresentation(jar.source)}"println "jar.version:\n${extractStringRepresentation(jar.version)}" }def printJavadocProperties() {printHeader("javadoc Task")println "javadoc.classpath:\n${extractStringRepresentation(javadoc.classpath)}"println "javadoc.destinationDir:\n${extractStringRepresentation(javadoc.destinationDir)}"println "javadoc.excludes:\n${extractStringRepresentation(javadoc.excludes)}"println "javadoc.executable:\n${extractStringRepresentation(javadoc.executable)}"println "javadoc.failOnError:\n${extractStringRepresentation(javadoc.failOnError)}"println "javadoc.includes:\n${extractStringRepresentation(javadoc.includes)}"println "javadoc.maxMemory:\n${extractStringRepresentation(javadoc.maxMemory)}"println "javadoc.options:\n${extractStringRepresentation(javadoc.options)}"println "javadoc.source:\n${extractStringRepresentation(javadoc.source)}"println "javadoc.title:\n${extractStringRepresentation(javadoc.title)}" }def String extractStringRepresentation(Object object) {String returnStringif (object in String){returnString = "\t${object}\n"}else if (object in File){returnString = "\t${object.canonicalPath}\n"}else if (object in FileCollection) // FileTree is a FileCollection{StringBuilder filesStr = new StringBuilder()def files = object.filesfiles.each{ file ->filesStr << "\t" << file.canonicalPath << "\n" }returnString = filesStr.toString()}else if (object in CompileOptions){StringBuilder compileOptionsStr = new StringBuilder()def compileProperties = object.propertiescompileProperties.each{ compileProperty ->if (compileProperty.value in DebugOptions){compileOptionsStr << "\t" << compileProperty.key << ": " << extractStringRepresentation(compileProperty.value) << "\n"}else if (compileProperty.value in DependOptions){compileOptionsStr << "\t" << compileProperty.key << ": " << extractStringRepresentation(compileProperty.value) << "\n"}else if (compileProperty.value in ForkOptions){compileOptionsStr << "\t" << compileProperty.key << ": " << extractStringRepresentation(compileProperty.value) << "\n"}else if (compileProperty.key != "class"){compileOptionsStr << "\t" << compileProperty.key << ": " << compileProperty.value << "\n"} }returnString = compileOptionsStr.toString()}else if (object in DebugOptions){returnString = "\t${object.debugLevel}"}else if (object in DependOptions){returnString = "\t${object.classpath}"}else if (object in ForkOptions){returnString = "\t${object.executable} executable with ${object.tempDir} temp directory" }else if (object in Set || object in Boolean || object in Number || object in Enum){returnString = "\t${object.toString()}\n"}else if (object in Manifest){StringBuilder manifestStr = new StringBuilder()def manifestAttributes = object.getAttributes()manifestAttributes.each{ manifestAttribute ->manifestStr << "\t" << manifestAttribute.key << ": " << manifestAttribute.value << "\n" }returnString = manifestStr.toString()}else if (object in MinimalJavadocOptions){returnString = extractJavadocOptionsAsString(object)}else if (object == null){returnString = "\tnull\n"}else{returnString = "\t${object?.class} was unexpected type.\n"}return returnString }def String extractJavadocOptionsAsString(MinimalJavadocOptions javadocOptions) {StringBuilder javadocOptionsStr = new StringBuilder()javadocOptionsStr << "\tjavadoc.bootClasspath:"def bootClasspathFiles = javadocOptions.bootClasspathbootClasspathFiles.each{ bootClasspathFile ->javadocOptionsStr << "\t\t" << bootClasspathFile.canonicalName << "\n" }javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.classpath:"def classpathFiles = javadocOptions.classpathclasspathFiles.each{ classpathFile ->javadocOptionsStr << "\t\t" << classpathFile.canonicalName << "\n"}javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.destinationDirectory: " << javadocOptions.destinationDirectory?.canonicalName << "\n"javadocOptionsStr << "\tjavadocOptions.doclet: " << javadocOptions.doclet << "\n"javadocOptionsStr << "\tjavadocOptions.docletpath:"def docletpath = javadocOptions.docletpathdocletpath.each{ docletEntry ->javadocOptionsStr << "\t\t" << docletEntry.canonicalName << "\n"}javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.encoding: " << javadocOptions.encoding << "\n"javadocOptionsStr << "\tjavadocOptions.extDirs:"def extDirs = javadocOptions.extDirsextDirs.each{ extDir ->javadocOptionsStr << "\t\t" << extDir.canonicalName << "\n"}javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.header: " << javadocOptions.header << "\n"javadocOptionsStr << "\tjavadocOptions.JFlags:"def jflags = javadocOptions.JFlagsjflags.each{ jflag ->javadocOptionsStr << "\t\t" << jflag << "\n"}javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.locale: " << javadocOptions.locale << "\n"javadocOptionsStr << "\tjavadocOptions.memberLevel: " << javadocOptions.memberLevel << "\n"javadocOptionsStr << "\tjavadocOptions.optionFiles:"def optionFiles = javadocOptions.optionFilesoptionFiles.each{ optionFile ->javadocOptionsStr << "\t\t" << optionFile.canonicalName << "\n"}javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.outputLevel: " << javadocOptions.outputLevel << "\n"javadocOptionsStr << "\tjavadocOptions.overview: " << javadocOptions.overview << "\n"javadocOptionsStr << "\tjavadocOptions.source: " << javadocOptions.source << "\n"javadocOptionsStr << "\tjavadocOptions.sourceNames:"def sourceNames = javadocOptions.sourceNamessourceNames.each{ sourceName ->javadocOptionsStr << "\t\t" << sourceName << "\n"}javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.windowTitle: " << javadocOptions.windowTitle << "\n"return javadocOptionsStr.toString() }def printHeader(String headerText) {println headerSeparatorprintln "= ${headerText.center(MAX_COLUMNS-4)} ="println headerSeparator }我在此構(gòu)建文件中使用了Groovy @Field批注 ,以使對其應(yīng)用到的變量可用于構(gòu)建文件中的方法。 @Field注釋直到Groovy 1.8才可用,這使我想起了有關(guān)Gradle和Groovy的其他重要信息:Gradle使用其自己的預(yù)包裝Groovy,而不是可能在自己的計(jì)算機(jī)上安裝的任何其他版本的Groovy。 您可以使用gradle --version命令確定哪個版本的Groovy。 下一個屏幕快照展示了我的Groovy版本( 2.1.6 ) 與我的Gradle安裝(版本1.10)使用的Groovy版本(1.8.6)不同。 因?yàn)镚radle 1.10隨Groovy 1.8.6一起提供 ,所以我可以使用@Field注釋 。
由于最后一個腳本的輸出太長了,因此我在這里將其顯示為文本而不是圖像。
在build-java-plugin-metadata.gradle上運(yùn)行Running Gradle的輸出
================================================================================ = compileJava Task = ================================================================================ compileJava.classpath:compileJava.destinationDir:C:\java\examples\groovyExamples\gradleExample\build\classes\maincompileJava.source:C:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\Main.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\Main2.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\Main3.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\Main4.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\Temperature.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\TemperatureScale.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\TemperatureUnit.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\TemperatureUnit2.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\TemperatureUnit3.javacompileJava.options:bootClasspath: nullfork: falseencoding: nulldeprecation: falsewarnings: trueforkOptions: null executable with null temp directoryfailOnError: trueuseDepend: falseincludeJavaRuntime: falseuseAnt: falsecompilerArgs: []debug: trueextensionDirs: nullcompiler: nulldebugOptions: nullverbose: falseoptimize: falsedependOptions: listFiles: falsecompileJava.includes:[]compileJava.excludes:[]compileJava.sourceCompatibility:1.7compileJava.targetCompatibility:1.7================================================================================ = jar Task = ================================================================================ jar.appendix:nulljar.archiveName:gradleExample.jarjar.archivePath:C:\java\examples\groovyExamples\gradleExample\build\libs\gradleExample.jarjar.baseName:gradleExamplejar.caseSensitive:truejar.classifier:jar.destinationDir:C:\java\examples\groovyExamples\gradleExample\build\libsjar.dirMode:nulljar.duplicatesStrategy:INCLUDEjar.entryCompression:DEFLATEDjar.excludes:[]jar.extension:jarjar.fileMode:nulljar.includeEmptyDirs:truejar.includes:[]jar.manifest:Manifest-Version: 1.0jar.source:C:\java\examples\groovyExamples\gradleExample\build\tmp\jar\MANIFEST.MFjar.version:null================================================================================ = javadoc Task = ================================================================================ javadoc.classpath:C:\java\examples\groovyExamples\gradleExample\build\classes\mainC:\java\examples\groovyExamples\gradleExample\build\resources\mainjavadoc.destinationDir:C:\java\examples\groovyExamples\gradleExample\build\docs\javadocjavadoc.excludes:[]javadoc.executable:nulljavadoc.failOnError:truejavadoc.includes:[]javadoc.maxMemory:nulljavadoc.options:javadoc.bootClasspath:javadocOptions.classpath:javadocOptions.destinationDirectory: nulljavadocOptions.doclet: nulljavadocOptions.docletpath:javadocOptions.encoding: nulljavadocOptions.extDirs:javadocOptions.header: nulljavadocOptions.JFlags:javadocOptions.locale: nulljavadocOptions.memberLevel: nulljavadocOptions.optionFiles:javadocOptions.outputLevel: QUIETjavadocOptions.overview: nulljavadocOptions.source: nulljavadocOptions.sourceNames:javadocOptions.windowTitle: nulljavadoc.source:C:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\Main.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\Main2.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\Main3.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\Main4.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\Temperature.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\TemperatureScale.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\TemperatureUnit.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\TemperatureUnit2.javaC:\java\examples\groovyExamples\gradleExample\src\main\java\dustin\examples\TemperatureUnit3.javajavadoc.title:gradleExample API:helpWelcome to Gradle 1.10.To run a build, run gradle ...To see a list of available tasks, run gradle tasksTo see a list of command-line options, run gradle --helpBUILD SUCCESSFULTotal time: 14.041 secs上面顯示的示例可以很好地識別與Java Gradle插件關(guān)聯(lián)的特定屬性。 這很好用,但是它的局限性包括需要為每個需要其值的屬性編寫顯式代碼。 這意味著沒有必要知道所有可用屬性的進(jìn)一步限制(我使用文檔在上面的示例中顯式輸出了值)。 進(jìn)一步暗示的限制是,上面的腳本將來將不會顯示添加到這些任務(wù)的任何屬性值。 下一個Gradle構(gòu)建示例基于先前的示例,但是此示例未明確聲明要顯示的任務(wù)和屬性。 而是查找與根項(xiàng)目關(guān)聯(lián)的所有任務(wù),然后打印與每個任務(wù)關(guān)聯(lián)的所有屬性。
構(gòu)建java插件元數(shù)據(jù)反射.gradle
// build-java-plugin-metadata-reflection.gradle // // Displays the properties associated with the tasks associated with the Gradle // root project. //import groovy.transform.Fieldapply plugin: 'java'@Field int MAX_COLUMNS = 80 @Field String headerSeparator = "=".multiply(MAX_COLUMNS)def rootProject = getRootProject() def tasks = rootProject.tasks tasks.each { task ->printTaskProperties(task) }def printTaskProperties(Task task) {printHeader("Task " + task.name)def taskProperties = task.propertiestaskProperties.each{ taskProperty ->println "${task.name}.${taskProperty.key}=${extractStringRepresentation(taskProperty.value)}"} }def String extractStringRepresentation(Object object) {String returnStringif (object in String){returnString = "\t${object}\n"}else if (object in File){returnString = "\t${object.canonicalPath}\n"}else if (object in FileCollection) // FileTree is a FileCollection{StringBuilder filesStr = new StringBuilder()def files = object.filesfiles.each{ file ->filesStr << "\t" << file.canonicalPath << "\n" }returnString = filesStr.toString()}else if (object in CompileOptions){StringBuilder compileOptionsStr = new StringBuilder()def compileProperties = object.propertiescompileProperties.each{ compileProperty ->if (compileProperty.value in DebugOptions){compileOptionsStr << "\t" << compileProperty.key << ": " << extractStringRepresentation(compileProperty.value) << "\n"}else if (compileProperty.value in DependOptions){compileOptionsStr << "\t" << compileProperty.key << ": " << extractStringRepresentation(compileProperty.value) << "\n"}else if (compileProperty.value in ForkOptions){compileOptionsStr << "\t" << compileProperty.key << ": " << extractStringRepresentation(compileProperty.value) << "\n"}else if (compileProperty.key != "class"){compileOptionsStr << "\t" << compileProperty.key << ": " << compileProperty.value << "\n"} }returnString = compileOptionsStr.toString()}else if (object in DebugOptions){returnString = "\t${object.debugLevel}"}else if (object in DependOptions){returnString = "\t${object.classpath}"}else if (object in ForkOptions){returnString = "\t${object.executable} executable with ${object.tempDir} temp directory" }else if (object in Set || object in List || object in Boolean || object in Number || object in Enum || object in Class){returnString = "\t${object.toString()}\n"}else if (object in Manifest){StringBuilder manifestStr = new StringBuilder()def manifestAttributes = object.getAttributes()manifestAttributes.each{ manifestAttribute ->manifestStr << "\t" << manifestAttribute.key << ": " << manifestAttribute.value << "\n" }returnString = manifestStr.toString()}else if (object in MinimalJavadocOptions){returnString = extractJavadocOptionsAsString(object)}else if (object in Convention){StringBuilder conventionStr = new StringBuilder()object.plugins.each?.keyset{ plugin ->conventionStr << "\t" << plugin << "\n"}returnString = conventionStr.toString()}else if (object in LoggingManager){returnString = "\n\tCurrent Log Level: ${object.level}\n\tStandard Error: ${object.standardErrorCaptureLevel}\n\tStandard Output: ${object.standardOutputCaptureLevel}\n"}else if (object == null){returnString = "\tnull\n"}else{returnString = "\t${object?.class} was unexpected type with value of ${object}.\n"}return returnString }def String extractJavadocOptionsAsString(MinimalJavadocOptions javadocOptions) {StringBuilder javadocOptionsStr = new StringBuilder()javadocOptionsStr << "\tjavadoc.bootClasspath:"def bootClasspathFiles = javadocOptions.bootClasspathbootClasspathFiles.each{ bootClasspathFile ->javadocOptionsStr << "\t\t" << bootClasspathFile.canonicalName << "\n" }javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.classpath:"def classpathFiles = javadocOptions.classpathclasspathFiles.each{ classpathFile ->javadocOptionsStr << "\t\t" << classpathFile.canonicalName << "\n"}javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.destinationDirectory: " << javadocOptions.destinationDirectory?.canonicalName << "\n"javadocOptionsStr << "\tjavadocOptions.doclet: " << javadocOptions.doclet << "\n"javadocOptionsStr << "\tjavadocOptions.docletpath:"def docletpath = javadocOptions.docletpathdocletpath.each{ docletEntry ->javadocOptionsStr << "\t\t" << docletEntry.canonicalName << "\n"}javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.encoding: " << javadocOptions.encoding << "\n"javadocOptionsStr << "\tjavadocOptions.extDirs:"def extDirs = javadocOptions.extDirsextDirs.each{ extDir ->javadocOptionsStr << "\t\t" << extDir.canonicalName << "\n"}javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.header: " << javadocOptions.header << "\n"javadocOptionsStr << "\tjavadocOptions.JFlags:"def jflags = javadocOptions.JFlagsjflags.each{ jflag ->javadocOptionsStr << "\t\t" << jflag << "\n"}javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.locale: " << javadocOptions.locale << "\n"javadocOptionsStr << "\tjavadocOptions.memberLevel: " << javadocOptions.memberLevel << "\n"javadocOptionsStr << "\tjavadocOptions.optionFiles:"def optionFiles = javadocOptions.optionFilesoptionFiles.each{ optionFile ->javadocOptionsStr << "\t\t" << optionFile.canonicalName << "\n"}javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.outputLevel: " << javadocOptions.outputLevel << "\n"javadocOptionsStr << "\tjavadocOptions.overview: " << javadocOptions.overview << "\n"javadocOptionsStr << "\tjavadocOptions.source: " << javadocOptions.source << "\n"javadocOptionsStr << "\tjavadocOptions.sourceNames:"def sourceNames = javadocOptions.sourceNamessourceNames.each{ sourceName ->javadocOptionsStr << "\t\t" << sourceName << "\n"}javadocOptionsStr << "\n"javadocOptionsStr << "\tjavadocOptions.windowTitle: " << javadocOptions.windowTitle << "\n"return javadocOptionsStr.toString() }def printHeader(String headerText) {println headerSeparatorprintln "= ${headerText.center(MAX_COLUMNS-4)} ="println headerSeparator }因?yàn)榇溯敵鍪轻槍εcGradle構(gòu)建的根項(xiàng)目相關(guān)聯(lián)的所有Tasks相關(guān)的所有屬性,所以輸出太長而無法在此處包含。 并非所有的屬性值實(shí)例都具有extractStringRepresentation(Object object)方法準(zhǔn)備處理的類,但是可以將這些情況添加到該方法的if-else if結(jié)構(gòu)中以進(jìn)行處理。 此版本的Gradle構(gòu)建比早期版本更通用,并打印出與Task關(guān)聯(lián)的屬性,這些屬性按Task分組。
由于Gradle構(gòu)建與Groovy緊密耦合,因此可以使用Groovy語法和功能來了解有關(guān)Gradle構(gòu)建的更多信息。 這篇文章中的示例利用了許多Groovy的優(yōu)點(diǎn)。 上面的Gradle構(gòu)建代碼之所以如此冗長,是因?yàn)榇蠖鄶?shù)用于屬性值的Gradle類都沒有重寫toString()方法,因此,如果沒有特殊的代碼來調(diào)用特定的方法來獲得有用的表示,就不會顯示出真正有用的輸出 。 在本文的示例中我沒有這樣做,但是要解決缺少覆蓋的toString()方法的另一種方法是使用Groovy的攔截功能 ( metaClass.invokeMethod )攔截對toString()調(diào)用并提供覆蓋的版本。 那將基本上與上面使用的代碼相同,但是將被封裝在攔截對象中,而不是包含在腳本代碼中。
結(jié)論
Gradle確實(shí)有很好的文檔(特別是Gradle用戶指南和Gradle構(gòu)建語言參考 ),并且可以從該文檔中輕松訪問與Java Plugin for Gradle(和其他插件)相關(guān)的大多數(shù)任務(wù)和屬性。 但是,我想知道如何以編程方式識別重要的約定,以防萬一文檔被誤解,或者我使用的版本與文檔所支持的版本不同。 這篇文章的另一個目的是演示與Gradle合作時了解Groovy的有用性。 出于這個原因,我相信Gradle日益重要的地位不免會增加對Groovy的興趣。
翻譯自: https://www.javacodegeeks.com/2014/01/identifying-gradle-conventions.html
總結(jié)
以上是生活随笔為你收集整理的识别Gradle约定的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux网络命令详解(linux网络
- 下一篇: 为什么iphone6splus充电头会发