diff --git a/buildSrc/.gitignore b/buildSrc/.gitignore new file mode 100644 index 0000000000..452be348b6 --- /dev/null +++ b/buildSrc/.gitignore @@ -0,0 +1,4 @@ +*.sw? +.gradle +build +!src/main/groovy/org/springframework/build diff --git a/buildSrc/README.md b/buildSrc/README.md new file mode 100644 index 0000000000..082f8de99e --- /dev/null +++ b/buildSrc/README.md @@ -0,0 +1,11 @@ +Welcome to the SpringSource *shared Gradle sources* project + +---- + +This project provides shared Gradle sources for automating Spring Project builds. + +For complete documentation, please visit the [project wiki](https://github.com/SpringSource/spring-build-gradle/wiki) + +Or clone the wiki and view it offline using [Gollum](https://github.com/github/gollum) + +`git clone git://github.com/SpringSource/spring-build-gradle.wiki.git` diff --git a/buildSrc/checks.gradle b/buildSrc/checks.gradle new file mode 100644 index 0000000000..38e92e1967 --- /dev/null +++ b/buildSrc/checks.gradle @@ -0,0 +1,90 @@ + +/* + * Copyright 2002-2010 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 + * + * 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. + */ + +/** + * Issue a snapshot dependency report across all Java projects. Detects not + * only direct snapshot dependencies, but transitive as well. + * + * @author Chris Beams + * @see snapshotDependencyCheck + */ +task snapshotDependencyReport { + description = 'Issues a snapshot dependency report across all Java projects' + + doFirst() { + def snapshotDependencies = new HashMap>() + + javaprojects.each { project -> + project.sourceSets.main.compileClasspath.allDependencies.each { dep -> + if (dep.version?.endsWith('SNAPSHOT')) { + if (snapshotDependencies[project] == null) + snapshotDependencies[project] = new ArrayList() + snapshotDependencies[project].add(dep) + } + } + } + + project.hasSnapshotDependencies = snapshotDependencies.size() > 0 + + if (project.hasSnapshotDependencies) { + println "The following snapshot dependencies were found:" + snapshotDependencies.each { entry -> + println "${entry.key} depends on:" + entry.value.each { dep -> + println " ${dep}" + } + } + } + } +} + + +/** + * Abort the build if any Java projects have snapshot dependencies. It important + * that any non-snapshot release be checked for snapshot dependencies before + * final publication, as snapshot dependencies may change and thus make the + * release unstable and/or unreproducable. + * + * This task will be added to the build lifecycle automatically if the release + * is non-snapshot. + * + * -PignoreSnapshotDependencies will bypass aborting the build. A use case for + * this option would be if a transitive dependency out of your control is a + * snapshot release and you wish to proceed with releasing anyway. + * + * @author Chris Beams + * @see snapshotDependencyReport + */ +task snapshotDependencyCheck(dependsOn: snapshotDependencyReport) { + group = 'Verification' + description = 'Aborts the build if any Java project has snapshot dependencies.' + + // bind to build lifecycle if we're a non-snapshot release + if (version.releaseType != 'SNAPSHOT') { + check.dependsOn snapshotDependencyCheck + } + + onlyIf { + project.hasSnapshotDependencies && + !project.hasProperty('ignoreSnapshotDependencies') + } + doFirst { + throw new GradleException( + "aborting '${name}' task due to snapshot dependencies. " + + "supply -PignoreSnapshotDependencies to override") + } +} diff --git a/buildSrc/dist.gradle b/buildSrc/dist.gradle new file mode 100644 index 0000000000..c2aadc91a0 --- /dev/null +++ b/buildSrc/dist.gradle @@ -0,0 +1,150 @@ +/* + * Copyright 2002-2010 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 + * + * 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. + */ + +// ----------------------------------------------------------------------------- +// Task definitions related to releasing the project +// +// @author Chris Beams +// ----------------------------------------------------------------------------- + +buildscript { + repositories { + mavenRepo urls: 'http://repository.springsource.com/maven/bundles/release' + } + dependencies { + classpath group: 'org.springframework.build', + name: 'org.springframework.build.aws.ant', + version: '3.0.3.RELEASE' + } +} + + +// ensure that every project has been evaluated before this script +// this allows us to look up tasks below and dereference dynamically +// assigned properties like 'docsSpec' below +project.subprojects.each { project -> + evaluationDependsOn project.path +} + +task check { + group = 'Verification' +} + +task build(dependsOn: [check, assemble]) { + group = 'Build' +} + +/** + * Build the distribution zip file. + * + * @author Chris Beams + */ +task distArchive(type: Zip) { + group = 'Build' + + destinationDir = buildDir + archiveName = "${project.name}-${project.version}.zip" + checksumPath = "${destinationDir}/${archiveName}.sha1" + def zipRootDir = "${project.name}-${project.version}" + + description = "Builds the distribution zip file at ${project.relativePath(destinationDir)}/${archiveName}" + + // depend on all projects with an assemble task + dependsOn subprojects*.tasks*.matching { task -> task.name == 'assemble' } + + // we need the docsSpec to be defined before evaluating this task + project.evaluationDependsOn(':docs') + + // set up outputs for use by incremental build and by tasks like 'cleanDist' + // the archive zip file will be added automatically to outputs.files + // but we must add the sha1 checksum ourselves + outputs.files file(checksumPath) + + // configure the contents of the zip file. remember that this is a + // configuration phase event. no zip is being created yet. the Zip + // task we extend will do that for us during the execution phase. + into(zipRootDir) { + // add all jars from java subprojects + into('bin') { + from javaprojects.collect { project -> project.libsBinDir } + } + + // add all source jars from java subprojects + into('src') { + from javaprojects.collect { project -> project.libsSrcDir } + } + + into('') { + from('docs/src/info') + } + + into("docs/api") { + from("docs/build/api") + } + + into("docs/reference") { + from("docs/build/reference") + } + } + + // once the zip has been written, create a sha1 hash for it + // this will write out the file at ${checksumPath} + doLast { + ant.checksum(file: archivePath, algorithm: 'SHA1', fileext: '.sha1') + assert file(checksumPath).isFile(): "${checksumPath} was not created" + } +} + +/** + * Upload the distribution zip file. + * + * @author Luke Taylor + * @author Chris Beams + */ +task uploadArchives(overwrite: true, dependsOn: distArchive) { // base plugin adds one we need to overwrite + group = 'Buildmaster' + description = 'Uploads the distribution zip file.' + + configurations { antlibs } + dependencies { + antlibs "org.springframework.build:org.springframework.build.aws.ant:3.0.3.RELEASE", + "net.java.dev.jets3t:jets3t:0.6.1" + } + + def releaseType = version.releaseType.toString().toLowerCase() + + doLast() { + println "Uploading: ${distArchive.archivePath} to s3" + project.ant { + taskdef(resource: 'org/springframework/build/aws/ant/antlib.xml', + classpath: configurations.antlibs.asPath) + s3(accessKey: s3AccessKey, secretKey: s3SecretAccessKey) { + upload(bucketName: 'dist.springframework.org', file: distArchive.archivePath, + toFile: releaseType + "/${rootProject.abbreviation}/${distArchive.archiveName}", publicRead: 'true') { + metadata(name: 'project.name', value: rootProject.description) + metadata(name: 'release.type', value: releaseType) + metadata(name: 'bundle.version', value: version) + metadata(name: 'package.file.name', value: distArchive.archiveName) + } + upload(bucketName: 'dist.springframework.org', file: "${distArchive.archivePath}.sha1", + toFile: releaseType + "/${rootProject.abbreviation}/${distArchive.archiveName}.sha1", publicRead: 'true') + } + } + } +} + + + diff --git a/buildSrc/docbook.gradle b/buildSrc/docbook.gradle new file mode 100644 index 0000000000..2ad4b55fef --- /dev/null +++ b/buildSrc/docbook.gradle @@ -0,0 +1,315 @@ +/* + * Copyright 2002-2010 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 + * + * 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. + */ +import org.xml.sax.XMLReader; +import org.xml.sax.InputSource; +import org.apache.xml.resolver.CatalogManager; +import org.apache.xml.resolver.tools.CatalogResolver; + +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.*; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import java.util.zip.*; + +import org.apache.fop.apps.*; + +import org.gradle.api.logging.LogLevel; + +import com.icl.saxon.TransformerFactoryImpl; +import ch.qos.logback.classic.Level; +import org.slf4j.LoggerFactory; + +buildscript { + repositories { + mavenCentral() + mavenRepo name: 'Shibboleth Repo', urls: 'http://shibboleth.internet2.edu/downloads/maven2' + } + dependencies { + def fopDeps = ['org.apache.xmlgraphics:fop:0.95-1@jar', + 'org.apache.xmlgraphics:xmlgraphics-commons:1.3', + 'org.apache.xmlgraphics:batik-bridge:1.7@jar', + 'org.apache.xmlgraphics:batik-util:1.7@jar', + 'org.apache.xmlgraphics:batik-css:1.7@jar', + 'org.apache.xmlgraphics:batik-dom:1.7', + 'org.apache.xmlgraphics:batik-svg-dom:1.7@jar', + 'org.apache.avalon.framework:avalon-framework-api:4.3.1'] + + classpath 'org.apache.xerces:resolver:2.9.1', + 'saxon:saxon:6.5.3', + 'org.apache.xerces:xercesImpl:2.9.1', + fopDeps, + 'net.sf.xslthl:xslthl:2.0.1', + 'net.sf.docbook:docbook-xsl:1.75.2:resources@zip' + } + +} + +/** + * Gradle Docbook plugin implementation. + *

+ * Creates three tasks: docbookHtml, docbookHtmlSingle and docbookPdf. + * Each task takes a single File on which it operates. + * + * @author Luke Taylor + */ +// Add the plugin tasks to the project +task docbookHtml(type: DocbookHtml) { + setDescription('Generates chunked docbook html output.') + xdir = 'html' + classpath = buildscript.configurations.classpath +} + +task docbookHtmlSingle(type: Docbook) { + setDescription('Generates single page docbook html output.') + xdir = 'htmlsingle' + classpath = buildscript.configurations.classpath +} + +task docbookPdf(type: DocbookFoPdf) { + setDescription('Generates PDF docbook output.') + extension = 'fo' + xdir = 'pdf' + classpath = buildscript.configurations.classpath +} + +/** + */ +public class Docbook extends DefaultTask { + @Input + String extension = 'html'; + + @Input + boolean XIncludeAware = true; + + @Input + boolean highlightingEnabled = true; + + String admonGraphicsPath; + + @InputDirectory + File sourceDirectory = new File(project.getProjectDir(), "build/reference-work"); + + @Input + String sourceFileName; + + @InputFile + File stylesheet; + + @OutputDirectory + File docsDir = new File(project.getBuildDir(), "reference"); + + @InputFiles + Configuration classpath + + @TaskAction + public final void transform() { + // the docbook tasks issue spurious content to the console. redirect to INFO level + // so it doesn't show up in the default log level of LIFECYCLE unless the user has + // run gradle with '-d' or '-i' switches -- in that case show them everything + switch (project.gradle.startParameter.logLevel) { + case LogLevel.DEBUG: + case LogLevel.INFO: + break; + default: + logging.captureStandardOutput(LogLevel.INFO) + logging.captureStandardError(LogLevel.INFO) + } + + SAXParserFactory factory = new org.apache.xerces.jaxp.SAXParserFactoryImpl(); + factory.setXIncludeAware(XIncludeAware); + docsDir.mkdirs(); + + File srcFile = new File(sourceDirectory, sourceFileName); + String outputFilename = srcFile.getName().substring(0, srcFile.getName().length() - 4) + '.' + extension; + + File oDir = new File(getDocsDir(), xdir) + File outputFile = new File(oDir, outputFilename); + + Result result = new StreamResult(outputFile.getAbsolutePath()); + CatalogResolver resolver = new CatalogResolver(createCatalogManager()); + InputSource inputSource = new InputSource(srcFile.getAbsolutePath()); + + XMLReader reader = factory.newSAXParser().getXMLReader(); + reader.setEntityResolver(resolver); + TransformerFactory transformerFactory = new TransformerFactoryImpl(); + transformerFactory.setURIResolver(resolver); + URL url = stylesheet.toURL(); + Source source = new StreamSource(url.openStream(), url.toExternalForm()); + Transformer transformer = transformerFactory.newTransformer(source); + + if (highlightingEnabled) { + File highlightingDir = new File(getProject().getBuildDir(), "highlighting"); + if (!highlightingDir.exists()) { + highlightingDir.mkdirs(); + extractHighlightFiles(highlightingDir); + } + + transformer.setParameter("highlight.source", "1"); + transformer.setParameter("highlight.xslthl.config", new File(highlightingDir, "xslthl-config.xml").toURI().toURL()); + + if (admonGraphicsPath != null) { + transformer.setParameter("admon.graphics", "1"); + transformer.setParameter("admon.graphics.path", admonGraphicsPath); + } + } + + preTransform(transformer, srcFile, outputFile); + + transformer.transform(new SAXSource(reader, inputSource), result); + + postTransform(outputFile); + } + + private void extractHighlightFiles(File toDir) { + File docbookZip = classpath.files.find { file -> file.name.contains('docbook-xsl-')}; + + if (docbookZip == null) { + throw new GradleException("Docbook zip file not found"); + } + + ZipFile zipFile = new ZipFile(docbookZip); + + Enumeration e = zipFile.entries(); + while (e.hasMoreElements()) { + ZipEntry ze = (ZipEntry) e.nextElement(); + if (ze.getName().matches(".*/highlighting/.*\\.xml")) { + String filename = ze.getName().substring(ze.getName().lastIndexOf("/highlighting/") + 14); + copyFile(zipFile.getInputStream(ze), new File(toDir, filename)); + } + } + } + + private void copyFile(InputStream source, File destFile) { + destFile.createNewFile(); + FileOutputStream to = null; + try { + to = new FileOutputStream(destFile); + byte[] buffer = new byte[4096]; + int bytesRead; + + while ((bytesRead = source.read(buffer)) > 0) { + to.write(buffer, 0, bytesRead); + } + } finally { + if (source != null) { + source.close(); + } + if (to != null) { + to.close(); + } + } + } + + protected void preTransform(Transformer transformer, File sourceFile, File outputFile) { + } + + protected void postTransform(File outputFile) { + } + + private CatalogManager createCatalogManager() { + CatalogManager manager = new CatalogManager(); + manager.setIgnoreMissingProperties(true); + ClassLoader classLoader = this.getClass().getClassLoader(); + StringBuilder builder = new StringBuilder(); + String docbookCatalogName = "docbook/catalog.xml"; + URL docbookCatalog = classLoader.getResource(docbookCatalogName); + + if (docbookCatalog == null) { + throw new IllegalStateException("Docbook catalog " + docbookCatalogName + " could not be found in " + classLoader); + } + + builder.append(docbookCatalog.toExternalForm()); + + Enumeration enumeration = classLoader.getResources("/catalog.xml"); + while (enumeration.hasMoreElements()) { + builder.append(';'); + URL resource = (URL) enumeration.nextElement(); + builder.append(resource.toExternalForm()); + } + String catalogFiles = builder.toString(); + manager.setCatalogFiles(catalogFiles); + return manager; + } +} + +/** + */ +class DocbookHtml extends Docbook { + + @Override + protected void preTransform(Transformer transformer, File sourceFile, File outputFile) { + String rootFilename = outputFile.getName(); + rootFilename = rootFilename.substring(0, rootFilename.lastIndexOf('.')); + transformer.setParameter("root.filename", rootFilename); + transformer.setParameter("base.dir", outputFile.getParent() + File.separator); + } +} + +/** + */ +class DocbookFoPdf extends Docbook { + + /** + * From the FOP usage guide + */ + @Override + protected void postTransform(File foFile) { + FopFactory fopFactory = FopFactory.newInstance(); + + OutputStream out = null; + final File pdfFile = getPdfOutputFile(foFile); + logger.debug("Transforming 'fo' file " + foFile + " to PDF: " + pdfFile); + + try { + out = new BufferedOutputStream(new FileOutputStream(pdfFile)); + + Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out); + + TransformerFactory factory = TransformerFactory.newInstance(); + Transformer transformer = factory.newTransformer(); + + Source src = new StreamSource(foFile); + + Result res = new SAXResult(fop.getDefaultHandler()); + + switch (project.gradle.startParameter.logLevel) { + case LogLevel.DEBUG: + case LogLevel.INFO: + break; + default: + // only show verbose fop output if the user has specified 'gradle -d' or 'gradle -i' + LoggerFactory.getILoggerFactory().getLogger('org.apache.fop').level = Level.ERROR + } + + transformer.transform(src, res); + + } finally { + if (out != null) { + out.close(); + } + } + + if (!foFile.delete()) { + logger.warn("Failed to delete 'fo' file " + foFile); + } + } + + private File getPdfOutputFile(File foFile) { + return new File(foFile.parent, this.project.rootProject.name + '-reference.pdf') + } +} diff --git a/buildSrc/docs.gradle b/buildSrc/docs.gradle new file mode 100644 index 0000000000..5402c2d6a5 --- /dev/null +++ b/buildSrc/docs.gradle @@ -0,0 +1,278 @@ +/* + * Copyright 2002-2010 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 + * + * 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. + */ + +apply plugin: 'base' +apply from: "$rootDir/buildSrc/docbook.gradle" +apply from: "$rootDir/buildSrc/preconditions.gradle" + +description = "${rootProject.description} Documentation" + +task build(dependsOn: assemble) { + group = 'Build' + description = 'Builds reference and API documentation and archives' +} + + +/** + * Build aggregated JavaDoc HTML for all core project classes. Result is + * suitable for packaging into a distribution zip or viewing directly with + * a browser. + * + * @author Chris Beams + * @author Luke Taylor + * @see http://gradle.org/0.9-rc-1/docs/javadoc/org/gradle/api/tasks/javadoc/Javadoc.html + */ + task api(type: Javadoc) { + group = 'Documentation' + description = "Builds aggregated JavaDoc HTML for all core project classes." + + // this task is a bit ugly to configure. it was a user contribution, and + // Hans tells me it's on the roadmap to redesign it. + srcDir = file("${projectDir}/src/api") + destinationDir = file("${buildDir}/api") + tmpDir = file("${buildDir}/api-work") + optionsFile = file("${tmpDir}/apidocs/javadoc.options") + options.stylesheetFile = file("${srcDir}/spring-javadoc.css") + options.links = ["http://static.springframework.org/spring/docs/3.0.x/javadoc-api"] + options.overview = "${srcDir}/overview.html" + options.docFilesSubDirs = true + title = "${rootProject.description} ${version} API" + + // collect all the sources that will be included in the javadoc output + source javaprojects.collect {project -> + project.sourceSets.main.allJava + } + + // collect all main classpaths to be able to resolve @see refs, etc. + // this collection also determines the set of projects that this + // task dependsOn, thus the runtimeClasspath is used to ensure all + // projects are included, not just *dependencies* of all classes. + // this is awkward and took me a while to figure out. + classpath = files(javaprojects.collect {project -> + project.sourceSets.main.runtimeClasspath + }) + + // copy the images from the doc-files dir over to the target + doLast { task -> + copy { + from file("${task.srcDir}/doc-files") + into file("${task.destinationDir}/doc-files") + } + } +} + +/** + * Expand ${...} variables within docbook sources. This is a workaround + * accomodating the fact that the current docbook plugin has no way of + * parameterizing and replacing normal XML entities. + * + * Note that this task represents an implementation detail and it is + * unfortunate that it pollutes the listing of available tasks, e.g. + * during `gradle -t`. It's a good example of the need for 'task visibility' - + * a feature not yet implemented, but on the Gradle roadmap. + * + * @author Chris Beams + * @see http://jira.codehaus.org/browse/GRADLE-1026 + */ +task preprocessDocbookSources { + description = 'Expands ${...} variables within docbook sources.' + + doLast { + docbookSrcDir = file('src/reference/docbook') + docbookResourceDir = file('src/reference/resources/') + docbookWorkDir = file('build/reference-work') + + // copy everything but index.xml + copy { + into(docbookWorkDir) + from(docbookSrcDir) { exclude '**/index.xml' } + } + copy { + into(docbookWorkDir) + from(docbookResourceDir) + } + // copy index.xml and expand ${...} variables along the way + // e.g.: ${version} needs to be replaced in the header + copy { + into(docbookWorkDir) + from(docbookSrcDir) { include '**/index.xml' } + expand(version: "$version") + } + } +} + +// ----------------------------------------------------------------------------- +// Configure the three docbook* tasks that are added to the project by the +// 'docbook' plugin. +// ----------------------------------------------------------------------------- +task reference(dependsOn: [docbookHtml, docbookHtmlSingle, docbookPdf]) { + group = 'Documentation' + description = 'Generates all HTML and PDF reference documentation.' + + doLast { + // copy images and css into respective html dirs + ['html', 'htmlsingle'].each { dir -> + copy { + into "${buildDir}/reference/${dir}/images" + from "src/reference/resources/images" + } + copy { + into "${buildDir}/reference/${dir}/css" + from "src/reference/resources/css" + } + } + } +} + +[docbookHtml, docbookPdf, docbookHtmlSingle]*.sourceFileName = 'index.xml'; +[docbookHtml, docbookHtmlSingle, docbookPdf]*.dependsOn preprocessDocbookSources + +docbookHtml.stylesheet = file('src/reference/resources/xsl/html-custom.xsl') +docbookHtmlSingle.stylesheet = file('src/reference/resources/xsl/html-single-custom.xsl') +docbookPdf.stylesheet = file('src/reference/resources/xsl/pdf-custom.xsl') +def imagesDir = file('src/reference/resources/images'); +docbookPdf.admonGraphicsPath = "${imagesDir}/admon/" + + +/** + * + * @see http://www.gradle.org/0.9-preview-3/docs/userguide/userguide_single.html#sec:copying_files + * @see http://www.gradle.org/0.9-preview-3/docs/javadoc/org/gradle/api/file/CopySpec.html + */ +docsSpec = copySpec { + into("${version}") { + from('src/info/changelog.txt') + } + + into("${version}/api") { + from(api.destinationDir) + } + + into("${version}/reference") { + from("${buildDir}/reference") + } +} + +task archive(type: Zip, dependsOn: [api, reference]) { + group = "Documentation" + description = "Creates a zip archive of reference and API documentation." + + baseName = rootProject.name + '-docs' + + // drop it right in the root of the build dir for simplicity + destinationDir = buildDir + + // use the copy spec above to specify the contents of the zip + with docsSpec +} + +configurations { archives } +artifacts { archives archive } + +configurations { scpAntTask } +dependencies { + scpAntTask("org.apache.ant:ant-jsch:1.8.1") +} + +checkForProps(taskPath: project.path + ':uploadArchives', requiredProps: ['sshHost', 'sshUsername', 'sshPrivateKey', 'remoteDocRoot']) + +if (role == 'buildmaster') { + uploadArchives { + def docsPath = "${rootProject.name}/docs" + def docsUrl = "http://${sshHost}/${docsPath}/${version}" + def remoteDocsDir = "${remoteDocRoot}/${docsPath}/" + def fqRemoteDir = "${sshUsername}@${sshHost}:${remoteDocsDir}" + + group = 'Buildmaster' + + description = "Uploads and unpacks documentation archive" + (sshHost ? " to ${docsUrl}" : ": Host is not specified") + + uploadDescriptor = false + + repositories { + add(new org.apache.ivy.plugins.resolver.SshResolver()) { + name = 'sshHost: ' + sshHost // used for debugging + host = sshHost + user = sshUsername + if (project.hasProperty('sshPrivateKey')) { + keyFile = sshPrivateKey as File + } + addArtifactPattern "${remoteDocsDir}/${archive.archiveName}" + } + } + + configurations { scpAntTask } + dependencies { scpAntTask 'org.apache.ant:ant-jsch:1.8.1' } + + doFirst { + println "Uploading: ${archive.archivePath} to ${fqRemoteDir}" + } + + doLast { + project.ant { + taskdef(name: 'sshexec', + classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec', + classpath: configurations.scpAntTask.asPath) + + // copy the archive, unpack it, then delete it + def unpackCommand = """ + cd ${remoteDocsDir} && + rm -rf ${version} && + unzip -qKo ${archive.archiveName} && + rm ${archive.archiveName} + """ + + def wildcardSymlinkCommand = """ + cd ${remoteDocsDir} && + if [ -e ${version.wildcardValue} ]; then + currentWildcard=`readlink ${version.wildcardValue}` + else + currentWildcard=-1 + fi && + if [[ ${version} > \$currentWildcard ]]; then + rm -f ${version.wildcardValue} && + ln -s ${version} ${version.wildcardValue} + fi + """ + + def latestGASymlinkCommand = """ + cd ${remoteDocsDir} && + if [ -e latest-ga ]; then + latestGa=`readlink latest-ga` + else + latestGa=-1 + fi && + if [[ ${version} > \$latestGa ]]; then + rm -f latest-ga && + ln -s ${version} latest-ga + fi + """ + + println "Unpacking docs archive: ${unpackCommand}" + sshexec(host: sshHost, username: sshUsername, keyfile: sshPrivateKey, command: unpackCommand) + if (version.releaseType != 'SNAPSHOT') { + println "Creating wildcard symlink: ${wildcardSymlinkCommand}" + sshexec(host: sshHost, username: sshUsername, keyfile: sshPrivateKey, command: wildcardSymlinkCommand) + } + if (version.releaseType == 'RELEASE') { + println "Creating latest-ga symlink: ${latestGASymlinkCommand}" + sshexec(host: sshHost, username: sshUsername, keyfile: sshPrivateKey, command: latestGASymlinkCommand) + } + println "UPLOAD SUCCESSFUL - validate by visiting ${docsUrl}" + } + } + } +} diff --git a/buildSrc/maven-deployment.gradle b/buildSrc/maven-deployment.gradle new file mode 100644 index 0000000000..ef8da58e31 --- /dev/null +++ b/buildSrc/maven-deployment.gradle @@ -0,0 +1,266 @@ +/* + * Copyright 2002-2010 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 + * + * 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. + */ + +// ----------------------------------------------------------------------------- +// Tasks related to deploying Maven artifacts. +// +// @author Chris Beams +// ----------------------------------------------------------------------------- + +// check that upload-related properties are defined and fail early if not +// these properties ('s3AccessKey', etc) should be defined in +// 'gradle.properties' in $HOME/.gradle/gradle.properties +apply from: "$rootDir/buildSrc/preconditions.gradle" +def requiredProps = ['mavenSyncRepoDir', 's3AccessKey', 's3SecretAccessKey'] +checkForProps(taskPath: project.path + ':uploadArchives', requiredProps: requiredProps) + +/** + * Builds a source jar artifact for all main java sources. + * + * @author Luke Taylor + */ +task sourceJar(type: Jar) { + description = 'Builds a source jar artifact suitable for maven deployment.' + classifier = 'sources' + from sourceSets.main.java +} +build.dependsOn sourceJar + +jar.destinationDir = project.libsBinDir +sourceJar.destinationDir = project.libsSrcDir + +// Add the source jar archive to the set of artifacts for this project. +// Note that the regular 'jar' archive is already added by default. +artifacts { + archives sourceJar +} + + +/** + * Deploy gradle-built artifacts to a remote maven repository. Overrides and + * further customizes the 'uploadArchives' task contributed by the 'maven' + * plugin. + * + * The repository that artifacts are deployed to is determined conditionally + * based on the release type of the project version. Snapshot builds will + * be deployed via s3 to the springframework maven snapshot repository; + * milestone builds will happen via s3 as well; release builds will be deployed + * to the local filesystem to be sync'd via sourceforge SVN and ultimately + * deployed to maven central. + * + * Gradle will generate Maven poms on-the-fly during the deployment process. + * This process is customized to add ASL license information, and for projects + * that have the erlangLicense property set to true, the Erlang License will be + * added to the pom as well. + * + * @author Chris Beams + * @see 'mavenSyncRepoDir' in gradle.properties + * @see 's3AccessKey' in gradle.properties + * @see 's3SecretAccessKey' in gradle.properties + * @see `gradle install` for deploying artifacts to the local .m2 cache + * @see http://maven.apache.org/guides/mini/guide-central-repository-upload.html + */ +uploadArchives { + group = 'Buildmaster' + description = "Does a maven deploy of archives artifacts to " // url appended below + + // add a configuration with a classpath that includes our s3 maven deployer + configurations { deployerJars } + dependencies { + deployerJars "org.springframework.build.aws:org.springframework.build.aws.maven:3.0.0.RELEASE" + } + + // bring up a deployer and push to the appropriate repo for this release type + // note that repository and snapshotRepository are the same - it doesn't matter + // if it is actually a BUILD-SNAPSHOT, the snapshotRepository will kick in, + // otherwise it is ignored. + repositories.mavenDeployer { deployer -> + def repositoryUrl = 's3://maven.springframework.org/' + version.releaseType.toString().toLowerCase() + + description += repositoryUrl + configuration = configurations.deployerJars + s3credentials = [userName: project.properties.s3AccessKey, + passphrase: project.properties.s3SecretAccessKey] + repository(url: repositoryUrl) { authentication(s3credentials) } + snapshotRepository(url: repositoryUrl) { authentication(s3credentials) } + + configurePom(deployer.pom) + } + + if (version.releaseType == 'RELEASE') { + // we're dealing with a GA release (RELEASE), so bring up a second + // maven deployer and deploy to the maven sync repository filesystem + // location. The SVN commit must be done manually after the build. + repositories.mavenDeployer { deployer -> + repository(url: "file://${project.properties.mavenSyncRepoDir}") + + configurePom(deployer.pom) + } + } +} + + +/** + * Install gradle-built artifacts to the local m2 maven cache. + * Further customizes the 'install' task contributed by the 'maven' plugin. + */ +install { + group = 'Build' + description = "Does a maven install of archives artifacts to local m2 cache" + + configurePom(repositories.mavenInstaller.pom) +} + + +/** + * Generate a Maven pom.xml for use at build time. Dependency information will + * be based on Gradle metadata for the project, and other customizations such + * as licensing information and source compatibility settings are configured + * within. + * + * @author Chris Beams + * @see http://gradle.org/0.9-preview-3/docs/userguide/userguide_single.html#pomBuilder + */ +task generatePom { + group = 'Build' + description = 'Generates a Maven POM file suitable for use in building the project' + + generatedPomFileName = "pom.xml" + + // ensure changes in the classpath trigger regeneration of poms + inputs.files(project.sourceSets.main.compileClasspath) + + // ensure version changes in gradle.properties trigger regeneration of poms + inputs.files(new File(project.rootProject.rootDir, Project.GRADLE_PROPERTIES)) + + // enable partial cleaning with `gradle cleanGeneratePom` + outputs.files(generatedPomFileName) + + doLast() { + // customize the pom creation process + p = pom { + project { + name = project.description + properties { + setProperty('project.build.sourceEncoding', 'UTF8') + } + build { + plugins { + plugin { + groupId = 'org.apache.maven.plugins' + artifactId = 'maven-compiler-plugin' + configuration { + source = '1.5' + target = '1.5' + } + } + plugin { + groupId = 'org.apache.maven.plugins' + artifactId = 'maven-surefire-plugin' + configuration { + includes { + include = '**/*Tests.java' + } + excludes { + exclude = '**/*Abstract*.java' + } + } + } + } + resources { + resource { + directory = 'src/main/java' + includes = ['**/*'] + excludes = ['**/*.java'] + } + resource { + directory = 'src/main/resources' + includes = ['**/*'] + } + } + testResources { + testResource { + directory = 'src/test/java' + includes = ['**/*'] + excludes = ['**/*.java'] + } + testResource { + directory = 'src/test/resources' + includes = ['**/*'] + } + } + } + } + } + + // customizing the artifact id is a special case that must be configured + // after the pom is fully configured, otherwise it'll be overwritten + p.whenConfigured { pom -> pom.artifactId = project.name } + + configurePom(p) + + // write the pom.xml file out to the filesystem + p.writeTo(generatedPomFileName) + } + + // ensure that pom generation happens every time resources are processed + // (which practically means any time a build happens). if the dependencies + // for the project have been updated (in $rootDir/build.gradle), the pom + // will have diffs in it and the developer will be reminded to check in + // the change during the next commit cycle. + //processResources.dependsOn generatePom +} + + +/** + * Read dynamic 'optional' and 'provided' properties from gradle dependencies + * and translate them to their maven POM equivalents. + */ +def configurePom(def pom) { + pom.whenConfigured { generatedPom -> + def optionalDeps = configurations.testRuntime.allDependencies.findAll { gradleDep -> + gradleDep.asDynamicObject.hasProperty('optional') && gradleDep.optional + } + def providedDeps = configurations.testRuntime.allDependencies.findAll { gradleDep -> + gradleDep.asDynamicObject.hasProperty('provided') && gradleDep.provided + } + generatedPom.dependencies.each { mavenDep -> + mavenDep.optional = optionalDeps.any { optionalDep -> + optionalDep.group == mavenDep.groupId && + optionalDep.name == mavenDep.artifactId && + optionalDep.version == mavenDep.version + } + boolean isProvided = providedDeps.any { providedDep -> + providedDep.group == mavenDep.groupId && + providedDep.name == mavenDep.artifactId && + providedDep.version == mavenDep.version + } + if (isProvided) { + mavenDep.scope = 'provided' + } + } + } + + pom.project { + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution 'repo' + } + } + } +} diff --git a/buildSrc/maven-root-pom.gradle b/buildSrc/maven-root-pom.gradle new file mode 100644 index 0000000000..0658e46e3a --- /dev/null +++ b/buildSrc/maven-root-pom.gradle @@ -0,0 +1,65 @@ + +/* + * Copyright 2002-2010 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 + * + * 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. + */ + +/** + * Generate a root Maven pom.xml for use at build time. Contains nothing other + * than a 'modules' section aggregating child projects. This pom will never be + * installed locally or deployed remotely. Child projects will not explicitly + * declare this pom as their parent, given than nothing need be inherited from + * it. + * + * @author Chris Beams + * @see maven-deployment.gradle for per-project generatePom task + */ +task generatePom { + apply plugin: 'maven' + group = 'Build' + description = 'Generates a root Maven pom for convenience.' + + generatedPomFileName = "pom.xml" + + // ensure version changes in gradle.properties trigger regeneration of root pom + inputs.files(new File(project.rootProject.rootDir, Project.GRADLE_PROPERTIES)) + + // enable partial cleaning with `gradle cleanGeneratePom` + outputs.files(generatedPomFileName) + + doLast() { + // customize the pom creation process + p = pom { + project { + name = project.description + packaging = 'pom' + modules = javaprojects.collect { project -> project.name } + } + } + + // customizing the artifact id is a special case that must be configured + // after the pom is fully configured, otherwise it'll be overwritten + p.whenConfigured { pom -> pom.artifactId = project.name } + + // write the pom.xml file out to the filesystem + p.writeTo(generatedPomFileName) + } + + // ensure that pom generation happens every time resources are processed + // (which practically means any time a build happens). if the dependencies + // for the project have been updated (in $rootDir/build.gradle), the pom + // will have diffs in it and the developer will be reminded to check in + // the change during the next commit cycle. + //processResources.dependsOn generatePom +} diff --git a/buildSrc/preconditions.gradle b/buildSrc/preconditions.gradle new file mode 100644 index 0000000000..e5f0b0fa34 --- /dev/null +++ b/buildSrc/preconditions.gradle @@ -0,0 +1,19 @@ + +def requiredPropSets = [] + +gradle.taskGraph.whenReady { graph -> + requiredPropSets.each { args -> + if (graph.hasTask(args.taskPath)) { + def missingProps = args.requiredProps.findAll { prop -> + !project.hasProperty(prop) + } + if (missingProps) { + throw new GradleException("For executing the ${args.taskPath} task you need to set all ${missingProps} properties") + } + } + } +} +project.checkForProps = { Map args -> + requiredPropSets.add args +} + diff --git a/buildSrc/schema-publication.gradle b/buildSrc/schema-publication.gradle new file mode 100644 index 0000000000..f0483f8759 --- /dev/null +++ b/buildSrc/schema-publication.gradle @@ -0,0 +1,63 @@ +apply from: "$rootDir/buildSrc/preconditions.gradle" + +checkForProps(taskPath: project.path + ':publishSchema', + requiredProps: ['sshHost', 'sshUsername', 'sshPrivateKey', 'remoteDocRoot']) + +configurations { scpAntTask } +dependencies { scpAntTask("org.apache.ant:ant-jsch:1.8.1") } + +/** + * @author Chris Beams + */ +task publishSchema << { + def props = new Properties() + def file = new File("${projectDir}/src/main/resources/META-INF/spring.schemas") + if (file.exists()) { + file.withInputStream { + stream -> props.load(stream) + } + } + + if (!props.size()) { + return + } + + project.ant { + taskdef(name: 'scp', + classname: 'org.apache.tools.ant.taskdefs.optional.ssh.Scp', + classpath: configurations.scpAntTask.asPath) + taskdef(name: 'sshexec', + classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec', + classpath: configurations.scpAntTask.asPath) + + for (def key : props.keySet()) { + // process only explicitly-versioned entries in the file + // we'll deal with symlinking to the latest released version + // later below + // e.g.: + // spring-integration-2.0.xsd + // but not: + // spring-integration.xsd + if (key =~ /\d\.xsd/) { + // key entries are formatted as http://www.springframework.org/schema/... + // strip the protocol and domain, leaving just the path from 'schema' on + def remotePath = key.substring(key.indexOf('schema/')) + sshexec(keyfile: sshPrivateKey, + host: sshHost, + username: sshUsername, + command: "mkdir -p `dirname ${remoteDocRoot}/${remotePath}`") + scp(keyfile: sshPrivateKey, + file: "src/main/resources/${props.get(key)}", + todir: "${sshUsername}@${sshHost}:${remoteDocRoot}/${remotePath}") + } + } + } + + /* + def firstKey = props.keySet().iterator().next() + def path = firstKey.substring(firstKey.indexOf('schema/')) + def symlinkPath = (path =~ /-\d\.\d/).replaceFirst('') + + println "sshexec ln -s wtf ${symlinkPath}" + */ +} diff --git a/buildSrc/src/main/groovy/org/springframework/build/Version.groovy b/buildSrc/src/main/groovy/org/springframework/build/Version.groovy new file mode 100644 index 0000000000..e021592920 --- /dev/null +++ b/buildSrc/src/main/groovy/org/springframework/build/Version.groovy @@ -0,0 +1,81 @@ +/* + * Copyright 2002-2010 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 + * + * 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. + */ + +package org.springframework.build + +import org.gradle.api.InvalidUserDataException + + +class Version { + /** + * Indicates whether a version is a release, milestone, or snapshot + */ + static final String RELEASE = 'RELEASE' + static final String MILESTONE = 'MILESTONE' + static final String SNAPSHOT = 'SNAPSHOT' + + String value + String releaseType + int majorVersion + int minorVersion + + /** + * @param dotted -quad version spec, e.g.: 1.0.0.RELEASE + */ + public Version(String value) { + this.value = value; + this.releaseType = releaseTypeFor(value); + this.majorVersion = Integer.parseInt(this.value.substring(0, this.value.indexOf('.'))); + String afterMajor = this.value.substring(this.value.indexOf('.') + 1); + this.minorVersion = Integer.parseInt(afterMajor.substring(0, afterMajor.indexOf('.'))); + } + + public int getMajorVersion() { + return this.majorVersion; + } + + public int getMinorVersion() { + return this.minorVersion + } + + /** + * @return 1.0.x style + */ + public String getWildcardValue() { + return majorVersion + '.' + minorVersion + '.x'; + } + + /** + * @return the version string returned by {@link getValue ( )} + */ + public String toString() { + return this.getValue(); + } + + /** + * @param dotted -quad version spec, e.g.: 1.0.0.RELEASE + */ + public static String releaseTypeFor(String version) { + if (version.endsWith("RELEASE")) return RELEASE; + if (version.endsWith("SNAPSHOT")) return SNAPSHOT; + if (version.matches(".*\\.M[0-9]+\$")) return MILESTONE; + if (version.matches(".*\\.RC[0-9]+\$")) return MILESTONE; + + throw new InvalidUserDataException("unknown version scheme: " + + "versions must end in (SNAPSHOT|M[0-9]+|RC[0-9]+|RELEASE), " + + "but got (" + version + ")"); + } +} diff --git a/buildSrc/src/main/groovy/org/springframework/build/bundlor/BundlorPlugin.groovy b/buildSrc/src/main/groovy/org/springframework/build/bundlor/BundlorPlugin.groovy new file mode 100644 index 0000000000..f385bf1f67 --- /dev/null +++ b/buildSrc/src/main/groovy/org/springframework/build/bundlor/BundlorPlugin.groovy @@ -0,0 +1,125 @@ +/* + * Copyright 2002-2010 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 + * + * 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. + */ + +package org.springframework.build.bundlor + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.plugins.JavaPlugin +import org.gradle.api.logging.LogLevel + + +/** + * Contribute a 'bundlor' task capable of creating an OSGi manifest. Task is tied + * to the lifecycle by having the 'jar' task depend on 'bundlor'. Applies the 'java' + * plugin to the project if it has not already been applied. + * + * @author Chris Beams + * @author Luke Taylor + * @see http://www.springsource.org/bundlor + * @see http://static.springsource.org/s2-bundlor/1.0.x/user-guide/html/ch04s02.html + */ +public class BundlorPlugin implements Plugin { + + public void apply(Project project) { + // bundlor plugin functionality only makes sense for java projects + // if the java plugin is already applied, the following is a no-op + project.getPlugins().apply(JavaPlugin.class) + + // configuration that will be used when creating the ant taskdef classpath + project.configurations { bundlorconf } + project.dependencies { + bundlorconf 'com.springsource.bundlor:com.springsource.bundlor.ant:1.0.0.RELEASE', + 'com.springsource.bundlor:com.springsource.bundlor:1.0.0.RELEASE', + 'com.springsource.bundlor:com.springsource.bundlor.blint:1.0.0.RELEASE' + } + + project.tasks.add("bundlor") { + dependsOn project.compileJava + description = 'Generates an OSGi-compatibile MANIFEST.MF file.' + + /* TODO + // prescriptive defaults + bundleName = project.description + bundleVersion = project.version + bundleVendor = 'SpringSource' + //TODO bundleSymbolicName = project.basePackage + bundleSymbolicName = 'replace-me-with-base-package' + bundleManifestVersion = '2' + */ + + def template = new File(project.projectDir, 'template.mf') + def bundlorDir = new File("${project.buildDir}/bundlor") + def manifest = new File("${bundlorDir}/META-INF/MANIFEST.MF") + + // inform gradle what directory this task writes so that + // it can be removed when issuing `gradle cleanBundlor` + outputs.dir bundlorDir + + // incremental build configuration + // if the manifest output file already exists, the bundlor + // task will be skipped *unless* any of the following are true + // * template.mf has been changed + // * main classpath dependencies have been changed + // * main java sources for this project have been modified + outputs.files manifest + inputs.files template, project.sourceSets.main.runtimeClasspath + + // the bundlor manifest should be evaluated as part of the jar task's + // incremental build + project.jar { + dependsOn 'bundlor' + inputs.files manifest + } + + project.jar.manifest.from manifest + + doFirst { + project.ant.taskdef( + resource: 'com/springsource/bundlor/ant/antlib.xml', + classpath: project.configurations.bundlorconf.asPath) + + // the bundlor ant task writes directly to standard out + // redirect it to INFO level logging, which gradle will + // deal with gracefully + logging.captureStandardOutput(LogLevel.INFO) + + // TODO tell the jar task to use bundlor manifest instead of the default + // and customize it with all common headers + //project.jar.manifest { + //from manifest + //attributes['Bundle-SymbolicName'] = bundleSymbolicName + //attributes['Bundle-Name'] = bundleName + //attributes['Bundle-Vendor'] = bundleVendor + //attributes['Bundle-Version'] = bundleVersion + //attributes['Bundle-ManifestVersion'] = bundleManifestVersion + //} + + // the ant task will throw unless this dir exists + if (!bundlorDir.isDirectory()) + bundlorDir.mkdir() + + // execute the ant task, and write out the manifest file + project.ant.bundlor( + inputPath: project.sourceSets.main.classesDir, + outputPath: bundlorDir, + manifestTemplatePath: template) { + property(name: 'version', value: project.version) + } + } + } + } +} diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/bundlor.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/bundlor.properties new file mode 100644 index 0000000000..4a1b85d2ad --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/bundlor.properties @@ -0,0 +1 @@ +implementation-class=org.springframework.build.bundlor.BundlorPlugin diff --git a/buildSrc/wrapper.gradle b/buildSrc/wrapper.gradle new file mode 100644 index 0000000000..0abbb5ea3e --- /dev/null +++ b/buildSrc/wrapper.gradle @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2010 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 + * + * 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. + */ + +/** + * Generate gradlew and gradlew.bat scripts and associated files. These + * convenience scripts allow users to operate the build without being forced to + * download and install gradle. + * + * @author Chris Beams + * @see http://gradle.org/0.9.1/docs/userguide/userguide_single.html#gradle_wrapper + */ +task wrapper(type: Wrapper) { + group = 'Buildmaster' + description = "Generates gradlew and gradlew.bat bootstrap scripts" + gradleVersion = '0.9.2' + urlRoot='http://gradle.artifactoryonline.com/gradle/distributions' + // place jar file and properties into a + // subdirectory to avoid root dir clutter + jarPath = 'buildSrc/wrapper' +} diff --git a/buildSrc/wrapper/gradle-wrapper.jar b/buildSrc/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..8acea11e61 Binary files /dev/null and b/buildSrc/wrapper/gradle-wrapper.jar differ diff --git a/buildSrc/wrapper/gradle-wrapper.properties b/buildSrc/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..9485c578ee --- /dev/null +++ b/buildSrc/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Jan 24 12:08:02 ICT 2011 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=http\://gradle.artifactoryonline.com/gradle/distributions/gradle-0.9.2-bin.zip