diff --git a/build.gradle.kts b/build.gradle.kts index 65b0729..da1fb7c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,307 +14,381 @@ * limitations under the License. */ -import java.nio.file.Paths + +import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask import java.time.Instant +import java.util.* +import kotlin.reflect.KMutableProperty +import kotlin.reflect.full.declaredMemberProperties -buildscript { - // load properties from custom location - def propsFile = Paths.get("${projectDir}/../../gradle.properties").normalize().toFile() - if (propsFile.canRead()) { - println("Loading custom property data from: ${propsFile}") +/////////////////////////////// +////// PUBLISH TO SONATYPE / MAVEN CENTRAL +////// +////// TESTING : local maven repo +////// +////// RELEASE : sonatype / maven central, then +/////////////////////////////// - def props = new Properties() - propsFile.withInputStream {props.load(it)} - props.each {key, val -> project.ext.set(key, val)} - } - else { - ext.sonatypeUsername = "" - ext.sonatypePassword = "" - } - - // for plugin publishing and license sources - repositories { - maven {url "https://plugins.gradle.org/m2/"} - } - dependencies { - // this is the only way to also get the source code for IDE auto-complete - classpath "gradle.plugin.com.dorkbox:Licensing:1.2.2" - classpath "gradle.plugin.com.dorkbox:Licensing:1.2.2:sources" - } -} +println("\tGradle ${project.gradle.gradleVersion}") plugins { - id 'java' - id 'maven-publish' - id 'signing' + java + signing + `maven-publish` // close and release on sonatype - id 'io.codearte.nexus-staging' version '0.11.0' + id("io.codearte.nexus-staging") version "0.20.0" - id "com.dorkbox.CrossCompile" version "1.0.1" - id "com.dorkbox.VersionUpdate" version "1.2" + id("com.dorkbox.CrossCompile") version "1.0.1" + id("com.dorkbox.Licensing") version "1.4" + id("com.dorkbox.VersionUpdate") version "1.4.1" - // setup checking for the latest version of a plugin or dependency (and updating the gradle build) - id "se.patrikerdes.use-latest-versions" version "0.2.3" - id 'com.github.ben-manes.versions' version '0.16.0' + // setup checking for the latest version of a plugin or dependency + id("com.github.ben-manes.versions") version "0.21.0" + + kotlin("jvm") version "1.3.21" } -// this is the only way to also get the source code for IDE auto-complete -apply plugin: "com.dorkbox.Licensing" +object Extras { + // set for the project + const val description = "Unbuffered input and ANSI output support for Linux, MacOS, or Windows for Java 6+" + const val group = "com.dorkbox" + const val version = "3.6" -// give us access to api/implementation differences for building java libraries -apply plugin: 'java-library' + // set as project.ext + const val name = "Console" + const val id = "Console" + const val vendor = "Dorkbox LLC" + const val url = "https://git.dorkbox.com/dorkbox/Console" + val buildDate = Instant.now().toString() + val JAVA_VERSION = JavaVersion.VERSION_1_6.toString() + var sonatypeUserName = "" + var sonatypePassword = "" +} -project.description = 'Unbuffered input and ANSI output support for Linux, MacOS, or Windows for Java 6+' -project.group = 'com.dorkbox' -project.version = '3.6' +/////////////////////////////// +///// assign 'Extras' +/////////////////////////////// +description = Extras.description +group = Extras.group +version = Extras.version -project.ext.name = 'Console' -project.ext.url = 'https://git.dorkbox.com/dorkbox/Console' +val propsFile = File("$projectDir/../../gradle.properties").normalize() +if (propsFile.canRead()) { + println("\tLoading custom property data from: [$propsFile]") + val props = Properties() + propsFile.inputStream().use { + props.load(it) + } -sourceCompatibility = JavaVersion.VERSION_1_6 -targetCompatibility = JavaVersion.VERSION_1_6 + val extraProperties = Extras::class.declaredMemberProperties.filterIsInstance>() + props.forEach { (k, v) -> run { + val key = k as String + val value = v as String + + val member = extraProperties.find { it.name == key } + if (member != null) { + member.setter.call(Extras::class.objectInstance, value) + } + else { + project.extra.set(k, v) + } + }} +} licensing { license(License.APACHE_2) { - author 'dorkbox, llc' - url project.ext.url - note project.description + author(Extras.vendor) + url(Extras.url) + note(Extras.description) + note("Copyright 2011 - 2014, XIAM Solutions B.V. (http://www.xiam.nl)") } - license('Dorkbox Utils', License.APACHE_2) { - author 'dorkbox, llc' - url 'https://git.dorkbox.com/dorkbox/Utilities' + + license("Dorkbox Utils", License.APACHE_2) { + author(Extras.vendor) + url("https://git.dorkbox.com/dorkbox/Utilities") } - license('JAnsi', License.APACHE_2) { - copyright 2009 - author 'Progress Software Corporation' - author 'Joris Kuipers' - author 'Jason Dillon' - author 'Hiram Chirino' - url 'https://github.com/fusesource/jansi' + license("JAnsi", License.APACHE_2) { + copyright(2009) + author("Progress Software Corporation") + author("Joris Kuipers") + author("Jason Dillon") + author("Hiram Chirino") + url("https://github.com/fusesource/jansi") } - license('JLine2', License.BSD_2) { - copyright 2012 - author 'Marc Prud\'hommeaux ' - author 'Daniel Doubrovkine' - author 'Torbjorn Granlund' - author 'David MacKenzie' - url 'https://github.com/jline/jline2' + license("JLine2", License.BSD_2) { + copyright(2012) + author("'Marc Prud\'hommeaux '") + author("Daniel Doubrovkine") + author("Torbjorn Granlund") + author("David MacKenzie") + url("https://github.com/jline/jline2") } - license('JNA', License.APACHE_2) { - copyright 2011 - author 'Timothy Wall' - url 'https://github.com/twall/jna' + license("JNA", License.APACHE_2) { + copyright(2011) + author("Timothy Wall") + url("https://github.com/twall/jna") } - license('SLF4J', License.MIT) { - copyright 2008 - author 'QOS.ch' - url 'http://www.slf4j.org' + license("SLF4J", License.MIT) { + copyright(2008) + author("QOS.ch") + url("http://www.slf4j.org") } } sourceSets { main { java { - setSrcDirs Collections.singletonList('src') + setSrcDirs(listOf("src")) + + // want to include java files for the source. 'setSrcDirs' resets includes... + include("**/*.java") } } } - repositories { mavenLocal() // this must be first! jcenter() } - -dependencies { - // utilities dependencies compile only - compileOnly(project('Utilities')) - - // our main dependencies are ALSO the same as the limited utilities (they are not automatically pulled in from other sourceSets) - // needed by the utilities (custom since we don't want to include everything). IntelliJ includes everything, but our builds do not - - api 'net.java.dev.jna:jna:4.5.2' - api 'net.java.dev.jna:jna-platform:4.5.2' - - api 'org.slf4j:slf4j-api:1.7.25' -} - /////////////////////////////// -////// Task defaults +////// UTILITIES COMPILE /////////////////////////////// -tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' -} -tasks.withType(Jar) { - duplicatesStrategy DuplicatesStrategy.FAIL +// as long as the 'Utilities' project is ALSO imported into IntelliJ, class resolution will work (add the sources in the intellij project) +val utils : Configuration by configurations.creating - manifest { - attributes['Implementation-Version'] = version - attributes['Build-Date'] = Instant.now().toString() - attributes['Automatic-Module-Name'] = project.ext.name.toString() - } -} +fun javaFile(vararg fileNames: String): Iterable { + val fileList = ArrayList(fileNames.size) -/////////////////////////////// -////// UTILITIES COMPILE (for inclusion into jars) -/////////////////////////////// -static String[] utilFiles(String... fileNames) { - def fileList = [] as ArrayList - - for (name in fileNames) { - def fixed = name.replace('.', '/') + '.java' - fileList.add(fixed) + fileNames.forEach { name -> + fileList.add(name.replace('.', '/') + ".java") } return fileList } -task compileUtils(type: JavaCompile) { +task("compileUtils") { // we don't want the default include of **/*.java - getIncludes().clear() + includes.clear() - source = Collections.singletonList('../Utilities/src') + source = fileTree("../Utilities/src") + include(javaFile( + "dorkbox.util.OS", + "dorkbox.util.OSType", + "dorkbox.util.Property", + "dorkbox.util.FastThreadLocal", + "dorkbox.util.bytes.ByteBuffer2", - include utilFiles('dorkbox.util.OS', - 'dorkbox.util.OSType', - 'dorkbox.util.Property', - 'dorkbox.util.FastThreadLocal', - 'dorkbox.util.bytes.ByteBuffer2', + "dorkbox.util.jna.JnaHelper", + "dorkbox.util.jna.windows.Kernel32", + "dorkbox.util.jna.windows.structs.CONSOLE_SCREEN_BUFFER_INFO", + "dorkbox.util.jna.windows.structs.INPUT_RECORD", + "dorkbox.util.jna.windows.structs.SMALL_RECT", + "dorkbox.util.jna.windows.structs.COORD", + "dorkbox.util.jna.windows.structs.MOUSE_EVENT_RECORD", + "dorkbox.util.jna.windows.structs.KEY_EVENT_RECORD", + "dorkbox.util.jna.windows.structs.CharUnion", - 'dorkbox.util.jna.JnaHelper', - 'dorkbox.util.jna.windows.Kernel32', - 'dorkbox.util.jna.windows.structs.CONSOLE_SCREEN_BUFFER_INFO', - 'dorkbox.util.jna.windows.structs.INPUT_RECORD', - 'dorkbox.util.jna.windows.structs.SMALL_RECT', - 'dorkbox.util.jna.windows.structs.COORD', - 'dorkbox.util.jna.windows.structs.MOUSE_EVENT_RECORD', - 'dorkbox.util.jna.windows.structs.KEY_EVENT_RECORD', - 'dorkbox.util.jna.windows.structs.CharUnion', + "dorkbox.util.jna.linux.CLibraryPosix", + "dorkbox.util.jna.linux.structs.Termios" + )) - 'dorkbox.util.jna.linux.CLibraryPosix', - 'dorkbox.util.jna.linux.structs.Termios') - - classpath = sourceSets.main.compileClasspath + classpath = files(utils) destinationDir = file("$rootDir/build/classes_utilities") } -jar { - dependsOn compileUtils +/////////////////////////////// +////// Task defaults +/////////////////////////////// +tasks.withType { + options.encoding = "UTF-8" - // include applicable class files from subset of Utilities project - from compileUtils.destinationDir + sourceCompatibility = Extras.JAVA_VERSION + targetCompatibility = Extras.JAVA_VERSION } -///////////////////////////// -//// Maven Publishing + Release -///////////////////////////// -task sourceJar(type: Jar) { +tasks.jar.get().apply { + // include applicable class files from subset of Utilities project + from((tasks["compileUtils"] as JavaCompile).outputs) + + manifest { + // https://docs.oracle.com/javase/tutorial/deployment/jar/packageman.html + attributes["Name"] = Extras.name + + attributes["Specification-Title"] = Extras.name + attributes["Specification-Version"] = Extras.version + attributes["Specification-Vendor"] = Extras.vendor + + attributes["Implementation-Title"] = "${Extras.group}.${Extras.id}" + attributes["Implementation-Version"] = Extras.buildDate + attributes["Implementation-Vendor"] = Extras.vendor + } +} + +tasks.compileJava.get().apply { + println("\tCompiling classes to Java $sourceCompatibility") +} + + +dependencies { + // add compile utils to dependencies + implementation(files((tasks["compileUtils"] as JavaCompile).outputs)) + + val jna = api("net.java.dev.jna:jna:4.5.2") + val jnaPlatform = api("net.java.dev.jna:jna-platform:4.5.2") + + api("org.slf4j:slf4j-api:1.7.25") + + utils.dependencies += listOf(jna, jnaPlatform) +} + +/////////////////////////////// +////// PUBLISH TO SONATYPE / MAVEN CENTRAL +////// +////// TESTING : local maven repo +////// +////// RELEASE : sonatype / maven central, then +/////////////////////////////// +val sourceJar = task("sourceJar") { description = "Creates a JAR that contains the source code." - from sourceSets.main.java + from(sourceSets["main"].java) - classifier = "sources" + archiveClassifier.set("sources") } -task javaDocJar(type: Jar) { +val javaDocJar = task("javaDocJar") { description = "Creates a JAR that contains the javadocs." - classifier = "javadoc" + archiveClassifier.set("javadoc") } -// for testing, we don't publish to maven central, but only to local maven publishing { publications { - maven(MavenPublication) { - from components.java + create("maven") { + groupId = Extras.group + artifactId = Extras.id + version = Extras.version + + from(components["java"]) - artifact(javaDocJar) artifact(sourceJar) - - groupId project.group - artifactId project.ext.name - version project.version + artifact(javaDocJar) pom { - name = project.ext.name - url = project.ext.url - description = project.description + name.set(Extras.name) + description.set(Extras.description) + url.set(Extras.url) issueManagement { - url = "${project.ext.url}/issues".toString() - system = 'Gitea Issues' + url.set("${Extras.url}/issues") + system.set("Gitea Issues") } - organization { - name = 'dorkbox, llc' - url = 'https://dorkbox.com' + name.set(Extras.vendor) + url.set("https://dorkbox.com") } - developers { developer { - name = 'dorkbox, llc' - email = 'email@dorkbox.com' + id.set("dorkbox") + name.set(Extras.vendor) + email.set("email@dorkbox.com") } } - scm { - url = project.ext.url - connection = "scm:${project.ext.url}.git".toString() + url.set(Extras.url) + connection.set("scm:${Extras.url}.git") } } + + } + } + + + repositories { + maven { + setUrl("https://oss.sonatype.org/service/local/staging/deploy/maven2") + credentials { + username = Extras.sonatypeUserName + password = Extras.sonatypePassword + } } } - repositories { - maven { - url "https://oss.sonatype.org/service/local/staging/deploy/maven2" - credentials { - username sonatypeUsername - password sonatypePassword - } + + tasks.withType { + onlyIf { + publication == publishing.publications["maven"] && repository == publishing.repositories["maven"] } } + + tasks.withType { + onlyIf { + publication == publishing.publications["maven"] + } + } + + // output the release URL in the console + tasks["releaseRepository"].doLast { + val url = "https://oss.sonatype.org/content/repositories/releases/" + val projectName = Extras.group.replace('.', '/') + val name = Extras.name + val version = Extras.version + + println("Maven URL: $url$projectName/$name/$version/") + } } nexusStaging { - username sonatypeUsername - password sonatypePassword + username = Extras.sonatypeUserName + password = Extras.sonatypePassword } signing { - sign publishing.publications.maven + sign(publishing.publications["maven"]) } -// output the release URL in the console -releaseRepository.doLast { - def URL = 'https://oss.sonatype.org/content/repositories/releases/' - def projectName = project.group.toString().replaceAll('\\.', '/') - def name = project.ext.name - def version = project.version - println("Maven URL: ${URL}${projectName}/${name}/${version}/") -} -// we don't use maven with the plugin (it's uploaded separately to gradle plugins) -tasks.withType(PublishToMavenRepository) { - onlyIf { - repository == publishing.repositories.maven && publication == publishing.publications.maven +/////////////////////////////// +///// Prevent anything other than a release from showing version updates +//// https://github.com/ben-manes/gradle-versions-plugin/blob/master/README.md +/////////////////////////////// +tasks.named("dependencyUpdates") { + resolutionStrategy { + componentSelection { + all { + val rejected = listOf("alpha", "beta", "rc", "cr", "m", "preview") + .map { qualifier -> Regex("(?i).*[.-]$qualifier[.\\d-]*") } + .any { it.matches(candidate.version) } + if (rejected) { + reject("Release candidate") + } + } + } } + + // optional parameters + checkForGradleUpdate = true } -tasks.withType(PublishToMavenLocal) { - onlyIf { - publication == publishing.publications.maven - } + + +/////////////////////////////// +////// Gradle Wrapper Configuration. +///// Run this task, then refresh the gradle project +/////////////////////////////// +val wrapperUpdate by tasks.creating(Wrapper::class) { + gradleVersion = "5.2.1" + distributionUrl = distributionUrl.replace("bin", "all") } diff --git a/settings.gradle.kts b/settings.gradle.kts index d9d8f9f..cce9d6c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,14 +13,3 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -include("Utilities") - -for (project in rootProject.children) { - project.projectDir = file("../$project.name") - project.buildFileName = "utilities.gradle" - - assert (project.projectDir.directory) - assert (project.buildFile.file) -} - -enableFeaturePreview('STABLE_PUBLISHING')