commit 4b8f7803f37bc4c732a293077d9a09d788f75090 Author: Jörg Prante Date: Tue Nov 9 14:08:25 2021 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..acc234e --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +data +work +logs +build +target +/.idea +.DS_Store +*.iml +/.settings +/.classpath +/.project +/.gradle +*~ +*.orig diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..c42a779 --- /dev/null +++ b/build.gradle @@ -0,0 +1,28 @@ + +wrapper { + gradleVersion = "${project.property('gradle.wrapper.version')}" + distributionType = Wrapper.DistributionType.ALL +} + +ext { + user = 'jprante' + name = 'gradle-plugins' + description = 'Gradle plugins' + inceptionYear = '2021' + url = 'https://github.com/' + user + '/' + name + scmUrl = 'https://github.com/' + user + '/' + name + scmConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git' + scmDeveloperConnection = 'scm:git:ssh://git@github.com:' + user + '/' + name + '.git' + issueManagementSystem = 'Github' + issueManagementUrl = ext.scmUrl + '/issues' + licenseName = 'The Apache License, Version 2.0' + licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' +} + +subprojects { + apply plugin: 'java-library' + apply from: rootProject.file('gradle/ide/idea.gradle') + apply from: rootProject.file('gradle/compile/java.gradle') + apply from: rootProject.file('gradle/test/junit5.gradle') + apply from: rootProject.file('gradle/repositories/maven.gradle') +} diff --git a/gradle-plugin-docker/LICENSE.txt b/gradle-plugin-docker/LICENSE.txt new file mode 100644 index 0000000..8dada3e --- /dev/null +++ b/gradle-plugin-docker/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/gradle-plugin-docker/NOTICE.txt b/gradle-plugin-docker/NOTICE.txt new file mode 100644 index 0000000..a535351 --- /dev/null +++ b/gradle-plugin-docker/NOTICE.txt @@ -0,0 +1,6 @@ + +This work is derived from + +https://github.com/Itiviti/gradle-docker-build-plugin + +(Apache License 2.0) diff --git a/gradle-plugin-docker/README.adoc b/gradle-plugin-docker/README.adoc new file mode 100644 index 0000000..cfe8f17 --- /dev/null +++ b/gradle-plugin-docker/README.adoc @@ -0,0 +1,81 @@ += Gradle Plugin for Docker + +This repository provides a Gradle plugin for working with Docker. + +The plugin contains tasks for building and pushing +images based on a simple configuration block that specifies the container +name, the `Dockerfile`, task dependencies, and any additional file resources +required for the Docker build; tasks for populating placeholders in a +docker-compose template file with image versions resolved from +dependencies; and tasks for starting, stopping, and cleaning +up a named container based on a specified image + +== Documentation + +=== Tasks + +There are two task types + +* `DockerBuildTask` : task type for building a docker image +* `DockerPushTask` : task type for pushing a docker image + +Apply the plugin using standard gradle convention: + +[source] +---- +plugins { + id 'org.xbib.gradle.plugin.docker' version '' +} +---- + +=== Extensions + +The extension with name `docker` has the following attributes: + +- `enabled` if the task is enabled or not, default is `true` +- `executableName` the executable name of the docker binary, default is `docker` +- `registry` the DNS name of the registry, default is empty +- `imageName` the docker image name, default is empty +- `tag` the docker image tag, default is empty (which means `latest` in docker terminology) + +[source] +---- +docker { + enabled = true + registry = 'myhost.mydomain' + imageName = 'myimage' + tag = 'mytag' +} +---- + +=== Build a Docker image + +To build a docker image, run a task with type `DockerBuildTask`. + +==== Example + +[source] +---- +plugins { + id 'distribution' + id 'org.xbib.gradle.plugin.docker' +} + +task buildDockerImage(type: DockerBuildTask, group: 'docker') { + registry = 'hub.docker.com' + imageName = 'username/my-app' + tag = 'mytag' + dockerfile { + add(tasks.distTar.outputs.files.singleFile, '/') + } +} +---- + +=== Push a Docker image + +To push an image to a docker image repository, run a task with tyep `DockerPushTask` + + +== License + +This plugin is made available under the http://www.apache.org/licenses/LICENSE-2.0[Apache 2.0 License]. diff --git a/gradle-plugin-docker/build.gradle b/gradle-plugin-docker/build.gradle new file mode 100644 index 0000000..ec5a529 --- /dev/null +++ b/gradle-plugin-docker/build.gradle @@ -0,0 +1,65 @@ +plugins { + id 'java-gradle-plugin' + id 'groovy' + id 'com.gradle.plugin-publish' version '0.17.0' +} + +ext { + user = 'jprante' + name = 'gradle-plugin-docker' + description = 'Docker support in a Gradle plugin' + inceptionYear = '2016' + url = 'https://github.com/' + user + '/' + name + scmUrl = 'https://github.com/' + user + '/' + name + scmConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git' + scmDeveloperConnection = 'scm:git:ssh://git@github.com:' + user + '/' + name + '.git' + issueManagementSystem = 'Github' + issueManagementUrl = ext.scmUrl + '/issues' + licenseName = 'The Apache License, Version 2.0' + licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' +} + +dependencies { + api gradleApi() + implementation "org.codehaus.groovy:groovy-all:${project.property('groovy.version')}" + testImplementation gradleTestKit() +} + +compileGroovy { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +compileTestGroovy { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +validatePlugins { + failOnWarning = false +} + +gradlePlugin { + plugins { + dockerPlugin { + id = 'org.xbib.gradle.plugin.docker' + implementationClass = 'org.xbib.gradle.plugin.docker.DockerPlugin' + } + } +} + +if (project.hasProperty('gradle.publish.key')) { + pluginBundle { + website = 'https://github.com/jprante/gradle-plugin-docker' + vcsUrl = 'https://github.com/jprante/gradle-plugin-docker' + plugins { + dockerPlugin { + id = 'org.xbib.gradle.plugin.docker' + version = project.version + description = rootProject.ext.description + displayName = 'Gradle Docker Plugin' + tags = ['gradle', 'docker'] + } + } + } +} diff --git a/gradle-plugin-docker/gradle.properties b/gradle-plugin-docker/gradle.properties new file mode 100644 index 0000000..5364446 --- /dev/null +++ b/gradle-plugin-docker/gradle.properties @@ -0,0 +1 @@ +version = 2.2.0 diff --git a/gradle-plugin-docker/src/main/groovy/org/xbib/gradle/plugin/docker/DockerBuildTask.groovy b/gradle-plugin-docker/src/main/groovy/org/xbib/gradle/plugin/docker/DockerBuildTask.groovy new file mode 100644 index 0000000..b70c2bf --- /dev/null +++ b/gradle-plugin-docker/src/main/groovy/org/xbib/gradle/plugin/docker/DockerBuildTask.groovy @@ -0,0 +1,116 @@ +package org.xbib.gradle.plugin.docker + +import org.gradle.api.tasks.Exec +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.Optional + +class DockerBuildTask extends Exec { + + @InputDirectory + File basePath = new File('.') + + @Input + List buildArgs = [] + + @Input + List instructions = [] + + @Optional + @Input + String baseImage + + @Optional + @Input + String maintainer + + @Input + boolean enabled = true + + @Input + String executableName = 'docker' + + @Optional + @Input + String registry + + @Input + String imageName + + @Optional + @Input + String tag + + private Dockerfile dockerfile + + DockerBuildTask() { + File file = new File(project.buildDir, 'docker-' + name) + if (!file.exists()) { + file.mkdirs() + } + this.dockerfile = new Dockerfile(project, file) + setWorkingDir(dockerfile.workingDir) + } + + void dockerfile(Closure closure) { + dockerfile.with(closure) + } + + void dockerfile(String path) { + dockerfile(project.file(path)) + } + + void dockerfile(File baseFile) { + dockerfile.extendDockerfile(baseFile) + } + + @Override + void exec() { + if (enabled) { + File file = createDockerFile() + executeStagingBacklog() + commandLine buildCommandLine(file) + super.exec() + } + } + + private File createDockerFile() { + if (!dockerfile.hasBase()) { + dockerfile.from(baseImage ? baseImage : 'scratch') + } + if (maintainer) { + dockerfile.maintainer(maintainer) + } + if (instructions) { + dockerfile.appendAll(instructions) + } + File file = new File(workingDir, 'Dockerfile') + dockerfile.writeToFile(file) + logger.info "${dockerfile.instructions}" + file + } + + private void executeStagingBacklog() { + dockerfile.stagingBacklog.each() { closure -> closure() } + } + + private List buildCommandLine(File dockerfilename) { + List list = [ executableName, 'build', basePath.path ] + if (args) { + list.addAll(args) + } + list << '-f' << dockerfilename.absoluteFile.toString() + String fullImageName = imageName + if (registry) { + fullImageName = "${registry}/${imageName}".toString() + } + if (tag) { + fullImageName = "${fullImageName}:${tag}".toString() + } + list << '-t' << fullImageName + buildArgs.each { + list << '--build-arg' << it + } + list + } +} diff --git a/gradle-plugin-docker/src/main/groovy/org/xbib/gradle/plugin/docker/DockerPlugin.groovy b/gradle-plugin-docker/src/main/groovy/org/xbib/gradle/plugin/docker/DockerPlugin.groovy new file mode 100644 index 0000000..d943903 --- /dev/null +++ b/gradle-plugin-docker/src/main/groovy/org/xbib/gradle/plugin/docker/DockerPlugin.groovy @@ -0,0 +1,32 @@ +package org.xbib.gradle.plugin.docker + +import org.gradle.api.GradleException +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.logging.Logger +import org.gradle.api.logging.Logging +import org.gradle.api.plugins.BasePlugin +import org.gradle.util.GradleVersion + +class DockerPlugin implements Plugin { + + private static final Logger logger = Logging.getLogger(DockerPlugin) + + @Override + void apply(Project project) { + checkVersion() + logger.info "Docker plugin says hello" + project.with { + plugins.apply(BasePlugin) + } + project.ext.DockerBuildTask = DockerBuildTask.class + project.ext.DockerPushTask = DockerPushTask.class + } + + private static void checkVersion() { + String version = '6.4' + if (GradleVersion.current() < GradleVersion.version(version)) { + throw new GradleException("need Gradle ${version} or higher") + } + } +} diff --git a/gradle-plugin-docker/src/main/groovy/org/xbib/gradle/plugin/docker/DockerPushTask.groovy b/gradle-plugin-docker/src/main/groovy/org/xbib/gradle/plugin/docker/DockerPushTask.groovy new file mode 100644 index 0000000..25f818c --- /dev/null +++ b/gradle-plugin-docker/src/main/groovy/org/xbib/gradle/plugin/docker/DockerPushTask.groovy @@ -0,0 +1,50 @@ +package org.xbib.gradle.plugin.docker + +import org.gradle.api.tasks.Exec +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Optional + +class DockerPushTask extends Exec { + + @Input + boolean enabled = true + + @Input + String executableName = 'docker' + + @Optional + @Input + String registry + + @Input + String imageName + + @Optional + @Input + String tag + + DockerPushTask() { + } + + @Override + void exec() { + commandLine buildCommandLine() + super.exec() + } + + private List buildCommandLine() { + List list = [ executableName, 'push' ] + if (args) { + list.addAll(args) + } + String fullImageName = imageName + if (registry) { + fullImageName = "${registry}/${imageName}".toString() + } + if (tag) { + fullImageName = "${fullImageName}:${tag}".toString() + } + list << fullImageName.toString() + list + } +} diff --git a/gradle-plugin-docker/src/main/groovy/org/xbib/gradle/plugin/docker/Dockerfile.groovy b/gradle-plugin-docker/src/main/groovy/org/xbib/gradle/plugin/docker/Dockerfile.groovy new file mode 100644 index 0000000..45714ed --- /dev/null +++ b/gradle-plugin-docker/src/main/groovy/org/xbib/gradle/plugin/docker/Dockerfile.groovy @@ -0,0 +1,134 @@ +package org.xbib.gradle.plugin.docker + +import org.gradle.api.Project +import org.gradle.api.logging.Logger +import org.gradle.api.logging.Logging + +class Dockerfile { + + private static final Logger logger = Logging.getLogger(Dockerfile) + + final Project project + + final List instructions + + final File workingDir + + final List stagingBacklog + + final Closure copyCallback + + List baseInstructions + + Dockerfile(Project project, File workingDir) { + this.project = project + this.workingDir = workingDir + this.copyCallback = { Closure copyClosure -> project.copy(copyClosure) } + this.baseInstructions = [] + this.instructions = [] + this.stagingBacklog = [] + } + + def methodMissing(String name, args) { + if (name.toLowerCase() != name) { + return callWithLowerCaseName(name, args) + } + append("${name.toUpperCase()} ${args.join(' ')}") + } + + File file(Object name) { + project.file(name) + } + + Dockerfile append(def instruction) { + instructions.add(instruction.toString()) + this + } + + Dockerfile appendAll(List instructions) { + instructions.addAll(instructions*.toString()) + this + } + + void writeToFile(File destination) { + destination.withWriter { out -> + instructions.each() { line -> + out.writeLine(line) + } + } + } + + def callWithLowerCaseName(String name, args) { + String s = name.toLowerCase() + this."$s"(*args) + } + + void extendDockerfile(File baseFile) { + baseInstructions = baseFile as String[] + } + + void from(String baseImage) { + baseInstructions = ["FROM ${baseImage}"] + } + + void cmd(List cmd) { + append('CMD ["' + cmd.join('", "') + '"]') + } + + void entrypoint(List cmd) { + append('ENTRYPOINT ["' + cmd.join('", "') + '"]') + } + + void add(File source, String destination='/') { + File target + if (source.isDirectory()) { + target = new File(workingDir, source.name) + } + else { + target = workingDir + } + if (source.absoluteFile != target.absoluteFile) { + logger.info "source = ${source} target = ${target}" + stagingBacklog.add { -> + copyCallback { + from source + into target + } + } + } + append("ADD ${source.name} ${destination}") + } + + void copy(File source, String destination='/') { + File target + if (source.isDirectory()) { + target = new File(workingDir, source.name) + } + else { + target = workingDir + } + if (source.absoluteFile != target.absoluteFile) { + stagingBacklog.add { -> + copyCallback { + from source + into target + } + } + } + append("COPY ${source.name} ${destination}") + } + + void label(Map labels) { + if (labels) { + instructions.add("LABEL " + labels.collect { k,v -> "\"$k\"=\"$v\"" }.join(' ')) + } + } + + List getInstructions() { + (baseInstructions + instructions)*.toString() + } + + boolean hasBase() { + baseInstructions.size() > 0 + } +} diff --git a/gradle-plugin-docker/src/test/groovy/org/xbib/gradle/plugin/docker/DockerPluginIntegrationTest.groovy b/gradle-plugin-docker/src/test/groovy/org/xbib/gradle/plugin/docker/DockerPluginIntegrationTest.groovy new file mode 100644 index 0000000..cdd0ca1 --- /dev/null +++ b/gradle-plugin-docker/src/test/groovy/org/xbib/gradle/plugin/docker/DockerPluginIntegrationTest.groovy @@ -0,0 +1,60 @@ +package org.xbib.gradle.plugin.docker + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +import static org.junit.jupiter.api.Assertions.assertEquals + +class DockerPluginIntegrationTest { + + private File projectDir + + private File dockerFile + + private File settingsFile + + private File buildFile + + @BeforeEach + void setup(@TempDir File testProjectDir) throws IOException { + this.projectDir = testProjectDir + this.settingsFile = new File(testProjectDir, "settings.gradle") + this.buildFile = new File(testProjectDir, "build.gradle") + } + + @Test + void testPlugin() { + String settingsFileContent = ''' +rootProject.name = 'docker-test' +''' + settingsFile.write(settingsFileContent) + String buildFileContent = ''' +plugins { + id 'org.xbib.gradle.plugin.docker' +} + +task myDockerBuild(type: DockerBuildTask) { + enabled = true + registry = 'localhost' + imageName = 'mytestimage' + dockerfile { + add(file('settings.gradle'), '/') + add(new File('/etc/hosts'), '/') + } +} + +''' + buildFile.write(buildFileContent) + BuildResult result = GradleRunner.create() + .withProjectDir(projectDir) + .withPluginClasspath() + .withArguments(":myDockerBuild", "--info", "--stacktrace", "--warning-mode=all") + .forwardOutput() + .build() + assertEquals(TaskOutcome.SUCCESS, result.task(":myDockerBuild").getOutcome()) + } +} diff --git a/gradle-plugin-git/build.gradle b/gradle-plugin-git/build.gradle new file mode 100644 index 0000000..d861a55 --- /dev/null +++ b/gradle-plugin-git/build.gradle @@ -0,0 +1,55 @@ +plugins { + id 'java-gradle-plugin' + id 'groovy' + id 'com.gradle.plugin-publish' version '0.17.0' +} + +apply plugin: 'groovy' +apply plugin: 'java-gradle-plugin' +apply plugin: 'com.gradle.plugin-publish' + +dependencies { + api gradleApi() + api "org.xbib:groovy-git:${project.property('groovy-git.version')}" + testImplementation gradleTestKit() + testImplementation "org.spockframework:spock-core:${project.property('spock.version')}" +} + +compileGroovy { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +compileTestGroovy { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +validatePlugins { + failOnWarning = false +} + +gradlePlugin { + plugins { + gitPlugin { + id = 'org.xbib.gradle.plugin.git' + implementationClass = 'org.xbib.gradle.plugin.git.GitPlugin' + } + } +} + +if (project.hasProperty('gradle.publish.key')) { + pluginBundle { + website = 'https://github.com/jprante/groovy-git' + vcsUrl = 'https://github.com/jprante/groovy-git.git' + plugins { + gitPlugin { + id = 'org.xbib.gradle.plugin.git' + version = project.version + description = rootProject.ext.description + displayName = rootProject.ext.description + tags = ['gradle', 'plugin', 'git'] + } + } + } +} diff --git a/gradle-plugin-git/gradle.properties b/gradle-plugin-git/gradle.properties new file mode 100644 index 0000000..0e6d8d6 --- /dev/null +++ b/gradle-plugin-git/gradle.properties @@ -0,0 +1 @@ +version = 2.0.1 \ No newline at end of file diff --git a/gradle-plugin-git/src/main/groovy/org/xbib/gradle/plugin/git/GitPlugin.groovy b/gradle-plugin-git/src/main/groovy/org/xbib/gradle/plugin/git/GitPlugin.groovy new file mode 100644 index 0000000..31f7ed4 --- /dev/null +++ b/gradle-plugin-git/src/main/groovy/org/xbib/gradle/plugin/git/GitPlugin.groovy @@ -0,0 +1,30 @@ +package org.xbib.gradle.plugin.git + +import org.xbib.groovy.git.Git +import org.gradle.api.Plugin +import org.gradle.api.Project + +/** + * Plugin adding a {@code git} property to all projects that searches for a Git repo from the project's directory. + */ +class GitPlugin implements Plugin { + @Override + void apply(Project project) { + try { + Git git = Git.open(currentDir: project.rootDir) + project.gradle.buildFinished { + project.logger.info "closing git repo: ${git.repository.rootDir}" + git.close() + } + project.allprojects { prj -> + if (prj.ext.has('git')) { + prj.logger.warn("project ${prj.path} already has a git property, overriding") + } + prj.ext.git = git + } + } catch (Exception e) { + project.logger.debug("failed trying to find git repository for ${project.path}", e) + project.ext.git = null + } + } +} diff --git a/gradle-plugin-git/src/test/groovy/org/xbib/gradle/plugin/git/GitPluginTest.groovy b/gradle-plugin-git/src/test/groovy/org/xbib/gradle/plugin/git/GitPluginTest.groovy new file mode 100644 index 0000000..caecc04 --- /dev/null +++ b/gradle-plugin-git/src/test/groovy/org/xbib/gradle/plugin/git/GitPluginTest.groovy @@ -0,0 +1,108 @@ +package org.xbib.gradle.plugin.git + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.gradle.util.GradleVersion +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import org.xbib.groovy.git.Git +import spock.lang.Specification + +class GitPluginTest extends Specification { + @Rule TemporaryFolder tempDir = new TemporaryFolder() + File projectDir + File buildFile + + def setup() { + projectDir = tempDir.newFolder('project') + buildFile = projectFile('build.gradle') + } + + def 'with no repo, plugin sets git to null'() { + given: + buildFile << '''\ +plugins { + id 'org.xbib.gradle.plugin.git' +} + +task doStuff { + doLast { + assert git == null + } +} +''' + when: + def result = build('doStuff') + then: + result.task(':doStuff').outcome == TaskOutcome.SUCCESS + } + + def 'with repo, plugin opens the repo as git'() { + given: + Git git = Git.init(dir: projectDir) + projectFile('1.txt') << '1' + git.add(patterns: ['1.txt']) + git.commit(message: 'yay') + git.tag.add(name: '1.0.0') + + buildFile << '''\ +plugins { + id 'org.xbib.gradle.plugin.git' +} + +task doStuff { + doLast { + println git.describe() + } +} +''' + when: + def result = build('doStuff', '--quiet') + then: + result.task(':doStuff').outcome == TaskOutcome.SUCCESS + result.output.normalize() == '1.0.0\n' + } + + def 'with repo, plugin closes the repo after build is finished'() { + given: + Git git = Git.init(dir: projectDir) + projectFile('1.txt') << '1' + git.add(patterns: ['1.txt']) + git.commit(message: 'yay') + git.tag.add(name: '1.0.0') + + buildFile << '''\ +plugins { + id 'org.xbib.gradle.plugin.git' +} + +task doStuff { + doLast { + println git.describe() + } +} +''' + when: + def result = build('doStuff', '--info') + then: + result.task(':doStuff').outcome == TaskOutcome.SUCCESS + result.output.contains('closing git repo') + } + + private BuildResult build(String... args) { + return GradleRunner.create() + .withGradleVersion(GradleVersion.current().version) + .withPluginClasspath() + .withProjectDir(projectDir) + .forwardOutput() + .withArguments((args + '--stacktrace') as String[]) + .build() + } + + private File projectFile(String path) { + File file = new File(projectDir, path) + file.parentFile.mkdirs() + return file + } +} diff --git a/gradle-plugin-rpm/build.gradle b/gradle-plugin-rpm/build.gradle new file mode 100644 index 0000000..364c705 --- /dev/null +++ b/gradle-plugin-rpm/build.gradle @@ -0,0 +1,55 @@ +plugins { + id 'java-gradle-plugin' + id 'groovy' + id 'com.gradle.plugin-publish' version '0.17.0' +} + +apply plugin: 'groovy' +apply plugin: 'java-gradle-plugin' +apply plugin: 'com.gradle.plugin-publish' + +dependencies { + api gradleApi() + api "org.xbib:rpm-core:${project.property('rpm.version')}" + testImplementation gradleTestKit() +} + +compileGroovy { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +compileTestGroovy { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +validatePlugins { + // disable warning as failures because gradle plugin does not recognize @Delegate tag + failOnWarning = false +} + +gradlePlugin { + plugins { + rpmPlugin { + id = 'org.xbib.gradle.plugin.rpm' + implementationClass = 'org.xbib.gradle.plugin.RpmPlugin' + } + } +} + +if (project.hasProperty('gradle.publish.key')) { + pluginBundle { + website = 'https://github.com/jprante/rpm' + vcsUrl = 'https://github.com/jprante/rpm' + plugins { + rpmPlugin { + id = 'org.xbib.gradle.plugin.rpm' + version = project.version + description = rootProject.ext.description + displayName = rootProject.ext.description + tags = ['gradle', 'plugin', 'rpm'] + } + } + } +} diff --git a/gradle-plugin-rpm/gradle.properties b/gradle-plugin-rpm/gradle.properties new file mode 100644 index 0000000..eeb1390 --- /dev/null +++ b/gradle-plugin-rpm/gradle.properties @@ -0,0 +1 @@ +version = 2.1.0 diff --git a/gradle-plugin-rpm/src/main/groovy/org/xbib/gradle/plugin/Rpm.groovy b/gradle-plugin-rpm/src/main/groovy/org/xbib/gradle/plugin/Rpm.groovy new file mode 100644 index 0000000..18274d4 --- /dev/null +++ b/gradle-plugin-rpm/src/main/groovy/org/xbib/gradle/plugin/Rpm.groovy @@ -0,0 +1,51 @@ +package org.xbib.gradle.plugin + +import org.gradle.api.internal.file.copy.CopyAction +import org.gradle.api.tasks.Nested +import org.gradle.api.tasks.bundling.AbstractArchiveTask + +import java.util.concurrent.Callable + +class Rpm extends AbstractArchiveTask { + + @Delegate + @Nested + RpmExtension rpmExtension + + Rpm() { + rpmExtension = project.extensions.findByName('rpm') as RpmExtension + getArchiveExtension().set("rpm") + Callable archiveFileNameProvider = new Callable() { + @Override + String call() throws Exception { + constructArchiveFileName() + } + } + archiveFileName.set(project.provider(archiveFileNameProvider)) + } + + @Override + protected CopyAction createCopyAction() { + new RpmCopyAction(project, rpmExtension, this) + } + + private String constructArchiveFileName() { + StringBuilder sb = new StringBuilder() + if (packageName) { + sb.append(packageName) + } + if (packageVersion) { + sb.append('-').append(packageVersion) + } + if (packageRelease) { + sb.append('-').append(packageRelease) + } + if (arch) { + sb.append('.').append(arch.name().toLowerCase(Locale.ROOT)) + } + if (archiveExtension) { + sb.append('.').append(archiveExtension.get()) + } + sb.toString() + } +} diff --git a/gradle-plugin-rpm/src/main/groovy/org/xbib/gradle/plugin/RpmCopyAction.groovy b/gradle-plugin-rpm/src/main/groovy/org/xbib/gradle/plugin/RpmCopyAction.groovy new file mode 100644 index 0000000..d0d73d7 --- /dev/null +++ b/gradle-plugin-rpm/src/main/groovy/org/xbib/gradle/plugin/RpmCopyAction.groovy @@ -0,0 +1,212 @@ +package org.xbib.gradle.plugin + +import org.gradle.api.Project +import org.gradle.api.file.DuplicatesStrategy +import org.gradle.api.file.FileCopyDetails +import org.gradle.api.internal.file.CopyActionProcessingStreamAction +import org.gradle.api.internal.file.copy.CopyAction +import org.gradle.api.internal.file.copy.CopyActionProcessingStream +import org.gradle.api.internal.file.copy.FileCopyDetailsInternal +import org.gradle.api.tasks.WorkResult +import org.gradle.api.tasks.WorkResults +import org.xbib.rpm.Dependency +import org.xbib.rpm.Directory +import org.xbib.rpm.Link +import org.xbib.rpm.RpmBuilder +import org.xbib.rpm.payload.Directive +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.StandardOpenOption + +class RpmCopyAction implements CopyAction { + + Project project + + Rpm task + + RpmExtension ext + + RpmBuilder builder + + Path tempDir + + RpmCopyAction(Project project, RpmExtension rpmExtension, Rpm task) { + this.project = project + this.task = task + this.ext = rpmExtension + } + + @Override + WorkResult execute(CopyActionProcessingStream copyActionProcessingStream) { + if (ext.enabled) { + task.setDuplicatesStrategy(DuplicatesStrategy.INCLUDE) + tempDir = task.getTemporaryDir().toPath() + this.builder = createRpm() + copyActionProcessingStream.process(new StreamAction()) + addOther() + buildRpm() + } + WorkResults.didWork(true) + } + + RpmBuilder createRpm() { + RpmBuilder builder = new RpmBuilder() + builder.setPackage ext.packageName, ext.packageVersion, ext.packageRelease, ext.epoch + builder.setType ext.packageType + builder.setPlatform ext.arch, ext.os + builder.setGroup ext.packageGroup + builder.setBuildHost ext.buildHost + builder.setSummary ext.summary + builder.setDescription ext.packageDescription + builder.setLicense ext.license + builder.setPackager ext.packager + builder.setDistribution ext.distribution + builder.setVendor ext.vendor + builder.setUrl ext.url + builder.setPrefixes task.prefixes + builder.setPrivateKeyId task.getSigningKeyId() + builder.setPrivateKeyPassphrase task.getSigningKeyPassphrase() + builder.setPrivateKeyRing task.getSigningKeyRing() + builder.setPrivateKeyHashAlgo task.getSigningKeyHashAlgo() + builder.setSourceRpm(task.sourcePackage) + builder.setPreInstall task.preInstallFile?.text ?: task.preInstall + builder.setPostInstall task.postInstallFile?.text ?: task.postInstall + builder.setPreUninstall task.preUninstallFile?.text ?: task.preUninstall + builder.setPostUninstall task.postUninstallFile?.text ?: task.postUninstall + builder.setPreTrans task.preTransFile?.text ?: task.preTrans + builder.setPostTrans task.postTransFile?.text ?: task.postTrans + builder.setPreInstall prepareScripts(task, task.preInstallCommands) + builder.setPostInstall prepareScripts(task, task.postInstallCommands) + builder.setPreUninstall prepareScripts(task, task.preUninstallCommands) + builder.setPostUninstall prepareScripts(task, task.postUninstallCommands) + builder.setPreTrans prepareScripts(task, task.preTransCommands) + builder.setPostTrans prepareScripts(task, task.postTransCommands) + if (task.changeLogFile) { + builder.addChangelog task.changeLogFile?.toPath() + } + if (task.changeLog) { + builder.addChangelog(task.changeLog) + } + builder + } + + void addOther() { + for (Link link : task.links) { + builder.addLink(link.path, link.target, link.permissions) + } + for (Dependency dep : task.dependencies) { + builder.addDependency(dep.packageName, dep.flags, dep.version) + } + for (Dependency obsolete: task.obsoletes) { + builder.addObsoletes(obsolete.packageName, obsolete.flags, obsolete.version) + } + for (Dependency conflict : task.conflicts) { + builder.addConflicts(conflict.packageName, conflict.flags, conflict.version) + } + for (Dependency provides : task.provides) { + builder.addProvides(provides.packageName, provides.flags, provides.version) + } + for (Directory directory : task.directories) { + String user = directory.user ? directory.user : task.user + String group = directory.group ? directory.group : task.group + builder.addDirectory(directory.path, directory.permissions, null, user, group, directory.addParents) + } + } + + void buildRpm() { + Path path = task.archiveFile.get().asFile.toPath() + Files.createDirectories(path.parent) + Files.newByteChannel(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING).withCloseable { ch -> + builder.build(ch) + } + } + + private class StreamAction implements CopyActionProcessingStreamAction { + + @Override + void processFile(FileCopyDetailsInternal fileCopyDetailsInternal) { + boolean addParents = ext.addParentDirs != null ? ext.addParentDirs : task.addParentDirs + Path path = extractPath(tempDir, fileCopyDetailsInternal) + String p = "/${fileCopyDetailsInternal.path}" + if (Files.isSymbolicLink(path)) { + builder.addLink(p, Files.readSymbolicLink(path).toFile().path, -1) + } else if (!fileCopyDetailsInternal.isDirectory()) { + int mode = fileCopyDetailsInternal.mode + int dirmode = -1 + EnumSet directive = makeDirective(ext.fileType) + String user = ext.user ?: task.user + String group = ext.group ?: task.group + builder.addFile(p, path, mode, dirmode, directive, user, group, addParents) + } + } + } + + private static Path extractPath(Path tempDir, FileCopyDetails fileDetails) { + Path path + try { + path = fileDetails.file.toPath() + } catch (UnsupportedOperationException e) { + path = tempDir.resolve(fileDetails.path) + fileDetails.copyTo(path.toFile()) + } + path + } + + private static EnumSet makeDirective(List strings) { + EnumSet set = EnumSet.of(Directive.NONE) + for (String string : strings) { + set.add(Directive.valueOf(string.toUpperCase(Locale.ROOT))) + } + set + } + + private static String prepareScripts(Rpm task, List scripts) { + if (scripts != null && !scripts.isEmpty()) { + List list = [] + def stdDefines = standardScriptDefines(task) + if (stdDefines) { + list.add(stdDefines) + } + if (task.commonCommands) { + list.addAll(task.commonCommands) + } + list.addAll(scripts) + return concatAndRemoveShebangLines(list) + } else { + return null + } + } + + private static String standardScriptDefines(Rpm task) { + String.format(" RPM_ARCH=%s \n RPM_OS=%s \n RPM_PACKAGE_NAME=%s \n RPM_PACKAGE_VERSION=%s \n RPM_PACKAGE_RELEASE=%s \n\n", + task.arch?.toString()?.toLowerCase()?:'', + task.os?.toString()?.toLowerCase()?: '', + task.packageName, + task.packageVersion, + task.packageRelease) + } + + private static String concatAndRemoveShebangLines(Collection scripts) { + String shebang + StringBuilder result = new StringBuilder() + scripts.each { script -> + script?.eachLine { line -> + if (line.matches('^#!.*$')) { + if (!shebang) { + shebang = line + } else if (line != shebang) { + throw new IllegalArgumentException("mismatching #! script lines") + } + } else { + result.append line + result.append "\n" + } + } + } + if (shebang) { + result.insert(0, shebang + "\n") + } + result.toString() + } +} diff --git a/gradle-plugin-rpm/src/main/groovy/org/xbib/gradle/plugin/RpmExtension.groovy b/gradle-plugin-rpm/src/main/groovy/org/xbib/gradle/plugin/RpmExtension.groovy new file mode 100644 index 0000000..7fc6213 --- /dev/null +++ b/gradle-plugin-rpm/src/main/groovy/org/xbib/gradle/plugin/RpmExtension.groovy @@ -0,0 +1,409 @@ +package org.xbib.gradle.plugin + +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Optional +import org.xbib.rpm.Dependency +import org.xbib.rpm.Directory +import org.xbib.rpm.Link +import org.xbib.rpm.lead.Architecture +import org.xbib.rpm.lead.Os +import org.xbib.rpm.lead.PackageType + +class RpmExtension { + + @Optional + @Input + boolean enabled = true + + @Optional + @Input + String packageName + + @Optional + @Input + String packageVersion + + @Optional + @Input + String packageRelease + + @Optional + @Input + Integer epoch = 0 + + @Optional + @Input + String signingKeyPassphrase + + @Optional + @Input + String signingKeyRing + + @Optional + @Input + String signingKeyId + + @Optional + @Input + String signingKeyHashAlgo + + @Optional + @Input + String user + + @Optional + @Input + String group + + @Optional + @Input + String buildHost + + @Optional + @Input + String packageGroup + + @Optional + @Input + String packageDescription = '' + + @Optional + @Input + String summary + + @Optional + @Input + String license + + @Optional + @Input + String packager + + @Optional + @Input + String distribution + + @Optional + @Input + String vendor + + @Optional + @Input + String url + + @Optional + @Input + String sourcePackage + + @Optional + @Input + List fileType + + @Optional + @Input + Boolean addParentDirs = false + + @Optional + @Input + Architecture arch = Architecture.X86_64 + + @Optional + @Input + Os os = Os.LINUX + + @Optional + @Input + PackageType packageType = PackageType.BINARY + + @Input + List prefixes = new ArrayList() + + @Optional + @Input + Integer uid + + @Optional + @Input + Integer gid + + @Optional + @Input + String maintainer + + @Optional + @Input + String uploaders + + @Optional + @Input + String priority + + @Optional + @Input + String preInstall + + @Optional + @Input + File preInstallFile + + @Input + List preInstallCommands = [] + + @Optional + @Input + String postInstall + + @Optional + @Input + File postInstallFile + + @Input + List postInstallCommands = [] + + @Optional + @Input + String preUninstall + + @Optional + @Input + File preUninstallFile + + @Input + List preUninstallCommands = [] + + @Optional + @Input + String postUninstall + + @Optional + @Input + File postUninstallFile + + @Input + List postUninstallCommands = [] + + @Optional + @Input + String preTrans + + @Optional + @Input + File preTransFile + + @Input + List preTransCommands = [] + + @Optional + @Input + String postTrans + + @Optional + @Input + File postTransFile + + @Input + List postTransCommands = [] + + @Input + List commonCommands = [] + + @Input + List links = [] + + Link link(String path, String target) { + link(path, target, -1) + } + + Link link(String path, String target, int permissions) { + Link link = new Link(path, target, permissions) + links.add(link) + link + } + + @Input + List dependencies = [] + + @Input + List obsoletes = [] + + @Input + List conflicts = [] + + @Input + List recommends = [] + + @Input + List suggests = [] + + @Input + List enhances = [] + + @Input + List preDepends = [] + + @Input + List breaks = [] + + @Input + List replaces = [] + + @Input + List provides = [] + + Dependency requires(String packageName) { + requires(packageName, '') + } + + Dependency requires(String packageName, String version){ + requires(packageName, version, 0) + } + + Dependency requires(String packageName, String version, int flag) { + def dep = new Dependency(packageName, version, flag) + dependencies.add(dep) + dep + } + + Dependency obsoletes(String packageName) { + obsoletes(packageName, '') + } + + Dependency obsoletes(String packageName, String version) { + obsoletes(packageName, version, 0) + } + + Dependency obsoletes(String packageName, String version, int flag) { + def dep = new Dependency(packageName, version, flag) + obsoletes.add(dep) + dep + } + + Dependency conflicts(String packageName) { + conflicts(packageName, '') + } + + Dependency conflicts(String packageName, String version) { + conflicts(packageName, version, 0) + } + + Dependency conflicts(String packageName, String version, int flag) { + def dep = new Dependency(packageName, version, flag) + conflicts.add(dep) + dep + } + + Dependency recommends(String packageName) { + recommends(packageName, '') + } + + Dependency recommends(String packageName, String version) { + recommends(packageName, version, 0) + } + + Dependency recommends(String packageName, String version, int flag) { + def dep = new Dependency(packageName, version, flag) + recommends.add(dep) + dep + } + + Dependency suggests(String packageName) { + suggests(packageName, '') + } + + Dependency suggests(String packageName, String version) { + suggests(packageName, version, 0) + } + + Dependency suggests(String packageName, String version, int flag) { + def dep = new Dependency(packageName, version, flag) + suggests.add(dep) + dep + } + + Dependency enhances(String packageName) { + enhances(packageName, '') + } + + Dependency enhances(String packageName, String version) { + enhances(packageName, version, 0) + } + + Dependency enhances(String packageName, String version, int flag) { + def dep = new Dependency(packageName, version, flag) + enhances.add(dep) + dep + } + + Dependency preDepends(String packageName) { + preDepends(packageName, '') + } + + Dependency preDepends(String packageName, String version) { + preDepends(packageName, version, 0) + } + + Dependency preDepends(String packageName, String version, int flag) { + def dep = new Dependency(packageName, version, flag) + preDepends.add(dep) + dep + } + + Dependency breaks(String packageName) { + breaks(packageName, '') + } + + Dependency breaks(String packageName, String version) { + breaks(packageName, version, 0) + } + + Dependency breaks(String packageName, String version, int flag) { + def dep = new Dependency(packageName, version, flag) + breaks.add(dep) + dep + } + + Dependency replaces(String packageName) { + replaces(packageName, '') + } + + Dependency replaces(String packageName, String version) { + replaces(packageName, version, 0) + } + + Dependency replaces(String packageName, String version, int flag) { + def dep = new Dependency(packageName, version, flag) + replaces.add(dep) + dep + } + + Dependency provides(String packageName) { + provides(packageName, '') + } + + Dependency provides(String packageName, String version) { + provides(packageName, version, 0) + } + + Dependency provides(String packageName, String version, int flag) { + def dep = new Dependency(packageName, version, flag) + provides.add(dep) + dep + } + + @Input + List directories = [] + + Directory directory(String path) { + Directory directory = new Directory(path: path) + directories << directory + directory + } + + @Optional + @Input + File changeLogFile + + @Optional + @Input + String changeLog +} diff --git a/gradle-plugin-rpm/src/main/groovy/org/xbib/gradle/plugin/RpmPlugin.groovy b/gradle-plugin-rpm/src/main/groovy/org/xbib/gradle/plugin/RpmPlugin.groovy new file mode 100644 index 0000000..87e51bc --- /dev/null +++ b/gradle-plugin-rpm/src/main/groovy/org/xbib/gradle/plugin/RpmPlugin.groovy @@ -0,0 +1,31 @@ +package org.xbib.gradle.plugin + +import org.gradle.api.GradleException +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.plugins.BasePlugin +import org.gradle.util.GradleVersion + +class RpmPlugin implements Plugin { + + @Override + void apply(Project project) { + checkVersion() + project.plugins.apply(BasePlugin) + project.ext.Rpm = Rpm.class + project.with { + createExtension(project) + } + } + + private static void checkVersion() { + String version = '6.4' + if (GradleVersion.current() < GradleVersion.version(version)) { + throw new GradleException("need Gradle ${version} or higher") + } + } + + private static void createExtension(Project project) { + project.extensions.create('rpm', RpmExtension) + } +} diff --git a/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmFullTest.groovy b/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmFullTest.groovy new file mode 100644 index 0000000..f49e012 --- /dev/null +++ b/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmFullTest.groovy @@ -0,0 +1,336 @@ +package org.xbib.gradle.plugin + +import org.gradle.api.Project +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.xbib.rpm.RpmReader +import org.xbib.rpm.RpmReaderResult +import org.xbib.rpm.format.Format +import org.xbib.rpm.header.IntegerList +import org.xbib.rpm.header.StringList + +import java.nio.charset.StandardCharsets +import java.nio.file.Paths + +import static org.hamcrest.CoreMatchers.is +import static org.hamcrest.MatcherAssert.assertThat +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertNotNull +import static org.xbib.rpm.format.Flags.EQUAL +import static org.xbib.rpm.format.Flags.GREATER +import static org.xbib.rpm.format.Flags.LESS +import static org.xbib.rpm.header.HeaderTag.CONFLICTFLAGS +import static org.xbib.rpm.header.HeaderTag.CONFLICTNAME +import static org.xbib.rpm.header.HeaderTag.CONFLICTVERSION +import static org.xbib.rpm.header.HeaderTag.DISTRIBUTION +import static org.xbib.rpm.header.HeaderTag.FILEGROUPNAME +import static org.xbib.rpm.header.HeaderTag.FILEMODES +import static org.xbib.rpm.header.HeaderTag.FILEUSERNAME +import static org.xbib.rpm.header.HeaderTag.OBSOLETEFLAGS +import static org.xbib.rpm.header.HeaderTag.OBSOLETENAME +import static org.xbib.rpm.header.HeaderTag.OBSOLETEVERSION +import static org.xbib.rpm.header.HeaderTag.PREFIXES +import static org.xbib.rpm.lead.Architecture.I386 +import static org.xbib.rpm.lead.Os.LINUX +import static org.xbib.rpm.lead.PackageType.BINARY +import static org.xbib.rpm.payload.CpioHeader.DIR +import static org.xbib.rpm.payload.CpioHeader.FILE + +class RpmFullTest { + + File projectDir + + @BeforeEach + void setup() { + projectDir = new File("build/testrpm") + projectDir.mkdirs() + } + + + @Test + void testCopySpec() { + File bananaFile = new File(projectDir, 'test/banana') + bananaFile.parentFile.mkdirs() + bananaFile.withWriter { + out -> out.write('banana') + } + File srcDir = new File(projectDir, 'src') + srcDir.mkdirs() + String fruit = 'apple' + File appleFile = new File(srcDir, fruit) + appleFile.withWriter { + out -> out.write(fruit) + } + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.task([type: Rpm], 'buildRpm', { + packageName = 'test' + packageVersion = '1.0.0' + packageRelease = '1' + addParentDirs = true + from(bananaFile.absoluteFile.parent) { + into '/usr/share/myproduct/etc' + } + from(appleFile.absoluteFile.parent) { + into '/usr/local/myproduct/bin' + } + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + RpmReaderResult result = rpmReader.read(project.tasks.buildRpm.outputs.files.first().toPath()) + assertEquals([ + './usr/local/myproduct', + './usr/local/myproduct/bin', + './usr/local/myproduct/bin/apple', + './usr/share/myproduct', + './usr/share/myproduct/etc', + './usr/share/myproduct/etc/banana'], result.files*.name) + assertEquals([DIR, DIR, FILE, DIR, DIR, FILE], result.files*.type) + } + + @Test + void testExplicitDirectory() { + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.task([type: Rpm], 'buildRpm', { + packageName = 'test' + packageVersion = '1.0.0' + packageRelease = '1' + directory '/lib' + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + RpmReaderResult result = rpmReader.read(project.tasks.buildRpm.outputs.files.first().toPath()) + assertNotNull(result.files.find { it.name == './lib' }) + } + + @Test + void testFilter() { + File appleFile = new File(projectDir, 'src/apple') + appleFile.mkdirs() + appleFile.withWriter { + out -> out.write('{{BASE}}/apple') + } + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.task([type: Rpm], 'buildRpm', { + packageName = 'test' + packageVersion = '1.0.0' + packageRelease = '1' + from(appleFile.absoluteFile.parent) { + into '/usr/local/myproduct/bin' + filter({ line -> + return line.replaceAll(/\{\{BASE\}\}/, '/usr/local/myproduct') + }) + } + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + RpmReaderResult result = rpmReader.read(project.tasks.buildRpm.outputs.files.first().toPath()) + def scannerApple = result.files.find { it.name == './usr/local/myproduct/bin/apple' } + assertEquals(StandardCharsets.UTF_8.decode(scannerApple.contents).toString(), '/usr/local/myproduct/apple') + } + + @Test + void testCustomCopySpec() { + File srcDir = new File(projectDir, 'src') + srcDir.mkdirs() + String fruit = 'apple' + File appleFile = new File(srcDir, fruit) + appleFile.withWriter { + out -> out.write(fruit) + } + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + def customCopySpec = project.copySpec { + into('lib') { + from 'src' + } + } + project.task([type: Rpm], 'buildRpm', { + packageName = 'copyspec' + packageVersion = '1.0.0' + packageRelease = '1' + with customCopySpec + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + RpmReaderResult result = rpmReader.read(project.tasks.buildRpm.outputs.files.first().toPath()) + assertThat(result.files*.name, is(['./lib/apple'])) + } + + @Test + void testFileMode() { + File srcDir1 = new File(projectDir, 'src1') + srcDir1.mkdirs() + new File(srcDir1, 'apple').withWriter { out -> out.write('apple') } + File srcDir2 = new File(projectDir, 'src2') + srcDir2.mkdirs() + new File(srcDir2, 'banana').withWriter { out -> out.write('banana') } + File srcDir3 = new File(projectDir, 'src3') + srcDir3.mkdirs() + new File(srcDir3, 'cherry').withWriter { out -> out.write('cherry') } + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.task([type: Rpm], 'buildRpm', { + packageName = 'fileMode' + packageVersion = '2.0' + packageRelease = '2' + into '/tiny' + fileMode 0555 + from(srcDir1.absoluteFile) { + // should be default group + } + from(srcDir2.absoluteFile) { + fileMode 0666 + } + from(srcDir3.absoluteFile) { + fileMode 0555 + } + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + RpmReaderResult result = rpmReader.read(project.tasks.buildRpm.outputs.files.first().toPath()) + assertEquals([FILE, FILE, FILE], result.files*.type) + assertEquals(['./tiny/apple', './tiny/banana', './tiny/cherry'], result.files*.name) + assertThat([(short)0100555, (short)0100666, (short)0100555], is(result.format.header.getEntry(FILEMODES).values)) + } + + @Test + void testUserGroup() { + File srcDir = new File(projectDir, 'src') + srcDir.mkdirs() + new File(srcDir, 'apple').withWriter { out -> out.write('apple') } + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.task([type: Rpm], 'buildRpm', { + packageName = 'userTest' + packageVersion = '2.0' + packageRelease = '2' + user = 'joerg' + group = 'users' + from srcDir.absoluteFile + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + RpmReaderResult result = rpmReader.read(project.tasks.buildRpm.outputs.files.first().toPath()) + assertEquals([FILE], result.files*.type) + StringList users = result.format.header.getEntry(FILEUSERNAME)?.values as StringList + assertThat(['joerg'], is(users)) + StringList groups = result.format.header.getEntry(FILEGROUPNAME)?.values as StringList + assertThat(['users'], is(groups)) + } + + @Test + void testPrefix() { + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.task([type: Rpm], 'buildRpm', { + packageName = 'prefixes' + packageVersion = '1.0.0' + packageRelease = '1' + prefixes = ['/opt'] + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + RpmReaderResult result = rpmReader.read(project.tasks.buildRpm.outputs.files.first().toPath()) + assertThat(StringList.of('/opt') as StringList, is(result.format.header.getEntry(PREFIXES).values)) + } + + @Test + void testConflictsAndObsoletes() { + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + File srcDir = new File(projectDir, 'src') + srcDir.mkdirs() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.task([type: Rpm], 'buildRpm', { + packageName = 'testing' + packageVersion = '1.2' + packageRelease = '3' + packageType = BINARY + arch = I386 + os = LINUX + license = 'Free' + distribution = 'SuperSystem' + vendor = 'Super Associates, LLC' + url = 'http://www.example.com/' + obsoletes('blarg', '1.0', GREATER | EQUAL) + conflicts('blech') + conflicts('packageA', '1.0', LESS) + obsoletes('packageB', '2.2', GREATER) + obsoletes('packageC') + from(srcDir) + into '/opt/bleah' + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + def result = rpmReader.read(Paths.get(projectDir.toString(), 'build', 'distributions', 'testing-1.2-3.i386.rpm')) + Format format = result.format + StringList obsoletes = format.header.getEntry(OBSOLETENAME).values as StringList + StringList obsoleteVersions = format.header.getEntry(OBSOLETEVERSION).values as StringList + IntegerList obsoleteComparisons = format.header.getEntry(OBSOLETEFLAGS).values as IntegerList + StringList conflicts = format.header.getEntry(CONFLICTNAME).values as StringList + StringList conflictVersions = format.header.getEntry(CONFLICTVERSION).values as StringList + IntegerList conflictComparisons = format.header.getEntry(CONFLICTFLAGS).values as IntegerList + StringList distribution = format.header.getEntry(DISTRIBUTION).values as StringList + assertThat(StringList.of('SuperSystem') as StringList, is(distribution)) + assertThat('blarg', is(obsoletes.get(0))) + assertThat(GREATER | EQUAL, is(obsoleteComparisons.get(0))) + assertThat('blech', is(conflicts.get(0))) + assertThat('', is(conflictVersions.get(0))) + assertThat(0, is(conflictComparisons.get(0))) + assertThat('packageA', is(conflicts.get(1))) + assertThat('1.0', is(conflictVersions.get(1))) + assertThat(LESS, is(conflictComparisons.get(1))) + assertThat('packageB', is(obsoletes.get(1))) + assertThat('2.2', is(obsoleteVersions.get(1))) + assertThat(GREATER, is(obsoleteComparisons.get(1))) + assertThat('packageC', is(obsoletes.get(2))) + } + + @Test + void testFilesFromConfiguration() { + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.repositories { + mavenCentral() + } + project.configurations { + myconf + } + project.dependencies { + myconf "junit:junit:4.12" + } + project.task([type: Rpm], 'buildRpm', { + packageName = 'fromconfiguration' + packageVersion = '1.0.0' + packageRelease = '1' + into('/tmp') { + from project.configurations.myconf + } + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + RpmReaderResult result = rpmReader.read(project.tasks.buildRpm.outputs.files.first().toPath()) + assertThat(['./tmp/hamcrest-core-1.3.jar', './tmp/junit-4.12.jar'], is(result.files*.name)) + } +} diff --git a/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmPluginIntegrationTest.groovy b/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmPluginIntegrationTest.groovy new file mode 100644 index 0000000..575175a --- /dev/null +++ b/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmPluginIntegrationTest.groovy @@ -0,0 +1,57 @@ +package org.xbib.gradle.plugin + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +import static org.junit.jupiter.api.Assertions.assertEquals + +class RpmPluginIntegrationTest { + + private File projectDir + + private File settingsFile + + private File buildFile + + @BeforeEach + void setup(@TempDir File testProjectDir) throws IOException { + this.projectDir = testProjectDir + this.settingsFile = new File(testProjectDir, "settings.gradle") + this.buildFile = new File(testProjectDir, "build.gradle") + } + + @Test + void testPlugin() { + String settingsFileContent = ''' +rootProject.name = 'rpm-test' +''' + settingsFile.write(settingsFileContent) + String buildFileContent = ''' +plugins { + id 'org.xbib.gradle.plugin.rpm' +} + +rpm { + enabled = true +} + +task myRpm(type: Rpm) { + packageName = 'rpmIsUpToDate' + arch = org.xbib.rpm.lead.Architecture.NOARCH + os = org.xbib.rpm.lead.Os.LINUX +} +''' + buildFile.write(buildFileContent) + BuildResult result = GradleRunner.create() + .withProjectDir(projectDir) + .withArguments(":build", "--info") + .withPluginClasspath() + .forwardOutput() + .build() + assertEquals(TaskOutcome.UP_TO_DATE, result.task(":build").getOutcome()) + } +} diff --git a/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmScriptTest.groovy b/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmScriptTest.groovy new file mode 100644 index 0000000..6fe77d3 --- /dev/null +++ b/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmScriptTest.groovy @@ -0,0 +1,156 @@ +package org.xbib.gradle.plugin + +import org.gradle.api.Project +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.xbib.rpm.RpmReader +import org.xbib.rpm.changelog.ChangelogParser +import org.xbib.rpm.format.Format +import org.xbib.rpm.header.EntryType +import org.xbib.rpm.header.IntegerList +import org.xbib.rpm.header.StringList +import org.xbib.rpm.header.entry.SpecEntry +import java.time.LocalDateTime +import java.time.ZoneOffset +import static org.hamcrest.MatcherAssert.assertThat +import static org.hamcrest.CoreMatchers.* +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertNotNull +import static org.xbib.rpm.header.HeaderTag.POSTINSCRIPT +import static org.xbib.rpm.header.HeaderTag.POSTTRANSSCRIPT +import static org.xbib.rpm.header.HeaderTag.POSTUNSCRIPT +import static org.xbib.rpm.header.HeaderTag.PREINSCRIPT +import static org.xbib.rpm.header.HeaderTag.PRETRANSSCRIPT +import static org.xbib.rpm.header.HeaderTag.PREUNSCRIPT +import static org.xbib.rpm.header.HeaderTag.CHANGELOGNAME +import static org.xbib.rpm.header.HeaderTag.CHANGELOGTEXT +import static org.xbib.rpm.header.HeaderTag.CHANGELOGTIME + +class RpmScriptTest { + + File projectDir + + @BeforeEach + void setup() { + projectDir = new File("build/testrpm") + projectDir.mkdirs() + } + + @Test + void testInstallScripts() { + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.task([type: Rpm], 'buildRpm', { + packageName = 'installscripts' + packageVersion = '1.0' + packageRelease = '1' + preInstall = "echo 'Hello Pre World'" + postInstall = "echo 'Hello Post World'" + preUninstall = "echo 'Hello PreUn World'" + postUninstall = "echo 'Hello PostUn World'" + preTrans = "echo 'Hello PreTrans World'" + postTrans = "echo 'Hello PostTrans World'" + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + def result = rpmReader.read(project.tasks.buildRpm.outputs.files.first().toPath()) + Format format = result.format + assertThat(["echo 'Hello Pre World'"], is(format.header.getEntry(PREINSCRIPT)?.values)) + assertThat(["echo 'Hello Post World'"], is(format.header.getEntry(POSTINSCRIPT)?.values)) + assertThat(["echo 'Hello PreUn World'"], is(format.header.getEntry(PREUNSCRIPT)?.values)) + assertThat(["echo 'Hello PostUn World'"], is(format.header.getEntry(POSTUNSCRIPT)?.values)) + assertThat(["echo 'Hello PreTrans World'"], is(format.header.getEntry(PRETRANSSCRIPT)?.values)) + assertThat(["echo 'Hello PostTrans World'"], is(format.header.getEntry(POSTTRANSSCRIPT)?.values)) + } + + + @Test + void testInstallScriptFiles() { + String preinstall = getClass().getResource('preinstall.sh').text + File scriptDir = new File(projectDir, 'scripts') + scriptDir.mkdirs() + new File(scriptDir, 'preinstall.sh').withWriter { out -> out.write(preinstall) } + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.task([type: Rpm], 'buildRpm', { + packageName = 'installscripts' + packageVersion = '1.0' + packageRelease = '1' + preInstallFile = project.file('scripts/preinstall.sh') + postInstall = "echo 'Hello Post World'" + preUninstall = "echo 'Hello PreUn World'" + postUninstall = "echo 'Hello PostUn World'" + preTrans = "echo 'Hello PreTrans World'" + postTrans = "echo 'Hello PostTrans World'" + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + def result = rpmReader.read(project.tasks.buildRpm.outputs.files.first().toPath()) + Format format = result.format + assertThat(["#!/usr/bin/env bash\necho 'Hello from file'\n"], is(format.header.getEntry(PREINSCRIPT)?.values)) + assertThat(["echo 'Hello Post World'"], is(format.header.getEntry(POSTINSCRIPT)?.values)) + assertThat(["echo 'Hello PreUn World'"], is(format.header.getEntry(PREUNSCRIPT)?.values)) + assertThat(["echo 'Hello PostUn World'"], is(format.header.getEntry(POSTUNSCRIPT)?.values)) + assertThat(["echo 'Hello PreTrans World'"], is(format.header.getEntry(PRETRANSSCRIPT)?.values)) + assertThat(["echo 'Hello PostTrans World'"], is(format.header.getEntry(POSTTRANSSCRIPT)?.values)) + } + + @Test + void testChangeLog() { + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + String changelog = getClass().getResource('changelog').text + File changelogDir = new File(projectDir, 'changelog') + changelogDir.mkdirs() + new File(changelogDir, 'changelog').withWriter { out -> out.write(changelog) } + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.task([type: Rpm], 'buildRpm', { + packageName = 'changelog' + packageVersion = '1.0' + packageRelease = '1' + changeLogFile = project.file('changelog/changelog') + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + def result = rpmReader.read(project.tasks.buildRpm.outputs.files.first().toPath()) + Format format = result.format + assertDateEntryHeaderEqualsAt("Tue Feb 24 2015", format, + CHANGELOGTIME, 10, 0) + assertHeaderEqualsAt("Thomas Jefferson", format, + CHANGELOGNAME, 10, 4) + assertHeaderEqualsAt("- Initial rpm for this package", format, + CHANGELOGTEXT, 10, 9) + assertHeaderEqualsAt("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod \n" + + "tempor incididunt ut labore et dolore magna aliqua", format, + CHANGELOGTEXT, 10, 0) + } + + private static void assertDateEntryHeaderEqualsAt(String expected, Format format, EntryType entryType, int size, int pos) { + assertNotNull(format, "null format") + SpecEntry entry = format.getHeader().getEntry(entryType) + assertNotNull(entry, "Entry not found : " + entryType.getName()) + assertEquals(4, entry.getType(), "Entry type : " + entryType.getName()) + IntegerList values = (IntegerList) entry.getValues() + assertNotNull(values, "null values") + assertEquals(size, values.size(), "Entry size : " + entryType.getName()) + LocalDateTime localDate = LocalDateTime.ofEpochSecond(values.get(pos), 0, ZoneOffset.UTC) + assertEquals(expected, ChangelogParser.CHANGELOG_FORMAT.format(localDate), "Entry value : " + entryType.getName()) + } + + private static void assertHeaderEqualsAt(String expected, Format format, EntryType entryType, int size, int pos) { + assertNotNull(format, "null format") + SpecEntry entry = format.getHeader().getEntry(entryType) + assertNotNull(entry, "Entry not found : " + entryType.getName()) + assertEquals(8, entry.getType(), "Entry type : " + entryType.getName()) + StringList values = (StringList) entry.getValues() + assertNotNull(values, "null values") + assertEquals(size, values.size(), "Entry size : " + entryType.getName()) + assertEquals(expected, values.get(pos), "Entry value : " + entryType.getName()) + } +} diff --git a/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmSignTest.groovy b/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmSignTest.groovy new file mode 100644 index 0000000..907e823 --- /dev/null +++ b/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmSignTest.groovy @@ -0,0 +1,62 @@ +package org.xbib.gradle.plugin + +import org.gradle.api.Project +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.xbib.rpm.RpmReader +import org.xbib.rpm.signature.SignatureTag +import java.nio.file.Paths +import static org.junit.jupiter.api.Assertions.assertNotNull +import static org.junit.jupiter.api.Assertions.assertNull +import static org.xbib.rpm.lead.Architecture.I386 + +class RpmSignTest { + + File projectDir + + @BeforeEach + void setup() { + projectDir = new File("build/testrpm") + projectDir.mkdirs() + } + + @Test + void testUnsigned() { + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.task([type: Rpm], 'buildRpm', { + packageName = 'bleah' + packageVersion = '1.0' + packageRelease = '1' + arch = I386 + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + def res = rpmReader.read(Paths.get(projectDir.toString(), 'build', 'distributions', 'bleah-1.0-1.i386.rpm')) + assertNull(res.format.signatureHeader.getEntry(SignatureTag.LEGACY_PGP)) + } + + @Test + void testSign() { + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.task([type: Rpm], 'buildRpm', { + packageName = 'bleah' + packageVersion = '1.0' + packageRelease = '1' + arch = I386 + signingKeyId = 'F02C6D2C' + signingKeyPassphrase = 'test' + signingKeyRing = 'src/test/resources/test-secring.gpg' + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + def res = rpmReader.read(Paths.get(projectDir.toString(), 'build', 'distributions', 'bleah-1.0-1.i386.rpm')) + assertNotNull(res.format.signatureHeader.getEntry(SignatureTag.LEGACY_PGP)) + } +} diff --git a/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmSimpleTest.groovy b/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmSimpleTest.groovy new file mode 100644 index 0000000..450bfae --- /dev/null +++ b/gradle-plugin-rpm/src/test/groovy/org/xbib/gradle/plugin/RpmSimpleTest.groovy @@ -0,0 +1,104 @@ +package org.xbib.gradle.plugin + +import org.gradle.api.Project +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.xbib.rpm.RpmReaderResult +import org.xbib.rpm.RpmReader +import org.xbib.rpm.format.Format +import java.nio.file.Paths +import static org.hamcrest.MatcherAssert.assertThat +import static org.hamcrest.CoreMatchers.* +import static org.junit.jupiter.api.Assertions.assertTrue +import static org.xbib.rpm.format.Flags.EQUAL +import static org.xbib.rpm.format.Flags.GREATER +import static org.xbib.rpm.header.HeaderTag.ARCH +import static org.xbib.rpm.header.HeaderTag.DISTRIBUTION +import static org.xbib.rpm.header.HeaderTag.EPOCH +import static org.xbib.rpm.header.HeaderTag.NAME +import static org.xbib.rpm.header.HeaderTag.OS +import static org.xbib.rpm.header.HeaderTag.RELEASE +import static org.xbib.rpm.header.HeaderTag.VERSION +import static org.xbib.rpm.lead.Architecture.I386 +import static org.xbib.rpm.lead.Os.LINUX +import static org.xbib.rpm.lead.PackageType.BINARY + +class RpmSimpleTest { + + File projectDir + + @BeforeEach + void setup() { + projectDir = new File("build/testrpm") + projectDir.mkdirs() + } + + @Test + void simpleRpm() { + File srcDir = new File(projectDir, 'src') + srcDir.mkdirs() + new File(srcDir, 'apple').withWriter { out -> + out.write('apple') + } + File noParentsDir = new File(projectDir, 'noParentsDir') + noParentsDir.mkdirs() + new File(noParentsDir, 'alone').withWriter { out -> + out.write('alone') + } + Project project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.apply plugin: 'org.xbib.gradle.plugin.rpm' + project.task([type: Rpm], 'buildRpm', { + packageName = 'bleah' + packageVersion = '1.0' + packageRelease = '1' + packageType = BINARY + arch = I386 + os = LINUX + packageGroup = 'Development/Libraries' + packageDescription = 'Not a very interesting library.' + summary = 'Bleah blarg' + license = 'Free' + distribution = 'SuperSystem' + vendor = 'Super Associates, LLC' + url = 'http://www.example.com/' + requires('blarg', '1.0', GREATER | EQUAL) + requires('blech') + into '/opt/bleah' + from('src') { + fileType = ['config', 'noreplace'] + } + from('noParentsDir') { + into '/a/path/not/to/create' + } + link('/opt/bleah/banana', '/opt/bleah/apple') + }) + project.tasks.buildRpm.copy() + RpmReader rpmReader = new RpmReader() + RpmReaderResult result = rpmReader.read(Paths.get(projectDir.toString(), 'build', 'distributions', 'bleah-1.0-1.i386.rpm')) + Format format = result.format + assertThat(['bleah'], is(format.header.getEntry(NAME)?.values)) + assertThat(['1.0'], is(format.header.getEntry(VERSION)?.values)) + assertThat(['1'], is(format.header.getEntry(RELEASE)?.values)) + assertThat([0], is(format.header.getEntry(EPOCH)?.values)) + assertThat(['i386'], is(format.header.getEntry(ARCH)?.values)) + assertThat(['linux'], is(format.header.getEntry(OS)?.values)) + assertThat(['SuperSystem'], is(format.header.getEntry(DISTRIBUTION)?.values)) + assertTrue(result.files*.name.every { fileName -> + ['./a/path/not/to/create/alone', + './opt/bleah', + './opt/bleah/apple', + './opt/bleah/banana' + ].any { path -> + path.startsWith(fileName) + } + }) + assertTrue(result.files*.name.every { fileName -> + ['./a/path/not/to/create'].every { path -> + !path.startsWith(fileName) + } + }) + } +} diff --git a/gradle-plugin-rpm/src/test/resources/org/xbib/gradle/plugin/changelog b/gradle-plugin-rpm/src/test/resources/org/xbib/gradle/plugin/changelog new file mode 100644 index 0000000..19bca18 --- /dev/null +++ b/gradle-plugin-rpm/src/test/resources/org/xbib/gradle/plugin/changelog @@ -0,0 +1,24 @@ +* Tue Feb 24 2015 George Washington +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua +* Tue Feb 10 2015 George Washington +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. +* Mon Nov 17 2014 George Washington + consectetur, adipisci velit, sed quia non numquam eius modi + sunt explicabo. Nemo enim ipsam voluptatem quia vol + eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat + Excepteur sint occaecat cupidatat non proident, sunt +* Fri Mar 06 2009 John Adams +- nostrum exercitationem ullam corporis suscipit +* Thu Oct 16 2008 Thomas Jefferson +- Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, +* Thu Aug 23 2007 James Madison +eaque ipsa quae ab illo inventore veritatis et quasi architecto +* Mon Jun 04 2007 James Monroe +- adipisci velit, sed q +* Tue May 08 2007 James Madison +- dolore eu fugiat nulla pariatur +* Tue Apr 10 2007 James Monroe +-+// quis nostrum exercitationem ullam corporis +* Wed Nov 08 2006 James Madison +- Initial rpm for this package diff --git a/gradle-plugin-rpm/src/test/resources/org/xbib/gradle/plugin/preinstall.sh b/gradle-plugin-rpm/src/test/resources/org/xbib/gradle/plugin/preinstall.sh new file mode 100644 index 0000000..10b58f4 --- /dev/null +++ b/gradle-plugin-rpm/src/test/resources/org/xbib/gradle/plugin/preinstall.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +echo 'Hello from file' diff --git a/gradle-plugin-rpm/src/test/resources/test-secring.gpg b/gradle-plugin-rpm/src/test/resources/test-secring.gpg new file mode 100644 index 0000000..2044048 Binary files /dev/null and b/gradle-plugin-rpm/src/test/resources/test-secring.gpg differ diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..f6abd55 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,9 @@ +group = 'org.xbib.gradle.plugin' +name = 'gradle-plugins' +version = 0.0.1 + +groovy.version = 2.5.12 +gradle.wrapper.version = 6.6.1 +groovy-git.version = 2.0.1 +rpm.version = 2.1.0 +spock.version = 1.2-groovy-2.5 diff --git a/gradle/compile/groovy.gradle b/gradle/compile/groovy.gradle new file mode 100644 index 0000000..1abf883 --- /dev/null +++ b/gradle/compile/groovy.gradle @@ -0,0 +1,34 @@ +apply plugin: 'groovy' + +dependencies { + implementation "org.codehaus.groovy:groovy:${project.property('groovy.version')}:indy" +} + +compileGroovy { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +compileTestGroovy { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +tasks.withType(GroovyCompile) { + options.compilerArgs + if (!options.compilerArgs.contains("-processor")) { + options.compilerArgs << '-proc:none' + } + groovyOptions.optimizationOptions.indy = true +} + +task groovydocJar(type: Jar, dependsOn: 'groovydoc') { + from groovydoc.destinationDir + archiveClassifier.set('javadoc') +} + +configurations.all { + resolutionStrategy { + force "org.codehaus.groovy:groovy:${project.property('groovy.version')}:indy" + } +} diff --git a/gradle/compile/java.gradle b/gradle/compile/java.gradle new file mode 100644 index 0000000..c9bba7f --- /dev/null +++ b/gradle/compile/java.gradle @@ -0,0 +1,43 @@ + +apply plugin: 'java-library' + +java { + modularity.inferModulePath.set(true) +} + +compileJava { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +compileTestJava { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +jar { + manifest { + attributes('Implementation-Version': project.version) + } +} + +task sourcesJar(type: Jar, dependsOn: classes) { + classifier 'sources' + from sourceSets.main.allSource +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier 'javadoc' +} + +artifacts { + archives sourcesJar, javadocJar +} + +tasks.withType(JavaCompile) { + options.compilerArgs << '-Xlint:all,-fallthrough' +} + +javadoc { + options.addStringOption('Xdoclint:none', '-quiet') +} diff --git a/gradle/documentation/asciidoc.gradle b/gradle/documentation/asciidoc.gradle new file mode 100644 index 0000000..87ba22e --- /dev/null +++ b/gradle/documentation/asciidoc.gradle @@ -0,0 +1,55 @@ +apply plugin: 'org.xbib.gradle.plugin.asciidoctor' + +configurations { + asciidoclet +} + +dependencies { + asciidoclet "org.asciidoctor:asciidoclet:${project.property('asciidoclet.version')}" +} + + +asciidoctor { + backends 'html5' + outputDir = file("${rootProject.projectDir}/docs") + separateOutputDirs = false + attributes 'source-highlighter': 'coderay', + idprefix: '', + idseparator: '-', + toc: 'left', + doctype: 'book', + icons: 'font', + encoding: 'utf-8', + sectlink: true, + sectanchors: true, + linkattrs: true, + imagesdir: 'img', + stylesheet: "${projectDir}/src/docs/asciidoc/css/foundation.css" +} + + +/*javadoc { +options.docletpath = configurations.asciidoclet.files.asType(List) +options.doclet = 'org.asciidoctor.Asciidoclet' +//options.overview = "src/docs/asciidoclet/overview.adoc" +options.addStringOption "-base-dir", "${projectDir}" +options.addStringOption "-attribute", + "name=${project.name},version=${project.version},title-link=https://github.com/xbib/${project.name}" +configure(options) { + noTimestamp = true +} +}*/ + + +/*javadoc { + options.docletpath = configurations.asciidoclet.files.asType(List) + options.doclet = 'org.asciidoctor.Asciidoclet' + options.overview = "${rootProject.projectDir}/src/docs/asciidoclet/overview.adoc" + options.addStringOption "-base-dir", "${projectDir}" + options.addStringOption "-attribute", + "name=${project.name},version=${project.version},title-link=https://github.com/xbib/${project.name}" + options.destinationDirectory(file("${projectDir}/docs/javadoc")) + configure(options) { + noTimestamp = true + } +}*/ diff --git a/gradle/ide/idea.gradle b/gradle/ide/idea.gradle new file mode 100644 index 0000000..64e2167 --- /dev/null +++ b/gradle/ide/idea.gradle @@ -0,0 +1,13 @@ +apply plugin: 'idea' + +idea { + module { + outputDir file('build/classes/java/main') + testOutputDir file('build/classes/java/test') + } +} + +if (project.convention.findPlugin(JavaPluginConvention)) { + //sourceSets.main.output.classesDirs = file("build/classes/java/main") + //sourceSets.test.output.classesDirs = file("build/classes/java/test") +} diff --git a/gradle/publishing/publication.gradle b/gradle/publishing/publication.gradle new file mode 100644 index 0000000..2e2b2c0 --- /dev/null +++ b/gradle/publishing/publication.gradle @@ -0,0 +1,66 @@ + +apply plugin: "de.marcphilipp.nexus-publish" + +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + artifact sourcesJar + artifact javadocJar + pom { + name = project.name + description = rootProject.ext.description + url = rootProject.ext.url + inceptionYear = rootProject.ext.inceptionYear + packaging = 'jar' + organization { + name = 'xbib' + url = 'https://xbib.org' + } + developers { + developer { + id = 'jprante' + name = 'Jörg Prante' + email = 'joergprante@gmail.com' + url = 'https://github.com/jprante' + } + } + scm { + url = rootProject.ext.scmUrl + connection = rootProject.ext.scmConnection + developerConnection = rootProject.ext.scmDeveloperConnection + } + issueManagement { + system = rootProject.ext.issueManagementSystem + url = rootProject.ext.issueManagementUrl + } + licenses { + license { + name = rootProject.ext.licenseName + url = rootProject.ext.licenseUrl + distribution = 'repo' + } + } + } + } + } +} + +if (project.hasProperty("signing.keyId")) { + apply plugin: 'signing' + signing { + sign publishing.publications.mavenJava + } +} + +if (project.hasProperty("ossrhUsername")) { + nexusPublishing { + repositories { + sonatype { + username = project.property('ossrhUsername') + password = project.property('ossrhPassword') + packageGroup = "org.xbib" + } + } + } +} diff --git a/gradle/publishing/sonatype.gradle b/gradle/publishing/sonatype.gradle new file mode 100644 index 0000000..e1813f3 --- /dev/null +++ b/gradle/publishing/sonatype.gradle @@ -0,0 +1,11 @@ + +if (project.hasProperty('ossrhUsername') && project.hasProperty('ossrhPassword')) { + + apply plugin: 'io.codearte.nexus-staging' + + nexusStaging { + username = project.property('ossrhUsername') + password = project.property('ossrhPassword') + packageGroup = "org.xbib" + } +} diff --git a/gradle/repositories/maven.gradle b/gradle/repositories/maven.gradle new file mode 100644 index 0000000..ec58acb --- /dev/null +++ b/gradle/repositories/maven.gradle @@ -0,0 +1,4 @@ +repositories { + mavenLocal() + mavenCentral() +} diff --git a/gradle/test/junit5.gradle b/gradle/test/junit5.gradle new file mode 100644 index 0000000..4191db1 --- /dev/null +++ b/gradle/test/junit5.gradle @@ -0,0 +1,27 @@ + +def junitVersion = project.hasProperty('junit.version')?project.property('junit.version'):'5.7.2' +def hamcrestVersion = project.hasProperty('hamcrest.version')?project.property('hamcrest.version'):'2.2' + +dependencies { + testImplementation "org.junit.jupiter:junit-jupiter-api:${junitVersion}" + testImplementation "org.junit.jupiter:junit-jupiter-params:${junitVersion}" + testImplementation "org.hamcrest:hamcrest-library:${hamcrestVersion}" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}" +} + +test { + useJUnitPlatform() + failFast = true + testLogging { + events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED' + } + afterSuite { desc, result -> + if (!desc.parent) { + println "\nTest result: ${result.resultType}" + println "Test summary: ${result.testCount} tests, " + + "${result.successfulTestCount} succeeded, " + + "${result.failedTestCount} failed, " + + "${result.skippedTestCount} skipped" + } + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..33682bb --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..e4f5ffd --- /dev/null +++ b/settings.gradle @@ -0,0 +1,3 @@ +include 'gradle-plugin-git' +include 'gradle-plugin-rpm' +include 'gradle-plugin-docker'